Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2
-
Upload
meet-magento-italy -
Category
Presentations & Public Speaking
-
view
281 -
download
4
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/1.jpg)
![Page 2: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/2.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/3.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/4.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/5.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/6.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/7.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/8.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/9.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/10.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/11.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/12.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/13.jpg)
Risultato - Backend
![Page 14: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/14.jpg)
Risultato - Frontend (Importo < 50)
![Page 15: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/15.jpg)
Risultato - Frontend (Importo > 50)
![Page 16: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/16.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/17.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/18.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/19.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/20.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/21.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/22.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/23.jpg)
Plugin - Risultato
![Page 24: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/24.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/25.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/26.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/27.jpg)
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](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/28.jpg)
Layout - Risultato
![Page 29: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/29.jpg)
Grazie per l’attenzione
![Page 30: Enrico Aillaud - Sviluppo di un metodo di spedizione in Magento 2](https://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/30.jpg)
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://reader031.fdocument.pub/reader031/viewer/2022021922/589be00d1a28aba5108b563d/html5/thumbnails/31.jpg)
https://yameveo.com
https://twitter.com/yameveo
https://facebook.com/yameveo
Github: https://github.com/Yameveo/meetmagento.git
https://twitter.com/enr79