Комментарии 14
даже в bitrix меньше телодвижений.
Хотел бы подчеркнуть такой момент — все эти телодвижения приводят к тому, что колонки в грид добавляются независимо. Т.е., разработчика модуля не заботит, какие еще модули будут стоять в приложении, и на какие еще таблицы пойдут JOIN'ы.
вот это прям фича из фичей.
в любой нормальной CMS например в bitrix это достигается добавлением нового свойства через админку, без написания такой кучи кода — без программирования вообще.
и вывод поля в формах и списках админки настраивается через админку.
в wordpress к слову аналогично. разве что надо вывод в списках добавить, написав строк десять кода.
и вот у меня возникает резонный вопрос — зачем в магенто столько кода надо писать для реализации элементарной вещи?
ORM в Magento? Его там нет и никогда не было.
Я пересел на Magento с Java, на которой имел дело и с Hibernate, и с DataNucleus. То, что в статье говорится "It should be no surprise that Magento takes the ORM approach", не является основанием для заявления, что ORM в Magento присутствует. Для разминки изобразите средствами "Magento ORM" сущность с составным первичным ключом (состоящим из двух полей таблицы в БД), а затем попробуйте средствами "Magento ORM" извлечь коллекцию таких объектов. Для Hibernate и DataNucleus данная задача является тривиальной.
Ваша критика статьи станет конструктивной тогда, когда вы предложите свое решение описанной задачи, а не пронесетесь вихрем по комментам с шашкой наголо "так никто не делает, там делов-то на пару строк кода".
ORM — штука которая представляет запросы к б.д. на объктно ориентированном диалекте.
Ну и как будет выглядеть запрос на выборку объектов с составным первичным ключом в Magento ORM? А на обновление объекта?
Кстати, можете еще попробовать вытащить данные (email & full name) по всем клиентам, которые совершили транзакции (sales_payment_transaction, нужны данные из поля tnx_id), которые соответствуют определенным методам платежа (sales_order_payment.method) по заказам, созданным в определенный промежуток времени, используя всю мощь Magento ORM.
protected function _replaceAllAliasesInWhere($where)
{
$result = [];
foreach ($where as $item) {
$item = $this->_replaceAliaseInWhere($item, self::AS_FLD_CUSTOMER_DEPTH, self::AS_TBL_CUST, 'depth');
$item = $this->_replaceAliaseInWhere($item, self::AS_FLD_PARENT_ID, self::AS_TBL_CUST, 'parent_id');
$result[] = $item;
}
return $result;
}
protected function _replaceAliaseInWhere($where, $fieldAlias, $tableAlias, $fieldName)
{
$search = "`$fieldAlias`";
$replace = "`$tableAlias`.`$fieldName`";
$result = str_replace($search, $replace, $where);
return $result;
}
это всё заменяеться одной строкой
`$collection->addFieldToFilter('mytable.myfield',$yuorFilterValue)`
Вы немножко неправильно поняли назначение моего кода — он подменяет алиасы для дополнительных столбцов исходного SQL'а для WHERE-правила (да-да, в background'е "Magento ORM" спрятан самый обычный SQL, впрочем, как и в background'е других ORM framework'ов) полным значением имени столбца, с добавлением алиаса таблицы.
В вашем примере код
$collection->addFieldToFilter('mytable.myfield',$yuorFilterValue)
просто добавляет в список WHERE-правил еще одно условие. Этот код и так исполняется, когда Magento разбирает условия фильтрации данных грида, заданные пользователем через WebUI (трассировка от \Magento\Framework\View\Element\UiComponent\DataProvider\FilterPool::applyFilters как раз и выведет на метод "addFieldToFilter"). У Magento-коллекции есть метод "addFilterToMap", который позволяет ввести карту преобразований, аналогичных тем, которые делаю я, и выполнять их перед тем, как добавить условие фильтрации (\Magento\Framework\Data\Collection\AbstractDb::_translateCondition, вызывается из addFieldToFilter), вот только нет возможности вклиниться в поток выполнения команд через событие (применение фильтров идет после создания коллекции и до генерации события "core_collection_abstract_load_before"). Можно использовать механизм плагинов и обернуть, например, метод \Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory::getReport, чтобы он выполнял те же самые действия, что и в обсервере, плюс добавлял маппинг.
Регистрация around-плагина:
etc/di.xml
<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
<plugin
name="vendor_module_data_provider_collection_factory"
type="Vendor\Module\Plugin\Framework\View\Element\UiComponent\DataProvider\CollectionFactory"
sortOrder="100"
disabled="false"
/>
</type>
Код самого плагина, вызывающий класс-модификатор для добавления JOIN'ов к выборке и маппинг полей для их преобразования в фильтрах:
namespace Vendor\Module\Plugin\Framework\View\Element\UiComponent\DataProvider;
class CollectionFactory
{
protected $_subQueryModifier;
public function __construct(
Sub\QueryModifier $subQueryModufier
) {
$this->_subQueryModifier = $subQueryModufier;
}
public function aroundGetReport(
\Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory $subject,
\Closure $proceed,
$requestName
) {
$result = $proceed($requestName);
if ($requestName == 'customer_listing_data_source') {
if ($result instanceof \Magento\Customer\Model\ResourceModel\Grid\Collection) {
/* add JOINs to the select query */
$this->_subQueryModifier->populateSelect($result);
/* add fields to mapping */
$this->_subQueryModifier->addFieldsMapping($result);
}
}
return $result;
}
}
Код, который модифицирует выбоку аналогичный тому, что в статье. Код для маппинга трививален:
// depth
$fieldAlias = self::AS_FLD_CUSTOMER_DEPTH;
$fieldFullName = self::AS_TBL_CUST . '.' . Customer::ATTR_DEPTH;
$collection->addFilterToMap($fieldAlias, $fieldFullName);
Этот подход позволяет использовать механизмы Magento для замены алиасов истинными именами полей вместо "грязного хака".
Возможно потому, что Magento — не CMS.
Magento 2: добавление колонки к гриду админки