著者アーカイブ 杉浦

著者:杉浦

【Laravel】factory自動生成ツールlaravel-test-factory-helperの紹介

mpociot/laravel-test-factory-helper: Generate Laravel test factories from your existing models
 Laravelにはfactoryという機能があります。
データベースのテスト 5.5 Laravel#ファクトリの記述
 次の様にfactoryをdatabase/factories/以下に定義し、

use Faker\Generator as Faker;

$factory->define(App\User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
        'remember_token' => str_random(10),
    ];
});
// <a href="https://readouble.com/laravel/5.5/ja/database-testing.html#writing-factories">データベースのテスト 5.5 Laravel#ファクトリの記述</a>より引用

 次の様に呼び出すことでデータを生成し、モデルに代入された状態で使用できます。

public function testDatabase()
{
    $user = factory(App\User::class)->make();

    // モデルをテストで使用…
}

 ダミーの値はfakerというライブラリで生成します。
stympy/faker: A library for generating fake data such as names, addresses, and phone numbers.
 有用なライブラリなのですが様々な値生成方法を選べるためfactoryの定義にも悩みがちです。laravel-test-factory-helperはfactoryを自動生成します。

composer require mpociot/laravel-test-factory-helper

とcomposerで導入。

php artisan test-factory-helper:generate

とartisanを実行。するとモデル定義に従ってデータベースから値を取得、適した型のfakerをつけたfactoryをモデル分全て生成します。

著者:杉浦

逸脱の標準化、裏マニュアル、割れ窓理論とソースコードの品質検査の自動実行

 逸脱の標準化はチャレンジャー号爆発事故 – Wikipedia、裏マニュアルは東海村JCO臨界事故 – Wikipedia、あたりを端に発する、規則を守らないことが当然になっている様を指す言葉です。この手の話は大体安全マージンをとってある規則に従った手順を無視して、ぎりぎり異常の起きない(あるいは徐々に進行する異常)手順を実行してしまい、ちょっとしたアクシデントで致命的に壊れる、という結になります。
 割れ窓理論は次の様な悪しき行いでも放置され続けると増大し続ける、という理論です。

建物の窓が壊れているのを放置すると、誰も注意を払っていないという象徴になり、やがて他の窓もまもなく全て壊される

割れ窓理論 – Wikipedia

 上記二点から考えられるのは、ほんの少し危険な行為であっても即座直し続けなければとてもひどいことになる、ということです。 コーディングにおいてそういった危険行為を発見するための方法にLintやテストがあります。Lintとはソースコード検査プログラムのことであり、曖昧な処理、誤った意図で行われやすい記述、読み取り難い記述などを検出します。
 コーディングにおける危険行為を直し続けるにはLint、テストなどといったソースコードの品質検査を行い続ける必要があります。しかし手作業でこれを行い続けるのは現実的でありません。何度も同じ作業を行うことは退屈であり、コードを作ったり改造したりする時間の方をより多く取りたくなるものでソースコードの品質検査には多くの時間を割けません。上手く働く自動実行はこの時間と品質のトレードオフ問題を解決します。
 自動実行実現のための方針は、Lint、テストなどの作業を全てコードに起こし、gitにコミットする度の様なタイミングで自動実行させるようにする、というものです。仮に完成するコードが等しいものとした場合

検査用の仕組みの導入、作成にかかる時間 + 自動実行している間に手が止まる時間 < 繰り返し手作業で検査する時間

となる場合、お得です。最初は検査用コードを作るのに時間がかかりますが異なるプロジェクトであっても似たものを書くことが多い為、どんどん慣れて早くなります。またバグると致命的な部分、バグりやすい部分がわかってくるとテストの分量を調整できるようになり、検査の仕組みを余分に用意しにくくなります。
 今時のIDEにはgit hookや検査用ツールへのショートカットがありますので、小さな単一のツールから順々に備えていき、大きくしていくのがよいと思います。

著者:杉浦

エッセイ集「プログラマが知るべき97のこと」の紹介

 プログラマが知るべき97のこと
「プログラマが知るべき97のこと」はプログラマの様々な意見がまとまった文章の集まりです。元々は本であり、上記リンクはそれのエッセイ集の部分を抜き出したのだと思います。初版は2010年ですが特定の言語に依らないような内容が集まっており、今でも通用します。例えば、一つ目のエッセイ分別のある行動 | プログラマが知るべき97のことでは、その場しのぎの乱雑なコードをいかに早いうちに読みやすく扱いやすいコードに直すべきか、について述べられています。
 プログラマが知るべき97のことで述べられている話はマネジメントからコーディングまで多岐に渡る面白話でもあり、身につまされる話でもあります。

著者:杉浦

【Laravel】LaravelでDataTables.jsを楽に使うためのパッケージlaratablesの紹介

 freshbitsweb/laratables: Ajax support of DataTables (Laravel 5.5 – Laravel 5.8) Demo @
 JavaScriptにはDataTables.jsというリッチな表を簡単に作成するライブラリがあります。

DataTables | Table plug-in for jQuery

お手軽に機能付きテーブルを作るJavaScriptライブラリDataTables – 株式会社シーポイントラボ | 浜松のシステム開発会社
 DataTables.jsの基本的な使い方は、あらかじめHTMLコード上にtableタグで値を埋め込んで置き、DataTables.jsを適用して並び替え機能、絞り込み機能、ページネーション機能をつける、です。これは本当に1時間もかからずにリッチな表を作れる様なシンプルないい造りのライブラリなのですが問題がありました。それはあらかじめHTMLに埋め込む以上、初期読み込みにとても時間がかかりやすい点です。常に総数の実体をブラウザの初期段階で取得する必要があるため、総数が万件ある様なデータを対象にすると長い読み込み時間や崩れたデザインが現れだします。
 この問題を解決するには、ajaxを用いて適宜必要なデータのみを取得する基本的でない使い方をするのが良い方法です。しかしこの場合、サーバ側でDataTables.jsの提供するインタフェースに合わせたデータ処理のロジックを作る必要がでてきます。せっかく楽できるライブラリであったのに残念なことです。laratablesはこのDataTables.js用のロジックをLaravel内で簡単に記述するためのパッケージです。
 使い方は簡単。composerでプロジェクトに追加して、

composer require freshbitsweb/laratables

 Bladeに次の様にHTMLにテーブルのヘッダ、DataTablesにajaxの宛先と取得データのプロパティ名を記述、

<table id="simple-datatable-example" class="display" style="width:100%">
    <thead>
        <tr>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Mobile</th>
            <th>Email</th>
            <th>Gender</th>
            <th>Country</th>
        </tr>
    </thead>
</table>

@push('scripts')
    <script>
        $(document).ready(function() {
            $('#simple-datatable-example').DataTable({
                serverSide: true,
                processing: true,
                responsive: true,
                ajax: "{{ route('simple_datatables_users_data') }}",
                columns: [
                    { name: 'first_name' },
                    { name: 'last_name' },
                    { name: 'mobile' },
                    { name: 'email' },
                    { name: 'gender' },
                    { name: 'country' }
                ],
            });
        });
    </script>
@endpush

 ajax宛先のコントローラに次の様にLaratables::recordsOf();を検索対象のモデルクラスを呼ぶだけです。

    /**
     * return data of the simple datatables.
     *
     * @return Json
     */
    public function getSimpleDatatablesData()
    {
        return Laratables::recordsOf(User::class);
    }

 これだけで次のデモページの一部、Simpleのテーブルの完成です。

Laratables
 デモページにある様に、データに無関係なカラム、データの格納されたテーブルに関連したテーブルのデータも使えます。全てを把握できていませんがgithubの説明の文量からしてDataTablesそのものより多機能そうです。

freshbitsweb/laratables: Ajax support of DataTables (Laravel 5.5 – Laravel 5.8) Demo @

著者:杉浦

【Laravel】マイグレーションで扱うカラムにつける属性メソッドの読み取り

 Laravelにはデータベース定義を記述し、作成、ロールバックなどを行えるマイグレーション機能があります。このマイグレーションによるテーブル定義時にはカラムの属性を定義することが出来ます。
データベース:マイグレーション 5.5 Laravel#カラム修飾子
 例えば次です。

Schema::table('users', function (Blueprint $table) {
    $table->string('email')->nullable();
});
<a href="https://readouble.com/laravel/5.5/ja/migrations.html#column-modifiers">データベース:マイグレーション 5.5 Laravel#カラム修飾子</a>より引用

 これでメソッドnullableの動作によりカラムemailはnullを許すカラムになります。しかしnullable()メソッドの実態を見つけることは少し苦労を要します。
 素晴らしいide_helper(皮肉でなく本当にすごく便利)を生成する
barryvdh/laravel-ide-helper: Laravel IDE Helper
 を用いても、IDEはこのnullableへの道を見つけることが出来ません。
 これはメソッドnullrableが接続先のDBの種類によって動的に生成されているメソッドであるためです。
PHP: オーバーロード – Manual#メソッドのオーバーロード
 具体的に何が起きているかがわかる場所は、string()、integer()などの各カラム基本定義メソッドの返り値、ないし返り値が継承しているクラスvendor/laravel/framework/src/Illuminate/Support/Fluent.phpの中、そしてvendor/laravel/framework/src/Illuminate/Database/Schema/Blueprint.phpの中にあります。
 先のコードは

Schema::table('users', function (Blueprint $table) {
    $fluent = $table->string('email');
    /** @var Fluent $fluent */
    $fluent->nullable();
});

 となっており、Fluent内にnullable()は実装されていません。実装されていないメソッドが呼び出されようとする時、__call()が記述されているならば、__call()内部に記述された動作が実行されます。Fluentの__call()は次です。

    /**
     * Handle dynamic calls to the fluent instance to set attributes.
     *
     * @param  string  $method
     * @param  array   $parameters
     * @return $this
     */
    public function __call($method, $parameters)
    {
        $this->attributes[$method] = count($parameters) > 0 ? $parameters[0] : true;

        return $this;
    }

 Fluentのインスタンス内に与えられた属性を保持するのみです。この仕組みが理由で次の様なコードを書いてもバグは起きません。

Schema::table('users', function (Blueprint $table) {
    $table->string('email')->hogehoge();// 好きな名前でメソッドを呼び出せる
    $table->string('name')->nulable();// タイポしても気付かないかもしれないので、善し悪し
});

 $table->string(‘email’)->nullable();の様なカラム定義が繰り返される度にBlueprintのインスタンスである$tableはカラム定義のインスタンスであるFluentのインスタンスを新たに持ちます。クロージャ内の処理が終わった後、Schema::table()はBlueprint->build()を実行します。Blueprint->build()の中ではBlueprint->toSql()が実行されます。Blueprint->build()とBlueprint->toSql()の中身は次です。

    /**
     * Execute the blueprint against the database.
     *
     * @param  \Illuminate\Database\Connection  $connection
     * @param  \Illuminate\Database\Schema\Grammars\Grammar  $grammar
     * @return void
     */
    public function build(Connection $connection, Grammar $grammar)
    {
        // $connectionにデータベースとの接続、$grammarにデータベースの文法が入っている
        foreach ($this->toSql($connection, $grammar) as $statement) {
            $connection->statement($statement);
        }
    }
    
    /**
     * Get the raw SQL statements for the blueprint.
     *
     * @param  \Illuminate\Database\Connection  $connection
     * @param  \Illuminate\Database\Schema\Grammars\Grammar  $grammar
     * @return array
     */
    public function toSql(Connection $connection, Grammar $grammar)
    {
        $this->addImpliedCommands($grammar);// 文法クラスGrammarの中に入っているコマンドを取得する

        $statements = [];

        // Each type of command has a corresponding compiler function on the schema
        // grammar which is used to build the necessary SQL statements to build
        // the blueprint element, so we'll just call that compilers function.
        $this->ensureCommandsAreValid($connection);// SQLite用処理

        foreach ($this->commands as $command) {
// 文法クラス中のcompileから始まる名前のメソッドらの中に、要求された命令に対応するメソッドがあるならばそれを実行してSQL文の元の配列に追加
            $method = 'compile'.ucfirst($command->name);

            if (method_exists($grammar, $method)) {
                if (! is_null($sql = $grammar->$method($this, $command, $connection))) {
                    $statements = array_merge($statements, (array) $sql);
                }
            }
        }

        return $statements;
    }

 Bladeと同じです。特定のクラス中の特定の名前のメソッドがそのまま対応文法になっています。
【Laravel】Bladeの制御構文の探し方 – 株式会社シーポイントラボ | 浜松のシステム開発会社
 まだ終わりません。これでcompileCreateTable->getColumns->addModifiersと動きます。これが次です。

    /**
     * Create the main create table clause.
     *
     * @param  \Illuminate\Database\Schema\Blueprint  $blueprint
     * @param  \Illuminate\Support\Fluent  $command
     * @param  \Illuminate\Database\Connection  $connection
     * @return string
     */
    protected function compileCreateTable($blueprint, $command, $connection)
    {
        return sprintf('%s table %s (%s)',
            $blueprint->temporary ? 'create temporary' : 'create',
            $this->wrapTable($blueprint),
            implode(', ', $this->getColumns($blueprint))
        );
    }

    /**
     * Compile the blueprint's column definitions.
     *
     * @param  \Illuminate\Database\Schema\Blueprint $blueprint
     * @return array
     */
    protected function getColumns(Blueprint $blueprint)
    {
        $columns = [];

        foreach ($blueprint->getAddedColumns() as $column) {
            // Each of the column types have their own compiler functions which are tasked
            // with turning the column definition into its SQL format for this platform
            // used by the connection. The column's modifiers are compiled and added.
            $sql = $this->wrap($column).' '.$this->getType($column);

            $columns[] = $this->addModifiers($sql, $blueprint, $column);
        }

        return $columns;
    }

    /**
     * Add the column modifiers to the definition.
     *
     * @param  string  $sql
     * @param  \Illuminate\Database\Schema\Blueprint  $blueprint
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function addModifiers($sql, Blueprint $blueprint, Fluent $column)
    {
        foreach ($this->modifiers as $modifier) {
            if (method_exists($this, $method = "modify{$modifier}")) {
                $sql .= $this->{$method}($blueprint, $column);
            }
        }

        return $sql;
    }

 このaddModifiersでやっと終わりです。compileHogeHoge同様にmodifyHogeHogeが動きます。modifyHogeHogeがカラムに属性を追加するメソッドになります。modifyHogeHogeは文法クラスに詰まっています。文法クラスはvendor/laravel/framework/src/Illuminate/Database/Schema/Grammars以下に詰まっています。この中から使えるメソッドを抜き出し、ide_helperに追加すればIDEの自動補完が使えるようになります。例えばMySQLならば、次の様になります。

namespace Illuminate\Support{
    /**
     * @method Fluent after()
     * @method Fluent charset()
     * @method Fluent collate()
     * @method Fluent comment()
     * @method Fluent default()
     * @method Fluent first()
     * @method Fluent increment()
     * @method Fluent nullable()
     * @method Fluent srid()
     * @method Fluent storedAs()
     * @method Fluent unsigned()
     * @method Fluent virtualAs()
     */
    class Fluent {}
}

 よく使うuseCurrent()が抜けているので不完全です。少なくともこれで多少はカバーできます。

著者:杉浦

【PHP】リフレクションでprivateメソッドを単体テストする

 あるメソッドをテストしたい時があります。あるメソッドをprotected, privateなどの閉じたアクセス権にしたい時があります。両方に該当するメソッドが現れたときどうすればよいでしょうか。リフレクションはそういった時に役に立つ仕組みです。
 PHP: リフレクション – Manual

情報工学においてリフレクション (reflection) とは、プログラムの実行過程でプログラム自身の構造を読み取ったり書き換えたりする技術のことを指す。

 要はPHPの実行中にリフレクションをしてprivateメソッドの構造を読み取り、読み取った内容を実行することによって、アクセス権の問題をクリアしてテストします。具体的には次の様にします。

    /**
     * @throws ReflectionException
     * @see UbxFile::createObsOfRover() テスト対象のprivateメソッド
     */
    public function testCreateObsOfRover()
    {
        $ubx = UbxFile::all()->first();// ひとまずリフレクション対象クラスのインスタンスを作成。

        $reflection = new ReflectionClass($ubx);// それを参照してリフレクションクラスを作成
        $method = $reflection->getMethod('createObsOfRover');// リフレクションクラスからメソッドの情報を取得
        $method->setAccessible(true);// メソッドのアクセス権をアクセス可能に上書き

        $res = $method->invoke();// privateメソッドであるUbxFile::createObsOfRover()が実行される
        
        self::assertSame('expected', $res);// 実行結果と期待する値を比較するassert
    }

 このような形でリフレクション機能を用いることで任意のメソッドに好き勝手アクセスできます。この仕組みはテストのみでなくフレームワークのマジックメソッド内部でもしばしば用いられています。

著者:杉浦

【HTML】ウェブブラウザのHTML補完におけるブラウザ間の差異

 ウェブブラウザはHTMLコードなどの特定の形式の文書を構文解析して画面に描画します。この構文解析の動作の大部分はW3Cが定義しており、ほぼ全てのウェブブラウザはこれに従っています。

All Standards and Drafts – W3C

 ウェブブラウザは正しいHTMLコードを正しく読み込めます。しかし世の中に公開されているwebページのHTMLコードは正しい構文でないものも多くあります。例えば、tableタグ構造が欠けているのにtdを使う、閉じタグが欠けている、です。ウェブブラウザにはその様なページも一見壊れていない様にHTMLタグを補完する機能がよく備わっています。この記事ではこのHTMLタグ補完機能について述べます。
 昨今のブラウザはJavaScriptから構文解析器を呼び出せます。

DOMParser – Web API | MDN
 これに不完全なHTMLコードを構文解析させることでHTMLタグの補完を見てみます。
 次の一つ目がIE、二つ目がChromeです。これはタグの補完が上手く働いている例です。table->tbody->tr->tdという構造が正しく作られています。
 
 次の前者がIE、後者がChromeです。これはタグの補完が上手く働いている例です。table->tbody->tr->tdという構造が改めて作られています。

<table>
  <td></td>
<!--IE-->
<html>
<head>
  <META content="IE=11.0000" http-equiv="X-UA-Compatible">
</head>
<body>
<table>
  <tbody>
    <tr>
      <td></td>
    </tr>
  </tbody>
</table>
</body>
</html>

<table>
  <td></td>
<!--Chrome-->
<html>
<head></head>
<body>
<table>
  <tbody>
    <tr>
      <td></td>
    </tr>
  </tbody>
</table>
</body>
</html>

 次の前者がIE、後者がChromeです。これはブラウザによって補完結果が異なることを示す例です。pタグ内に閉じ忘れdivタグを置くミスによって、補完結果のDOMが変わっています。IEの壊れ方は恐ろしいです。divタグのミスなのにブラウザ上のHTMLコードではpタグが壊れています。

<div>
  <p>
    <div>
  </p>
</div>
<!--IE-->
<html>
<head>
  <META content="IE=11.0000" http-equiv="X-UA-Compatible">
</head>
<body>
<div>
  <p>
    <div><p></p></div>
</div>
</body>
</html>

<div>
  <p>
    <div>
  </p>
</div>
<!--Chrome-->
<html>
<head></head>
<body>
<div>
  <p></p>
  <div><p></p></div>
</div>
</body>
</html>

 同様のコードをFirefox、Opera、Microsoft Edge、にかけたところ幸いなことに補完結果はChromeと同様でした。しかし一例ながら単純なミスでもブラウザによって補完結果が異なることがあるとわかりました。複雑なHTMLコードの場合、IE以外のブラウザが変わらず一様なHTML補完をするか少々疑問です。HTMLは不正確であっても形はどうあれブラウザ上で止まらずに動き続けます。ブラウザの補完で補いきれなくなって画面が壊れてようやくミスが明るみにでます。これを避けるためにはソースコード時点でlintにかける等の厳密な管理が必要になります。

著者:杉浦

awesomeのまとめのsindresorhus/awesomeの紹介

 awrsomeとは畏敬を表す言葉です。

主な意味 畏怖(いふ)の念を起こさせる、荘厳な、畏敬の念に満ちた、うやうやしい、印象的な、すばらしい
awesome とは 意味・読み方・表現 | Weblio英和辞書

 Gitのリポジトリを見ているとawesome-hogehogeと名付けられたリポジトリに人気者が多いと気づきます。awesome-hogehogeというリポジトリはhogehogeに関連する素晴らしいモノをまとめたリンク集なのです。自分はvuejs/awesome-vuechiraggude/awesome-laravelなどによくお世話になっています。
 単にgitの検索でawesomeとググるのもいいですが自分では想像もつかない名前(大体知らない俗語)を用いた名前のリポジトリになっていることもあります。そういったことを避けるためにawesomeのawesomeを参照します。

 sindresorhus/awesome: 😎 Awesome lists about all kinds of interesting topics

 分類分けがされていてわかりやすいです。

著者:杉浦

【Laravel】Laravel開発者ツール拡張Clockworkの紹介

Clockwork
itsgoingd/clockwork: Clockwork – php dev tools integrated to your browser – server-side component
 ClockworkはLaravel内で実行された様々なデータを表示する開発者ツールの拡張です。
 とりあえずの使い方は次の様にcomposerでプロジェクトにインストールして

composer require itsgoingd/clockwork

 次のリンクから拡張をブラウザに追加するのみです。(Larvel5.5以前はconfig/app.phpにProvider追加が必要です。)
Clockwork – Chrome ウェブストア
Clockwork – Get this Extension for 🦊 Firefox (en-US)
 これだけで基本機能は使えます。詳細な機能は製作者のドキュメントとソースコード参照です。
 基本機能だけでも強力です。何ができるかというと次の5つです。
 一つ目はリクエストの中身を見ることです。ルートとコントローラとの対応を見ることができますが、これ自体はChrome標準のNetworkタブの機能と大差ありません。タブ切り替えがいらない利便性が主目的でしょう。

 二つ目は実行時間です。Laravel内部の実行内容で時間を区切れる点が特長です。図はいささか単純ですが、複雑化してくるとボトルネックを探すことが容易になり便利です。

 三つ目はコード内で発行しているログの内容の取得です。図に使ったコードではデータベースを待ち受けてログファイルに吐き出す機能がついており、このようになっています。わざわざサーバにログファイルを取りにいかなくて済む、GUIで整理されて見やすい、といった点が特長です。

 四つ目は発行されたSQL文、その発行場所と実行時間の一覧です。これは特に便利です。SQLの観点から何を改善すれば高速化できるのかがとても分かりやすいです。長時間かかるクエリ、異様に多く発行されるクエリあたりが見つかったら赤信号で、これはそれらを見つけやすくしてくれます。

 五つ目はセッション情報です。普段サーバに隠れている部分であり、いちいちdumpする必要がなくなります。

 基本的な機能は前述の5つですが、xdebugによるコードのステップ実行や、Clockwork備え付けのメソッドを使って特別なログを出力することも可能です。

著者:杉浦

【PhpStorm】PhpStormのショートカットキーを覚えるためのプラグインKey Promoter X

Key Promoter X – Plugins | JetBrains
 Key Promoter Xは何らかの操作を行った際、その操作に対応するショートカットキーがあるならば、そのショートカットキーを通知するプラグインです。これを用いることでPhpStormをより効率的に使えるようになります。
 具体的に何をするかというと次のgifです。

引用元:Key Promoter X – Plugins | JetBrains
 コマンドを打ち込むとやかましいくらい通知が出ます。ショートカットキーによる操作を心がけることで、このうっとおしい通知を減らします。この心がけが長く続くと、知っている操作をほとんどショートカットキーで行う様になります。
 このプラグインは知っている操作をよりうまく行うための矯正具です。真により上手くPhpStormを使えるようになるためには、このプラグイン以外に頼るのみでなく、知らない操作を吸収していくことが更に必要になります。