引き続きCakePHP3のbakeによる自動生成処理をカスタマイズしています。
今回は一覧画面に検索機能を追加してみました。
一覧画面のビューに検索フォームを追加する
検索フォームはボタンクリック時に右側からスライド表示されるようなモーダルウィンドウにしてみました。
index.twigにモーダルウィンドウを表示するボタンとモーダルウィンドウのHTMLを追記しました。
モーダルウィンドウのHTMLは以下を参考にしました。
参考:Bootstrap 4 left sidebar with modal
<button type="button" class="btn btn-flat btn-outline-secondary" data-toggle="modal" data-target="#{{ pluralVar }}-search-form-modal">検索</button> {# モーダルの検索フォームを追加 #} <div class="modal search-form fade" id="{{ pluralVar }}-search-form-modal" tabindex="-1" role="dialog" aria-labelledby="{{ pluralVar }}-search-form-modal-label" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">{{ comment_data.table_comment }}検索</h5> </div> <div class="modal-body"> <?= $this->Form->create(null, ['type' => 'get', 'id' => '{{ pluralVar }}-search-form']) ?> {% for field in fields %} {% set jp_value = comment_data.column_comments[field] %} {% if field not in ['delete_flag'] %} <div class="row"> <div class="col-md-12 col-sm-12"> <div class="form-group"> <?= $this->Form->control('{{ field }}', ['class' => 'form-control', 'label' => '{{ jp_value }}', 'value' => @$params['{{ field }}']]); ?> </div> </div> </div> {% endif %} {% endfor %} <div class="row"> <div class="col-md-12"> <div class="form-group"> <?= $this->Form->button('検索', ['class' => "btn btn-flat btn-outline-secondary btn-block"]) ?> </div> </div> </div> <?= $this->Form->end() ?> </div> <div class="modal-footer"> </div> </div> </div> </div>
/* 検索フォーム */ .modal.search-form .modal-dialog { position: fixed; margin: auto; width: 320px; height: 100%; -webkit-transform: translate3d(0%, 0, 0); -ms-transform: translate3d(0%, 0, 0); -o-transform: translate3d(0%, 0, 0); transform: translate3d(0%, 0, 0); } .modal.search-form .modal-content { height: 100%; overflow-y: auto; } .modal.search-form .modal-body { padding: 15px 15px 80px; } .modal.search-form.fade .modal-dialog { right: -320px; -webkit-transition: opacity 0.3s linear, right 0.3s ease-out; -moz-transition: opacity 0.3s linear, right 0.3s ease-out; -o-transition: opacity 0.3s linear, right 0.3s ease-out; transition: opacity 0.3s linear, right 0.3s ease-out; } .modal.search-form.fade.show .modal-dialog { right: 0; } .modal.search-form.fade.show .modal-dialog .modal-content { border-radius: 0; border: none; }
モーダルウィンドウを開いたときの見た目はこんな感じです。
一覧表示の上の検索ボタンをクリックすると右側からスライド表示されます。
コントローラーを自動生成するタスククラスとtwigテンプレートを編集
コントローラークラスはbakeで自動生成する際、テーブルのカラム情報がBakeTemplateにセットされていませんでした。一覧情報を取得するときのwhere()に指定する検索条件配列を作成するにあたってテーブルのカラムごとのWhere句の追加が必要となります。そのため、index.twigテンプレートだけでなくControllerTask.phpについても以下のような修正を実施しました。
public function bakeController($controllerName, array $data) { $data += [ 'name' => null, 'namespace' => null, 'prefix' => null, 'actions' => null, 'helpers' => null, 'components' => null, 'plugin' => null, 'pluginPath' => null, ]; + // コメント情報をセット + $this->BakeTemplate->set('comment_data', $this->getColumnCommentData($data['pluralName'])); + + // コネクションマネージャーからbake対象テーブルのカラム定義を取得 + $db = ConnectionManager::get('default'); + $collection = $db->getSchemaCollection(); + $table_schema = $collection->describe($data['pluralName']); + $columns = $table_schema->columns(); + $fields = []; + foreach ($columns as $column) { + $fields[$column] = $table_schema->getColumn($column); + } + $data += [ + 'columns' => $columns, + 'fields' => $fields, + ]; $this->BakeTemplate->set($data); $contents = $this->BakeTemplate->generate('Controller/controller'); $path = $this->getPath(); $filename = $path . $controllerName . 'Controller.php'; $this->createFile($filename, $contents); return $contents; }
public function index() { -{% set belongsTo = Bake.aliasExtractor(modelObj, 'BelongsTo') %} -{% if belongsTo %} - $this->paginate = [ - 'contain' => [{{ Bake.stringifyList(belongsTo, {'indent': false})|raw }}] - ]; -{% endif %} - ${{ pluralName }} = $this->paginate($this->{{ currentModelName }}); + $request = $this->request->getQueryParams(); + $this->set('params', $request); + $conditions = $this->_getCondition($request); + ${{ pluralName }} = $this->paginate($this->{{ currentModelName }}->find()->where($conditions)); $this->set(compact('{{ pluralName }}')); } + /** + * 検索条件を生成する + * @param unknown $request + */ + private function _getCondition($request) { + $conditions = []; +{% for field_name, field_values in fields %} +{% if field_name not in ['delete_flag'] %} +{% set jp_value = comment_data.column_comments[field_name] %} + // {{ jp_value }} + if (isset($request['{{ field_name }}']) && !is_null($request['{{ field_name }}']) && +$request['{{ field_name }}'] !== '') { + $conditions['{{ field_name }} LIKE'] = "%{$request['{{ field_name }}']}%"; + } +{% endif %} +{% endfor %} + return $conditions; + }
15行目は前回作成したコメント情報を取得する処理です。今回、重要なのは18~25行目の処理になります。
検索条件は一律でLIKE検索してます(^^;
カラムの型ごとに処理を切り分けた方が良いと思います。
それと前回の記事で紹介したConnectionManagerよるテーブルのコメント情報を取得する処理についてわざわざ自分でクエリを書かなくてもよかったみたいです。あらかじめCakePHP3に用意されている関数を使用することでテーブルの細かな情報を取得できることがわかりました。
参考:[SOLVED] CakePHP3 get table fields info (schema) – Need Help – Cake Software Foundation, Inc.
ControllerTask.php内テーブルのカラム情報をBakeTemplateにセットする方法について調べてたら見つけましたv(^^)v
前回のコメント情報を取得する処理の方はcoalesce関数による代替名の設定なんかをやってるのでこのまま直さないかも(^^;
その他
当初、MySQLのテーブルのコメントにオプションを用意することで下記のメモに記載するような細かな自動生成機能を作成しようと思ってましたが、どうやらコメントに入力可能な文字数が60文字までのようでした。
参考:Table comment length in MySQL – Stack Overflow
メモ
- ConnectionManagerで取得したカラム定義情報を元に日付項目の時はdatepickerを表示する
- bakeの際に何等かの方法で細かな独自のオプション受け取り、それを元に以下のような機能追加を検討する
- 検索対象カラムを設定
- LIKE検索、完全一致検索
- 選択肢設定