Łukasz Bajsarowicz

My name is

Magento Developer @ 

Composition That Benefits!

8 years of Magento evolution

March 2007

and it's "Smart Autoloader"

Core

Community

Local

"Lazy" programmers copying whole modules
from core/ to local/ to change single methods.

and Almighty Mage:: Singleton

Models instantiation?

Mage::getModel('core/url_rewrite')

... and helpers.

Mage::helper('customer')

Event logging?

Mage::log('Customer cannot be saved.')

Store information?

Mage::app()->getStore()

Events Publishing

Mage::dispatchEvent('my_own_event')

Registry handling

Mage::register('my_variable', 'and value')
Mage::registry('my_variable')

and Inheritance Everywhere (!)

... new lightweight model?

class MyCompany_Module_Model_Customer extends Mage_Core_Model_Abstract

Lightweight helper?

class MyCompany_Module_Helper_Data extends Mage_Core_Helper_Abstract

Add extra method to the model?

class MyCompany_Module_Model_Customer extends Mage_Customer_Model_Customer

... overused by programmers even when they do not write Magento-related code.

and Class Extensibility

... argh! One more thing to remember!

require_once Mage::getModuleDir('controllers', 'Mage_Customer').DS.'AccountController.php'

New Action in existing Controller?

class MyCompany_Module_AccountController extends Mage_Customer_AccountController

... as Magento is unable to autoload original, extended Controller.

Let's create new Controller

class MyCompany_Module_CustomController extends Mage_Core_Controller_Front_Action

and Global XML Configuration

Each and every value from XML configuration...

<global>
   <models>
      <customer>
          <rewrite>
              <customer>MyCompany_Customer_Model_Customer</customer>
          </rewrite>
      </customer>
   </models>
</global>

Is parsed to one huge configuration PHP array.
... the latest loaded module "wins" the configuration.

and Nosy Observers

Both in Core and external modules...

class Mage_CurrencySymbol_Model_Observer
{
    public function currencyDisplayOptions(Varien_Event_Observer $observer)
    {
        $baseCode = $observer->getEvent()->getBaseCode();
        $currencyOptions = $observer->getEvent()->getCurrencyOptions();
        $currencyOptions->setData(Mage::helper('currencysymbol')
            ->getCurrencyOptions($baseCode));
        return $this;
    }
}

Observers are modyfying received data!

November 2015

... 8  years after Magento 1 release

Developers should understand that Magento 2 way of doing something is actually OOP way of doing something. We did not invent a wheel.

We just try to follow good OOP/OOD practices.

IGOR MINIAILO

Magento 2 architect, part of Community Engineering Team

and PSR (PHP Standard Recommendation)

namespace MyCompany\MyModule\Model;

class MyModel implements IdentityInterface
{
    ...
}

Clearly defined in documentation "Programming Best Practices"

https://devdocs.magento.com/guides/v2.2/ext-best-practices/extension-coding/common-programming-bp.html

and Dependency Injection

namespace MyCompany\MyModule\Setup;

use Magento\Framework\Setup\UpgradeDataInterface;

class UpgradeData implements UpgradeDataInterface
{
    ...

    public function __construct(
        BlockRepositoryInterface $blockRepository,
        BlockInterfaceFactory $blockFactory
    ) {
        $this->blockRepository = $blockRepository;
        $this->blockFactory = $blockFactory;
    }

    ...
}

You need? You inject!

and Service Contract concept

Abstract classes

Interfejsy

Conversation with another module is based on Interfaces, defined in API

public function __construct(ProductInterface $product) {
    ...
}
<preference for="Magento\Catalog\Api\Data\ProductInterface"
    type="Magento\Catalog\Model\Product" />

Declaration of prefered implementation

<type name="MyCompany\Module\Controller\ProductController">
    <arguments>
        <argument name="product" xsi:type="object">MyCompany\Module\Model\Product</argument>
    </arguments>
</type>

Injection of specific Interface implementation

and Proxy (Interceptor) Design Pattern

Extensibility of public methods by composition.

and Unit Tests mocking / stubbing

use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;

public function setUp()
{
    $objectManager = new ObjectManager($this);

    $this->urlBuilderMock = $this->getMockBuilder(
        \Magento\Framework\UrlInterface::class
    )->disableOriginalConstructor()->getMock();

    $this->testedObject = $this->objectManager->getObject(
        \Some\Fancy\Object::class,
        ['urlBuilder' => $urlBuilderMock]
    );
}

and "Tailored" configuration

Configuration zones in Magento

- Administration (adminhtml)

- Store front (frontend)

- Global (base)

- Web API REST (webapi_rest)

- Web API SOAP (webapi_soap)

and Independent Observers

Data modification in observers is now a bad practice

https://devdocs.magento.com/guides/v2.2/coding-standards/technical-guidelines.html#14-events
class SampleEventObserverThatModifiesInputs
{
    /**
     * @param \Magento\Framework\Event\Observer $observer
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        /** @var \Magento\Framework\App\DataObject $transport */
        $transport = $observer->getData('transport');

        if ($transport->getData('some_value') === true) {
            $transport->setData('output_return_value', true);
        }
    }
}

So, where's that composition?

Extended version of Use / Implement diagram is available on Vinai Kopp's Twitter account.

and continuous work to get rid of "legacy"

223 open

5337 closed

... thanks to the power of Community

2017 / 2018

A

C

I

D

tomicity

onsistency

solation

urability

gets new mindset!