Linuxなどのメモ書き

Magento2 エクステンションの作成 その4


1. 概要

Magento2 エクステンションの作成 その3の続き。

ここでは、管理画面に投稿内容の一覧表示ページを作成する。「Magento2 エクステンションの作成 その2」で作成した/admin/topic/posts/indexのページに一覧データを表示する。

2. テンプレートの修正

まずはlayoutファイルを修正する。「Magento2 エクステンションの作成 その2」でview/adminhtml/layout/topic_posts_index.xmlを作成したが、このファイルを修正する。

view/adminhtml/layout/topic_posts_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchem
aLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <title>
            Posts
        </title>
    </head>
    <body>
        <referenceContainer name="content">
            <!-- 外部のテンプレートファイルを読み込みview/adminhtml/templates/posts.htmlを参照 -->
            <block class="Magento\Backend\Block\Template" template="BitHive_Topic::posts.phtml"/>
            <!-- -view/adminhtml/ui_component/topic_listing.xmlを参照 -->
            <uiComponent name="topic_listing"/>
        </referenceContainer>
    </body>
</page>

赤の行を追加した。

Magento2ではUI componentsという仕組みを使い、xmlでGrid(一覧表示用のテーブル)やフォームの定義を行い、それを呼び出す形でページを作成していく。追加した<uiComponent name="topic_listing"/>はview/adminhtml/ui_component/topic_listing.xmlで定義したコンポーネントを呼び出すことを意味する。

次にUI componentsのコンポーネントであるview/adminhtml/ui_component/topic_listing.xmlを作成して一覧表示用のGridを定義する。このファイルで、Gridのカラム等を定義する。

view/adminhtml/ui_component/topic_listing.xml

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <argument name="data" xsi:type="array">
        <item name="js_config" xsi:type="array">
            <item name="provider" xsi:type="string">topic_listing.topic_listing_data_source</item>
        </item>
    </argument>
    <settings>
        <spinner>spinner_columns</spinner>
        <deps>
            <dep>topic_listing.topic_listing_data_source</dep>
        </deps>
        <buttons>
            <!-- 追加ボタンを置く -->
            <button name="add">
                <url path="*/*/new"/>
                <class>primary</class>
                <label translate="true">Add New Topic</label>
            </button>
        </buttons>
    </settings>
    <!-- Gridに表示するデータの取得方法を指定 -->
    <dataSource name="topic_listing_data_source" component="Magento_Ui/js/grid/provider">
        <settings>
            <storageConfig>
                <param name="indexField" xsi:type="string">post_id</param>
            </storageConfig>
            <updateUrl path="mui/index/render"/>
        </settings>
        <!-- DataProviderの設定。name属性で指定した名前でデータの取得要求を行うので、etc/di.xmlの設定と合わせておく必要がある -->
        <dataProvider class="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider" name="topic_listing_data_source">
            <settings>
                <requestFieldName>id</requestFieldName>
                <primaryFieldName>post_id</primaryFieldName>
            </settings>
        </dataProvider>
    </dataSource>
    <listingToolbar name="listing_top">
<!--
        <bookmark name="bookmarks"/>
-->
        <columnsControls name="columns_controls"/>
        <filters name="listing_filters"/>
        <paging name="listing_paging"/>
    </listingToolbar>
    <!-- Gridに表示するカラムの定義 -->
    <columns name="spinner_columns">
        <selectionsColumn name="ids">
            <settings>
                <resizeEnabled>false</resizeEnabled>
                <resizeDefaultWidth>60</resizeDefaultWidth>
                <indexField>post_id</indexField>
            </settings>
        </selectionsColumn>
        <column name="post_id">
            <settings>
                <filter>textRange</filter>
                <sorting>asc</sorting>
                <label translate="true">ID</label>
            </settings>
        </column>
        <column name="message">
            <settings>
                <filter>text</filter>
                <dataType>text</dataType>
                <label translate="true">Message</label>
            </settings>
        </column>
        <column name="date" class="Magento\Ui\Component\Listing\Columns\Date" component="Magento_Ui/js/grid/columns/date">
            <settings>
<!-- timezone設定をfalseにするとUTCのまま表示される
                <timezone>false</timezone>
-->
                <filter>dateRange</filter>
                <dataType>date</dataType>
                <label translate="true">Date</label>
            </settings>
        </column>
	<column name="created" class="Magento\Ui\Component\Listing\Columns\Date" component="Magento_Ui/js/grid/columns/date">
            <settings>
                <filter>dateRange</filter>
                <dataType>date</dataType>
                <label translate="true">Created</label>
            </settings>
        </column>
	<column name="modified" class="Magento\Ui\Component\Listing\Columns\Date" component="Magento_Ui/js/grid/columns/date">
            <settings>
                <filter>dateRange</filter>
                <dataType>date</dataType>
                <label translate="true">Updated</label>
            </settings>
        </column>
        <!-- Actionカラムの内容はBitHive\Topic\Ui\Component\Listing\Columns\PostActionsで作成する -->
        <actionsColumn name="actions" class="BitHive\Topic\Ui\Component\Listing\Columns\PostActions" sortOrder="200">
            <settings>
                <indexField>post_id</indexField>
            </settings>
        </actionsColumn>
    </columns>
</listing>

<dataSource>部分だけややこしいので補足する。<dataSource>でGrid内に表示するデータの取得方法を定義する。 component="Magento_Ui/js/grid/provider"や<updateUrl path="mui/index/render"/>の指定はGridのJavaScript関連の処理に影響するが、デフォルトのまま使用すればよい(というかどのようなカスタマイズが可能か不明)。

<dataProvider>タグでデータの取得方法を指定する。DataProviderクラスは標準のMagento\Framework\View\Element\UiComponent\DataProvider\DataProviderを使用する。name属性で指定している"topic_listing_data_source"は、DataProviderにデータ取得要求をする際のRequestNameになる。この名前は後に出て来るdi.xmlでの設定と合わせておく必要がある。

 

3. DataProvider関連の設定

Gridのデータ取得にはDataProviderを使用するが、'topic_listing_data_source'に対するデータ取得要求を処理できるようにDependency Injectionの設定を行う。これにはetc/di.xmlファイルを作成する。

etc/di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="BitHive\Topic\Model\ResourceModel\Post\Grid\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult">
        <arguments>
            <argument name="mainTable" xsi:type="string">bithive_topic_post</argument>
            <argument name="resourceModel" xsi:type="string">BitHive\Topic\Model\ResourceModel\Post</argument>
        </arguments>
    </virtualType>
    <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
        <arguments>
            <argument name="collections" xsi:type="array">
                <item name="topic_listing_data_source" xsi:type="string">BitHive\Topic\Model\ResourceModel\Post\Grid\Collection</item>
            </argument>
        </arguments>
    </type>
</config>

di.xmlはDependency Injectionの設定/カスタマイズを行うためのファイル。Topic/etc/di.xmlではTopicモジュール内でのDIの設定を行うことになる。このetc/di.xmlでは以下の二つの設定を行っている。

(1) DIでCollectionFactoryを作成する際のコンストラクタ引数を指定

これは<type>タグで指定している。

Topicモジュール内でMagento\Framework\View\Element\UiComponent\DataProvider\CollectionFactoryを生成する際、$collectionsコンストラクタ引数に以下のような配列を渡すように設定している。

コンストラクタ引数($collections)へ渡される引数

[
    'topic_listing_data_source' => 'BitHive\Topic\Model\ResourceModel\Post\Grid\Collection'
]

'topic_listing_data_source'はtopic_listing.xmlの<dataProvder>タグのname属性の値と合わせておく(名前が不一致だとページアクセス時に"Not registered handle topic_listing_data_source"のようなエラーが表示される)。これでDataProviderから'topic_listing_data_source'のデータ取得要求があった場合に、BitHive\Topic\Model\ResourceModel\Post\Grid\Collectionを返すようになる。

 

(2) BitHive\Topic\Model\ResourceModel\Post\Grid\Collectionの定義

(1)で指定したBitHive\Topic\Model\ResourceModel\Post\Grid\Collectionクラスは存在しない。<virtualType>タグでどのようなクラスかを定義すれば、Magento2が自動で作成しDIで注入してくれる。

ここでは、BitHive\Topic\Model\ResourceModel\Post\Grid\CollectionはMagento\Framework\View\Element\UiComponent\DataProvider\SearchResultを継承し、コンストラクタ引数に以下の値を渡すように指定している。

  • $mainTable: 'bithive_topic_post'
  • $resourceModel: 'BitHive\Topic\Model\ResourceModel\Post'

$mainTableと$resourceModelでどのテーブルからデータを取得してくるかを指定できる。

4. Actionカラムの内容を生成

Gridのアクションカラムの内容をBitHive\Topic\Ui\Component\Listing\Columns\PostActionsで作成するように設定したので、本クラスを作成する。

Ui/Component/Listing/Columns/PostActions.php

<?php
namespace BitHive\Topic\Ui\Component\Listing\Columns;

use Magento\Framework\View\Element\UiComponent\ContextInterface;
use Magento\Framework\View\Element\UiComponentFactory;
use Magento\Ui\Component\Listing\Columns\Column;
use Magento\Framework\UrlInterface;

class PostActions extends Column
{
    /**
     * @var UrlInterface
     */
    protected $urlBuilder;

    /**
     * @param ContextInterface $context
     * @param UiComponentFactory $uiComponentFactory
     * @param UrlInterface $urlBuilder
     * @param array $components
     * @param array $data
     */
    public function __construct(
        ContextInterface $context,
        UiComponentFactory $uiComponentFactory,
        UrlInterface $urlBuilder,
        array $components = [],
        array $data = []
    ) {
        $this->urlBuilder = $urlBuilder;
        parent::__construct($context, $uiComponentFactory, $components, $data);
    }

    /**
     * Prepare Data Source
     *
     * @param array $dataSource
     * @return array
     */
    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
            foreach ($dataSource['data']['items'] as &$item) {
                $item[$this->getData('name')]['edit'] = [
                    'href' => $this->urlBuilder->getUrl(
                        'topic/posts/edit',
                        ['id' => $item['post_id']]
                    ),
                    'label' => __('Edit'),
                    'hidden' => false,
                ];
                $item[$this->getData('name')]['delete'] = [
                    'href' => $this->urlBuilder->getUrl(
                        'topic/posts/delete',
                        ['id' => $item['post_id']]
                    ),
                    'label' => __('Delete'),
                    'hidden' => false,
                    'confirm' => [
                        'title' => __('Delete ID: %1', $item['post_id']),
                        'message' => __('Are you sure you want to delete a ID: %1 record?', $item['post_id'])
                    ]
                ];
            }
        }

        return $dataSource;
    }
}

ここでは、それほど難しいことはしていないので詳細は省略するが、Edit/Deleteボタンを生成している。

5. 表示の確認

ここまでで作業は完了。あとは./bin/magento cache:cleanと./bin/magento setup:di:compileを実行してページにアクセスすればGridが表示されるはず。

まだデータが無いので空のGridが表示されるが、以下のようの直接SQLを実行してテスト用のデータを挿入してみればレコードも表示される。

INSERT INTO  bithive_topic_post (message, date) VALUES ('Hello', NOW());

 

図1 作成したGridページ

 

現時点でTopic配下は以下のようになっている。

./registration.php
./Model/ResourceModel/Post/Collection.php
./Model/ResourceModel/Post.php
./Model/Post.php
./view/adminhtml/templates/posts.phtml
./view/adminhtml/layout/topic_posts_index.xml
./view/adminhtml/ui_component/topic_listing.xml
./Ui/Component/Listing/Columns/PostActions.php
./Setup/InstallSchema.php
./Controller/Adminhtml/Posts/Index.php
./etc/module.xml
./etc/di.xml
./etc/adminhtml/menu.xml
./etc/adminhtml/routes.xml

今回はここまで。Magento2 エクステンションの作成 その5に続きます。

DataProvider周りは色々クラスが出て来てややこしいので補足を「Magento2 DataProvider関連のメモ」に追加しました。

 


最終更新 2018/12/10 15:18:34 - kztomita
(2018/12/05 12:53:10 作成)
添付ファイル
ss.jpg - kztomita