Русский
Русский
English
Статистика
Реклама

Magento 2

Из песочницы ObjectManager в Magento 2

10.10.2020 14:23:52 | Автор: admin

ObjectManager можно назвать одной из основных концепций, которая лежит в основе построения Magento2, и абсолютно новый если брать в сравнении с Magento1. Если мы вспомним Magento1, то там, для создания нужных нам для работы объектов, мы использовали класс Mage, который предоставлял статические методы для создания разных типов объектов будь то модели, ресурс-модели, хелперы, или для создания объектов, которые мы хотели иметь в едином экземпляре(метод Mage::getSingleton). При создании Magento2 команда разработчиков отказалась от этой идеи и имплементировали принцип инъекции зависимостей и сервис-контрактов(ServiceContracts). Именно это позволило сделать Magento2 такой гибкой, легко кастомизируемой и тестируемой. Так же наличие функционала построенного вокруг ObjectManagerа делает возможным наличие всего функционала кастомизации поведения системы, который мы можем настраивать посредством конфигурационного файла di.xml.


Если смотреть глобально на функционал, который реализует ObjectManager, то можно сказать, что он является некой реализацией DI container, который в мире PHP представлен в виде PSR-11, хотя сам ObjectManager напрямую не реализует Psr\Container\ContainerInterface (и не имеет метода has, наличие которого предполагает Psr\Container\ContainerInterface). Он является централизованным средством для создания и получения объектов. Наличие такого централизованного класса для генерации необходимых объектов несет в себе следующие преимущества.


  • Нам не нужно в ручную инициализировать и менеджить объекты (так же нужно сказать, что ObjectManager используется для генерации объектов внутри классов Factory и Proxy, которые создаются посредством кодогенерации)
  • является возможным через настройки прописать какую именно реализацию некоторого интерфейса должен получать класс и использовать принцип инверсии зависимостей
  • систему становится легче тестировать
  • возможно использовать Proxy-классы и классы фабрики (Factory)
  • Экономия ресурсов сервера, так как некоторые из объектов повторно не инициализируются, а берутся из кэша уже созданные до этого объекты (настройка shared)

Если более детально рассмотреть последний пункт, то нужно сказать, что сам класс Magento\Framework\ObjectManager\ObjectManager имеет protected атрибут $_sharedInstances = []. Именно этот атрибут содержит объекты, которые не должны быть созданы более 1 раза и при запросе на их получение просто берет их из этого массива (кэша) по ключу ключом является полное имя класса, которое включает пространство имен(namespace). Но как именно класс ObjectManager знает какие классы должны быть помещены в этот массив?

Все объекты, которые создаются через ObjectManager по-умолчанию имеют настройку shared=true. Но это поведение можно поменять для этого служит специальная настройка shared в xml-файле. Для примера можно взять объявление классов слушателей (observer).



<observer name="legacy_model_save"          instance="Magento\Framework\EntityManager\Observer\BeforeEntitySave" shared="false"/>

Такой класс будет инстанциироваться каждый раз как новый объект. Также такая настройка есть у объектов, которые передаются в конструктор через конструкцию type. Как было сказано выше, этот параметр равен true по-умолчанию, чтобы экономить ресурсы сервера.


Сейчас хотелось бы сфокусироваться на процессе инициализации класса ObjectManager и том как он инстанциирует объекты. В этом месте нужно сделать оговорку, что ниже в статье будет рассматриваться процесс применимо к приложению типа Http.


Если посмотреть на файл index.php, то мы можем увидеть, что в нем используется класс Magento\Framework\App\Bootstrap
И сначала вызывается его статический метод create, который принимает 2 параметра:


  • адрес корневой директории проекта
  • массив параметров $_SERVER + настройки адресов директорий

Внутри метода create вызывается статический метод createObjectManagerFactory, который инстанциирует объект класса Magento\Framework\App\ObjectManagerFactory и передает его в конструктор класса Bootstrap, где он используется, чтобы создать объект класса Magento\Framework\App\ObjectManager. Именно этот объект и используется в последствии, чтобы инстанциировать все далее используемые объекты. Далее в методе Magento\Framework\App\Http::launch объекту класса ObjectManager задается конфигурация через вызов метода Magento\Framework\App\ObjectManager::configure. Параметром этого метода является уже подготовленный для использования массив настроек с файлов di.xml. Именно благодаря этим настройкам ObjectManager реализует работу таких возможностей как preference, type, virtualType. Сами эти настройки не хранятся в классе ObjectManager он делегирует их использование классу Magento\Framework\ObjectManager\Config\Config, который реализует Magento\Framework\ObjectManager\ConfigInterface. Этот класс обрабатывает массив настроек с файлов di.xml и объединяет их по типам: preference, type, virtualType и потом позволяет получать их в подготовленном виде. Так же именно этот класс хранит карту preferenceов и отдает ObjectManagerу правильное имя объекта для создания.


Далее в работе приложения используются 2 метода класса ObjectManager: create и get. Разница этих методов состоит в том, что метод create всегда создает новый объект переданного класса (можно сказать, что это реализация паттерна Factory method), а метод get при повторном запросе объекта класса, который уже создавался ранее, просто отдаст его из кэша.


Если рассмотреть детальнее эти методы то они оба создают объекты через специальную фабрику (класс, который имплементирует интерфейс Magento\Framework\ObjectManager\FactoryInterface), которая в зависимости от режима работы приложения может быть представлена классами, которые находятся в пространстве имен Magento\Framework\ObjectManager\Factory. Такая фабрика получает через механизм рефлексии php аргументы конструктора необходимого класса и рекурсивно их инициализирует. Потом эти подготовленные аргументы передаются в метод Magento\Framework\ObjectManager\Factory\AbstractFactory::createObject, который и возвращает готовый к использованию объект. Далее ObjectManager может или просто вернуть такой объект или сохранить его в кэше для дальнейшего использования, в зависимости от настроек, как было указано выше.


Так же следует обратить внимание на пространство имен Magento\Framework\ObjectManager\Code\Generator. Классы, которые находятся в нем, используются для того, чтобы сгенерировать Factory и Proxy классы, которые передаются в пользовательские классы как аргументы конструктора (Proxy должен задаваться как аргумент конструктора через файл di.xml) и создаются через механизм кодогенерации мадженты. Proxy-классы, как очевидно из названия, используются для того, чтобы уменьшить нагрузку на сервер путем замены оригинального класса на его proxy-класс, который инициализирует оригинальный класс только в том случае, если он вызывается (реализация паттерн Proxy). Классы фабрики используются для создания объектов внутри кастомного кода, обычно это объекты классов доменных моделей. Сами классы Factory реализуют паттерн factory method, имея публичный метод create, который внутри себя вызывает ObjectManager и инстанциирует объекты посредством использования метода Magento\Framework\App\ObjectManager::create.

Подробнее..
Категории: Php , Magento , Magento 2

За что я люблю Magento 2

21.12.2020 18:22:45 | Автор: admin

Знаете, сейчас, в эпоху хороших фреймворков принято презирать всякие {название CMS, которую считаете ужасной} и прочие битриксы. И не мудрено, ведь эти вещи изначально создавались как будто не для программистов а для кодеров. Это можно оправдать наличием большого количества легаси, т.к. они писались давным-давно в далёкой-далёкой галактике. Они решают множество нужных и полезных задач, имеют огромные коммьюнити и тысячи плагинов, но когда ты смотришь под капот - медленно седеющие волосы на голове начинают шевелиться в такт "архитектуре".


Дисклеймер
  1. Все нижеуказанное не несет никакой ценности для опытных Magento разработчиков, т.к. не содержит ничего для них нового. Эта статья написана скорее с целью популяризации Magento 2, и немного - хвастовства в виде "смотри как оно умеет". Также, возможно, статья подойдет новичкам в качестве туториала.

  2. Я не спорю, что помимо плюсов есть еще и минусы, и не говорю что Magento идеальна во всех местах.

Я один раз заглянул в проект на ModX (и пусть меня закидают ссаными тапками камнями), и мой мир никогда не будет прежним. Возможно, поэтому, когда в разговоре меня спрашивают, с чем я работаю, а в ответ слышат "magento", сразу кривятся носы, а мнение, скорее всего, падает куда-то очень низко.

Мне обидно от этого, ведь Magento уже давно не (да и никогда до конца не была) топ-примером того, как никогда делать не стоит. Напротив, начиная со второй версии, разработчики двигаются по правильному пути. Да, есть еще много легаси, а некоторые решения заставляют округлить зенки и накрыть лицо пятерней, но в целом, на данный момент, на magento 2 можно и легко (и во многом система сама диктует) построить грамотную архитектуру проекта/модуля.

Итак, топ вещей, которые реализованы не (намного) хуже, а где-то и лучше, чем в популярных фреймворках:

Мощная система DI

Мы не задумываемся над созданием объектов, система делает все за нас. Мы просто указываем список нужных параметров в конструкторе с типами, и используем их

<?phpnamespace Vendor\Module\Model;use Vendor\Module\Api\FooInterface;use Vendor\Module\Model\Bar;class SomeModel{    private $foo;    private $bar;    private $param    public function __construct(FooInterface $foo, Bar $bar, string $param)    {        $this->foo = $foo;        $this->bar = $bar;        $this->param = $param;    }}

Хочу отметить, что тонкие настройки аргументов, указание классов для интерфейсов и многое другое - описывается в xml файле di.xml:

<?xml version="1.0" encoding="UTF-8"?><config xmlns:xsi="http://personeltest.ru/away/www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">    <!-- body --></config>

1. Подмена классов и указание реализации для интерфейсов

указываем preference для интерфейса, и потом везде в коде используем только интерфейс

<preference for="Vendor\Module\Api\FooInterface"             type="Vendor\Module\Model\Foo" />

Также можно сделать наследника какого-то класса, и сказать, что теперь везде должен использоваться наследник. Соответственно во всех конструкторах и использованиях ObjectManager объект родительского класса подменится на объект дочернего.

<preference for="Vendor\Module\Model\Bar"             type="Vendor\Module\Model\BarChild" />

2. Указание аргументов

Мы можем указать для конкретного класса список его аргументов, или подменить какой-либо параметр

<type name="Vendor\Module\Model\SomeModel">    <arguments>        <argument name="bar" xsi:type="object">Vendor\Module\Model\BarChild</argument>        <argument name="param" xsi:type="string">some string</argument>    </arguments></type>

3. Виртуальные типы

Виртуальный тип - это обычный класс с набором своих личных параметров. Такие виртуальные типы физически не существуют, и могут быть использованы только как аргументы в других классах

<virtualType name="Vendor\Module\Model\SomeModelForSomethingElse"              type="Vendor\Module\Model\SomeModel">    <arguments>        <argument name="param" xsi:type="string">another string</argument>    </arguments></virtualType><type name="Vendor\Module\Model\SomeService">    <arguments>        <argument name="someModel" xsi:type="object">Vendor\Module\Model\SomeModelForSomethingElse</argument>    </arguments></type>

4. Плагины

Практически на любой существующий публичный метод класса можно повесить плагины. Можно выбрать, когда будет выполняться плагин - до (префикс before), во время (префикс around) или после (префикс after) выполнения метода. Давайте рассмотрим пример:

<?phpnamespace Vendor\Module\Model;class SomeService{    public function doSomething(Foo $foo, Bar $bar, string $param, int $number)    {        // something    }}

Задаём плагин:

<type name="Vendor\Module\Model\SomeService">    <plugin name="Vendor_Module::MyCustomPlugin"             type="Vendor\Module\Plugin\SomeServicePlugin" /></type>

Код плагина (методы плагина должны называться: префикс + название основного метода с большой буквы):

<?phpnamespace Vendor\Module\Plugin;use Vendor\Module\Model\SomeService;class SomeServicePlugin{    // вызывается до вызова основного метода. Мы можем изменить входные параметры.    public function beforeDoSomething(SomeService $subject, Foo $foo, Bar $bar, string $param, int $number)    {        $param = 'change param';        // если изменять параметры не нужно - то можно ничего не возвращать        return [$foo, $bar, $param, $number];    }    // метод вызывается "во время" вызова основного метода. В параметрах - Closure - это собственно основной метод    public function aroundDoSomething(SomeService $subject, \Closure $proceed, Foo $foo, Bar $bar, string $param, int $number)    {        // do something        $result = $proceed($foo, $bar, $param, $number); // вызываем основной метод        // do something else        return $result;    }    // метод вызывается после вызова основного метода. Мы можем менять результат    public function afterDoSomething(SomeService $subject, $result, Foo $foo, Bar $bar, string $param, int $number)    {        $result += 1; // меняем результат        return $result;    }}

Также в каждый метод плагина передаётся сам покрываемый плагином объект. Это удобно, если нам нужно вызвать какой-то другой его метод в процессе выполнения плагина.

5. ObjectManager

Если нам нужно создавать объекты на лету в процессе выполнения алгоритма - для этого есть ObjectManager. Он имеет два метода - get и create. get - берет существующий экземпляр класса (или создает его, если еще не создавал ранее), а create - создаёт.

Взгляните на это объявление пула процессоров:

<?phpnamespace Vendor\Module\Model;use Magento\Framework\ObjectManagerInterface;class ProcessorPool{    private $objectManager;    private $processors;    public function __construct(ObjectManagerInterface $objectManager, array $processors)    {        $this->objectManager = $objectManager;        $this->processors = $processors;    }    public function getProcessor(string $code)    {        return $this->objectManager->get($this->processors[$code]);    }}

И xml:

<type name="Vendor\Module\Model\ProcessorPool">    <arguments>        <argument name="processors" xsi:type="array">            <item name="foo" xsi:type="string">Vendor\Module\Model\Processor\FooProcessor</item>            <item name="bar" xsi:type="string">Vendor\Module\Model\Processor\BarProcessor</item>        </argument>    </arguments></type>

С учетом того, что все di.xml всех модулей мержатся в одну большую инструкцию для ObjectManager - мы можем добиться довольно высокой гибкости кода. Где-то в другом модуле мы можем описать еще один процессор, и заменить один из существующих:

<type name="Vendor\Module\Model\ServicePool">    <arguments>        <argument name="processors" xsi:type="array">            <item name="foo" xsi:type="string">Vendor\NewModule\Model\Processor\NewFooProcessor</item>            <item name="something" xsi:type="string">Vendor\NewModule\Model\Processor\SomethingProcessor</item>        </argument>    </arguments></type>

6. Автогенерация фабрик и прокси

В некоторых случаях нам нужно всегда создавать новый объект, например - entity-модель. Для этого лучше всего подходят фабрики. Но нам не нужно писать код фабрики руками, для нас это сделает встроенный автогенератор. Достаточно в конструкторе просто дописать слово Factory к требуемому классу, и мы получим его фабрику. Это работает также и с интерфейсами:

<?phpnamespace Vendor\Module\Model;use Vendor\Module\Api\Data\SomeModelInterfaceFactory;class SomeModelRepository{    private $someModelFactory;    // класс \Vendor\Module\Api\Data\SomeModelInterfaceFactory будет сгенерирован автоматически    public function __construct(SomeModelInterfaceFactory $someModelFactory)    {        $this->someModelFactory = $someModelFactory;    }    public function doSomething()    {        // создаст объект класса, имплементирующего \Vendor\Module\Api\Data\SomeModelInterface со всеми его зависимостями        $someModel = $this->someModelFactory->create();    }}

Если у нас есть какой-то сервис, который при инициализации тратит много ресурсов, и мы не уверены, будем ли мы точно его использовать в другом классе - мы можем обернуть его в Proxy. Мы можем дописать "\Proxy" точно также, как и "Factory" к типу параметра в конструкторе, но это нарушит расширяемость кода, поэтому лучше задавать Proxy через di.xml

<?phpnamespace Vendor\Module\Model;class SomeModelClass{    private $someBigService;    public function __construct(SomeBigService $someBigService)    {        $this->someBigService = $someBigService;    }    public function doSomething(bool $condition)    {        // мы не уверены, что сервис нам понадобится, и т.к. его инициализация занимает много времени        // лучше создавать его только тогда, когда он точно нужен        if ($condition) {            $this->someBigService->execute();        }    }}

di.xml

<type name="Vendor\Module\Model\SomeModelClass">    <arguments>        <argument name="someBigService"                   xsi:type="object">Vendor\Module\Model\SomeBigService\Proxy</argument>    </arguments></type>

И, вуаля, объект SomeBigService создастся только в момент вызова execute().

Layout

Layout, на мой взгляд, одно из самых гибких реализаций для сборки страницы. Реализация xml layouts в Magento позволяет расширить или изменить страницу из множества мест, будь то модуль, тема, или другой участок кода. Layout файл в Magento обычно называется примерно так:

catalog_product_view.xml

Название файла - это handle, где catalog - перекликается с названием модуля (это название роута в конфигурации модуля), product - название папки, в которой лежит контроллер, а view - название контроллера. Это типовое наименование позволяет не указывать в контроллере, какой именно Layout выбирать, и подставляется автоматически. Однако ничто не мешает назвать layout по своему, и указать его название в контроллере. Т.к. это xml - мы можем подключить сколько угодно layout в контроллере, и они все будут смержены в один.

Для добавления на страницу продукта какого-то расширяемого блока, нам достаточно написать:

<?xml version="1.0"?><!-- Vendor/Module/view/frontend/layout/catalog_product_view.xml --><page xmlns:xsi="http://personeltest.ru/away/www.w3.org/2001/XMLSchema-instance"      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">    <body>        <referenceContainer name="content">            <!-- Мы имеем аттрибуты before и after, чтобы указать место, в котором нужно будет вывести блок -->            <container name="vendor.module.some.container"                       htmlTag="div"                       htmlClass="my_custom_container"                       before="-">                <block class="Magento\Framework\View\Element\Template"                       name="vendor.module.custom_product_block"                       template="Vendor_Module::product/view/custom_block.phtml" />            </container>        </referenceContainer>    </body></page>

Я намеренно обернул блок в контейнер. Теперь в другом модуле мы можем без проблем добавить в то же место еще один блок, перед или после существующего:

<?xml version="1.0"?><!-- Vendor/AnotherModule/view/frontend/layout/catalog_product_view.xml --><page xmlns:xsi="http://personeltest.ru/away/www.w3.org/2001/XMLSchema-instance"      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">    <body>        <referenceContainer name="vendor.module.some.container">            <block class="Magento\Framework\View\Element\Template"                   name="vendor.another_module.custom_product_block"                   template="Vendor_AnotherModule::another_custom_block.phtml"                    after="vendor.module.custom_product_block"/>        </referenceContainer>    </body></page>

Layouts также являются "наследуемыми":

<?xml version="1.0"?><page xmlns:xsi="http://personeltest.ru/away/www.w3.org/2001/XMLSchema-instance"      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">    <body>        <!-- Подключаем какой-то другой layout -->        <update handle="my_custom_layout_handle" />        <!-- можно удалять ненужное -->        <referenceContainer name="container1" remove="true"/>        <referenceBlock name="child_block1" remove="true"/>        <!-- Или переместить: например container3 внутрь container2 -->        <move element="container3" destination="container2"/>    </body></page>

Т.к. практически все отображение в Magento использует layouts, то можно смело утверждать (с некоторыми оговорками), что это даёт возможность кастомизировать что угодно и где угодно (ну почти).

ViewModel

Когда разрабатываешь систему, которая требует отображения множества различных данных на фронте, в том числе - повторяющиеся на некоторых страницах данные, приходится постоянно пробрасывать эти самые данные через Controller во View. Это может быть утомительно, и приходится придумывать различного рода уловки, расширения, чтобы получать эти данные на уровне View, не повторяясь в контроллерах.

Долгое время в Magento использовались классы блоков (например Magento\Catalog\Block\Product\View), которые предоставляли доступ к данным из template - вида

<?php // Vendor/Module/view/frontend/templates/some_template.phtml// внутри template доступна переменная $block, являющаяся объектом указанного в layoutкласса?><?= $block->getSomeData() ?>

Но с годами блоки разрастались, обрастали наследниками (т.к. содержали в себе много нужного в других местах кода), и превращались в полотна из несвязанных между собой методов. В Magento 2.2 были представлены ViewModel, как возможность использовать сразу несколько моделей внутри template, и построить свой код архитектурно грамотнее:

<?xml version="1.0"?><page xmlns:xsi="http://personeltest.ru/away/www.w3.org/2001/XMLSchema-instance"      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">    <body>        <block class="Magento\Framework\View\Element\Template"               name="some_name"               template="Vendor_Module::some_template.phtml">            <arguments>                <argument name="some_view_model" xsi:type="object">Vendor\Module\ViewModel\SomeViewModel</argument>                <argument name="another_view_model" xsi:type="object">Vendor\Module\ViewModel\AnotherViewModel</argument>            </arguments>        </block>    </body></page>

и в template:

<?php/** @var Vendor\Module\ViewModel\SomeViewModel $someViewModel */$someViewModel = $block->getSomeViewModel();/** @var Vendor\Module\ViewModel\AnotherViewModel $anotherViewModel */$anotherViewModel = $block->getAnotherViewModel();?>

Соответственно, одну ViewModel можно использовать на многих страницах, не завися и не задумываясь о контроллере.

Declarative Schema

Самый популярный способ накатывать обновления на БД - это миграции. И я видел множество проектов, где папки с миграциями, да и сами миграции выглядели довольно внушительно. И вдобавок (если уж говорить о продуктовой разработке, когда пользователи получают новые версии продукта для обновления, как раз Magento-случай), если разворачивать все с нуля - все миграции должны быть выполнены.

Declarative Schema - это, по сути, текущее состояние таблицы, описанное в xml файле. Нам не нужно писать и поддерживать миграции, мы просто меняем xml файлик. Magento сама считывает его, сравнивает с текущим состоянием таблицы в БД, и меняет таблицу, если это необходимо.

Конечно, далеко не все миграции - это изменение структуры БД, поэтому наряду с Declarative Schema существует еще и механизм патчей (php-классов, выполняющих какую-то логику).

UI компоненты

Т.к. xml - довольно гибкий формат, он позволяет нам достаточно многое. Помните layoutы? Xml Layouts + DI позволяют нам строить дерево JS компонентов для рендеринга страницы также гибко, как и дерево PHP блоков. Взгляните на layout для чекаута (осторожно, очень много текста)

checkout_index_index.xml
<?xml version="1.0"?><!--/** * Copyright  Magento, Inc. All rights reserved. * See COPYING.txt for license details. */--><page xmlns:xsi="http://personeltest.ru/away/www.w3.org/2001/XMLSchema-instance" layout="checkout" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">    <body>        <referenceContainer name="content">            <block class="Magento\Checkout\Block\Onepage" name="checkout.root" template="Magento_Checkout::onepage.phtml" cacheable="false">                <arguments>                    <argument name="jsLayout" xsi:type="array">                        <item name="types" xsi:type="array">                            <item name="form.input" xsi:type="array">                                <item name="component" xsi:type="string">Magento_Ui/js/form/element/abstract</item>                                <item name="config" xsi:type="array">                                    <item name="provider" xsi:type="string">checkoutProvider</item>                                    <item name="deps" xsi:type="array">                                        <item name="0" xsi:type="string">checkoutProvider</item>                                    </item>                                    <item name="template" xsi:type="string">ui/form/field</item>                                    <item name="elementTmpl" xsi:type="string">ui/form/element/input</item>                                </item>                            </item>                        </item>                        <item name="components" xsi:type="array">                            <item name="checkout" xsi:type="array">                                <item name="component" xsi:type="string">uiComponent</item>                                <item name="config" xsi:type="array">                                    <item name="template" xsi:type="string">Magento_Checkout/onepage</item>                                </item>                                <item name="children" xsi:type="array">                                    <item name="errors" xsi:type="array">                                        <item name="sortOrder" xsi:type="string">0</item>                                        <item name="component" xsi:type="string">Magento_Ui/js/view/messages</item>                                        <item name="displayArea" xsi:type="string">messages</item>                                    </item>                                    <item name="authentication" xsi:type="array">                                        <item name="sortOrder" xsi:type="string">1</item>                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/authentication</item>                                        <item name="displayArea" xsi:type="string">authentication</item>                                        <item name="children" xsi:type="array">                                            <!--Additional authentication fields-->                                            <item name="errors" xsi:type="array">                                                <item name="sortOrder" xsi:type="string">0</item>                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/authentication-messages</item>                                                <item name="displayArea" xsi:type="string">messages</item>                                            </item>                                        </item>                                    </item>                                    <item name="progressBar" xsi:type="array">                                        <item name="sortOrder" xsi:type="string">0</item>                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/progress-bar</item>                                        <item name="displayArea" xsi:type="string">progressBar</item>                                        <item name="config" xsi:type="array">                                            <item name="deps" xsi:type="array">                                                <item name="0" xsi:type="string">checkout.steps.shipping-step.shippingAddress</item>                                                <item name="1" xsi:type="string">checkout.steps.billing-step.payment</item>                                            </item>                                        </item>                                    </item>                                    <item name="estimation" xsi:type="array">                                        <item name="sortOrder" xsi:type="string">10</item>                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/estimation</item>                                        <item name="displayArea" xsi:type="string">estimation</item>                                        <item name="config" xsi:type="array">                                            <item name="template" xsi:type="string">Magento_Checkout/estimation</item>                                            <item name="deps" xsi:type="array">                                                <item name="0" xsi:type="string">checkout.sidebar</item>                                            </item>                                        </item>                                    </item>                                    <item name="steps" xsi:type="array">                                        <item name="component" xsi:type="string">uiComponent</item>                                        <item name="displayArea" xsi:type="string">steps</item>                                        <item name="children" xsi:type="array">                                            <item name="shipping-step" xsi:type="array">                                                <item name="component" xsi:type="string">uiComponent</item>                                                <item name="sortOrder" xsi:type="string">1</item>                                                <item name="children" xsi:type="array">                                                    <item name="step-config" xsi:type="array">                                                        <item name="component" xsi:type="string">uiComponent</item>                                                        <item name="children" xsi:type="array">                                                            <item name="shipping-rates-validation" xsi:type="array">                                                                <item name="children" xsi:type="array">                                                                    <!--Step configuration components-->                                                                </item>                                                            </item>                                                        </item>                                                    </item>                                                    <item name="shippingAddress" xsi:type="array">                                                        <item name="config" xsi:type="array">                                                            <item name="deps" xsi:type="array">                                                                <item name="0" xsi:type="string">checkout.steps.shipping-step.step-config</item>                                                                <item name="1" xsi:type="string">checkoutProvider</item>                                                            </item>                                                            <item name="popUpForm" xsi:type="array">                                                                <item name="element" xsi:type="string">#opc-new-shipping-address</item>                                                                <item name="options" xsi:type="array">                                                                    <item name="type" xsi:type="string">popup</item>                                                                    <item name="responsive" xsi:type="boolean">true</item>                                                                    <item name="innerScroll" xsi:type="boolean">true</item>                                                                    <item name="title" xsi:type="string" translate="true">Shipping Address</item>                                                                    <item name="trigger" xsi:type="string">opc-new-shipping-address</item>                                                                    <item name="buttons" xsi:type="array">                                                                        <item name="save" xsi:type="array">                                                                            <item name="text" xsi:type="string" translate="true">Ship Here</item>                                                                            <item name="class" xsi:type="string">action primary action-save-address</item>                                                                        </item>                                                                        <item name="cancel" xsi:type="array">                                                                            <item name="text" xsi:type="string" translate="true">Cancel</item>                                                                            <item name="class" xsi:type="string">action secondary action-hide-popup</item>                                                                        </item>                                                                    </item>                                                                </item>                                                            </item>                                                        </item>                                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/shipping</item>                                                        <item name="provider" xsi:type="string">checkoutProvider</item>                                                        <item name="sortOrder" xsi:type="string">10</item>                                                        <item name="children" xsi:type="array">                                                            <item name="customer-email" xsi:type="array">                                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/form/element/email</item>                                                                <item name="displayArea" xsi:type="string">customer-email</item>                                                                <item name="tooltip" xsi:type="array">                                                                    <item name="description" xsi:type="string" translate="true">We'll send your order confirmation here.</item>                                                                </item>                                                                <item name="children" xsi:type="array">                                                                    <item name="before-login-form" xsi:type="array">                                                                        <item name="component" xsi:type="string">uiComponent</item>                                                                        <item name="displayArea" xsi:type="string">before-login-form</item>                                                                        <item name="children" xsi:type="array">                                                                            <!-- before login form fields -->                                                                        </item>                                                                    </item>                                                                    <item name="additional-login-form-fields" xsi:type="array">                                                                        <item name="component" xsi:type="string">uiComponent</item>                                                                        <item name="displayArea" xsi:type="string">additional-login-form-fields</item>                                                                        <item name="children" xsi:type="array">                                                                            <!-- additional login form fields -->                                                                        </item>                                                                    </item>                                                                </item>                                                            </item>                                                            <item name="before-form" xsi:type="array">                                                                <item name="component" xsi:type="string">uiComponent</item>                                                                <item name="displayArea" xsi:type="string">before-form</item>                                                                <item name="children" xsi:type="array">                                                                    <!-- before form fields -->                                                                </item>                                                            </item>                                                            <item name="before-fields" xsi:type="array">                                                                <item name="component" xsi:type="string">uiComponent</item>                                                                <item name="displayArea" xsi:type="string">before-fields</item>                                                                <item name="children" xsi:type="array">                                                                    <!-- before fields -->                                                                </item>                                                            </item>                                                            <item name="address-list" xsi:type="array">                                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/shipping-address/list</item>                                                                <item name="displayArea" xsi:type="string">address-list</item>                                                            </item>                                                            <item name="address-list-additional-addresses" xsi:type="array">                                                                <item name="component" xsi:type="string">uiComponent</item>                                                                <item name="displayArea" xsi:type="string">address-list-additional-addresses</item>                                                                <item name="children" xsi:type="array">                                                                    <!-- address-list-additional-addresses -->                                                                </item>                                                            </item>                                                            <item name="before-shipping-method-form" xsi:type="array">                                                                <item name="component" xsi:type="string">uiComponent</item>                                                                <item name="displayArea" xsi:type="string">before-shipping-method-form</item>                                                                <item name="children" xsi:type="array">                                                                    <!-- address-list-additional-addresses -->                                                                </item>                                                            </item>                                                            <item name="shipping-address-fieldset" xsi:type="array">                                                                <item name="component" xsi:type="string">uiComponent</item>                                                                <item name="config" xsi:type="array">                                                                    <item name="deps" xsi:type="array">                                                                        <item name="0" xsi:type="string">checkoutProvider</item>                                                                    </item>                                                                </item>                                                                <item name="displayArea" xsi:type="string">additional-fieldsets</item>                                                                <item name="children" xsi:type="array">                                                                    <!-- The following items override configuration of corresponding address attributes -->                                                                    <item name="region" xsi:type="array">                                                                        <!-- Make region attribute invisible on frontend. Corresponding input element is created by region_id field -->                                                                        <item name="visible" xsi:type="boolean">false</item>                                                                    </item>                                                                    <item name="region_id" xsi:type="array">                                                                        <item name="component" xsi:type="string">Magento_Ui/js/form/element/region</item>                                                                        <item name="config" xsi:type="array">                                                                            <item name="template" xsi:type="string">ui/form/field</item>                                                                            <item name="elementTmpl" xsi:type="string">ui/form/element/select</item>                                                                            <item name="customEntry" xsi:type="string">shippingAddress.region</item>                                                                        </item>                                                                        <item name="validation" xsi:type="array">                                                                            <item name="required-entry" xsi:type="boolean">true</item>                                                                        </item>                                                                        <!-- Value of region_id field is filtered by the value of county_id attribute -->                                                                        <item name="filterBy" xsi:type="array">                                                                            <item name="target" xsi:type="string"><![CDATA[${ $.provider }:${ $.parentScope }.country_id]]></item>                                                                            <item name="field" xsi:type="string">country_id</item>                                                                        </item>                                                                    </item>                                                                    <item name="postcode" xsi:type="array">                                                                        <!-- post-code field has custom UI component -->                                                                        <item name="component" xsi:type="string">Magento_Ui/js/form/element/post-code</item>                                                                        <item name="validation" xsi:type="array">                                                                            <item name="required-entry" xsi:type="boolean">true</item>                                                                        </item>                                                                    </item>                                                                    <item name="company" xsi:type="array">                                                                        <item name="validation" xsi:type="array">                                                                            <item name="min_text_length" xsi:type="number">0</item>                                                                        </item>                                                                    </item>                                                                    <item name="fax" xsi:type="array">                                                                        <item name="validation" xsi:type="array">                                                                            <item name="min_text_length" xsi:type="number">0</item>                                                                        </item>                                                                    </item>                                                                    <item name="telephone" xsi:type="array">                                                                        <item name="config" xsi:type="array">                                                                            <item name="tooltip" xsi:type="array">                                                                                <item name="description" xsi:type="string" translate="true">For delivery questions.</item>                                                                            </item>                                                                        </item>                                                                    </item>                                                                </item>                                                            </item>                                                        </item>                                                    </item>                                                </item>                                            </item>                                            <item name="billing-step" xsi:type="array">                                                <item name="component" xsi:type="string">uiComponent</item>                                                <item name="sortOrder" xsi:type="string">2</item>                                                <item name="children" xsi:type="array">                                                    <item name="payment" xsi:type="array">                                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/payment</item>                                                        <item name="config" xsi:type="array">                                                            <item name="title" xsi:type="string" translate="true">Payment</item>                                                            <item name="sortOrder" xsi:type="string">20</item>                                                        </item>                                                        <item name="children" xsi:type="array">                                                            <item name="renders" xsi:type="array">                                                                <item name="component" xsi:type="string">uiComponent</item>                                                                <item name="children" xsi:type="array">                                                                    <!-- merge payment method renders here -->                                                                </item>                                                            </item>                                                            <item name="additional-payment-validators" xsi:type="array">                                                                <item name="component" xsi:type="string">uiComponent</item>                                                                <item name="children" xsi:type="array">                                                                    <!-- merge payment validators here -->                                                                    <item name="email-validator" xsi:type="array">                                                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/payment/email-validator</item>                                                                    </item>                                                                </item>                                                            </item>                                                            <item name="customer-email" xsi:type="array">                                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/form/element/email</item>                                                                <item name="displayArea" xsi:type="string">customer-email</item>                                                                <item name="tooltip" xsi:type="array">                                                                    <item name="description" xsi:type="string" translate="true">We'll send your order confirmation here.</item>                                                                </item>                                                                <item name="children" xsi:type="array">                                                                    <item name="before-login-form" xsi:type="array">                                                                        <item name="component" xsi:type="string">uiComponent</item>                                                                        <item name="displayArea" xsi:type="string">before-login-form</item>                                                                        <item name="children" xsi:type="array">                                                                            <!-- before login form fields -->                                                                        </item>                                                                    </item>                                                                    <item name="additional-login-form-fields" xsi:type="array">                                                                        <item name="component" xsi:type="string">uiComponent</item>                                                                        <item name="displayArea" xsi:type="string">additional-login-form-fields</item>                                                                        <item name="children" xsi:type="array">                                                                            <!-- additional login form fields -->                                                                        </item>                                                                    </item>                                                                </item>                                                            </item>                                                            <item name="place-order-captcha" xsi:type="array">                                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/checkout/placeOrderCaptcha</item>                                                                <item name="displayArea" xsi:type="string">place-order-captcha</item>                                                                <item name="formId" xsi:type="string">payment_processing_request</item>                                                                <item name="configSource" xsi:type="string">checkoutConfig</item>                                                            </item>                                                            <item name="beforeMethods" xsi:type="array">                                                                <item name="component" xsi:type="string">uiComponent</item>                                                                <item name="displayArea" xsi:type="string">beforeMethods</item>                                                                <item name="children" xsi:type="array">                                                                    <!-- merge additional data before payment methods here -->                                                                </item>                                                                <item name="validation" xsi:type="array">                                                                    <item name="validate-select" xsi:type="string">true</item>                                                                </item>                                                                <!-- Value of region_id field is filtered by the value of county_id attribute -->                                                                <item name="filterBy" xsi:type="array">                                                                    <item name="target" xsi:type="string">${ $.provider }:${ $.parentScope }.country_id</item>                                                                    <item name="field" xsi:type="string">country_id</item>                                                                </item>                                                            </item>                                                            <item name="payments-list" xsi:type="array">                                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/payment/list</item>                                                                <item name="displayArea" xsi:type="string">payment-methods-list</item>                                                                <item name="config" xsi:type="array">                                                                    <item name="deps" xsi:type="array">                                                                        <item name="0" xsi:type="string">checkout.steps.billing-step.payment.renders</item>                                                                        <item name="1" xsi:type="string">checkout.steps.billing-step.payment.additional-payment-validators</item>                                                                    </item>                                                                </item>                                                                <item name="children" xsi:type="array">                                                                    <item name="before-place-order" xsi:type="array">                                                                        <item name="component" xsi:type="string">uiComponent</item>                                                                        <item name="displayArea" xsi:type="string">before-place-order</item>                                                                        <item name="dataScope" xsi:type="string">before-place-order</item>                                                                        <item name="provider" xsi:type="string">checkoutProvider</item>                                                                        <item name="config" xsi:type="array">                                                                            <item name="template" xsi:type="string">Magento_Checkout/payment/before-place-order</item>                                                                        </item>                                                                    </item>                                                                </item>                                                            </item>                                                            <!-- merge your payment methods here -->                                                            <item name="afterMethods" xsi:type="array">                                                                <item name="component" xsi:type="string">uiComponent</item>                                                                <item name="displayArea" xsi:type="string">afterMethods</item>                                                                <item name="children" xsi:type="array">                                                                    <!-- merge additional data after payment methods here -->                                                                </item>                                                            </item>                                                        </item>                                                    </item>                                                </item>                                            </item>                                        </item>                                    </item>                                    <item name="sidebar" xsi:type="array">                                        <item name="sortOrder" xsi:type="string">50</item>                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/sidebar</item>                                        <item name="displayArea" xsi:type="string">sidebar</item>                                        <item name="config" xsi:type="array">                                            <item name="template" xsi:type="string">Magento_Checkout/sidebar</item>                                            <item name="deps" xsi:type="array">                                                <item name="0" xsi:type="string">checkout.steps</item>                                            </item>                                        </item>                                        <item name="children" xsi:type="array">                                            <item name="summary" xsi:type="array">                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/summary</item>                                                <item name="displayArea" xsi:type="string">summary</item>                                                <item name="config" xsi:type="array">                                                    <item name="template" xsi:type="string">Magento_Checkout/summary</item>                                                </item>                                                <item name="children" xsi:type="array">                                                    <item name="totals" xsi:type="array">                                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/totals</item>                                                        <item name="displayArea" xsi:type="string">totals</item>                                                        <item name="config" xsi:type="array">                                                            <item name="template" xsi:type="string">Magento_Checkout/summary/totals</item>                                                        </item>                                                        <item name="children" xsi:type="array">                                                            <!-- sort order for this totals is configured on admin panel-->                                                            <!-- Stores->Configuration->SALES->Sales->General->Checkout Totals Sort Order -->                                                            <item name="subtotal" xsi:type="array">                                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/subtotal</item>                                                                <item name="config" xsi:type="array">                                                                    <item name="title" xsi:type="string" translate="true">Cart Subtotal</item>                                                                </item>                                                            </item>                                                            <item name="shipping" xsi:type="array">                                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/shipping</item>                                                                <item name="config" xsi:type="array">                                                                    <item name="title" xsi:type="string" translate="true">Shipping</item>                                                                    <item name="notCalculatedMessage" xsi:type="string" translate="true">Not yet calculated</item>                                                                </item>                                                            </item>                                                            <item name="grand-total" xsi:type="array">                                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/grand-total</item>                                                                <item name="config" xsi:type="array">                                                                    <item name="title" xsi:type="string" translate="true">Order Total</item>                                                                </item>                                                            </item>                                                        </item>                                                    </item>                                                    <item name="itemsBefore" xsi:type="array">                                                        <item name="component" xsi:type="string">uiComponent</item>                                                        <item name="children" xsi:type="array">                                                            <!-- merge your components here -->                                                        </item>                                                    </item>                                                    <item name="cart_items" xsi:type="array">                                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/cart-items</item>                                                        <item name="children" xsi:type="array">                                                            <item name="details" xsi:type="array">                                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/item/details</item>                                                                <item name="children" xsi:type="array">                                                                    <item name="thumbnail" xsi:type="array">                                                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/item/details/thumbnail</item>                                                                        <item name="displayArea" xsi:type="string">before_details</item>                                                                    </item>                                                                    <item name="subtotal" xsi:type="array">                                                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/item/details/subtotal</item>                                                                        <item name="displayArea" xsi:type="string">after_details</item>                                                                    </item>                                                                    <item name="message" xsi:type="array">                                                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/item/details/message</item>                                                                        <item name="displayArea" xsi:type="string">item_message</item>                                                                    </item>                                                                </item>                                                            </item>                                                        </item>                                                    </item>                                                    <item name="itemsAfter" xsi:type="array">                                                        <item name="component" xsi:type="string">uiComponent</item>                                                        <item name="children" xsi:type="array">                                                            <!-- merge your components here -->                                                        </item>                                                    </item>                                                </item>                                            </item>                                            <item name="shipping-information" xsi:type="array">                                                <item name="component" xsi:type="string">Magento_Checkout/js/view/shipping-information</item>                                                <item name="config" xsi:type="array">                                                    <item name="deps" xsi:type="string">checkout.steps.shipping-step.shippingAddress</item>                                                </item>                                                <item name="displayArea" xsi:type="string">shipping-information</item>                                                <item name="children" xsi:type="array">                                                    <item name="ship-to" xsi:type="array">                                                        <item name="component" xsi:type="string">Magento_Checkout/js/view/shipping-information/list</item>                                                        <item name="displayArea" xsi:type="string">ship-to</item>                                                    </item>                                                </item>                                            </item>                                        </item>                                    </item>                                </item>                            </item>                            <item name="checkoutProvider" xsi:type="array">                                <item name="component" xsi:type="string">uiComponent</item>                            </item>                        </item>                    </argument>                </arguments>            </block>        </referenceContainer>        <referenceContainer name="page.messages" remove="true"/>    </body></page>

Мы задаем инструкции для рендеринга страницы так, как будто мы делаем это в PHP Array, но с более наглядным отображением, и возможностью расширения. Благодаря xml и Magento 2 мы можем подменить любой кусочек или добавить что-то свое.

В админке таким же образом можно расширить любую UI Component форму, грид или что-то еще (да, еще остались формы и гриды, написанные "по-старому" в PHP классах), например вот таким образом можно добавить колонку на UI Grid:

<?xml version="1.0" encoding="UTF-8"?><!--/** * Copyright  Magento, Inc. All rights reserved. * See COPYING.txt for license details. */--><listing xmlns:xsi="http://personeltest.ru/away/www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">    <columns name="sales_order_columns">        <column name="refunded_to_store_credit" class="Magento\Sales\Ui\Component\Listing\Column\Price">            <settings>                <label translate="true">Refunded to Store Credit</label>                <visible>false</visible>            </settings>        </column>    </columns></listing>

Напоследок хочу отметить то, что коммьюнити не стоит на месте в плане новинок, например последние на данный момент версии Magento поддерживают только php 7.3 и 7.4, elasticsearch 7.4/7.6

P.S. Я хочу еще раз подчеркнуть, что в статье приводятся достоинства, которые, в свою очередь, не лишены недостатков :). Я не преследовал цель заставить всех поверить, что Magento - квинтэссенция всего, и нужно срочно бросать свое {cms/frameworkName} и переходить на Magento. Я лишь хочу показать, что Magento 2 не для "кодинга", а очень даже для "программирования".

Подробнее..
Категории: Php , Cms , Архитектура , Magento , Magento 2

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru