転職したらスマレジだった件

スマレジのエンジニアやまてのテックブログです。マジレス大歓迎です。

独学エンジニアの課題として、ログ解析システムを作った。 Step5. プログラムからのSQLの操作①

こんにちは!

スマレジ・テックファーム の Webエンジニア やまて と申します。

はじめに

「独学エンジニアの課題として、ログ解析システムを作った。」というタイトルで、課題の製作物完成までの道のりを投稿しています。

GitHub の Public リポジトリで閲覧できるようにしています。

github.com

独学エンジニア とは

『独学エンジニア』とは、Web開発(主にサーバーサイド)の動画学習教材です。

dokugaku-engineer.com

連載の目次

「独学エンジニアの課題として、ログ解析システムを作った。」の連載については、以下の順に投稿しています。

ryamate.hatenablog.com

今回は Step5. プログラムからのSQLの操作① です。

作成する予定の以下の 2 つの取得機能のうち、今回は 1 について作成します。

  1. 最もビュー数の多い記事
  2. 指定したドメインコードの人気順

目次

環境

バージョン
macOS Big Sur 11.6
Docker Desktop 4.7.0
PHP 8.1.7
MySQL 8.0.28

インポートしたデータ形式の確認

domain_code page_title count_views total_response_size
ドメインコード ページタイトル 各時間のページ表示回数 合計レスポンスサイズ
aa Main_Page 4 0
aa Wikipedia 1 0

1. 処理の流れの確認

最もビュー数の多い記事を、指定した記事数分だけビュー数が多い順にソートし、ドメインコードとページタイトル、ビュー数を提示する

という要件を満たすため、以下の流れで処理します。

  1. 入力値の受け取り
  2. 入力値のバリデーション(正の整数かどうか)
  3. SELECT 文の実行
    • Step4 で作成した SQL をプログラムから実行するように、 PHP ファイルを作成します。
  4. 結果の表示

2. ファイルの作成・編集

以下の 3 ファイルを作成して、編集します。

lib/sql.php、lib/validation.php については、プログラム間で共通化します。

2-1. most_viewed_pages.php作成・編集

呼び出して処理を実行するプログラムを作成・編集します。

<?php

require_once 'lib/sql.php';
require_once 'lib/validation.php';

const NO_ARG = 1;
const DEFAULT_NUM_OF_SEARCH = 10;

// 1. 入力値の受け取り
if ($_SERVER['argc'] === NO_ARG) {
    $input = DEFAULT_NUM_OF_SEARCH;
} else {
    $input = $_SERVER['argv'][1];
}

// 2. 入力値のバリデーション(正の整数かどうか)
$error = validationInputOfMostViewedPages($input);

// 数字以外→エラーメッセージ
if (!empty($error)) {
    echo $error;
} else {
    // 3. SELECT文の実行
    $data = getMostViewedPages($input);

    // 4. 結果の表示
    foreach ($data as $record) {
        echo '"' . $record['domain_code'] . '", "' . $record['page_title'] . '", ' . $record['count_views'] . PHP_EOL;
    }
}

検索件数を設定しなかった場合、 10 件をデフォルト値としておきます。

2-2. lib/sql.php作成・編集

下記2つのメソッドを書きます。

  • PDO でのMySQL への接続
  • SQL 実行
<?php

/**
 * DB接続
 *
 * @return PDO
 */
function dbConnect(): PDO
{
    $dbHost = 'db';
    $dbUsername = 'test_user';
    $dbPassword = 'pass';
    $dbDatabase = 'test_database';
    $dataSourceName = "mysql:host=$dbHost;dbname=$dbDatabase;charset=utf8mb4";

    try {
        $dbh = new PDO($dataSourceName, $dbUsername, $dbPassword, [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        ]);
    } catch (PDOException $e) {
        echo 'DB接続エラー' . $e->getMessage();
        exit();
    };

    return $dbh;
}

/**
 * 最もビュー数の多い記事を、指定した記事数分だけビュー数が多い順にソートし、ドメインコードとページタイトル、ビュー数を取得する。
 *
 * @param string $input コマンドラインで受け取った入力値 ex. 10
 * @return array $results ex. [ 0 => ['domain_code' => 'en.m', 'page_title' => 'Main_Page', 'count_views' => 122058],...
 */
function getMostViewedPages(string $input): array
{
    $sql = <<<SQL
        SELECT
            domain_code,
            page_title,
            count_views
        FROM
            page_views
        ORDER BY
            count_views DESC
        LIMIT
            :input
        ;
        SQL;

    $dbh = dbConnect(); // DB接続
    $stmt = $dbh->prepare($sql); // 実行準備
    $stmt->bindValue(':input', (int)$input, PDO::PARAM_INT);
    $stmt->execute();
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
    $dbh = null; // DB切断
    return $results;
}

PDO::FETCH_ASSOC: は、結果セットに 返された際のカラム名で添字を付けた配列を返します。

(引用:PHP: PDOStatement::fetch - Manual

$results の中身は、例えば以下のような配列です。

array (
  0 => 
  array (
    'domain_code' => 'en.m',
    'page_title' => 'Main_Page',
    'count_views' => 122058,
  ),
  1 => 
  array (
    'domain_code' => 'en',
    'page_title' => 'Main_Page',
    'count_views' => 69181,
  ),
)

2-3. lib/validation.php の作成・編集

コマンドラインでの入力値をバリデーションするメソッドを書きます。

<?php

require_once 'lib/sql.php';

/**
 * most_viewed_pages.php のコマンドラインでの入力値をバリデーションする。
 *
 * @param string $input コマンドラインで受け取った入力値 ex. 10
 * @return string $error
 */
function validationInputOfMostViewedPages(string $input): string
{
    $error = '';
    if (((int)$input < 0) || !preg_match('/^-?[0-9]+$/', $input)) {
        $error = '1 以上の整数を入力してください。' . PHP_EOL;
    }
    return $error;
}

3. プログラムの使い方

下記コマンドを実行します。

docker compose exec app php most_viewed_pages.php 20

コマンド実行例❶

most_viewed_pages.php の後に半角スペースを開けて、指定するページ数を入力します。

# r_yamate @ mbp in ~/Documents/code/wikipedia-log-analysis-tool on git:feature/create-program x [7:25:16]
$ docker compose exec app php most_viewed_pages.php 20
"en.m", "Main_Page", 122058
"en", "Main_Page", 69181
"en", "Special:Search", 26630
"de", "Wikipedia:Hauptseite", 20739
"en.m", "Special:Search", 19119
"ja", "メインページ", 18475
"es.m", "Wikipedia:Portada", 15335
"es", "Wikipedia:Portada", 15261
"fr", "Wikipédia:Accueil_principal", 14744
"thankyou", "Thank_You/en", 13449
"ru", "Заглавная_страница", 13336
"en", "Lotfi_A._Zadeh", 12864
"it", "Pagina_principale", 12731
"zh", "Wikipedia:首页", 10782
"pt", "Wikipédia:Página_principal", 10485
"de.m", "Wikipedia:Hauptseite", 10386
"ja.m", "メインページ", 9421
"en", "Bible", 9024
"fr.m", "Wikipédia:Accueil_principal", 8705
"en", "-", 7227

コマンド実行例❷

検索件数を指定しなかった場合、 10 件表示されます。

# r_yamate @ mbp in ~/Documents/code/wikipedia-log-analysis-tool on git:feature/create-program x [7:28:44]
$ docker compose exec app php most_viewed_pages.php
"en.m", "Main_Page", 122058
"en", "Main_Page", 69181
"en", "Special:Search", 26630
"de", "Wikipedia:Hauptseite", 20739
"en.m", "Special:Search", 19119
"ja", "メインページ", 18475
"es.m", "Wikipedia:Portada", 15335
"es", "Wikipedia:Portada", 15261
"fr", "Wikipédia:Accueil_principal", 14744
"thankyou", "Thank_You/en", 13449

コマンド実行例❸

バリデーションエラーの場合、エラーメッセージが表示されます。

# r_yamate @ mbp in ~/Documents/code/wikipedia-log-analysis-tool on git:feature/create-program x [7:29:36]
$ docker compose exec app php most_viewed_pages.php a
1 以上の整数を入力してください。

おわりに

今回は「独学エンジニアの課題として、ログ解析システムを作った。」の Step5. プログラムからのSQLの操作① でした。

次回は、Step6. プログラムからのSQLの操作② について投稿します。

ありがとうございました。



息子5歳がママの料理の手伝いをするのが好きで作ってくれたおにぎり。