111

Applying Code Customizations to Magento 2 (Part 1)info2.magento.com/rs/magentosoftware/images/M2... · namespace Magento\Framework\Event; class Manager implements ManagerInterface

  • Upload
    ngonga

  • View
    226

  • Download
    4

Embed Size (px)

Citation preview

Applying Code

Customizations to

Magento 2 (Part 1)

Anton Kril Architect, Magento 2

Copyright © 2015 Magento, Inc. All Rights Reserved.

Magento®, eBay Enterprise™ and their respective logos are trademarks, service marks, registered trademarks, or registered service marks of eBay, Inc. or its subsidiaries. Other trademarks or service marks contained in this presentation are the property of the respective companies with which they are associated.

This presentation is for informational and discussion purposes only and should not be construed as a commitment of Magento, Inc. or eBay Enterprise (“eBay Enterprise”) or of any of their subsidiaries or affiliates. While we attempt to ensure the accuracy, completeness and adequacy of this presentation, neither Magento, Inc., eBay Enterprise nor any of their subsidiaries or affiliates are responsible for any errors or will be liable for the use of, or reliance upon, this presentation or any of the information contained in it. Unauthorized use, disclosure or dissemination of this information is expressly prohibited.

Legal Disclaimer

Interactions with Magento2

Code

Extension

UI Model

UI

Model

Service Contracts

Service Contracts

Vendor

Customization

UI Model

Model

Service Contracts

Vendor

Customization Points

Low-level Linking

High-level Configuration

Admin Configuration

Customization Points

events.xml

routes.xml

cache.xml webapi.xml

layout

di.xml

Object B Object C Object A

Object B

acl.xml

Store Configuration

Store Configuration

• In admin application: Stores->Configuration

• Values stored in Database

• Configured in system.xml

• Default values in config.xml

High-level Configuration

XML is like violence: if it doesn’t solve your problem, you aren’t using enough of it.

Chris Maden

Routing

High-level Configuration

Event Manager

events.xml

layout

Application Subsystems

Area Application

EntryPoint

Cron App

Web App

WebAPI

Admin

Frontend Media App

Low Level Linking

OOP

1. Composability

2. Modularity

Composability

Composability

Split your code to lots of small

chunks and then compose them to

build your application

Context Dependence

Object totally dependent on on it’s environment

EventManager

Config Invoker

Context Dependence

namespace Magento\Framework\Event;

class Manager implements ManagerInterface

{

public function dispatchEvent($eventName, array $eventData)

{

$observers = Mage::getConfig()->getObservers($eventName);

foreach ($observers as $observer) {

Mage::getSingleton('core/event_invoker')->invoke($observer);

}

}

// some other code

}

Application A Application B

Context Independence

Config Invoker

AlternativeConfig

EventManager

Config Invoker

Dependency Injection

Dependencies are not located within object but are

provided to that object by environment

Dependency Injection

namespace Magento\Framework\Event; class Manager implements ManagerInterface { public function __construct( Invoker $invoker, Config $eventConfig, $prefix = '' ) { $this->_invoker = $invoker; $this->_eventConfig = $eventConfig; $this->_prefix = $prefix; } // some other code }

Seams

di.xml

<config>

<type name="Magento\Framework\Event\Manager">

<arguments>

<argument name="prefix" xsi:type="string">eventPrefix</argument>

<argument name="eventConfig" xsi:type="object">

My\Alternative\Event\Config

</argument>

</arguments>

</type>

</config>

di.xml

<config>

<type name="Magento\Framework\Event\Manager">

<plugin name="logging" type="My\Module\Event\Logger"/>

</type>

</config>

Unit Tests

class ManagerTest extends \PHPUnit_Framework_TestCase

{

protected function setUp()

{

$this->_invoker = $this->getMock('Magento\Framework\Event\Invoker');

$this->_eventConfigMock = $this->getMock('Magento\Framework\Event\Config');

$this->_eventManager = new \Magento\Framework\Event\Manager(

$this->_invoker,

$this->_eventConfigMock

);

}

}

SOLId

1. Single Responsibility – Lots of small objects

2. Open-Closed – Each object has multiple extension points

3. Liskov Substitution – Polymorphism for composability

4. Interface Segregation – Granularity

Modularity

Module AB

Module B Module A

soliD

Coupled

Decoupled

Implementation

Module B

Module A Implementation Adapter

Interface

Module AB

Adapter

Module C

Implementation

Thank you!

Anton Krill [email protected]

Q & A

Applying Code Customizations to Magento 2

Applying Code

Customizations to

Magento 2 (Part 2)

Eugene Tulika Architect, Magento Platform Services

Legal Disclaimer

Copyright © 2015 Magento, Inc. All Rights Reserved.

Magento®, eBay Enterprise™ and their respective logos are trademarks, service marks,

registered trademarks, or registered service marks of eBay, Inc. or its subsidiaries. Other

trademarks or service marks contained in this presentation are the property of the

respective companies with which they are associated.

This presentation is for informational and discussion purposes only and should not be

construed as a commitment of Magento, Inc. or eBay Enterprise (“eBay Enterprise”) or of

any of their subsidiaries or affiliates. While we attempt to ensure the accuracy,

completeness and adequacy of this presentation, neither Magento, Inc., eBay Enterprise

nor any of their subsidiaries or affiliates are responsible for any errors or will be liable for

the use of, or reliance upon, this presentation or any of the information contained in it.

Unauthorized use, disclosure or dissemination of this information is expressly prohibited.

Service Contracts And Compatible Customizations

Extensions Compatibility Challenges

Interfaces may be changed in a new version

Extensions may depend on optional modules which is turned off

Extensions may depend on undocumented behavior

How to ensure that two extensions will be compatible in a new

version?

Challenges for Developer

How to understand what functionality of the extension is stable and

what is not?

How to implement extension in the way that it will keep backward

compatibility but can evolve?

Stable APIs

Backward Compatible:

Classes or Interfaces are not removed

Methods of the classes keeps signature between versions

Interfaces neither changes existing methods nor add new ones

Explicit Interfaces

No generic data types as “mixed”, “object” or “array”

Few ways to make promises in Magento 2

Semantic Versioning of the

modules makes dependencies

between modules explicit

{

"name": "magento/module-catalog-inventory",

"require": {

"magento/module-customer": "0.74.0-beta2"

},

"type": "magento2-module"

}

/**

* @api

*/

interface AuthorizationInterface

{

/**

* Check current user permission on resource and privilege

*

* @param string $resource

* @param string $privilege

* @return boolean

*/

public function isAllowed($resource, $privilege = null);

}

@api annotation identifies subset

of the methods with the stable APIs

Enforced by tools and static tests

Magento 1.x Domain Level API

Model is an entry point to the Module

Interface implicitly defined via the

database schema

No single place for the business rules

They can be in:

Controllers

Models

Helpers

Templates

Model

Resource Model

Client getData()

Repositories

Service Contracts

Models

Resource Models

Web API clients

M2 Module

Blocks Templates Controllers

Other M2 Modules

Services

Data Objects

Service Contracts

Domain Level API

Single way to define API for the business

feature

Defines strong interface

Single place to implement business rules

All interactions with the module are safe to

go through the contracts: same behavior

guaranteed

Repositories

Service Contracts

Models

Resource Models

M2 Module

Blocks Templates Controllers

Services

Data Objects

Service Contracts Interfaces

Service Contracts

Service

Interfaces Data Interface

Data interfaces

Defines data structures, used as input and

output types of the business operations

Examples: Customer, Product, Region,

Currency, etc.

Service interfaces

Defines business operations

Examples: load, delete, save, change

password, etc.

They are just PHP Interfaces

More on Data Interfaces

Has just setters and getters to describe

a data

Reusable across different Service

interfaces

Encapsulates all the data needed to

process service request

Can be Serialized

Annotations are used to extract the data

More on Service Interfaces

Defines public operations supported by

the module

Methods are independent and

stateless.

Invocation of one method should not

affect the result of another

Methods combined in interface by

cohesion principle

Annotated with types information

Classes Implementing Data Interfaces

It can be Model:

All the setters and getters should be

declared explicitly

No magic methods

It can be Any PHP class:

Implements data interface and any

other methods

It can be Data Object:

Implements just methods from the

data interface

Models

Data Objects

Data Interfaces

Implementation of Service Interfaces

Resource Models:

Used for persistence operations

Implements load/save/delete

methods and accept Data Interface

as an input

Services:

Implements operations and business

rules around them

Service Interfaces

Resource Models Services

Use Service Contracts

Define dependency on service interface in the constructor

class CreateCustomer extends \Magento\Customer\Controller\Account

{

public function __construct(

AccountManagementInterface $accountManagement

) {

$this->accountManagement = $accountManagement;

}

public function execute()

{

$customer = $this->getRequest()->getParam('customer');

$password = $this->getRequest()->getParam('password');

$redirectUrl = $this->getRequest()->getParam('redirect_url');

$customer = $this->accountManagement

->createAccount($customer, $password, $redirectUrl);

}

}

Re-Implement Service Contracts

Define a preference in DI: it will point on a new implementation

All the constructors will be injected with a new implementation

<preference for="Magento\Customer\Api\AccountManagementInterface"

type="SomeVendor\NewExtension\Model\AccountManagement" />

<preference for="Magento\Customer\Api\Data\RegionInterface"

type="SomeVendor\NewExtension\Model\Data\Region" />

Customize Service Contracts

Plugins is a way to add new behavior each time Service Interface

implementation is invoked

/** * Plugin after create customer that updates any newsletter subscription that may have existed. * * @param CustomerRepositoryInterface $subject * @param CustomerInterface $customer * @return CustomerInterface */ public function afterSave(CustomerRepositoryInterface $subject, CustomerInterface $customer) { $this->subscriberFactory->create()->updateSubscription($customer->getId()); return $customer; }

Extend Data Interfaces

Extension Attributes is a way to Extend Data Interfaces from third-

party module

Added via xml configuration, generated as an object

Review fields

Catalog Inventory fields

Rating and Reviews Module Catalog

Inventory Module

Product Data Interface

Product fields

Generated Extension Attributes

<extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">

<attribute

code="bundle_product_options"

type="Magento\Bundle\Api\Data\OptionInterface[]" />

</extension_attributes>

interface ProductExtensionInterface extends \Magento\Framework\Api\ExtensionAttributesInterface

{

/**

* @return \Magento\Bundle\Api\Data\OptionInterface[]

*/

public function getBundleProductOptions();

/**

* @param \Magento\Bundle\Api\Data\OptionInterface[] $bundleProductOptions

* @return $this

*/

public function setBundleProductOptions($bundleProductOptions);

...

}

Summary

Magento 2.x gives stronger promises on public APIs

Service Contracts are the way to define API for the Business features

Service Contracts are the single entry point to functionality of the module

Customizable via dependency injection, plugins and extension attributes

Customizations become available for all the clients of Service Contracts

Thank you!

Eugene Tulika [email protected]

@vrann

Q & A

Applying Code Customizations to Magento 2

Sergii Shymko Senior Software Engineer

Code Generation

in Magento 2

Copyright © 2015 Magento, Inc. All Rights Reserved.

Magento®, eBay Enterprise™ and their respective logos are trademarks, service marks, registered trademarks, or registered service marks of eBay, Inc. or its subsidiaries. Other trademarks or service marks contained in this presentation are the property of the respective companies with which they are associated.

This presentation is for informational and discussion purposes only and should not be construed as a commitment of Magento, Inc. or eBay Enterprise (“eBay Enterprise”) or of any of their subsidiaries or affiliates. While we attempt to ensure the accuracy, completeness and adequacy of this presentation, neither Magento, Inc., eBay Enterprise nor any of their subsidiaries or affiliates are responsible for any errors or will be liable for the use of, or reliance upon, this presentation or any of the information contained in it. Unauthorized use, disclosure or dissemination of this information is expressly prohibited.

Legal Disclaimer

Introduction to Code Generation

Automatic programming – generation of computer program

Source code generation Generation based on template

Allows to write code at higher abstraction level

Enables aspect-oriented programming (AOP)

Enables generic programming – parameterization over types

Avoids writing boilerplate code

Code Generation in Magento 1.x

Code Generation in Magento 2

Code Generation in Magento 2

Code is generated:

On the fly (development) Autoload non-existing class that follows naming pattern

Beforehand (production) Run CLI tools php

dev/tools/Magento/Tools/Di/compiler.php

Location of generated code:

var/generation/

Factories

Factory creates objects

Single method – create()

Used for non-injectables, i.e. entities

Isolation from Object Manager

Type safety

IDE auto-completion

Class name pattern: \Namespace\ClassFactory

Factory Usage

namespace Magento\Catalog\Model\Product;

class Copier

{

public function __construct(

\Magento\Catalog\Model\ProductFactory $productFactory

) {

$this->productFactory = $productFactory;

}

public function copy(\Magento\Catalog\Model\Product $product) {

$duplicate = $this->productFactory->create();

// ...

}

}

app/code/Magento/Catalog/Model/Product/Copier.php

Generated Factory (Simplified)

namespace Magento\Catalog\Model; class ProductFactory { public function __construct( \Magento\Framework\ObjectManagerInterface $objectManager ) { $this->objectManager = $objectManager; }

public function create(array $data = array()) { return $this->objectManager->create(

'\\Magento\\Catalog\\Model\\Product',

$data

); } }

var/generation/Magento/Catalog/Model/ProductFactory.php

Proxies

Implementation of GoF pattern

Follows interface of subject

Delays creation of subject

Delays creation of dependencies

Forwards calls to subject

Used for optional dependencies of DI

Class name pattern: \Namespace\Class\Proxy

Proxy Usage in DI Config

<config>

<type name="Magento\Catalog\Model\Resource\Product\Collection">

<arguments>

<argument name="customerSession" xsi:type="object">

Magento\Customer\Model\Session\Proxy

</argument>

</arguments>

</type>

</config>

app/code/Magento/Catalog/etc/di.xml

Generated Proxy (Simplified)

namespace Magento\Customer\Model\Session; class Proxy extends \Magento\Customer\Model\Session { protected function getSubject() { if (!$this->subject) { $this->subject = $this->objectManager->get( '\\Magento\\Customer\\Model\\Session' ); } return $this->subject; } public function getCustomerId() { return $this->getSubject()->getCustomerId(); }

// ...

}

var/generation/Magento/Customer/Model/Session/Proxy.php

Interception

Primary customization approach

AOP-like mechanism

Used for plugins

Attach behavior to public methods

Before

After

Around

Plugins declared in DI config

Plugin Implementation

namespace Magento\Store\App\Action\Plugin;

class StoreCheck

{

public function aroundDispatch(

\Magento\Framework\App\Action\Action $subject,

\Closure $proceed,

\Magento\Framework\App\RequestInterface $request

) {

if (!$this->storeManager->getStore()->getIsActive()) {

throw new \Magento\Framework\App\InitException(

'Current store is not active.'

);

}

return $proceed($request);

}

}

app/code/Magento/Store/App/Action/Plugin/StoreCheck.php

Plugin Declaration in DI Config

<config>

<type name="Magento\Framework\App\Action\Action">

<plugin name="storeCheck"

type="Magento\Store\App\Action\Plugin\StoreCheck"

sortOrder="10"/>

</type>

</config>

app/code/Magento/Store/etc/di.xml

Generated Interceptor (Simplified)

namespace Magento\Framework\App\Action\Action; class Interceptor extends \Magento\Framework\App\Action\Action { public function dispatch(

\Magento\Framework\App\RequestInterface $request

) { $pluginInfo = $this->pluginList->getNext(

'\\Magento\\Framework\\App\\Action\\Action', 'dispatch'

); if (!$pluginInfo) { return parent::dispatch($request); } else { return $this->___callPlugins(

'dispatch', func_get_args(), $pluginInfo

); } } }

var/generation/Magento/Framework/App/Action/Action/Interceptor.php

Code Generation for Service Layer

Service layer – ultimate public API

Services implement stateless operations

Generated code:

Repository*

Persistor*

Search Results

Extension Attributes

* – may be removed in future releases

Generated Repository (Simplified)

namespace Magento\Sales\Api\Data\Order;

class Repository implements \Magento\Sales\Api\OrderRepositoryInterface {

public function __construct( \Magento\Sales\Api\Data\OrderInterfacePersistor $orderPersistor, \Magento\Sales\Api\Data\OrderSearchResultInterfaceFactory $searchResultFactory ) { $this->orderPersistor = $orderPersistor; $this->searchResultFactory = $searchResultFactory; }

public function get($id); public function create(\Magento\Sales\Api\Data\OrderInterface $entity); public function getList(\Magento\Framework\Api\SearchCriteria $criteria); public function remove(\Magento\Sales\Api\Data\OrderInterface $entity); public function flush(); }

var/generation/Magento/Sales/Api/Data/Order/Repository.php

Extension Attributes

Extension to data interfaces from 3rd party

modules

Attributes declared in configuration

Attribute getters/setters generated

Type-safe attribute access

IDE auto-completion

Class name pattern: \Namespace\ClassExtensionInterf

ace

\Namespace\ClassExtension

Declaration of Extension Attributes

<config>

<custom_attributes for="Magento\Catalog\Api\Data\ProductInterface">

<attribute code="price_type" type="integer" />

</custom_attributes>

</config>

app/code/Magento/Bundle/etc/data_object.xml

Entity with Extension Attributes

namespace Magento\Catalog\Api\Data; interface ProductInterface

extends \Magento\Framework\Api\CustomAttributesDataInterface {

/** * @return \Magento\Catalog\Api\Data\ProductExtensionInterface|null */ public function getExtensionAttributes(); public function setExtensionAttributes(

\Magento\Catalog\Api\Data\ProductExtensionInterface $attributes

);

// ... }

app/code/Magento/Catalog/Api/Data/ProductInterface.php

Generated Interface of Extension Attributes

namespace Magento\Catalog\Api\Data;

interface ProductExtensionInterface

extends \Magento\Framework\Api\ExtensionAttributesInterface { /** * @return integer */ public function getPriceType(); /** * @param integer $priceType * @return $this */ public function setPriceType($priceType); // ... }

var/generation/Magento/Catalog/Api/Data/ProductExtensionInterface.php

Generated Implementation of Extension

Attributes

namespace Magento\Catalog\Api\Data; class ProductExtension extends \Magento\Framework\Api\AbstractSimpleObject implements \Magento\Catalog\Api\Data\ProductExtensionInterface { /** * @return integer */ public function getPriceType() { return $this->_get('price_type'); } /** * @param integer $priceType * @return $this */ public function setPriceType($priceType) { return $this->setData('price_type', $priceType); }

// ... }

var/generation/Magento/Catalog/Api/Data/ProductExtension.php

Loggers

Implementation of GoF pattern Decorator

Activated with the profiler

Object Manager wraps instances with loggers

Tracks method call stack

Forwards calls to original methods

Class name pattern: \Namespace\Class\Logger

Summary of Code Generation

DI Factory

Proxy

Interception

Service Layer Repository

Persistor

Search Results

Extension Attributes

Logger

Thank you!

Sergii Shymko [email protected]

Q & A

Code Generation in Magento 2

Andrey Konosov Architect, Magento 2

Caching

Optimizations for

Code Development

Legal Disclaimer

Copyright © 2015 Magento, Inc. All Rights Reserved.

Magento®, eBay Enterprise™ and their respective logos are trademarks, service marks, registered trademarks, or registered service marks of eBay, Inc. or its subsidiaries. Other trademarks or service marks contained in this presentation are the property of the respective companies with which they are associated.

This presentation is for informational and discussion purposes only and should not be construed as a commitment of Magento, Inc. or eBay Enterprise (“eBay Enterprise”) or of any of their subsidiaries or affiliates. While we attempt to ensure the accuracy, completeness and adequacy of this presentation, neither Magento, Inc., eBay Enterprise nor any of their subsidiaries or affiliates are responsible for any errors or will be liable for the use of, or reliance upon, this presentation or any of the information contained in it. Unauthorized use, disclosure or dissemination of this information is expressly prohibited.

Cache Structure

Caches

Configuration

DI

Event

Settings

Layout

CMS

Category

Product

Block HTML

</>

Nav

Footer

Menu

View Files

Location

Fallback

Data Definition Language

Tmp

Integrity

Index

EAV

Template

Labels

Page Cache

CMS

Category

Product

Translations

En It

De

Fr

Integrations

OAuth

Web Services

SOAP

REST

WSDL

Frontend Development

> magento cache:flush

Frontend Development

Theme creation (theme.xml, bind to store)

Layout modifications

Less files

Changes in existing images

Overrides for static files

pub

static

var

cache

page_cache

Server-side Development

Backend Development

New blocks, models, templates

Layout modifications

Plugins modifications

New plugins, events

var

cache

page_cache

generation

Custom Cache

class Custom extends \Magento\Framework\Cache\Frontend\Decorator\TagScope { const TYPE_IDENTIFIER = ‘my_custom_cache'; const CACHE_TAG = ‘MY_CUSTOM'; public function __construct(FrontendPool $cacheFrontendPool) { parent::__construct($cacheFrontendPool->get(self::TYPE_IDENTIFIER), self::CACHE_TAG); } }

Custom Cache (cache.xml)

<type name=“custom" translate="label,description" instance=“My\Cache"> <label>Custom cache</label> <description>This is my storage.</description> </type>

Page Cache

Page Cache

EVERY PAGE IS CACHEABLE BY DEFAULT

Page Cache

Public Private

Address

Cart

Name

Wishlist

Product

Category

CMS

Login

Thank you!

Credits: Icons designed by Freepik

Andrey Konosov [email protected]

Q & A

Caching Optimizations for Code Development