Magento 2 modulfejlesztés lépésről lépésre – 2. rész
Cikksorozatunk előző részében bemutattuk, miért érdemes webáruház fejlesztéséhez a Magento 2-t választani, és hogyan kezdhetünk bele a saját, felhasználói modulok fejlesztésébe. Összefoglaltuk a munkához szükséges követelményeket, bemutattuk, hogyan telepíthetjük a webáruházunk üzemeltetéséhez szükséges rendszert, és felvázoltuk a munka kezdetéhez nélkülözhetetlen beállításokat. Bemutattuk egy alap modul felépítését, valamint belekezdtünk annak elkészítésébe.
Ebben a cikkben folytatjuk a munkát, és komolyabb vizekre evezünk. Sok más, hasznos funkció melett megismerkedünk az adminisztrációs felületen a modulunkhoz tartozó menüpontok létrehozásának folyamatával, az editáláshoz szükséges admin block-ok létrehozásával, illetve a controller-ek és layout létrehozásával is.
A következő témákkal fogunk megismerkedni:
- 1) Admin menüpont és táblázat (grid) elkészítése
- 2) UI Components avagy az admin táblázat (grid) új kialakítása
- 3) UI component osztályok
- 4) Adminhtml controller-ek
- 5) Object manager konfigurációs
- 6) Editáláshoz szükséges admin block-ok létrehozása
- 7) Controller-ek és layout létrehozása
1) Admin menüpont és táblázat (grid) elkészítése
Első lépésben létre kell hoznunk az adminisztrációs felületen a modulunkhoz tartozó menüpontot. Ezt külön (új) főmenüben is elhelyezhetjük, de célszerű a modul működéséhez igazodva besorolni a már létező főmenüpontok alá. Jelen esetben a Content főmenüpontban helyezzük el a sajátunkat.
Ehhez szükségünk lesz egy új file-ra. Ezt a menüpontot az app/code/Aion/Test/etc/adminhtml/ könyvtárban lévő menu.xml-ben valósíthatjuk meg. A fájl tartalma:
<?xml version="1.0"?> <!-- /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Backend:etc/menu.xsd"> <menu> <add id="Aion_Test::content_elements" title="Test Extension" module="Magento_Backend" sortOrder="10" parent="Magento_Backend::content" resource="Magento_Backend::content_elements"/> <add id="Aion_Test::aion_test" title="Manage Items" module="Aion_Test" sortOrder="10" parent="Aion_Test::content_elements" action="test/test" resource="Aion_Test::test"/> </menu> </config>
A file-ban első lépésben definiálunk egy főelemet, ami nem más, mint az id=Aion_Test::content_elements és a menüpontot ez alá helyezzük el, úgy hogy a menüpont (id=Aion_Test::aion_test) parent-nél a főelemet adjuk meg. Ha mindent jól csináltunk, az adminisztrációs felületen a Content főmenüpontban megjelenik a saját almenüpontunk is.
A menüpontnál még fontos megemlíteni az Action=”test/test” paramétert, ami a később kialakítandó adminhtml controller útvonalát hivatott megadni. A következő lépésben szükséges elkészíteni az adminhtml controllert és layout file-t, ami a grid megjelenítésért felelős.
Azonban előtte létre kell hoznunk egy abstract controller osztályt, hogy a backend jogosultság kezelést egy helyen valósítsuk meg. Az abstract controller osztályt az app/code/Aion/Test/Controller/Adminhtml/ könyvtárban lévő Test.php-ban valósítjuk meg. A fájl tartalma:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Controller\Adminhtml; /** * Aion manage items controller */ abstract class Test extends \Magento\Backend\App\Action { /** * Core registry * * @var \Magento\Framework\Registry */ protected $_coreRegistry = null; /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry */ public function __construct(\Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry) { $this->_coreRegistry = $coreRegistry; parent::__construct($context); } /** * Init page * * @param \Magento\Backend\Model\View\Result\Page $resultPage * @return \Magento\Backend\Model\View\Result\Page */ protected function initPage($resultPage) { $resultPage->setActiveMenu('Aion_Test::aion_test') ->addBreadcrumb(__('Test'), __('Test')) ->addBreadcrumb(__('Items'), __('')); return $resultPage; } /** * Check the permission to run it * * @return boolean */ protected function _isAllowed() { return $this->_authorization->isAllowed('Aion_Test::test_menu'); } }
Az abstract controller initPage() függvénye (metódusa) felelős az aktív menüpont beállítása mellett a breadcrumb (morzsa menü) útvonal beállításáért is. A másik fontos függvény az _isAllowed(), ami az adminisztrátor jogosultságot ellenőrzi és kezeli.
Ezután elkészítjük az admin táblázat (grid) kezeléséhez szükséges controllert is, amit az imént említett abstract controller-ből fogunk kiterjeszteni. A controller osztályt az app/code/Aion/Test/Controller/Adminhtml/Test könyvtárban lévő Index.php-ban valósítjuk meg. A fájl tartalma:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Controller\Adminhtml\Test; class Index extends \Aion\Test\Controller\Adminhtml\Test { /** * @var \Magento\Framework\View\Result\PageFactory */ protected $resultPageFactory; /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, \Magento\Framework\View\Result\PageFactory $resultPageFactory ) { $this->resultPageFactory = $resultPageFactory; parent::__construct($context, $coreRegistry); } /** * Index action * * @return \Magento\Framework\Controller\ResultInterface */ public function execute() { /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ $resultPage = $this->resultPageFactory->create(); $this->initPage($resultPage)->getConfig()->getTitle()->prepend(__('Items')); return $resultPage; } }
A controller-ben lévő $resultPage és $this->resultPageFactory helyettesíti Magento 1.x-ből megismert $this->loadLayout() és $this->renderLayout() hívásokat. Ahhoz, hogy a Magento 2.0 felismerje a létrehozott adminhtml controller-ek útvonalát, ezt definiálnunk kell egy külön fájl-ban. Az útvonal definiálását az app/code/Aion/Test/etc/adminhtml/ könyvtárban lévő routes.xml-ban valósítjuk meg. A fájl tartalma:
<?xml version="1.0"?> <!-- /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> <router id="admin"> <route id="test" frontName="test"> <module name="Aion_Test" before="Magento_Backend" /> </route> </router> </config>
A fájlban két lényeges tag és hozzá tartozó paraméter látható. Az első a <router id=”admin”> ami jelzi, hogy ez egy backend útvonal. A második a <route id=”test” frontName=”test”> ahol a frontName határozza meg az elkészült adminhtml controllerek fő útvonalát (az admin url utáni első paramétert).
Következő lépésben létre kell hoznunk a collection-t, melynek feladata, hogy a fenti admin táblázatot (grid) kiszolgálja a szükséges adatokkal. A collection-t az app/code/Aion/Model/ResourceModel/Test/Grid/ könyvtárban lévő Collection.php-ban valósítjuk meg. A fájl tartalma:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Model\ResourceModel\Test\Grid; use Magento\Framework\Api\Search\SearchResultInterface; use Magento\Framework\Search\AggregationInterface; use Aion\Test\Model\ResourceModel\Test\Collection as TestCollection; /** * Collection for displaying grid of Aion Items */ class Collection extends TestCollection implements SearchResultInterface { /** * @var AggregationInterface */ protected $aggregations; /** * @param \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param string $mainTable * @param string $eventPrefix * @param string $eventObject * @param string $resourceModel * @param string $model * @param string|null $connection * @param \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory, \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Store\Model\StoreManagerInterface $storeManager, $mainTable, $eventPrefix, $eventObject, $resourceModel, $model = 'Magento\Framework\View\Element\UiComponent\DataProvider\Document', $connection = null, \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null ) { parent::__construct( $entityFactory, $logger, $fetchStrategy, $eventManager, $storeManager, $connection, $resource ); $this->_eventPrefix = $eventPrefix; $this->_eventObject = $eventObject; $this->_init($model, $resourceModel); $this->setMainTable($mainTable); } /** * @return AggregationInterface */ public function getAggregations() { return $this->aggregations; } /** * @param AggregationInterface $aggregations * @return $this */ public function setAggregations($aggregations) { $this->aggregations = $aggregations; } /** * Retrieve all ids for collection * Backward compatibility with EAV collection * * @param int $limit * @param int $offset * @return array */ public function getAllIds($limit = null, $offset = null) { return $this->getConnection()->fetchCol($this->_getAllIdsSelect($limit, $offset), $this->_bindParams); } /** * Get search criteria. * * @return \Magento\Framework\Api\SearchCriteriaInterface|null */ public function getSearchCriteria() { return null; } /** * Set search criteria. * * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria * @return $this * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function setSearchCriteria(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria = null) { return $this; } /** * Get total count. * * @return int */ public function getTotalCount() { return $this->getSize(); } /** * Set total count. * * @param int $totalCount * @return $this * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function setTotalCount($totalCount) { return $this; } /** * Set items list. * * @param \Magento\Framework\Api\ExtensibleDataInterface[] $items * @return $this * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function setItems(array $items = null) { return $this; } }
A fájlban definiált osztály felelős a kialakítandó admin táblázatban (grid) az adatok hozzáadásáért, keresés és lapozás implementálásáért. A következőkben leírt UI Components megfelelő működéséhez szükséges a fenti függvények implementálása.
Másik előnye, hogy az itt definiált osztályt könnyen máshol is fel tudjuk használni, amennyiben máshol is megszeretnénk jeleníteni a modul adatait admin táblázatban (grid), például egy product vagy customer ajax tab-on az adminisztrációs felületen.
Már csak egy dolog van hátra, ami nem más, mint az Index controllerhez tartozó layout file elkészítése. A layout file-t az app/code/Aion/Test/view/adminhtml/layout/ könyvtárban lévő test_test_index.xml-ban valósítjuk meg. Jól látható a korábban definiált route a fájl nevében: alap route -> könyvtár -> controller action. A fájl tartalma:
<?xml version="1.0"?> <!-- /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ --> <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="test_test_listing"/> </referenceContainer> </body> </page>
A layout fájlban lévő „content” referencia konténerben van definiálva a korábban említett UI component file neve, amire a következő pontban térünk ki részletesen.
2) UI Components avagy az admin táblázat (grid) új kialakítása
A Magento 2.0-ban bevezetett UI component-ek használatával sokkal könnyebben tudunk admin táblázatot (grid) létrehozni és emellett az adminisztrátor számára sokkal több lehetőséget nyújt a táblázatban történő kereséshez, szűréshez, az oszlopok tetszőleges megjelenítéséhez. Emellett külön megjelenítések menthetők le.
A UI component-ek működéséhez több fájlt is létre kell hoznunk és megfelelően implementálnunk. A legfontosabb fájl, ami az admin táblázat működését és megjelenését meghatározza egy xml fájl. Ez a mi modulunk esetében a test_test_listing.xml nevet kapta (lásd előző pont) és az app/code/Aion/Test/view/adminhtml/ui_component könyvtárban van elhelyezve. A fájl nagyon hosszú, így tartalmát darabolva jelenítjük meg cikkünkben.
<?xml version="1.0" encoding="UTF-8"?> <!-- /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ --> <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">test_test_listing.test_test_listing_data_source</item> <item name="deps" xsi:type="string">test_test_listing.test_test_listing_data_source</item> </item> <item name="spinner" xsi:type="string">test_test_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 Item</item> <item name="class" xsi:type="string">primary</item> <item name="url" xsi:type="string">*/*/new</item> </item> </item> </argument> <dataSource name="test_test_listing_data_source"> <argument name="dataProvider" xsi:type="configurableObject"> <argument name="class" xsi:type="string">TestGridDataProvider</argument> <argument name="name" xsi:type="string">test_test_listing_data_source</argument> <argument name="primaryFieldName" xsi:type="string">test_id</argument> <argument name="requestFieldName" xsi:type="string">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> </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>
A fájlban lévő első argument tag-ben vannak definiálva az alábbiak:
- adat forrás név (test_test_listing_data_source) lásd második dataSource tag: <dataSource name=”test_test_listing_data_source”>
- oszlopok tag neve: test_test_columns, erre továbbiakban lesz szükségünk
- az új elem hozzáadása és egyéb gombok definiálása, lásd: <item name=”buttons” xsi:type=”array”> tag
<container name="listing_top"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="template" xsi:type="string">ui/grid/toolbar</item> </item> </argument> <bookmark name="bookmarks"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="storageConfig" xsi:type="array"> <item name="namespace" xsi:type="string">test_test_listing</item> </item> </item> </argument> </bookmark> <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">test_test_listing.test_test_listing.test_test_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>
Az xml fájlt tovább böngészve definiálásra kerülnek a táblázat felett elhelyezkedő funkciók. Ezek az alábbiak:
- lementhetjük az aktuális táblázat megjelenést több view-ban, lásd: <bookmark name=”bookmarks”> tag
- beállíthatjuk túl sok oszlop esetén, hogy melyek jelenjenek meg és az előbb említett bookmarks-nál menthetjük le, lásd: <component name=”columns_controls”> tag
<filterSearch name="fulltext"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="provider" xsi:type="string">test_test_listing.test_test_listing_data_source</item> <item name="chipsProvider" xsi:type="string">test_test_listing.test_test_listing.listing_top.listing_filters_chips</item> <item name="storageConfig" xsi:type="array"> <item name="provider" xsi:type="string">test_test_listing.test_test_listing.listing_top.bookmarks</item> <item name="namespace" xsi:type="string">current.search</item> </item> </item> </argument> </filterSearch> <filters name="listing_filters"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="columnsProvider" xsi:type="string">test_test_listing.test_test_listing.test_test_columns</item> <item name="storageConfig" xsi:type="array"> <item name="provider" xsi:type="string">test_test_listing.test_test_listing.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">test_test_listing.test_test_listing.listing_top.listing_filters</item> <item name="imports" xsi:type="array"> <item name="visible" xsi:type="string">test_test_listing.test_test_listing.test_test_columns.${ $.index }:visible</item> </item> </item> </item> </argument> </filters>
Hozzáadásra kerül a text alapú kereső és a táblázat szűrése (filters). Ezek az alábbiak:
- varchar, text típusú oszlopokban kereshetünk egy input mezőben, lásd: <filterSearch name=”fulltext”> tag
- minden egyes oszlopot szűrhetünk megfelelő paraméterek szerint view(Aion\Test\Ui\Component\Listing\Column\Test\Options), select, dátum, ID(range), text típusú szűrések, lásd: <filters name=”listing_filters”> tag
<massaction name="listing_massaction"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="selectProvider" xsi:type="string">test_test_listing.test_test_listing.test_test_columns.ids</item> <item name="indexField" xsi:type="string">test_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="test/test/massDelete"/> <item name="confirm" xsi:type="array"> <item name="title" xsi:type="string" translate="true">Delete items</item> <item name="message" xsi:type="string" translate="true">Are you sure you wan't to delete selected items?</item> </item> </item> </argument> </action> <action name="disable"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="type" xsi:type="string">disable</item> <item name="label" xsi:type="string" translate="true">Disable</item> <item name="url" xsi:type="url" path="test/test/massDisable"/> </item> </argument> </action> <action name="enable"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="type" xsi:type="string">enable</item> <item name="label" xsi:type="string" translate="true">Enable</item> <item name="url" xsi:type="url" path="test/test/massEnable"/> </item> </argument> </action> </massaction>
A massaction tag-en belül kerülnek hozzáadásra tetszőleges általunk definiált műveletek, melyek a tömeges adatmódosításra szolgálnak. A modulunkban ezek az alábbiak:
- tömeges törlés, lásd: <action name=”delete”> tag
- tömeges engedélyezés és tiltás, lásd: <action name=”disable”> és <action name=”enable”> tag-ek. Ezek a modulunk adatbázis táblájában korában kialakított is_active adatot módosítják.
<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">test_test_listing.test_test_listing.listing_top.bookmarks</item> <item name="namespace" xsi:type="string">current.paging</item> </item> <item name="selectProvider" xsi:type="string">test_test_listing.test_test_listing.test_test_columns.ids</item> </item> </argument> </paging> </container>
A <paging name=”listing_paging”> tag implementálja lapozást és a listázott elemek számának választhatóságát (select) a táblázatunkban.
<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">test_test_listing.test_test_listing.listing_top.bookmarks</item> <item name="namespace" xsi:type="string">current.paging</item> </item> <item name="selectProvider" xsi:type="string">test_test_listing.test_test_listing.test_test_columns.ids</item> </item> </argument> </paging> </container>
Fentiek után következik a táblázat oszlopainak meghatározása, lásd: <columns name=”test_test_columns”> tag. Ennek nevét már a fájl elején definiáltuk. A korábban említett mass action-ökhez beállított ID mező, lásd: <selectionsColumn name=”ids”> tag.
<column name="test_id"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="filter" xsi:type="string">textRange</item> <item name="sorting" xsi:type="string">asc</item> <item name="label" xsi:type="string" translate="true">ID</item> </item> </argument> </column> <column name="name"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="editor" xsi:type="array"> <item name="editorType" xsi:type="string">text</item> <item name="validation" xsi:type="array"> <item name="required-entry" xsi:type="boolean">true</item> </item> </item> <item name="filter" xsi:type="string">text</item> <item name="label" xsi:type="string" translate="true">Name</item> </item> </argument> </column> <column name="email"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="editor" xsi:type="array"> <item name="editorType" xsi:type="string">text</item> <item name="validation" xsi:type="array"> <item name="required-entry" xsi:type="boolean">true</item> </item> </item> <item name="filter" xsi:type="string">text</item> <item name="label" xsi:type="string" translate="true">Email</item> </item> </argument> </column> <column name="creation_time" class="Magento\Ui\Component\Listing\Columns\Date"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="filter" xsi:type="string">dateRange</item> <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/date</item> <item name="dataType" xsi:type="string">date</item> <item name="label" xsi:type="string" translate="true">Created</item> </item> </argument> </column> <column name="update_time" class="Magento\Ui\Component\Listing\Columns\Date"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="filter" xsi:type="string">dateRange</item> <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/date</item> <item name="dataType" xsi:type="string">date</item> <item name="label" xsi:type="string" translate="true">Modified</item> </item> </argument> </column> <column name="sort_order"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="editor" xsi:type="array"> <item name="editorType" xsi:type="string">text</item> <item name="validation" xsi:type="array"> <item name="required-entry" xsi:type="boolean">true</item> </item> </item> <item name="filter" xsi:type="string">text</item> <item name="label" xsi:type="string" translate="true">Sort Order</item> </item> </argument> </column> <column name="is_active"> <argument name="data" xsi:type="array"> <item name="options" xsi:type="array"> <item name="disable" xsi:type="array"> <item name="value" xsi:type="string">0</item> <item name="label" xsi:type="string" translate="true">Disabled</item> </item> <item name="enable" xsi:type="array"> <item name="value" xsi:type="string">1</item> <item name="label" xsi:type="string" translate="true">Enabled</item> </item> </item> <item name="config" xsi:type="array"> <item name="filter" xsi:type="string">select</item> <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/select</item> <item name="editor" xsi:type="string">select</item> <item name="dataType" xsi:type="string">select</item> <item name="label" xsi:type="string" translate="true">Status</item> </item> </argument> </column> <actionsColumn name="actions" class="Aion\Test\Ui\Component\Listing\Column\TestActions"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="indexField" xsi:type="string">test_id</item> </item> </argument> </actionsColumn> </columns> </listing>
Ezt követően a táblázatban lévő oszlopokat kell meghatároznunk. Az egyes oszlopoknál beállíthatjuk a típust, pl.: text, select, textRange, dateRange stb. Az utolsó oszlop az alap action-öket tartalmazza, lásd: <actionsColumn name=”actions” class=”Aion\Test\Ui\Component\Listing\Column\TestActions”> tag
Ezzel el is készültünk a grid definíciós xml-lel (test_test_listing.xml). A továbbiakban megnézünk néhány osztályt, ami az utolsó oszlopban lévő action-ökért felel.
3) UI component osztályok
Az előző pontban kialakított grid definíciós xml-ben található action oszlop működéséhez szükségünk van egy osztályra, mely a megjelenítést és a működést segítik. Az első az előző pontban látható <actionsColumn name=”actions” class=”Aion\Test\Ui\Component\Listing\Column\TestActions”> tag-ben látható a TestActions osztály.
A fájl az app/code/Aion/Test/Ui/Component/Listing/Column könyvtárban van elhelyezve TestActions.php néven. A fájl tartalma:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Ui\Component\Listing\Column; use Magento\Framework\UrlInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Framework\View\Element\UiComponentFactory; use Magento\Ui\Component\Listing\Columns\Column; /** * Class TestActions */ class TestActions extends Column { /** * Url path */ const URL_PATH_EDIT = 'test/test/edit'; const URL_PATH_DELETE = 'test/test/delete'; /** * @var UrlInterface */ protected $urlBuilder; /** * Constructor * * @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) { if (isset($item['test_id'])) { $item[$this->getData('name')] = [ 'edit' => [ 'href' => $this->urlBuilder->getUrl( static::URL_PATH_EDIT, [ 'test_id' => $item['test_id'] ] ), 'label' => __('Edit') ], 'delete' => [ 'href' => $this->urlBuilder->getUrl( static::URL_PATH_DELETE, [ 'test_id' => $item['test_id'] ] ), 'label' => __('Delete'), 'confirm' => [ 'title' => __('Delete "${ $.$data.name }"'), 'message' => __('Are you sure you wan\'t to delete a "${ $.$data.name }" record?') ] ] ]; } } } return $dataSource; } }
Az osztály előállítja a mass action megjelenítéséhez szükséges tömböt a megfelelő formátumban. A file elején lévő konstantsoknál fontos a pontos útvonal meghatározása, hogy a megfelelő adminhtml controller-re mutassanak.
4) Adminhtml controller-ek
A grid teljes működéséhez néhány controller-t még el kell készíteni. Nézzük sorban őket.
A tömeges törléshez a massDelete controller-t használjuk. A fájl az app/code/Aion/Test/Controller/Adminhtml/Test/ könyvtárban van elhelyezve MassDelete.php néven. A fájl tartalma:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Controller\Adminhtml\Test; use Magento\Framework\Controller\ResultFactory; use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Aion\Test\Model\ResourceModel\Test\CollectionFactory; /** * Class MassDelete */ class MassDelete extends \Magento\Backend\App\Action { /** * @var Filter */ protected $filter; /** * @var CollectionFactory */ protected $collectionFactory; /** * @param Context $context * @param Filter $filter * @param CollectionFactory $collectionFactory */ public function __construct(Context $context, Filter $filter, CollectionFactory $collectionFactory) { $this->filter = $filter; $this->collectionFactory = $collectionFactory; parent::__construct($context); } /** * Execute action * * @return \Magento\Backend\Model\View\Result\Redirect * @throws \Magento\Framework\Exception\LocalizedException|\Exception */ public function execute() { $collection = $this->filter->getCollection($this->collectionFactory->create()); $collectionSize = $collection->getSize(); foreach ($collection as $item) { $item->delete(); } $this->messageManager->addSuccess(__('A total of %1 record(s) have been deleted.', $collectionSize)); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); return $resultRedirect->setPath('*/*/'); } }
A controller osztály execute() függvénye – vagyis az action – egy collection-t kap (\Magento\Ui\Component\MassAction\Filter osztálytól), amin végig iterálva törli az elemeket. A tömeges státusz módosításhoz a massEnable és massDisable controller-eket használjuk.
A fájlok az app/code/Aion/Test/Controller/Adminhtml/Test/ könyvtárban vannak elhelyezve MassEnable.php és MassDisable.php néven. A fájlok tartalma:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Controller\Adminhtml\Test; use Magento\Framework\Controller\ResultFactory; use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Aion\Test\Model\ResourceModel\Test\CollectionFactory; /** * Class MassEnable */ class MassEnable extends \Magento\Backend\App\Action { /** * @var Filter */ protected $filter; /** * @var CollectionFactory */ protected $collectionFactory; /** * @param Context $context * @param Filter $filter * @param CollectionFactory $collectionFactory */ public function __construct(Context $context, Filter $filter, CollectionFactory $collectionFactory) { $this->filter = $filter; $this->collectionFactory = $collectionFactory; parent::__construct($context); } /** * Execute action * * @return \Magento\Backend\Model\View\Result\Redirect * @throws \Magento\Framework\Exception\LocalizedException|\Exception */ public function execute() { $collection = $this->filter->getCollection($this->collectionFactory->create()); foreach ($collection as $item) { $item->setIsActive(true); $item->save(); } $this->messageManager->addSuccess(__('A total of %1 record(s) have been enabled.', $collection->getSize())); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); return $resultRedirect->setPath('*/*/'); } } <?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Controller\Adminhtml\Test; use Magento\Framework\Controller\ResultFactory; use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Aion\Test\Model\ResourceModel\Test\CollectionFactory; /** * Class MassDisable */ class MassDisable extends \Magento\Backend\App\Action { /** * @var Filter */ protected $filter; /** * @var CollectionFactory */ protected $collectionFactory; /** * @param Context $context * @param Filter $filter * @param CollectionFactory $collectionFactory */ public function __construct(Context $context, Filter $filter, CollectionFactory $collectionFactory) { $this->filter = $filter; $this->collectionFactory = $collectionFactory; parent::__construct($context); } /** * Execute action * * @return \Magento\Backend\Model\View\Result\Redirect * @throws \Magento\Framework\Exception\LocalizedException|\Exception */ public function execute() { $collection = $this->filter->getCollection($this->collectionFactory->create()); foreach ($collection as $item) { $item->setIsActive(false); $item->save(); } $this->messageManager->addSuccess(__('A total of %1 record(s) have been disabled.', $collection->getSize())); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); return $resultRedirect->setPath('*/*/'); } }
A két controller működése nagyon hasonló egymáshoz. Mindkettő a Filter osztálytól kapott collection-ön iterál végig, és állítja be az is_active data kulcsot massEnbale esetén true-ra, míg massDisable esetén false-ra, majd menti a collection elemeit.
5) Object manager konfigurációs
Ahhoz, hogy az elkészített admin táblázat(grid) megfelelően működjön, meg kell adnunk a forrás adat objektumokat és filter-eket. Ehhez szükségünk lesz egy definíciós xml-re. A fájl az app/code/Aion/Test/etc/ könyvtárban van elhelyezve di.xml néven. A fájl tartalma:
<?xml version="1.0"?> <!-- /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory"> <arguments> <argument name="collections" xsi:type="array"> <item name="test_test_listing_data_source" xsi:type="string">Aion\Test\Model\ResourceModel\Test\Grid\Collection</item> </argument> </arguments> </type> <type name="Aion\Test\Model\ResourceModel\Test\Grid\Collection"> <arguments> <argument name="mainTable" xsi:type="string">aion_test</argument> <argument name="eventPrefix" xsi:type="string">aion_test_grid_collection</argument> <argument name="eventObject" xsi:type="string">test_grid_collection</argument> <argument name="resourceModel" xsi:type="string">Aion\Test\Model\ResourceModel\Test</argument> </arguments> </type> <virtualType name="TestGirdFilterPool" type="Magento\Framework\View\Element\UiComponent\DataProvider\FilterPool"> <arguments> <argument name="appliers" xsi:type="array"> <item name="regular" xsi:type="object">Magento\Framework\View\Element\UiComponent\DataProvider\RegularFilter</item> <item name="fulltext" xsi:type="object">Magento\Framework\View\Element\UiComponent\DataProvider\FulltextFilter</item> </argument> </arguments> </virtualType> <virtualType name="TestGridDataProvider" type="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider"> <arguments> <argument name="collection" xsi:type="object" shared="false">Aion\Test\Model\ResourceModel\Test\Collection</argument> <argument name="filterPool" xsi:type="object" shared="false">TestGirdFilterPool</argument> </arguments> </virtualType> </config>
Ebben a fájlban definiáljuk a grid-hez szükséges collection-t (lásd: <item name=”test_test_listing_data_source” xsi:type=”string”>Aion\Test\Model\ResourceModel\Test\Grid\Collection</item>), filter-t és data provider-t, mely UI component megfelelő működéséhez szükséges.
Az egyes elemek editálását, mentését és egyenkénti törlését a következőkben írjuk le.
6) Editáláshoz szükséges admin block-ok létrehozása
Ahhoz, hogy a modulhoz tartozó adatokat létre tudjuk hozni az admin felületen és szerkeszteni tudjuk, szükségünk lesz a megfelelő osztályokra. Első lépésben a container osztályt kell létrehozni, mely később a form-ot fogja tartalmazni.
Az osztályt az Aion/Test/Block/Adminhtml/ könyvtárban lévő Test.php fájlban valósítjuk meg:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Block\Adminhtml; /** * Adminhtml Aion items content block */ class Test extends \Magento\Backend\Block\Widget\Grid\Container { /** * @return void */ protected function _construct() { $this->_blockGroup = 'Aion_Test'; $this->_controller = 'adminhtml_test'; $this->_headerText = __('Items'); $this->_addButtonLabel = __('Add New Item'); parent::_construct(); } }
Az osztályban lényeges a megfelelő blockGroup és controller meghatározása.
A következő lépésben szükségünk lesz a form container osztályra. Itt határozzuk meg szerkesztetés alatt álló objektum admin oldalának title-jét, és adhatunk hozzá tetszőleges button-okat az alap gombokon kívül, vagy távolíthatunk el.
Az osztályt az Aion/Test/Block/Adminhtml/Test könyvtárban lévő Edit.php fájlban valósítjuk meg:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Block\Adminhtml; /** * Adminhtml Aion items content block */ class Test extends \Magento\Backend\Block\Widget\Grid\Container { /** * @return void */ protected function _construct() { $this->_blockGroup = 'Aion_Test'; $this->_controller = 'adminhtml_test'; $this->_headerText = __('Items'); $this->_addButtonLabel = __('Add New Item'); parent::_construct(); } }
Amennyiben WYSWYG editort is szeretnénk használni például textarea típusú mezőhöz, akkor azt a _construct() függvényben kell elhelyezni, vagy a prepareLayout() függvényben. Az osztályban lévő getHeaderText() függvény határozza meg az admin oldal title értékét.
Az utolsó block, amit el kell készítenünk, a form megjelenítését és kezelését végzi. Az osztályt az Aion/Test/Block/Adminhtml/Test/Edit könyvtárban lévő Form.php fájlban valósítjuk meg:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Block\Adminhtml\Test\Edit; /** * Adminhtml Aion item edit form */ class Form extends \Magento\Backend\Block\Widget\Form\Generic { /** * @var \Magento\Cms\Model\Wysiwyg\Config */ protected $_wysiwygConfig; /** * @var \Magento\Store\Model\System\Store */ protected $_systemStore; /** * @param \Magento\Backend\Block\Template\Context $context * @param \Magento\Framework\Registry $registry * @param \Magento\Framework\Data\FormFactory $formFactory * @param \Magento\Cms\Model\Wysiwyg\Config $wysiwygConfig * @param \Magento\Store\Model\System\Store $systemStore * @param array $data */ public function __construct( \Magento\Backend\Block\Template\Context $context, \Magento\Framework\Registry $registry, \Magento\Framework\Data\FormFactory $formFactory, \Magento\Cms\Model\Wysiwyg\Config $wysiwygConfig, \Magento\Store\Model\System\Store $systemStore, array $data = [] ) { $this->_wysiwygConfig = $wysiwygConfig; $this->_systemStore = $systemStore; parent::__construct($context, $registry, $formFactory, $data); } /** * Init form * * @return void */ protected function _construct() { parent::_construct(); $this->setId('test_form'); $this->setTitle(__('Item Information')); } /** * Prepare form * * @return $this */ protected function _prepareForm() { $model = $this->_coreRegistry->registry('test_item'); /** @var \Magento\Framework\Data\Form $form */ $form = $this->_formFactory->create( ['data' => ['id' => 'edit_form', 'action' => $this->getData('action'), 'method' => 'post']] ); $form->setHtmlIdPrefix('item_'); $fieldset = $form->addFieldset( 'base_fieldset', ['legend' => __('General Information'), 'class' => 'fieldset-wide'] ); if ($model->getId()) { $fieldset->addField('test_id', 'hidden', ['name' => 'test_id']); } $fieldset->addField( 'name', 'text', [ 'name' => 'name', 'label' => __('Name'), 'title' => __('Name'), 'required' => true ] ); $fieldset->addField( 'email', 'text', [ 'name' => 'email', 'label' => __('Email'), 'title' => __('Email'), 'required' => true, 'class' => 'validate-email' ] ); $fieldset->addField( 'is_active', 'select', [ 'label' => __('Status'), 'title' => __('Status'), 'name' => 'is_active', 'required' => true, 'options' => ['1' => __('Enabled'), '0' => __('Disabled')] ] ); if (!$model->getId()) { $model->setData('is_active', '1'); } $fieldset->addField( 'sort_order', 'text', [ 'name' => 'sort_order', 'label' => __('Sort Order'), 'title' => __('Sort Order'), 'required' => false ] ); $form->setValues($model->getData()); $form->setUseContainer(true); $this->setForm($form); return parent::_prepareForm(); } }
Az osztály _prepareForm() függvényében adjuk hozzá a szerkesztésre szánt mezőket, ami a mi esetünkben a name, email és sort_order mezők. Ezek mellett szerepel még a multistore kezelés szempontjából fontos store_id field is, illetve is_active field is, ami jelen esetben select típusú és a szerkesztés alatt álló elem státuszát hivatott beállítani.
A fent említett három osztállyal el is készítettük az adminisztrációs felületen történő szerkesztéshez szükséges fájlokat.
7) Controller-ek és layout létrehozása
Az editálás megvalósításához a fenti osztályokon kívül szükségünk lesz még a megfelelő controller osztályokra és layout fájlokra. Az első osztályt az Aion/Test/Controller/Adminhtml/Test/ könyvtárban lévő NewAction.php fájlban valósítjuk meg:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Controller\Adminhtml\Test; class NewAction extends \Aion\Test\Controller\Adminhtml\Test { /** * @var \Magento\Backend\Model\View\Result\ForwardFactory */ protected $resultForwardFactory; /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory ) { $this->resultForwardFactory = $resultForwardFactory; parent::__construct($context, $coreRegistry); } /** * Create new item * * @return \Magento\Framework\Controller\ResultInterface */ public function execute() { /** @var \Magento\Framework\Controller\Result\Forward $resultForward */ $resultForward = $this->resultForwardFactory->create(); return $resultForward->forward('edit'); } }
Az osztály az új elemek létrehozására szolgál és lényegében az action függvénye (execute()) átirányít az Edit controller osztályra. A következő lépésben létrehozzuk a szerkesztéshez szükséges controller-t.
Az osztályt az Aion/Test/Controller/Adminhtml/Test/ könyvtárban lévő Edit.php fájlban valósítjuk meg:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Controller\Adminhtml\Test; class Edit extends \Aion\Test\Controller\Adminhtml\Test { /** * @var \Magento\Framework\View\Result\PageFactory */ protected $resultPageFactory; /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, \Magento\Framework\View\Result\PageFactory $resultPageFactory ) { $this->resultPageFactory = $resultPageFactory; parent::__construct($context, $coreRegistry); } /** * Edit item * * @return \Magento\Framework\Controller\ResultInterface * @SuppressWarnings(PHPMD.NPathComplexity) */ public function execute() { // 1. Get ID and create model $id = $this->getRequest()->getParam('test_id'); $model = $this->_objectManager->create('Aion\Test\Model\Test'); // 2. Initial checking if ($id) { $model->load($id); if (!$model->getId()) { $this->messageManager->addError(__('This item no longer exists.')); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); return $resultRedirect->setPath('*/*/'); } } // 3. Set entered data if was error when we do save $data = $this->_objectManager->get('Magento\Backend\Model\Session')->getFormData(true); if (!empty($data)) { $model->setData($data); } // 4. Register model to use later in blocks $this->_coreRegistry->register('test_item', $model); /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ $resultPage = $this->resultPageFactory->create(); // 5. Build edit form $this->initPage($resultPage)->addBreadcrumb( $id ? __('Edit Item') : __('New Item'), $id ? __('Edit Item') : __('New Item') ); $resultPage->getConfig()->getTitle()->prepend(__('Items')); $resultPage->getConfig()->getTitle()->prepend($model->getId() ? $model->getName() : __('New Item')); return $resultPage; } }
Az edit action(execute() függvény) első lépésben lekéri a test_id paramétert. Ezt követően inicializálja az Aion/Test/Model/Test modell osztályt. Amennyiben a test_id paraméternek van értéke, a modellt megpróbálja betöltelni az említett id-val.
Sikertelen esetben hibaüzenet állít be, majd visszairányít. Ellenkező esetben a betöltött modellt a registry-ben tárolja ($this->_coreRegistry->register(’test_item’, $model)). Ezt olvassa ki a registry-ből a fent már említett form container osztály is, és használja fel.
Végezetül létrehozza az oldalt ($resultPage), majd beállítja az oldal title paraméterét és breadcrumb-ot is. A controller-hez tartozó layout fájlt az Aion/Test/view/adminhtml/layout/ könyvtárban lévő test_test_edit.xml fájlban valósítjuk meg:
<?xml version="1.0"?> <!-- /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <update handle="editor"/> <body> <referenceContainer name="content"> <block class="Aion\Test\Block\Adminhtml\Test\Edit" name="test_test_edit"/> </referenceContainer> </body> </page>
A következő lépés a mentés elkészítése. Az osztályt az Aion/Test/Controller/Adminhtml/Test/ könyvtárban lévő Save.php fájlban valósítjuk meg:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Controller\Adminhtml\Test; class Save extends \Aion\Test\Controller\Adminhtml\Test { /** * Save action * * @return \Magento\Framework\Controller\ResultInterface */ public function execute() { /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); // check if data sent $data = $this->getRequest()->getPostValue(); if ($data) { $id = $this->getRequest()->getParam('test_id'); $model = $this->_objectManager->create('Aion\Test\Model\Test')->load($id); if (!$model->getId() && $id) { $this->messageManager->addError(__('This item no longer exists.')); return $resultRedirect->setPath('*/*/'); } // init model and set data $model->setData($data); // try to save it try { // save the data $model->save(); // display success message $this->messageManager->addSuccess(__('You saved the item.')); // clear previously saved data from session $this->_objectManager->get('Magento\Backend\Model\Session')->setFormData(false); // check if 'Save and Continue' if ($this->getRequest()->getParam('back')) { return $resultRedirect->setPath('*/*/edit', ['test_id' => $model->getId()]); } // go to grid return $resultRedirect->setPath('*/*/'); } catch (\Exception $e) { // display error message $this->messageManager->addError($e->getMessage()); // save data in session $this->_objectManager->get('Magento\Backend\Model\Session')->setFormData($data); // redirect to edit form return $resultRedirect->setPath('*/*/edit', ['test_id' => $this->getRequest()->getParam('test_id')]); } } return $resultRedirect->setPath('*/*/'); } }
A controller osztály első lépésben várja a korábban kialakított form által posztolt adatokat ($data = $this->getRequest()->getPostValue();). Amennyiben ez nem egy üres tömb, inicializálja az Aion/Test/Model/Test modell osztályt és ha létezik a paraméterként kapott test_id is (vagyis nem új objektum mentésére kerül sor), akkor betölti a megfelelő id-val. Ezt követően a post-ban kapott adatokat beállítja majd menti a modellt.
Amennyiben mindezzel elkészültünk, akkor a korábban kialakított admin grid-ből (táblázat) új objektumokat tudunk hozzáadni és menteni, majd ezeket szerkeszteni. Még egy fontos controller van hátra, ami a törlést hivatott megvalósítani.
Az osztályt az Aion/Test/Controller/Adminhtml/Test/ könyvtárban lévő Delete.php fájlban valósítjuk meg:
<?php /** * Copyright © 2016 AionNext Ltd. All rights reserved. * See COPYING.txt for license details. */ namespace Aion\Test\Controller\Adminhtml\Test; class Delete extends \Aion\Test\Controller\Adminhtml\Test { /** * Delete action * * @return \Magento\Framework\Controller\ResultInterface */ public function execute() { /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); // check if we know what should be deleted $id = $this->getRequest()->getParam('test_id'); if ($id) { try { // init model and delete $model = $this->_objectManager->create('Aion\Test\Model\Test'); $model->load($id); $model->delete(); // display success message $this->messageManager->addSuccess(__('You deleted the item.')); // go to grid return $resultRedirect->setPath('*/*/'); } catch (\Exception $e) { // display error message $this->messageManager->addError($e->getMessage()); // go back to edit form return $resultRedirect->setPath('*/*/edit', ['test_id' => $id]); } } // display error message $this->messageManager->addError(__('We can\'t find the item to delete.')); // go to grid return $resultRedirect->setPath('*/*/'); } }
A delete action (execute() függvény) első lépésben lekéri a test_id paramétert. Ezt követően inicializálja az Aion/Test/Model/Test model osztályt. Amennyiben a test_id paraméternek van értéke, a modellt megpróbálja betölteni az említett id-val, majd elvégzi a törlést.
Folytatása következik
Ebben a cikkben ismét átvettünk néhány témakört, melyek segítenek a saját Magento 2.0 modulod fejlesztésében. Bízunk benne, hogy sikerült átadnunk mindazt a hasznos tudást, mely hozzájárul ahhoz, hogy funkcionális modulokat fejlesztess, elvégezd azok beállításait, valamint olyan fájlokat és elemeket szerkeszthess, mint az adatbázis tábla, modell, collection, block, admin táblázat, layout stb.
A 2. RÉSZNEK VÉGE, DE HAMAROSAN FOLYTATJUK! A cikk első részét ide kattintva olvashatod. A következő részben ismét érdekes és hasznos témakörökkel, többek közt az observer-ek létrehozásával és implementálásával ismerkedhetszt meg.
15 éve foglalkozom e-kereskedelmi megoldások fejlesztésével. 2009 óta Magento webáruházakat készítek. Mára több, mint 250 Magento e-kereskedelmi projekt van mögöttem. Ez a leggyorsabban fejlődő területek egyike. Fejlődnek a technológiák és vele a platform is, illetve azok a rendszerek, amelyeket egy webáruházzal integrálunk, legyen az bankkártyás fizetés, vállalatirányítási rendszer vagy hírlevélküldő szolgáltatás, és persze formálódnak a vásárlói szokások is.