如何將帶過濾器的列添加到 Magento 2 訂單網格?
已發表: 2020-02-03通常,Magento 2 商店管理員在使用和自定義訂單網格時需要額外的選項——基於特定的開箱即用參數進行過濾可能成為真正的挑戰。
最近,一位 Magento 開發人員向我提出了一個問題。 他試圖在 Magento 2.3.1 上擴展訂單網格。 網絡上的舊帖子並沒有幫助 - 自然,自過去兩年以來,Magento 發生了很大變化。
根據他的問題,我建議您看一下特定案例的解決方案:
我們需要在訂單網格中添加一列 - 包含完成購買的客戶的一些區域代碼。 此外,商店管理員必須能夠按此新添加的列過濾訂單。
這似乎很容易,但有幾件事值得關注。 例如,購買的購物者可能沒有任何送貨地址——在虛擬訂單的情況下。 或者,我們應該如何列出這些地區? 在開始開發時,所有這些都應考慮在內。 基於前面提到的問題,我們假設:
- 虛擬產品將沒有交付區域('null')。 這將幫助您根據此參數選擇它們,
- 區域將被列出並查看代碼,而無需將其轉換為標籤,就像在默認的 Magento 2 中一樣。
*請注意,本文末尾將提供一個指向 GitHub 上開放訪問模塊的鏈接。 不過,如果您無法完成本文,我會在本段中包含鏈接:https://github.com/mageworx/articles-extended-orders-grid。
然而,儘管時間不夠,我還是鼓勵你繼續閱讀。?
因此,要將新列添加到訂單網格,您需要:
目錄
- 1.新建模塊
- 2. 在網格中添加一列
- 解釋
- 3. 向列添加數據
- 如何添加額外的列?
- [更新] 如何添加包含訂單商品信息的列?
1.新建模塊
首先,讓我們決定模塊和供應商名稱。 好吧,我不需要選擇供應商名稱——它是 MageWorx(好像我有選擇,開個玩笑)。 我仍然可以選擇模塊名稱。 讓它成為ExtendedOrdersGrid (順便說一句,我們有一個 Magento 2 的同名擴展名)。 事實上,在命名空間中使用 MageWorx 作為供應商名稱並不賦予您請求免費支持的權利。 無論如何,如果我們的支持團隊成員度過了一個愉快的周末,您仍然可以在星期一嚐試一下。?
讓我們創建以下目錄:`app/code/MageWorx/ExtendedOrdersGrid`。 要註冊一個模塊,我們需要一些標准文件:
> registration.php php <?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'MageWorx_ExtendedOrdersGrid', __DIR__ ); > composer.json json { "name": "mageworx/module-extended-orders-grid", "description": "Extended Orders Grid Extension", "require": { "magento/module-ui" : ">=100.1.0 < 102", "magento/module-sales" : ">=100.0.0 <103" }, "type": "magento2-module", "version": "1.0.0", "license": [ "OSL-3.0", "AFL-3.0" ], "autoload": { "files": [ "registration.php" ], "psr-4": { "MageWorx\\ExtendedOrdersGrid\\": "" } } } > etc/module.xml xml <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <module name="MageWorx_ExtendedOrdersGrid" setup_version="1.0.0"> <sequence> <module name="Magento_Sales"/> <module name="Magento_Ui"/> </sequence> </module> </config>
需要注意的是,我已經刪除了自動添加到我的 IDE 中的版權。 因此,您可以毫無問題地使用此代碼。 ?
然後,運行一些命令:
> sudo -u www-data php bin/magento module:enable MageWorx_ExtendedOrdersGrid > sudo -u www-data php bin/magento setup:upgrade
瞧! 現在,我們的模塊可以在 Magento 2 中看到了! 哦,如果您在遠程服務器上工作,請不要忘記在測試前傳輸文件。
2. 在網格中添加一列
然後,使用 Magento 2 UI,讓我們在標準網格中添加一個新列。 為此,創建一個文件:
> view/adminhtml/ui_component/sales_order_grid.xml
具有以下內容(其含義我們將進一步討論):
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"> <columns name="sales_order_columns"> <column name="code"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/column</item> <item name="label" xsi:type="string" translate="true">Region Code</item> <item name="sortOrder" xsi:type="number">60</item> <item name="align" xsi:type="string">left</item> <item name="dataType" xsi:type="string">text</item> <item name="visible" xsi:type="boolean">true</item> <item name="filter" xsi:type="string">text</item> </item> </argument> </column> </columns> </listing>
在這裡,您需要指定名稱不會從任何地方取出。 對於有經驗的開發人員來說,這很清楚,但對於那些只了解 Magento 2 的人,我將在本段末尾添加一些解釋。
我們使用標準的“列”節點將列添加到網格中,其中“代碼”名稱下的新列也應添加。 接下來,讓我們在網格中寫入我們列的屬性:
1)組件。 這是一個 JS 類,負責創建和處理此列。 它位於 Magento_Ui 模塊中,地址如下:
`vendor/magento/module-ui/view/base/web/js/grid/columns/column.js`
事實上,如果你是一個好奇的開發者,也可以看看其他的實現。 那裡有很多令人興奮的東西。
2)標籤。 這是帶有列名的行,將顯示給最終用戶。 如果 `translate` 屬性已經建立,不要忘記將它添加到 i18n 本地化文件中。 ?
3)排序順序。 這是網格中的列位置。 如果該模塊已安裝在從未由商店管理員管理過的 Magento 2 上,它將生效。 否則,在正在使用的 Magento 2 上,無論我們做什麼,我們的列都會被添加到列表的末尾。
4)對齊。 這意味著對齊列內容。 我想這很清楚。
5)數據類型。 這是我們將要操作的數據類型。 在我們的例子中,這只是一行文本。 但是,如果我們談論產品數量,它可以是列表或布爾值,也可以是數字。
6)可見。 這只不過是列可見性,儘管很大程度上取決於先前是否使用過網格。
有關網格的所有數據都存儲在 Magento 數據庫中的 `ui_bookmark` 表中。 因此,如果在我們的模塊安裝時沒有關於修改網格的列的記錄,不要指望任何奇蹟。
7)過濾器。 這是過濾器類型。 在這裡,我們指定應該像處理常規文本一樣進行過濾。 在運行代碼時,它將轉換為 MySQL `LIKE %value%` 條件。
解釋
長話短說,擴展 UI 組件的名稱必須與原始組件的名稱相對應。 在我們的例子中,它是 `vendor/magento/module-sales/view/adminhtml/ui_component/sales_order_grid.xml`,它是從 `view/adminhtml/ui_component/sales_order_grid.xml` 模塊根目錄計算的。
UI 網格本身使用 `vendor/magento/module-sales/view/adminhtml/layout/sales_order_index.xml` 佈局添加到所需的控制器,如下所示:
xml <?xml version="1.0"?> <!-- /** * Copyright Magento, Inc. 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="styles"/> <body> <referenceContainer name="content"> <uiComponent name="sales_order_grid"/> </referenceContainer> </body> </page>
這意味著*將 `sales_order_grid` 名稱下的 UI 組件添加到頁面內容* - 就像塊的情況一樣。 然而,我們得到的不是塊,而是 `uiComponent` 及其屬性和限制。
現在,使用以下命令清除 Magento 2 緩存:
> sudo -u www-data php bin/magento cache:clean config
並檢查訂單網格中的結果:
3. 向列添加數據
您可能已經註意到該列已經出現,但它的內容看起來並不像預期的那樣……那裡根本沒有顯示任何數據。 很公平,我們沒有添加任何內容,因此那裡沒有內容。
讓我們開始編寫一個簡單的插件來幫助您填寫我們的專欄。 為此,讓我們捕獲網格集合查詢,在所需的表和網格中進行連接。 該插件將如下所示:
> app/code/MageWorx/ExtendedOrdersGrid/Plugin/AddDataToOrdersGrid.php
php <?php namespace MageWorx\ExtendedOrdersGrid\Plugin; /** * Class AddDataToOrdersGrid */ class AddDataToOrdersGrid { /** * @var \Psr\Log\LoggerInterface */ private $logger; /** * AddDataToOrdersGrid constructor. * * @param \Psr\Log\LoggerInterface $customLogger * @param array $data */ public function __construct( \Psr\Log\LoggerInterface $customLogger, array $data = [] ) { $this->logger = $customLogger; } /** * @param \Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory $subject * @param \Magento\Sales\Model\ResourceModel\Order\Grid\Collection $collection * @param $requestName * @return mixed */ public function afterGetReport($subject, $collection, $requestName) { if ($requestName !== 'sales_order_grid_data_source') { return $collection; } if ($collection->getMainTable() === $collection->getResource()->getTable('sales_order_grid')) { try { $orderAddressTableName = $collection->getResource()->getTable('sales_order_address'); $directoryCountryRegionTableName = $collection->getResource()->getTable('directory_country_region'); $collection->getSelect()->joinLeft( ['soa' => $orderAddressTableName], 'soa.parent_id = main_table.entity_id AND soa.address_type = \'shipping\'', null ); $collection->getSelect()->joinLeft( ['dcrt' => $directoryCountryRegionTableName], 'soa.region_id = dcrt.region_id', ['code'] ); } catch (\Zend_Db_Select_Exception $selectException) { // Do nothing in that case $this->logger->log(100, $selectException); } } return $collection; } }
它將引用以下類:
`Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory`
> etc/adminhtml/di.xml xml <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <!-- Plugins --> <!-- Adds additional data to the orders grid collection --> <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory"> <plugin name="mageworx_extended_orders_grid_add_data_to_orders_grid" type="MageWorx\ExtendedOrdersGrid\Plugin\AddDataToOrdersGrid" sortOrder="10" disabled="false"/> </type> </config>
該插件按以下方式運行:
因為它絕對會捕獲所有集合,所以讓我們將驗證添加到所需的 `sales_order_grid` 表中。 當它被找到並且 Magento 嘗試獲取這方面的數據時,我們將表與 `sales_order_address` 地址通過`order_id` (`sales_order_grid` 表中的`entity_id` 和`sales_order_address` 表中的`parent_id` 進行連接( `soa` 別名))。 現在,我們可以訪問客戶的訂單送貨地址數據,我們可以使用這些數據來確定“region_id”。 它位於“sales_order_address”表中的一個數字。 這個數字對應於 `directory_country_region` 表中的索引(`dcrt` 別名)。 由於我們需要上面提到的表格中的區域代碼,讓我們連接“代碼”列。 這個精確的列將得到輸出(對應於 `sales_order_grid.xml` 中的 `column` 值)。
然後,清除緩存:
> sudo -u www-data php bin/magento cache:clean config
登錄管理面板到訂單網格。 如果一切都正確完成,我們將看到我們的區域代碼顯示:
可在 GitHub 上免費訪問該模塊:https://github.com/mageworx/articles-extended-orders-grid。
重要的旁注!
要向該列添加任何數據,需要獲取“your_column_name”列以及創建集合時添加的所有所需數據。 也就是說,您需要做一些不同的事情——替換錶名並編寫自己的聯接。 另外,如果需要,不要忘記編輯 `sales_order_grid.xml` 文件中的列名。
如何添加額外的列?
如果您決定再添加一列,請遵循以下 Git 提交中描述的指南:https://github.com/mageworx/articles-extended-orders-grid/commit/d31c364a25ce493ab64731c5ca0481e146dbbac3
在那裡,我們已將sales_order_address
表中的telephone
列添加到網格中,以獲取shipping
類型的地址。 正如您在提交代碼中看到的那樣,不需要對代碼進行重大修改。
此外,這些列可以從標準的“訂單網格”界面成功導出。
以下是帶有“電話”列的網格的樣子:
在下面的屏幕截圖中,您可以看到導出到 .csv 文件的相同訂單:
[更新] 如何添加包含訂單商品信息的列?
如您所知,所有訂單都有數量,從一個開始到超出數量(是的,商人的夢想)。 但是我們如何在訂單網格中顯示該信息以更輕鬆地開始搜索或運行分析?
我們不能像之前那樣只添加一列,因為在這種情況下,每一行我們只會得到一個產品名稱或 SKU。 或者,訂單記錄將被複製……我們也不需要那種亂七八糟的東西。
因此,我將嘗試解釋我們如何以正確的方式做到這一點(在我看來)。
假設我們需要訂單網格中的“產品名稱”數據列。
首先,讓我們在sales_order_grid
定義中添加一個新列,就像我們之前所做的那樣:
<columns> .... <column name="name"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/column</item> <item name="filter" xsi:type="string">text</item> <item name="label" xsi:type="string" translate="true">Product Name</item> <item name="visible" xsi:type="boolean">false</item> <item name="sortOrder" xsi:type="number">70</item> </item> </argument> </column> </columns>
然後,我們只需要為我們的新列構建正確的查詢。 它必須包含按該訂單購買的每個產品的名稱,以逗號分隔,能夠按該列值進行搜索等。讓我們在mageworx_extended_orders_grid_add_data_to_orders_grid
插件中創建一個新方法:
/** * Adds products name column to the orders grid collection * * @param OrderGridCollection $collection * @return OrderGridCollection */ private function addProductsNameColumn(OrderGridCollection $collection): OrderGridCollection { return $collection; }
並在原始方法體內命名該方法:
if ($collection->getMainTable() === $collection->getResource()->getTable('sales_order_grid')) { try { $orderAddressTableName = $collection->getResource()->getTable('sales_order_address'); ... // Add product's name column $this->addProductsNameColumn($collection); } catch (\Zend_Db_Select_Exception $selectException) { ...
要在一列中獲取所需的數據,我們必須在單個選擇中創建一個包含兩列的子選擇: order_id
和name
(產品名稱),稍後可以將其加入到主集合中:
// Get original table name $orderItemsTableName = $collection->getResource()->getTable('sales_order_item'); // Create new select instance $itemsTableSelectGrouped = $collection->getConnection()->select(); // Add table with columns which must be selected (skip useless columns) $itemsTableSelectGrouped->from( $orderItemsTableName, [ 'name' => new \Zend_Db_Expr('GROUP_CONCAT(DISTINCT name SEPARATOR \',\')'), 'order_id' => 'order_id' ] ); // Group our select to make only one column for one order $itemsTableSelectGrouped->group('order_id');
說明:
-
$collection->getConnection()->select()
行將創建一個新的Magento\Framework\Db\Select
實例。
這是必需的,因為我們不能使用集合中的原始選擇,因為它裡面有自己的數據,任何修改都會導致錯誤。 -
name
列必須包含指定訂單的所有產品名稱,即必須使用\Zend_Db_Expr('GROUP_CONCAT(DISTINCT name SEPARATOR \',\')')
表達式對其進行分組。 為此,我們稍後將group('order_id')
添加到選擇中。 沒有分組,我們就不能使用GROUP_CONCAT
函數。
現在,我們可以將我們的子選擇添加到主集合中,這將是addProductsNameColumn
方法的邏輯結束:
// Add our sub-select to main collection with only one column: name $collection->getSelect() ->joinLeft( ['soi' => $itemsTableSelectGrouped], 'soi.order_id = main_table.entity_id', ['name'] ); return $collection;
說明:
-
soi
是我們的偽表的別名。 -
order_id
是一個鍵,我們用它來將我們的主表(網格)鏈接到訂單項目數據。 -
['name']
是唯一的列,它被添加到結果中,因為我們不需要其他信息。
最終結果可在該示例的官方存儲庫中找到。
這是特定提交的鏈接:https://github.com/mageworx/articles-extended-orders-grid/commit/0cdffcd4ba66cacb2fd857ba7626fdbcfc0d6fe3
這是該列在我們的暫存主機上的外觀:
這是導出的結果(CSV):
以下是嘗試使用“黑色”產品(在我們的開發主機上)搜索訂單時查詢的樣子:
選擇main_table
.*, soat
。 telephone
, dcrt
。 code
, soi
。 name
FROM sales_order_grid
AS main_table
左連接sales_order_address
AS soat
ON soat.parent_id = main_table.entity_id AND soat.address_type = 'shipping'
左連接directory_country_region
AS dcrt
ON soat.region_id = dcrt.region_id
LEFT JOIN (SELECT GROUP_CONCAT(DISTINCT name SEPARATOR ',') AS name
, sales_order_item
. order_id
FROM sales_order_item
GROUP BY order_id
) AS soi
ON soi.order_id = main_table.entity_id
soi
name
LIKE '%Black%'
顯然,這不是輸出數據的最快方式。 但是,這可能是最簡單的一個。 最好的方法是在單獨的表(order_id,products_name)的單獨列中累積有關產品名稱的數據,然後添加此表,無需額外分組和任何子選擇。
為此,我們將組 ('order_id') 添加到我們的選擇中(在方法代碼的末尾)。
select 表示一個元素。
組表示選擇方法。
我想就是這樣。 如果您有任何問題或要求,請在評論欄中留下評論。