View this presentation

Applying Code
Customizations to
Magento 2 (Part 1)
Anton Kril
Architect, Magento 2
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.
Interactions with Magento2
Code
Extension
UI
Model
Service
Contracts
UI
Vendor
Model
Service
Contracts
Customization
UI
Model
Service
Contracts
Vendor
Model
Customization Points
Customization Points
Admin Configuration
High-level Configuration
acl.xml
routes.xml
layout
events.xml
cache.xml
webapi.xml
di.xml
Low-level Linking
Object B
Object B
Object C
Object A
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
High-level Configuration
events.xml
Event Manager
layout
Routing
Application Subsystems
EntryPoint
Application
Area
Cron App
WebAPI
Web App
Admin
Media App
Frontend
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
}
Context Independence
Application A
Config
Invoker
EventManager
Alternative
Config
Application B
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.
2.
3.
4.
Single Responsibility – Lots of small objects
Open-Closed – Each object has multiple extension points
Liskov Substitution – Polymorphism for composability
Interface Segregation – Granularity
Modularity
soliD
Coupled
Module A
Module B
Implementation
Decoupled
Module AB
Module A
Adapter
Module B
Implementation
Interface
Module AB
Adapter
Module C
Implementation
Thank you!
Applying Code Customizations to Magento 2
Q&A
Anton Krill
[email protected]
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
How to ensure that two extensions will be compatible in a new
version?



Interfaces may be changed in a new version
Extensions may depend on optional modules which is turned off
Extensions may depend on undocumented behavior
Challenges for Developer
How to implement extension in the way that it will keep backward
compatibility but can evolve?
How to understand what functionality of the extension is stable and
what is not?
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 annotation identifies subset
of the methods with the stable APIs
Enforced by tools and static tests
/**
* @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);
}
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
Client
getData()
Model
Resource
Model
Service Contracts
Other M2 Modules
M2 Module
Blocks
Web API clients
Controllers
Templates
Service Contracts
Repositories
Models
Resource
Models
Services
Data
Objects
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
M2 Module
Blocks
Controllers
Templates
Service Contracts
Repositories
Models
Resource
Models
Services
Data
Objects
Service Contracts Interfaces
They are just PHP Interfaces
Service interfaces
Data interfaces
 Defines business operations
 Defines data structures, used as input and
output types of the business operations
 Examples: load, delete, save, change
password, etc.
 Examples: Customer, Product, Region,
Currency, etc.
Service Contracts
Service
Interfaces
Data Interface
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
Data Interfaces
Models
Data
Objects
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 thirdparty module
 Added via xml configuration, generated as an object
Product Data
Interface
Product fields
Rating and
Reviews
Module
Review fields
Catalog
Inventory fields
Catalog
Inventory
Module
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!
Applying Code Customizations to Magento 2
Q&A
Eugene Tulika
[email protected]
@vrann
Sergii Shymko
Senior Software Engineer
Code Generation
in Magento 2
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.
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
var/generation/
dev/tools/Magento/Tools/Di/compiler.php
 Location of generated code:
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
app/code/Magento/Catalog/Model/Product/Copier.php
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();
// ...
}
}
Generated Factory (Simplified)
var/generation/Magento/Catalog/Model/ProductFactory.php
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
);
}
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:
Proxy Usage in DI Config
app/code/Magento/Catalog/etc/di.xml
<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>
Generated Proxy (Simplified)
var/generation/Magento/Customer/Model/Session/Proxy.php
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();
}
// ...
}
Interception




Primary customization approach
AOP-like mechanism
Used for plugins
Attach behavior to public methods
 Before
 After
 Around
Plugin Implementation
app/code/Magento/Store/App/Action/Plugin/StoreCheck.php
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);
}
}
Plugin Declaration in DI Config
app/code/Magento/Store/etc/di.xml
<config>
<type name="Magento\Framework\App\Action\Action">
<plugin name="storeCheck"
type="Magento\Store\App\Action\Plugin\StoreCheck"
sortOrder="10"/>
</type>
</config>
Generated Interceptor (Simplified)
var/generation/Magento/Framework/App/Action/Action/Interceptor.php
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
);
}
}
}
Code Generation for Service Layer
 Service layer – ultimate public API
 Services implement stateless operations
 Generated code:




Repository*
Persistor*
Search Results
Extension Attributes
Generated Repository (Simplified)
var/generation/Magento/Sales/Api/Data/Order/Repository.php
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
public
public
public
public
function
function
function
function
function
get($id);
create(\Magento\Sales\Api\Data\OrderInterface $entity);
getList(\Magento\Framework\Api\SearchCriteria $criteria);
remove(\Magento\Sales\Api\Data\OrderInterface $entity);
flush();
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:
Declaration of Extension Attributes
app/code/Magento/Bundle/etc/data_object.xml
<config>
<custom_attributes for="Magento\Catalog\Api\Data\ProductInterface">
<attribute code="price_type" type="integer" />
</custom_attributes>
</config>
Entity with Extension Attributes
app/code/Magento/Catalog/Api/Data/ProductInterface.php
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
);
}
// ...
Generated Interface of Extension Attributes
var/generation/Magento/Catalog/Api/Data/ProductExtensionInterface.php
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);
}
// ...
Generated Implementation of Extension
Attributes
var/generation/Magento/Catalog/Api/Data/ProductExtension.php
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);
}
}
// ...
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!
Code Generation in Magento 2
Q&A
Sergii Shymko
[email protected]
Resources
 github.com
 magento/magento2 – Magento 2 Community Edition
 magento/magento2-community-edition – Composer
project for Magento 2 CE
 devdocs.magento.com




Factories
Proxies
Plugins
Definition compilation tool
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
Category
Product
CMS
Block HTML
Nav
</>
Menu
Footer
View Files
Location
Fallback
Data Definition Language
Integrity
Index
Tmp
EAV
Template
Labels
Page Cache
CMS
Category
Product
Translations
De
Fr
En
It
Integrations
OAuth
Web Services
SOAP
REST
WSDL
Frontend Development
> magento cache:flush
Frontend Development
Theme creation (theme.xml, bind to store)
Layout modifications
Overrides for static files
Changes in existing images
Less files
pub
static
var
cache
page_cache
Server-side Development
Backend Development
New blocks, models, templates
Layout modifications
New plugins, events
Plugins modifications
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
Product
CMS
Address
Public
Category
Name
Private
Cart
Login
Wishlist
Thank you!
Caching Optimizations for Code Development
Q&A
Andrey Konosov
[email protected]
Credits: Icons designed by Freepik