Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

31

Transcript of Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Page 1: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2
Page 2: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Panoramica del modulo

• Struttura del modulo in Magento 2

• Registrazione del modulo e configurazione

• Backend

• Classe di Modello

• DI.xml e Plugin

• Frontend

Page 3: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Registrazione del modulo

<?php

\Magento\Framework\Component\ComponentRegistrar::register(

\Magento\Framework\Component\ComponentRegistrar::MODULE,

'Meetmagento_Shipping',

__DIR__

);

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">

<module name="Meetmagento_Shipping" setup_version="1.0.0">

<sequence>

<module name="Magento_OfflineShipping"/>

<module name="Magento_Catalog"/>

</sequence>

</module>

</config>

Module.xml

• Dichiarazione del modulo

• Dipendenza su:

• Magento_OfflineShipping

• Magento_Catalog

• Dipendenze sulle classi che osserviamo

Registration.php

• Punto di entrata del modulo

• Serve a Magento per identificare i moduli

installati nel sistema

Page 4: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Backend - system.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">

<system>

<section id="carriers">

<group id="shippingmeetmagento" translate="label" type="text" sortOrder="99" showInDefault="1" showInWebsite="1"

showInStore="1">

<label>Shipping Meet Magento</label>

<field id="active" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1"

showInStore="0">

<label>Abilitato</label>

<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>

</field>

<field id="title" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1"

showInStore="1">

<label>Titolo</label>

</field>

<field id="name" translate="label" type="text" sortOrder="30" showInDefault="1" showInWebsite="1"

showInStore="1">

<label>Nome del metodo di spedizione</label>

</field>

<field id="price" translate="label" type="text" sortOrder="40" showInDefault="1" showInWebsite="1"

showInStore="0">

<label>Prezzo di invio</label>

<validate>validate-number validate-zero-or-greater</validate>

</field>

<field id="sallowspecific" translate="label" type="select" sortOrder="50" showInDefault="1"

showInWebsite="1" showInStore="0">

<label>Paesi permessi per l'invio</label>

<frontend_class>shipping-applicable-country</frontend_class>

<source_model>Magento\Shipping\Model\Config\Source\Allspecificcountries</source_model>

</field>

<field id="specificcountry" translate="label" type="multiselect" sortOrder="51" showInDefault="1"

showInWebsite="1" showInStore="0">

<label>Invio a paesi selezionati</label>

<source_model>Magento\Directory\Model\Config\Source\Country</source_model>

<can_be_empty>1</can_be_empty>

</field>

<field id="attribute_set" translate="label" type="text" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="0">

<label>Attribute set dei prodotti attivi</label>

</field>

<field id="free_shipping_amount" translate="label" type="text" sortOrder="70" showInDefault="1" showInWebsite="1" showInStore="0">

<label>Importo minimo carrello per l'invio gratuito</label>

</field>

<field id="special_product_amount" translate="label" type="text" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="0">

<label>Importo minimo prodotto invio entro 24h</label>

</field>

</group>

</section>

</system>

</config>

Page 5: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Backend - config.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">

<default>

<carriers>

<shippingmeetmagento>

<active>0</active>

<sallowspecific>0</sallowspecific>

<model>Meetmagento\Shipping\Model\Carrier\Shipping</model>

<name>Shipping Meet Magento Method</name>

<price>4.99</price>

<title>Shipping Meet Magento</title>

<specificerrmsg>Metodo di spedizione non disponibile.</specificerrmsg>

<attribute_set>0,15</attribute_set>

<free_shipping_amount>50</free_shipping_amount>

<special_product_amount>35</special_product_amount>

</shippingmeetmagento>

</carriers>

</default>

</config>

Page 6: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Modello - Service Contract

<?php

namespace Meetmagento\Shipping\Model\Carrier;

use Magento\Quote\Model\Quote\Address\RateRequest;

use Magento\Catalog\Api\Data\ProductInterface;

use Magento\Quote\Model\Quote\Item;

/**

* Class Shipping

* @package Meetmagento\Shipping\Model\Carrier

*/

class Shippingmeetmagento extends \Magento\Shipping\Model\Carrier\AbstractCarrier implements

\Magento\Shipping\Model\Carrier\CarrierInterface

{

protected $_code = 'shippingmeetmagento';

protected $_isFixed = true;

protected $_rateResultFactory;

protected $_rateMethodFactory;

SERVICE CONTRACT

• Insieme di interfacce PHP definite da

un modulo

• Suddiviso in:

• Data Interface

• Service Interface

Page 7: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Modello - ObjectManager

/**

* Shippingmeetmagento constructor.

* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig

* @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory

* @param \Psr\Log\LoggerInterface $logger

* @param \Magento\Framework\ObjectManagerInterface $objectManager

* @param array $data

*/

public function __construct(

\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,

\Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory,

\Psr\Log\LoggerInterface $logger,

\Magento\Framework\ObjectManagerInterface $objectManager,

array $data = []

)

{

$this->_objectManager = $objectManager;

parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);

}

• Nel costruttore dovrò avere:

• $scopeConfig

• $rateErrorFactory

• $logger

• $data

• Estendo con:

• $objectManager

• Necessario implementare il

metodo pubblico

collectRates(RateRequest

$request)

Page 8: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Modello - ObjectManager

/**

* @param RateRequest $request

* @return bool

*/

public function collectRates(RateRequest $request)

{

if (!$this->getConfigFlag('active')) {

return false;

}

if ($request->getAllItems()) {

.....

}

$shippingPrice = $this->getConfigData(‘price');

$result = $this->_objectManager->create(‘Magento\Shipping\Model\Rate\Result’);

$method = $this->_objectManager->create(‘Magento\Quote\Model\Quote\Address\RateResult\Method’);

$method->setCarrier('shippingmeetmagento');

$method->setCarrierTitle($this->getConfigData('title'));

$method->setMethod('shippingmeetmagento');

$method->setMethodTitle($this->getConfigData('name'));

$method->setPrice($shippingPrice);

$method->setCost($shippingPrice);

$result->append($method);

return $result;

}

• Inizializzazione oggetti tramite

ObjectManager che è a sua volta

istanza della classe

Magento\Framework\ObjectManag

er\ObjectManager

• ->create()

• ->get()

• Il $method corrisponde al nostro

metodo di spedizione

• Il $result è quello che vedremo

apparire per selezionare il metodo

di spedizione

Page 9: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Modello - Factories

/**

* Shippingmeetmagento constructor.

* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig

* @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory

* @param \Psr\Log\LoggerInterface $logger

* @param \Magento\Shipping\Model\Rate\ResultFactory $rateResultFactory

* @param \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory

* @param array $data

*/

public function __construct(

\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,

\Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory,

\Psr\Log\LoggerInterface $logger,

\Magento\Framework\ObjectManagereInterface $objectManager,

\Magento\Shipping\Model\Rate\ResultFactory $rateResultFactory,

\Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory,

array $data = []

)

{

$this->_rateResultFactory = $rateResultFactory;

$this->_rateMethodFactory = $rateMethodFactory;

parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);

}

• Nel costruttore dovrò avere:

• $scopeConfig

• $rateErrorFactory

• $logger

• $data

• Estendo aggiungendo

• $rateResultFactory

• $rateMethodFactory

• Necessario implementare il

metodo pubblico

collectRates(RateRequest

$request)

Page 10: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Modello - Factories

/**

* @param RateRequest $request

* @return bool

*/

public function collectRates(RateRequest $request)

{

if (!$this->getConfigFlag('active')) {

return false;

}

if ($request->getAllItems()) {

.....

}

$shippingPrice = $this->getConfigData(‘price');

$result = this->_objectManager->create('Magento\Shipping\Model\Rate\Result');

$result = $this->_rateResultFactory->create();

$method = this->_objectManager->create('Magento\Quote\Model\Quote\Address\RateResult\Method');

$method = $this->_rateMethodFactory->create();

$method->setCarrier('shippingmeetmagento');

$method->setCarrierTitle($this->getConfigData('title'));

$method->setMethod('shippingmeetmagento');

$method->setMethodTitle($this->getConfigData('name'));

$method->setPrice($shippingPrice);

$method->setCost($shippingPrice);

$result->append($method);

return $result;

}

• Inizializzazione oggetti tramite

classi Factory

• ->create()

• ->get()

• Il $method corrisponde al nostro

metodo di spedizione

• Il $result è quello che vedremo

apparire per selezionare il

metodo di spedizione

Page 11: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Perché?

Oggetti istanziabili

dall’objectManager

SINGLETON

Oggetti NON istanziabili

dall’objectManager

Oggetti con ciclo di

vita temporaneo

Oggetti che hanno

bisogno di input

esterni

Sessione

Magento\Catalog\Model\Product

vendor\Magento\module-shipping\Model\Rate\Result

FACTORIES

• Creano un istanza di

classi che non si

possono iniettare

direttamente

• Dipendono dall’OM

• generation/Magento

var\generation\Magento\Shipping\Model\Rate\ResultFactory

Page 12: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Modello - Metodi

/**

* @param ProductInterface $product

* @return bool

*/

public function isAvailableForProduct(ProductInterface $product)

{

$attributeSets = array_map("intval", explode(",", $this->getConfigData('attribute_set')));

return in_array($product->getAttributeSetId(), $attributeSets) && $this->getConfigFlag('active');

}

/**

* @param RateRequest $request

* @return bool

*/

public function collectRates(RateRequest $request)

{

if (!$this->getConfigFlag('active')) {

return false;

}

$total = 0;

if ($request->getAllItems()) {

foreach ($request->getAllItems() as $item) {

$total += $item->getPrice();

}

}

if($this->getConfigData('free_shipping_amount') < $total){

$shippingPrice = $this->getConfigData(0);

} else {

$shippingPrice = $this->getConfigData('price');

}

....

Page 13: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Risultato - Backend

Page 14: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Risultato - Frontend (Importo < 50)

Page 15: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Risultato - Frontend (Importo > 50)

Page 16: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Plugin - Definizione

• Plugin (o Interception)

• Per osservare metodi senza dover modificare classi originali

• Magento\Catalog\Helper\Product -> initProduct()

• Magento\Catalog\Block\Product\AbstractProduct -> getAddToCartUrl()

• I plugin non possono essere utilizzati per:

• Final Class

• Final Method

• Classi create senza Dependency Injection

Page 17: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Plugin - 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\Helper\Product">

<plugin name="MeetmagentoShippingProductHelper" type="Meetmagento\Shipping\Plugin\Helper\Product" disabled="false" sortOrder="10" />

</type>

<type name="Magento\Catalog\Block\Product\AbstractProduct">

<plugin name="MeetmagentoShippingPlugin1" type="Meetmagento\Shipping\Plugin\Block\Catalog\Product\AbstractProductPlugin1"

disabled="false" sortOrder="100"/>

<plugin name="MeetmagentoShippingPlugin2" type="Meetmagento\Shipping\Plugin\Block\Catalog\Product\AbstractProductPlugin2"

disabled="true" sortOrder="200"/>

</type>

</config>

Page 18: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Plugin - Interception

•INTERCEPTION:

Pattern di sviluppo software che consente di inserire dinamicamente codice senza

cambiare necessariamente il comportamento della classe originale.

Classe 1

Richiama

Classe2::getAddToCartUrl()

Classe 2

Implementa

getAddToCartUrl()

Plugin 1

Before / Around / After

getAddToCartUrl()

Page 19: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Plugin - Listener

1. Before Listener

• Convenzione: before{NomeMetodo} -> beforeGetProductPrice()

• Non ha bisogno di restituire un valore

3. Around Listener

• Convenzione: around{NomeMetodo} -> aroundGetProductPrice()

• Deve restituire un valore

2. After Listener

• Convenzione: after{NomeMetodo} -> afterGetProductPrice()

• Non ha bisogno di restituire un valore

Page 20: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Plugin - Before Listener

• Prima proprietà del metodo deve essere sempre il

$subject (sarà un ListProduct\Interceptor)

• La regola di trasformazione è:

• getProductPrice($product)

• beforeGetProductPrice($subject,$product)

public function beforeGetProductPrice(

$subject,

$product

)

{

var_dump(get_class($subject));

var_dump('Plugin1 - beforeGetProductPrice');

}

Page 21: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Plugin - After Listener

• La prima e unica proprietà è il $subject istanza

dell’oggetto che si sta osservando (del tipo

ListProduct\Interceptor)

• La regola di trasformazione è:

• getProductPrice($product)

• afterGetProductPrice($subject)

public function afterGetProductPrice($subject)

{

var_dump('Plugin1 - afterGetProductPrice');

}

Page 22: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Plugin - Around Listener

• Prima proprietà del metodo deve essere sempre il

$subject (sarà un ListProduct\Interceptor)

• La seconda proprietà è sempre il $proceed di

\Closure

• La regola di trasformazione è:

• getProductPrice($product)

• aroundGetProductPrice($subject)

public function aroundGetProductPrice(

$subject,

\Closure $proceed,

$product

)

{

return $proceed($product);

}

Page 23: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Plugin - Risultato

Page 24: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Frontend - Layout

Container BlocchiLayouts

• Per una pagina generica, componenti:

• Page layout

• Page configuration

• <module_dir>/view/frontend/layo

ut

Page 25: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Frontend - Layout

• Suddivisi in:

• Page - <page>

• Layout - <layout>

• Base layout in:

• <dir_modulo>/view/frontend/layout

/vendor/magento/module-

catalog/view/frontend/layout/catalog_product_view.xml

app/code/Meetmagento/Shipping/view/frontend/layout/catalog_

product_view.xml

<?xml version="1.0"?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">

<body>

<referenceContainer name="product.info.main">

<block class="Meetmagento\Shipping\Block\Product\Shipping" name="shipmeetmagento.div" as="shipmeetmagento"

template=“Meetmagento_Shipping::placeholder.phtml" before=“product.info.price”/>

</referenceContainer>

</body>

</page>

Page 26: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Frontend - Blocco<?php

namespace Meetmagento\Shipping\Block\Product;

use Magento\Framework\Registry;

use Magento\Framework\View\Element\Template;

use Meetmagento\Shipping\Model\Carrier\Shipping as ShippingModel;

class Shipping extends Template

{

/**

* @var Registry

*/

private $registry;

/**

* @var ShippingModel

*/

private $shippingModel;

/**

* @param Template\Context $context

* @param array $data

* @param Registry $registry

* @param ShippingModel $shippingModel

*/

public function __construct(Template\Context $context, array $data = [], Registry $registry, ShippingModel $shippingModel)

{

parent::__construct($context, $data);

$this->_isScopePrivate = true;

$this->registry = $registry;

$this->shippingModel = $shippingModel;

}

/**

* @return string

*/

public function toHtml()

{

/** @var \Magento\Catalog\Api\Data\ProductInterface $product */

$product = $this->registry->registry('current_product');

$condition = $product->getPrice() > $this->shippingModel->getConfigData('special_product_amount');

if (!$this->shippingModel->isAvailableForProduct($product) || !$condition) {

return '';

} else {

$this->setMessage('Spedizione entro 24h');

return parent::toHtml();

}

}

}

Page 27: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Frontend - Layout e Template

<?xml version="1.0"?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">

<body>

<referenceContainer name="product.info.main">

<block class="Meetmagento\Shipping\Block\Product\Shipping" name="shipmeetmagento.div" as="shipmeetmagento" template="Meetmagento_Shipping::placeholder.phtml"

before="product.info.price"/>

</referenceContainer>

</body>

</page>

<div style="

background: greenyellow;

color: black;

width: 190px;

text-align: center;

padding: 3px;

">

<?php echo $this->getMessage(); ?>

</div>

• view/frontend/templates/placeholder.phtml

• view/frontend/layout/catalog_product_view.xml

Page 28: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Layout - Risultato

Page 29: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Grazie per l’attenzione

Page 30: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

Fonti

• Documentazione ufficiale Magento 2

http://devdocs.magento.com

• Alan Storm

http://alanstorm.com/category/magento-2

• Magento 2 Developer’s Guide

Autore: Branko Ajzele Casa Editrice: Packt

• Marc Espinosa

• http://www.meetup.com/Barcelona-Magento-Commerce-

Meetup/members/182506058/

• https://github.com/mespinosaz/magento2-meetup-shipping-module

Page 31: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2

https://yameveo.com

https://twitter.com/yameveo

https://facebook.com/yameveo

Github: https://github.com/Yameveo/meetmagento.git

https://twitter.com/enr79