Help us understand the problem. What is going on with this article?

Magento2 管理画面のグリッド作成におけるUIComponentファイルの書き方

More than 1 year has passed since last update.

はじめに

この記事は Magento Advent Calendar 2018 の13日目です。

今回は、Magentoモジュールにおける管理画面のグリッドを作成する方法の一つ、UIComponentの書き方について、備忘録も兼ねて簡単に解説していこうと思います。

また私が初めてグリッドを作成した際、こちらの質問が大いに参考になりました。なので今回の記事もこれに準じていますが、コードは私が実際に書いたものを基にしているので幾分か差があります。

グリッドについて

まず始めにグリッドがどのような部品でできているのか画像で見てみましょう。
図1.png
これから書くコードをコピペすれば大体こんな感じのグリッドになります。(ちなみに上部のGridというタイトル表示はControllerで変更できます。)
これらの要素をUIComponentで記述していくことになります。

定義

今回のグリッドで扱うモジュール名やデータベース名は以下のものとします。
適宜自分のものと読み替えてください。

ベンダー名
Company
モジュール名
Module
テーブル名
table
カラム1
table_id
→主キー、int型、 auto_increment
カラム2
table_name
→varchar(255)

書き方

layoutファイルでUIComponentファイルを定義します。
このファイルはapp/code/Company/Module/adminhtml/view/layout/に配置します。

app/code/Company/Module/adminhtml/view/layout/module_table_index.xml
<?xml version="1.0"?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <uiComponent name="module_table_list"/>
        </referenceContainer>
    </body>
</page>

この場合、uiComponentノードで"module_table_list"と指定されているので、UIComponentファイルの名前はmodule_table_list.xmlとなります。
UIComponentファイルはapp/code/Company/Module/adminhtml/view/ui_component/に配置します。

UIComponentファイルは一見複雑そうに見えますが、実際には下記のシンプルな構造になっています。

  • <listing>
    • <argument>
    • <dataSource>
    • <container>
    • <columns>

作りたいグリッドによって、これらのノードが増えたり減ったりします。特に<container>の子ノードは不要なものを省くことができます。実際にコードを書くときは量が多いのでコピペしてリプレースする方が楽でしょう。コード内で出てくるmoduletableといった部分は適宜自分のモジュール名やテーブル名に置き換えてください。ではノードごとにコードを分けて解説していきます。

listingノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
<?xml version="1.0" encoding="UTF-8"?>

<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Ui/etc/ui_configuration.xsd">
<!--この中に以下のノードが入ります。-->
</listing>

最上位のノードです。

argumentノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
    <argument name="data" xsi:type="array">
        <item name="js_config" xsi:type="array">
            <item name="provider" xsi:type="string">module_table_list.module_table_listing_data_source</item>
            <item name="deps" xsi:type="string">module_table_list.module_table_listing_data_source</item>
        </item>
        <item name="spinner" xsi:type="string">module_table_columns</item>
        <item name="buttons" xsi:type="array">
            <item name="add" xsi:type="array">
                <item name="name" xsi:type="string">add</item>
                <item name="label" xsi:type="string" translate="true">Add New Data</item>
                <item name="class" xsi:type="string">primary</item>
                <item name="url" xsi:type="string">*/*/new</item>
            </item>
        </item>
    </argument>
  • <argument>にはモジュールに関する基本的なデータを記述します。
  • js_config/providerとdepsノードは"{ファイル名}.{データソース名}"とします。{データソース名}はわかりやすいように"{モジュール名}_{テーブル名}_listing_data_source"としています。(実際に{データソース名}を定義する箇所は次のノードです。)
  • spinnerノードはわかりやすいように"{モジュール名}_{テーブル名}_columns"としています。(後から出てきます。)
  • これ以降のコードでmodule_table_list等が出てきた場合、それは"{ファイル名}"などと同じです。
  • グリッド上部のボタンを設定する<button>には、レコードを追加するボタンを設定しています。buttons/add/urlノードでボタンを押した後のURLを変更できるので、Controllerでデータを追加する処理を記述しています。またlabelはボタン上に書かれる文字なので、役割に合わせて変更しましょう。

dataSourceノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
    <dataSource name="module_table_listing_data_source">
        <argument name="dataProvider" xsi:type="configurableObject">
            <argument name="class" xsi:type="string">Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider</argument>
            <argument name="name" xsi:type="string">module_table_listing_data_source</argument>
            <argument name="primaryFieldName" xsi:type="string">table_id</argument>
            <argument name="requestFieldName" xsi:type="string">table_id</argument>
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="update_url" xsi:type="url" path="mui/index/render"/>
                    <item name="storageConfig" xsi:type="array">
                        <item name="indexField" xsi:type="string">table_id</item>
                    </item>
                </item>
            </argument>
        </argument>
        <argument name="data" xsi:type="array">
            <item name="js_config" xsi:type="array">
                <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
            </item>
        </argument>
    </dataSource>
  • <dataSource>内のnameには{データソース名}を入れましょう。これ以降のコードでも頻繁に出てきます。
  • 一つ目の大きな<argument>はグリッドに表示されるデータを準備する役割を持つクラスを定義します。
    • classdi.xmlで定義される名前と同様にしなければなりません。
    • primaryFieldNameはデータベースの主キーと、requestFieldNameHTTPリクエスト変数と関連していて、両者は同じでよい場合がほとんどです。
  • 二つ目の大きな<argument>はグリッドのAjaxを担うJavascriptファイルを参照します。デフォルトではMagento/Ui/view/base/web/js/grid/provider.jsとなっています。

containerノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
    <container name="listing_top">
    <!--この中に以下のノードが入ります。-->
    </container>

最上位のノードです。namelisting_topはこれ以降のコードでたびたび出てきます。機能によって以下の子ノードに分かれます。

  • <argument>
  • <bookmark>
  • <component>
  • <filtersearch>
  • <filters>
  • <massaction>
  • <paging>

一気にすべて書くと長くなるのでノードごとにコードを区切って解説します。

argumentノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="template" xsi:type="string">ui/grid/toolbar</item>
            </item>
        </argument>

レイアウトとすべてのアクションを処理するテンプレートファイルを定義するノードです。デフォルトではMagento/Ui/view/base/web/templates/grid/toolbar.htmlとなっています。

bookmarkノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
        <bookmark name="bookmarks"/>

ブックマーク機能を追加するノードです。namebookmarksはこれ以降のコードで少しだけ出てきます。

componentノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
        <component name="columns_controls">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="columnsData" xsi:type="array">
                        <item name="provider" xsi:type="string">module_table_list.module_table_list.module_table_columns</item>
                    </item>
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/controls/columns</item>
                    <item name="displayArea" xsi:type="string">dataGridActions</item>
                </item>
            </argument>
        </component>
  • componentはグリッドを表示するJavascriptファイルを参照していて、デフォルトではMagento/Ui/view/base/web/templates/grid/controls/columns.htmlというテンプレートを使っているMagento/Ui/view/base/web/js/grid/controls/columns.jsを指定しています。
  • displayAreaはcontainer/argument/config/templateノードで定義されたテンプレートファイル内のgetRegion('dataGridActions')を参照しています。

filterSearchノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
        <filterSearch name="fulltext">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="provider" xsi:type="string">module_table_list.module_table_listing_data_source</item>
                    <item name="chipsProvider" xsi:type="string">module_table_list.module_table_list.listing_top.listing_filters_chips</item>
                    <item name="storageConfig" xsi:type="array">
                        <item name="provider" xsi:type="string">module_table_list.module_table_list.listing_top.bookmarks</item>
                        <item name="namespace" xsi:type="string">current.search</item>
                    </item>
                </item>
            </argument>
        </filterSearch>

このノードはデータのテキスト検索機能をページに追加します。わかりやすく言うと"Search by keyword"のやつです。この検索機能はInstallSchema.phpでインデックスを作成しないと機能しないようです。

filtersノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
        <filters name="listing_filters">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="columnsProvider" xsi:type="string">module_table_list.module_table_list.module_table_columns</item>
                    <item name="storageConfig" xsi:type="array">
                        <item name="provider" xsi:type="string">module_table_list.module_table_list.listing_top.bookmarks</item>
                        <item name="namespace" xsi:type="string">current.filters</item>
                    </item>
                    <item name="templates" xsi:type="array">
                        <item name="filters" xsi:type="array">
                            <item name="select" xsi:type="array">
                                <item name="component" xsi:type="string">Magento_Ui/js/form/element/ui-select</item>
                                <item name="template" xsi:type="string">ui/grid/filters/elements/ui-select</item>
                            </item>
                        </item>
                    </item>
                    <item name="childDefaults" xsi:type="array">
                        <item name="provider" xsi:type="string">module_table_list.module_table_list.listing_top.listing_filters</item>
                        <item name="imports" xsi:type="array">
                            <item name="visible" xsi:type="string">module_table_list.module_table_list.module_table_columns.${ $.index }:visible</item>
                        </item>
                    </item>
                </item>
                <item name="observers" xsi:type="array">
                    <item name="column" xsi:type="string">column</item>
                </item>
            </argument>
        </filters>
  • このノードはフィルターボタンを定義しています。
  • templatesでは特定のフィルタオプションをレンダリングするために使用されるファイルを定義することができます。この場合selectのみが定義されMagento/Ui/view/base/web/js/form/element/ui-select.jsMagento/Ui/view/base/web/templates/grid/filters/elements/ui-select.htmlが指定されています。
  • 今回はselectのみがデフォルトをオーバーライドするために定義されていますが、<filter>ノードや他のノードのデフォルト値はMagento/Ui/view/base/ui_component/etc/definition.xmlで定義されています。

massactionノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
        <massaction name="listing_massaction">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="selectProvider" xsi:type="string">module_table_list.module_table_list.module_table_columns.ids</item>
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/tree-massactions</item>
                    <item name="indexField" xsi:type="string">table_id</item>
                </item>
            </argument>
            <action name="delete">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="type" xsi:type="string">delete</item>
                        <item name="label" xsi:type="string" translate="true">Delete</item>
                        <item name="url" xsi:type="url" path="*/*/massDelete"/>
                        <item name="confirm" xsi:type="array">
                            <item name="title" xsi:type="string" translate="true">Delete</item>
                            <item name="message" xsi:type="string" translate="true">Do you want to delete selected row record?</item>
                        </item>
                    </item>
                </argument>
            </action>
        </massaction>
  • 選択したデータに対して一括で削除などを行う機能を追加するノードです。nameはユニークでなければなりません。
  • <argument>は基本的な情報を記述します。
  • <action>は実際に行う処理を指定しますが、今回は削除機能のみ搭載させています。
  • 他の機能はvender/magento/module-ui/view/base/ui_component/etc/definition.xmlに書いてあるので適宜参照してください。

pagingノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
        <paging name="listing_paging">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="storageConfig" xsi:type="array">
                        <item name="provider" xsi:type="string">module_table_list.module_table_list.listing_top.bookmarks</item>
                        <item name="namespace" xsi:type="string">current.paging</item>
                    </item>
                    <item name="selectProvider" xsi:type="string">module_table_list.module_table_list.module_table_columns.ids</item>
                </item>
            </argument>
        </paging>

一ページ当たりの列の表示量選択などの機能を追加するノードです。
以上で長かった<container>ノードは終了です。

columnsノード

app/code/Company/Module/adminhtml/view/ui_component/module_table_list.xml
    <columns name="module_table_columns">
        <selectionsColumn name="ids">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="indexField" xsi:type="string">table_id</item>
                    <item name="sortOrder" xsi:type="number">0</item>
                </item>
            </argument>
        </selectionsColumn>
        <column name="table_id">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Table ID</item>
                    <item name="sortOrder" xsi:type="number">10</item>
                </item>
            </argument>
        </column>
        <column name="table_name">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Table Name</item>
                    <item name="sortOrder" xsi:type="number">20</item>
                </item>
            </argument>
        </column>
        <actionsColumn name="actions" class="Company\Module\Ui\Component\Listing\Table\Column\Action">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="resizeEnabled" xsi:type="boolean">true</item>
                    <item name="resizeDefaultWidth" xsi:type="string">100</item>
                    <item name="indexField" xsi:type="string">table_id</item>
                    <item name="sortOrder" xsi:type="number">30</item>
                </item>
            </argument>
        </actionsColumn>
    </columns>
  • <selectionsColumn>は<massaction>のためにデータを選択するチェックボックスのカラムです。
  • <column>は実際のデータを表示するカラムです。
    • <name>には表示させたいテーブルのカラム名を入れましょう。(テーブルの指定自体はResourceModelの定義の段階で済んでいるはずです)
    • filterは<filter>で追加したフィルター機能の中で、カラムごとにどのようにフィルタリングさせるか指定できます。textの場合はテキスト形式のフィルタリングができるようになります。
    • labelはグリッドに表示するカラムの名前です。必ずしも実際のテーブルのカラム名と同様にする必要はありません。
  • <actionsColumn>は一つ一つのデータに対して削除や編集機能の処理をするリンクを表示するカラムを追加します。実際にどのような処理を追加するかはUIComponentではなくControllerで記述するためここでは省略します。

さいごに

このファイルの書き方についてより詳しく解説する開発者ガイドのようなものがなかなか見つけられないので書きました。私にもわかっていない部分が多いし間違いもあるかもしれませんが、これを読んだ方にとって少しでも参考になれば幸いです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした