magento 2 design patterns

26
MAGENTO 2 DESIGN PATTERNS by Max Pronko Magento Meetup Dublin 13 February 9, 2016

Upload: max-pronko

Post on 06-Jan-2017

2.721 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: Magento 2 Design Patterns

MAGENTO 2 DESIGN PATTERNSby Max Pronko

Magento Meetup Dublin 13February 9, 2016

Page 2: Magento 2 Design Patterns

ABOUT ME

➤ 6 years with Magento

➤ Magento 2 Blogger

➤ Father

➤ from Ukraine

➤ CTO @ GiftsDirect

Page 3: Magento 2 Design Patterns

MAGENTO 2 ARCHITECTURE DESIGN GOALS

What:

➤ Streamline customisations

➤ Simplify external integrations

How:

➤ Loose coupling between Modules

➤ SOLID Principles

➤ Design Patterns

➤ Configuration over customisation

3

Page 4: Magento 2 Design Patterns

S.O.L.I.D.Principles

4

Page 5: Magento 2 Design Patterns

SINGLE RESPONSIBILITY PRINCIPLE

➤ Class should have only 1 reason to change.

namespace Magento\Cms\Controller\Page;

class View extends \Magento\Framework\App\Action\Action { /** code */

public function execute() { $pageId = $this->getRequest()->getParam('page_id', $this->getRequest()->getParam('id', false)); $resultPage = $this->_objectManager->get('Magento\Cms\Helper\Page')->prepareResultPage($this, $pageId); if (!$resultPage) { $resultForward = $this->resultForwardFactory->create(); return $resultForward->forward('noroute'); } return $resultPage; } }

5

Page 6: Magento 2 Design Patterns

OPEN/CLOSED PRINCIPLE

➤ Classes should be open for extension, but closed for modification.

namespace Magento\Catalog\Controller\Adminhtml\Category;

class RefreshPath extends \Magento\Catalog\Controller\Adminhtml\Category { /** code */

public function execute() { $categoryId = (int)$this->getRequest()->getParam('id'); if ($categoryId) { $category = $this->_objectManager->create('Magento\Catalog\Model\Category')->load($categoryId);

/** @var \Magento\Framework\Controller\Result\Json $resultJson */ $resultJson = $this->resultJsonFactory->create(); return $resultJson->setData(['id' => $categoryId, 'path' => $category->getPath()]); } } }

6

Page 7: Magento 2 Design Patterns

LISKOV SUBSTITUTION PRINCIPLE

Source: https://lostechies.com

Page 8: Magento 2 Design Patterns

INTERFACE SEGREGATION PRINCIPLE

➤ Client should not be forced to depend on methods it does not use.

namespace Magento\Payment\Gateway\Http;

interface TransferInterface { public function getClientConfig(); public function getMethod(); public function getHeaders(); public function shouldEncode(); //Client Zend public function getBody(); public function getUri(); //Client Zend public function getAuthUsername(); // None public function getAuthPassword(); // None }

namespace Magento\Payment\Gateway\Http\Transfer;

interface AuthInterface { public function getUsername(); public function getPassword(); } interface ZendUrlEncoderInterface { public function shouldEncode(); } interface ConfigInterface { public function getValue(); }

namespace Magento\Payment\Gateway\Http;

interface TransferInterface { public function getMethod(); public function getHeaders(); public function getBody(); }

Decoupling example

8

Might be improved

Page 9: Magento 2 Design Patterns

DEPENDENCY INVERSION PRINCIPLE

➤ High-level modules should not depend on low-level modules. Both should depend on abstractions.namespace Magento\Framework;

class Image { /** * @var Image\Adapter\AdapterInterface */ protected $_adapter;

public function __construct( \Magento\Framework\Image\Adapter\AdapterInterface $adapter, $fileName = null ) { $this->_adapter = $adapter; $this->_fileName = $fileName; if (isset($fileName)) { $this->open(); } }

/** code */ }

9

Page 10: Magento 2 Design Patterns

SOME TIPS

➤ Create tiny classes to avoid monsters

➤ Build your code on abstractions (interfaces)

➤ Look inside code for good practices

➤ Refactor, refactor, refactor

10

Page 11: Magento 2 Design Patterns

DESIGN PATTERNSMagento 2 Edition

Page 12: Magento 2 Design Patterns

“Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice

-Christopher Alexander

DESIGN PATTERNS

12

Page 13: Magento 2 Design Patterns

MAGENTO 2 DESIGN PATTERNS

Page 14: Magento 2 Design Patterns

OBJECT MANAGER

➤ Dependency Injection Manager

➤ Knows how to instantiate classes

➤ Creates objects

➤ Provides shared pool of objects

➤ Enables lazy initialisation

Page 15: Magento 2 Design Patterns

OBJECT MANAGER

15

Patterns:

➤ Dependency Injection

➤ Singleton

➤ Builder

➤ Abstract Factory

➤ Factory Method

➤ Decorator

➤ Value Object

➤ Composition

➤ Strategy

➤ CQRS (command query responsibility segregation)

➤ more…

Page 16: Magento 2 Design Patterns

OBJECT MANAGER

Magento/Framework

16

Page 17: Magento 2 Design Patterns

FACTORY METHOD

17

namespace Magento\Catalog\Model;

class Factory { protected $_objectManager;

public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager) { $this->_objectManager = $objectManager; }

public function create($className, array $data = []) { $model = $this->_objectManager->create($className, $data);

if (!$model instanceof \Magento\Framework\Model\AbstractModel) { throw new \Magento\Framework\Exception\LocalizedException( __('%1 doesn\'t extends \Magento\Framework\Model\AbstractModel', $className) ); } return $model; } }

➤ Creates family of related objects.

Page 18: Magento 2 Design Patterns

FACTORY METHOD

Magento\FrameworkMagento\Catalog\Model

Page 19: Magento 2 Design Patterns

OBSERVERnamespace Magento\Catalog\Model;

use Magento\Catalog\Api\Data\ProductInterface; use Magento\Framework\DataObject\IdentityInterface; use Magento\Framework\Pricing\SaleableInterface;

class Product extends \Magento\Catalog\Model\AbstractModel implements IdentityInterface, SaleableInterface, ProductInterface { protected $_eventPrefix = 'catalog_product';

public function validate() { $this->_eventManager->dispatch($this->_eventPrefix . '_validate_before', $this->_getEventData()); $result = $this->_getResource()->validate($this); $this->_eventManager->dispatch($this->_eventPrefix . '_validate_after', $this->_getEventData()); return $result; } }

File: Meetup\Module\etc\adminhtml\events.xml <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> <event name="catalog_product_validate_before"> <observer name="meetup_module_product_validator" instance="Meetup\Module\Observer\ProductObserver" /> </event> </config>

Page 20: Magento 2 Design Patterns

OBSERVER

Domain Model Framework

20

➤ Distributed event handling system.

Page 21: Magento 2 Design Patterns

PROXY

File: app/code/Magento/Catalog/etc/di.xml <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <type name="Magento\Catalog\Model\ResourceModel\Product\Collection"> <arguments> <argument name="catalogUrl" xsi:type="object">Magento\Catalog\Model\ResourceModel\Url\Proxy</argument> <argument name="customerSession" xsi:type="object">Magento\Customer\Model\Session\Proxy</argument> </arguments> </type> </config>

➤ Support for resource consuming objects.

21

Page 22: Magento 2 Design Patterns

PROXYnamespace Magento\Catalog\Model\ResourceModel\Url;

use Magento\Framework\ObjectManagerInterface;

class Proxy extends \Magento\Catalog\Model\ResourceModel\Url { public function __construct( ObjectManagerInterface $objectManager, $instanceName = '\\Magento\\Catalog\\Model\\ResourceModel\\Url', $shared = true ) { $this->_objectManager = $objectManager; $this->_instanceName = $instanceName; $this->_isShared = $shared; }

protected function _getSubject() { if (!$this->_subject) { $this->_subject = true === $this->_isShared ? $this->_objectManager->get($this->_instanceName) : $this->_objectManager->create($this->_instanceName); } return $this->_subject; }

public function _getProductAttribute($attributeCode, $productIds, $storeId) { return $this->_getSubject()->_getProductAttribute($attributeCode, $productIds, $storeId); }

public function load(\Magento\Framework\Model\AbstractModel $object, $value, $field = null) { return $this->_getSubject()->load($object, $value, $field); } }

Page 23: Magento 2 Design Patterns

COMPOSITE

namespace Magento\Payment\Gateway\Request;

use Magento\Framework\ObjectManager\TMap; use Magento\Framework\ObjectManager\TMapFactory;

class BuilderComposite implements BuilderInterface { private $builders;

public function __construct( TMapFactory $tmapFactory, array $builders = [] ) { $this->builders = $tmapFactory->create( [ 'array' => $builders, 'type' => BuilderInterface::class ] ); }

public function build(array $buildSubject) { $result = []; foreach ($this->builders as $builder) { $result = $this->merge($result, $builder->build($buildSubject)); }

return $result; }

protected function merge(array $result, array $builder) { return array_replace_recursive($result, $builder); } }

Page 24: Magento 2 Design Patterns

COMPOSITE

Magento/Payment/Gateway

Page 25: Magento 2 Design Patterns

#ThanksQ&A

/maxpronkocom @max_pronkowww.maxpronko.com

Page 26: Magento 2 Design Patterns

MAGENTO 2 DESIGN PATTERNS

➤ Object Manager

➤ Event Observer

➤ Composition

➤ Factory Method

➤ Singleton

➤ Builder

➤ Factory

➤ State

➤ Strategy

➤ Adapter

➤ Command

➤ CQRS

➤ MVVM