クソ雑魚エンジニアのメモ帳

学んだことを書くところ

yii2のCRUDGenerator(scaffold)を改良した件

こんばんは。運動しなさすぎてフィットネスジムに入会しようか悩んでいるmorifujiです

概要

構築手順

めんどくさかったのでローカルでやっちゃいました :sweat_smile:

前提環境

  • Mac HighSierra
  • php 7.1
  • mysql5.7
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
cd basic
php yii serve

終了。はや。

localhost:8080/でアクセスできる

スクリーンショット 2018-08-30 23.59.48.png

解説

こんな感じ1

こんな感じ2

basic/                  アプリケーションのベース・パス
    composer.json       Composer によって使用される。パッケージ情報を記述
    config/             アプリケーションその他の構成情報を格納
        console.php     コンソール・アプリケーションの構成情報
        web.php         ウェブ・アプリケーションの構成情報
    commands/           コンソール・コマンドのクラスを格納
    controllers/        コントローラのクラスを格納
    models/             モデルのクラスを格納
    runtime/            実行時に Yii によって生成されるファイル (ログやキャッシュなど) を格納
    vendor/             インストールされた Composer パッケージ (Yii フレームワークそのものを含む) を格納
    views/              ビュー・ファイルを格納
    web/                アプリケーションのウェブ・ルート。ウェブ・アクセス可能なファイルを格納
        assets/         Yii によって発行されるアセット・ファイル (javascript と CSS) を格納
        index.php       アプリケーションのエントリ・スクリプト (ブートストラップ・スクリプト)
    yii                 Yii コンソール・コマンド実行スクリプト

こんな感じ3

DB接続

config/db.phpに以下の通り設定。

dsnってポートはport=3111;こう書くんですね

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=127.0.0.1;port=3111;dbname=hogehoge',
    'username' => 'root',
    'password' => 'password',
    'charset' => 'utf8'
];

出典:https://www.yiiframework.com/doc/guide/2.0/ja/start-workflow

gii

yii2のscaffoldツールはgiiと呼ばれているらしい

https://www.yiiframework.com/doc/guide/2.0/ja/start-gii

実はすでにインストールされていて、/index.php?r=giiを叩くとメニュー出てきた、思ったより多機能 :astonished:

スクリーンショット 2018-08-31 0.01.05.png

基本的にはこの2つで事足りる - Model Generator - CRUD Generator

Model Generator

DBに定義しているテーブルからモデルクラスを自動出力してくれる

この2つだけ記載すればあとはよしなにやってくれる。

  • Table Name
  • Model Class Name

TableNameに入力すると予測変換が出てきて少し感動。続けてキャメルケースでModelClassNameを書く。

最後にPreviewを押す。するとどんなファイルが出力されるか表示される。Generateで出力する

スクリーンショット 2018-08-31 0.07.01.png

CRUD Generator

ModelGeneraterによって出力されたModelを元に自動でCRUDのページ・ルーティング、果てはフォームも自動生成する

この3つを設定

  • ModelClass
  • SearchClass
  • ControllerClass

ModelClass

すでにあげたディレクトリ構成に従うとapp\models\{キャメルケース}となる

SearchClass

ドキュメントでは、すでにあげたディレクトリ構成に従い、suffixをSearchとしてapp\models\{キャメルケース}Searchとしている

ControllerClass

すでにあげたディレクトリ構成に従うとapp\controllers\{キャメルケース}Controllerとなる

スクリーンショット 2018-08-31 0.13.23.png

同じくPreviewを押してGenerate

スクリーンショット 2018-08-31 0.13.31.png

できた!

実際の画面は?

/index.php?r={モデル名}で表示されます

検索画面

スクリーンショット 2018-08-31 0.15.10.png

ご丁寧に、画面に表示できないプロパティはコメントアウトしてくれている。こういうところ嬉しいですよね :cry:

    <?php $form = ActiveForm::begin([
        'action' => ['index'],
        'method' => 'get',
    ]); ?>

    <?= $form->field($model, 'id') ?>

    <?= $form->field($model, 'email') ?>

    <?= $form->field($model, 'password') ?>

    <?= $form->field($model, 'nearest_station_id') ?>

    <?= $form->field($model, 'frequently_drinking_station_id') ?>

    <?php // echo $form->field($model, 'sex') ?>

    <?php // echo $form->field($model, 'payment_customer_token') ?>

    <?php // echo $form->field($model, 'payment_subscription_token') ?>

    <?php // echo $form->field($model, 'date_of_birth') ?>

    <?php // echo $form->field($model, 'name') ?>

    <?php // echo $form->field($model, 'role') ?>

    <?php // echo $form->field($model, 'franchise_id') ?>

    <?php // echo $form->field($model, 'corporation_id') ?>

    <?php // echo $form->field($model, 'encrypted_id') ?>

    <?php // echo $form->field($model, 'created_at') ?>

    <?php // echo $form->field($model, 'updated_at') ?>

    <?php // echo $form->field($model, 'deleted_at') ?>

    <div class="form-group">

詳細画面

So simple

スクリーンショット 2018-08-31 0.19.58.png

登録画面・更新画面

スクリーンショット 2018-08-31 0.23.30.png スクリーンショット 2018-08-31 0.23.40.png

特徴としてはこんな感じ。

  • パスワードがシークレットな表示 (画像でいうPassword)
  • enumで定義したカラムはドロップダウン表示 (画像でいうRole)
  • date型・time型は文字列として表示 (画像でいうDate Of Birth)

本題

date型・time型は文字列として表示ここがおしい。ここもきちんとdatepicker/timepicker出してくれたらわりと活躍するかなあと思ってましたが残念すぎる、。。。

ということで、この部分だけサクッとカスタマイズしましょう

テンプレートファイル編集

https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide/2.1/en/topics-creating-your-own-templates

これにしたがって、giiのscaffold出力ロジックをいじいじした。

結果、ここでいじいじしてるみたい。


  /**
     * Generates code for active field
     * @param string $attribute
     * @return string
     */
    public function generateActiveField($attribute)
    {
        $tableSchema = $this->getTableSchema();
        if ($tableSchema === false || !isset($tableSchema->columns[$attribute])) {
            if (preg_match('/^(password|pass|passwd|passcode)$/i', $attribute)) {
                return "\$form->field(\$model, '$attribute')->passwordInput()";
            }

            return "\$form->field(\$model, '$attribute')";
        }
        $column = $tableSchema->columns[$attribute];
        if ($column->phpType === 'boolean') {
            return "\$form->field(\$model, '$attribute')->checkbox()";
        }

        if ($column->type === 'text') {
            return "\$form->field(\$model, '$attribute')->textarea(['rows' => 6])";
        }

        if (preg_match('/^(password|pass|passwd|passcode)$/i', $column->name)) {
            $input = 'passwordInput';
        } else {
            $input = 'textInput';
        }

        if (is_array($column->enumValues) && count($column->enumValues) > 0) {
            $dropDownOptions = [];
            foreach ($column->enumValues as $enumValue) {
                $dropDownOptions[$enumValue] = Inflector::humanize($enumValue);
            }
            return "\$form->field(\$model, '$attribute')->dropDownList("
                . preg_replace("/\n\s*/", ' ', VarDumper::export($dropDownOptions)) . ", ['prompt' => ''])";
        }

        if ($column->phpType !== 'string' || $column->size === null) {
            return "\$form->field(\$model, '$attribute')->$input()";
        }

        return "\$form->field(\$model, '$attribute')->$input(['maxlength' => true])";
    }

なるほど。カラム名がpasswordとかpasswdとかならシークレットな表示にするのか笑

            return "\$form->field(\$model, '$attribute')->$input()";

日付型・時間型はここに引っかかっているらしい

となるとformを出力する必要があるので、Extensionから検索。だれか作ってるでしょ

datetimepickerプラグイン

あった。総ダウンロード数19000ぐらい、普通の感覚では少し不安かもしれないけど、他のextensionは一桁台ダウンロード数だったのでこのextensionの有用さがうかがえる

https://www.yiiframework.com/extension/zhuravljov/yii2-datetime-widgets

composerに追加

composer require zhuravljov/yii2-datetime-widgets

先ほどのGenerator.phpを編集

        if ($column->type === 'date') {
            return "\$form->field(\$model, '$attribute')->widget(\zhuravljov\yii\widgets\DatePicker::class, [
    'clientOptions' => [
        'format' => 'yyyy-mm-dd',
        'language' => 'ja',
        'autoclose' => true,
        'todayHighlight' => true,
    ],
    'clientEvents' => [],
])";
        }


        if ($column->type === 'time') {
            return "\$form->field(\$model, '$attribute')->widget(\zhuravljov\yii\widgets\DateTimePicker::class, [
    'clientOptions' => [
        'format' => 'hh:ii:00',
        'language' => 'ja',
        'autoclose' => true
    ]
])";
        }

        if (in_array($column->type, ["timestamp", "datetime"])) {
            return "\$form->field(\$model, '$attribute')->widget(\zhuravljov\yii\widgets\DateTimePicker::class, [
    'clientOptions' => [
        'format' => 'yyyy-mm-dd hh:ii:00',
        'language' => 'ja',
        'autoclose' => true
    ]
])";
        }

結果

もう一度CRUDGeneratorを使う

スクリーンショット 2018-08-31 0.38.00.png

このとき、overrideにチェックを入れてGenerate

そして登録画面・編集画面へ http://localhost:8080/index.php?r=users%2Fcreate

aaaaaa.gif

キタ━━━━━━━━m9( ゚∀゚)━━━━━━━━!!

所感

  • 普段使っていないfwは面白い
  • しかもscaffold使うとガシガシできて気持ちいい。
  • コミュニティは活発なようだがextensionの荒廃している感が否めない
  • 3コマンドで環境構築できるとか強すぎひん?
  • 地味にプロファイリングツールもついてたww

スクリーンショット 2018-08-31 0.50.16.png