Post on 11-May-2015
description
@akira28
Chi Sono• Co-fondatore di Yameveo
• 9 anni sviluppando in PHP
• Più di 3 anni di esperienza con Magento
• Lead developer di progetti Magento per Privalia, Reckitt Benckiser e Groupalia
• Zend Framework Certified Engineer
@akira28
Yameveo
Fondata nel 2012 a Barcellona, Yameveo è una società giovane, dinamica ed internazionale, specializzata
nell’e-commerce e nello sviluppo di applicazioni web. !
!
www.yameveo.com @Yameveo
@akira28
Yameveo StoreDecine di moduli per Magento e Prestashop
store.yameveo.com
@akira28
Di cosa parleremo
• Intro alle API SOAP di Magento
• Estensione delle API Magento
• Estensione 3rd party
• Creare una nuova chiamata API
• Il sistema Cron di Magento
@akira28
Magento SOAP
“Le API SOAP di Magento offrono la possibilità di gestire i negozi e-commerce, fornendo chiamate per lavorare con
risorse quali clienti, categorie, prodotti e ordini. Consentono inoltre di gestire i carrelli e l'inventario.”
Documentazione Magento
@akira28
Applicazioni• Integrazione con operatori logistici
• Integrazione con Warehouse
• Integrazione con CRM ed ERP
• Integrazione con altri servizi via middleware
• App mobile
• …
@akira28
API MagentoQuando viene effettuata una richiesta HTTP il sistema di
routing standard di Magento invia la richiesta ad una action del controller del modulo Mage_Api
!
Questa action istanzia un oggetto "Server API", lo inizializza con il tipo di API (SOAP, XML-RPC, etc.), ed in seguito
chiama il suo metodo “run”
@akira28
Come iniziare• Assicurati che l’endpoint sia accessibile:
www.example.com/api/v2_soap www.example.com/api/soap
• Definisci Utenti API e le risorse associate: System -> Web Services
• Dai un’occhiata al WSDLwww.example.com/api/v2_soap?wsdl=1 www.example.com/api/soap?wsdl=1
@akira28
Magento API flow
• Crea un Session ID effettuando una richiesta “login” con username e API key
• Salva il Session ID per effettuare altre chiamate
• Effettua le altre chiamate passando il Session ID
• Termina la sessione con endSession
@akira28
Testing API V1// connect to soap server $client = new SoapClient('http://apimagento.dev/api/soap?wsdl=1', array('cache_wsdl' => WSDL_CACHE_NONE, 'trace' => 1)); !// log in $session = $client->login('user', ‘password’); !$info = $client->call($session, 'catalog_product.info', '4'); !var_export($client->__getLastRequest());
http://www.php.net/manual/en/class.soapclient.php
@akira28
Esempio request V1
<?xml version="1.0" encoding="utf-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:Magento" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:call> <sessionId xsi:type="xsd:string">24eafa404acbd904f3c0978669102496</sessionId> <resourcePath xsi:type="xsd:string">catalog_product.info</resourcePath> <args xsi:type="xsd:int">4</args> </ns1:call> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
@akira28
Esempio response V1array(6) { 'product_id' => string(3) "4" 'sku' => string(3) “sku-1“ 'set' => string(2) "41" 'type' => string(12) "configurable" 'categories' => array(1) { [0] => string(1) "4" } 'websites' => array(1) { [0] => string(1) "1" } }
@akira28
Testing API V2// connect to soap server $client = new SoapClient('http://apimagento.dev/api/v2_soap?wsdl=1', array('cache_wsdl' => WSDL_CACHE_NONE, 'trace' => 1)); !// log in $session = $client->login('user', ‘password'); !$complexFilter = array( 'complex_filter' => array( array( 'key' => 'type', 'value' => array('key' => 'eq', 'value' => 'configurable') ) ) ); $list = $client->catalogProductList($session, $complexFilter); !var_export($client->__getLastRequest());
@akira28
Esempio request V2<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:Magento" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:catalogProductList> <sessionId xsi:type="xsd:string">c84d5edf23f22913066f4246d0949908</sessionId> <filters xsi:type="ns1:filters"> <complex_filter SOAP-ENC:arrayType="ns1:complexFilter[1]" xsi:type="ns1:complexFilterArray"> <item xsi:type="ns1:complexFilter"> <key xsi:type="xsd:string">type</key> <value xsi:type="ns1:associativeEntity"> <key xsi:type="xsd:string">eq</key> <value xsi:type="xsd:string">configurable</value> </value> </item> </complex_filter> </filters> <storeView xsi:nil="true" /> </ns1:catalogProductList> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
@akira28
Esempio response V2array(118) { [0] => class stdClass#2 (9) { public $product_id => string(2) "16" public $sku => string(5) "n2610" public $name => string(16) "Nokia 2610 Phone" public $set => string(2) "38" public $type => string(6) "configurable" public $category_ids => array(1) { [0] => string(1) "8" } public $website_ids => array(1) { [0] => string(1) "1" } public $price => double(149.99) public $available_quantity => int(996) } […]
@akira28
abstract class Mage_Api_Model_Server_Handler_Abstract { public function startSession(){[…]} ! public function endSession($sessionId){[…]} ! public function login($username, $apiKey){[…]} ! public function call($sessionId, $apiPath, $args = array()){[…]} public function multiCall($sessionId, array $calls = array(), $options = array()){[…]} public function resources($sessionId){[…]} public function globalFaults($sessionId){[…]} public function resourceFaults($sessionId, $resourceName){[…]} !} !
app/code/core/Mage/Api/Model/Server/Handler/Abstract.php
API SOAP Handler
@akira28
Differenze API V1 e V2
• V2 è adatta ad applicazioni scritte in linguaggi tipizzati come Java o .NET
• Il WSDL V2 è molto più grande
• Nella V2 esiste un metodo per ogni chiamata: V1 - $client->call($sid, ’catalog_product.info’, …);V2 - $client->catalogProductInfo($sid, …);
@akira28
@akira28
Problemi
• Le chiamate native non contengono abbastanza informazioni
• Le estensioni di terze parti quasi mai offrono API
• Non esistono call per alcune risorse
@akira28
Soluzioni
• Estensione delle API native
• Inclusione delle estensioni di terze parti
• Nuove call API
Estensione delle API native
@akira28
Estensione ProductInfo
• Configurazione del modulo
• Codice PHP
• WSDL
@akira28
Estensione ProductInfo - config
[…] <global> <models> […] <catalog> <rewrite> <product_api>Yameveo_Productinfo_Model_Catalog_Product_Api</product_api> <product_api_v2>Yameveo_Productinfo_Model_Catalog_Product_Api_V2</product_api_v2> </rewrite> </catalog> […] !
Yameveo/Productinfo/etc/config.xml
@akira28
class Yameveo_Productinfo_Model_Catalog_Product_Api extends Mage_Catalog_Model_Product_Api { […] public function info($productId, $store = null, $attributes = array(), $identifierType = null) { $product = $this->_getProduct($productId, $store, $identifierType); […] return $this->infoResult($result, $product, $attributes, $store); } […]
Yameveo/Productinfo/Model/Catalog/Product/Api.php
ProductInfo - codice
@akira28
ProductInfo - codice
class Yameveo_Productinfo_Model_Catalog_Product_Api extends Mage_Catalog_Model_Product_Api { […] protected function infoResult($result, $product, $attributes, $store) { […] } elseif ($product->isConfigurable()) { $childProducts = Mage::getModel('catalog/product_type_configurable')->getUsedProducts(null, $product); $skus = array(); foreach ($childProducts as $childProduct) { $skus[$childProduct->getId()][‘sku’] = $childProduct->getSku(); […] } $result['configurable_products_data'] = $skus; […] return $result; } }
Yameveo/Productinfo/Model/Catalog/Product/Api.php
@akira28
Estensione ProductInfo - wsdl[…] <complexType name="catalogProductReturnEntity"> <all> […] <element name="configurable_products_data" type="typens:childrenEntityArray" minOccurs="0"/> […] </all> </complexType> !<complexType name="childrenEntityArray"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:childrenEntity[]"/> </restriction> </complexContent> </complexType> <complexType name="childrenEntity"> <all> <element name="sku" type="xsd:string" minOccurs=“0"/> […] </all> </complexType> […] !
Yameveo/Productinfo/etc/wsdl.xml
Inclusione delle estensioni di terze parti
@akira28
Estensione OrderApi
• Configurazione del modulo
• Codice PHP
• WSDL
@akira28
M2E Pro
@akira28
Estensione OrderApi - config
![…] <models> <yameveo_orderapi> <class>Yameveo_OrderApi_Model</class> </yameveo_orderapi> <sales> <rewrite> <order_api>Yameveo_OrderApi_Model_Order_Api</order_api> <order_api_v2>Yameveo_OrderApi_Model_Order_Api_V2</order_api_v2> </rewrite> </sales> </models> […]
Yameveo/OrderApi/etc/config.xml
@akira28
Estensione M2ePro - codiceclass Yameveo_OrderApi_Model_Order_Api extends Mage_Sales_Model_Order_Api { public function info($orderIncrementId) { $result = parent::info($orderIncrementId); $ebayOrder = Mage::helper('M2ePro/Component_Ebay') ->getCollection('Order') ->addFieldToFilter('magento_order_id', $result['order_id']) ->getFirstItem(); ! if ($ebayOrder->getData('ebay_order_id')) { $result['ebay'] = array(); $result['ebay']['ebay_order_id'] = $ebayOrder->getData('ebay_order_id'); $result['ebay']['selling_manager_record_number'] = $ebayOrder->getData('selling_manager_record_number'); […] foreach ($ebayOrder->getItemsCollection() as $item) { $itemArray = array( […] 'buy_it_now_price' => $item->getData('buy_it_now_price'), […] ); ! $result['ebay']['items'][] = $itemArray; } } return $result; } […]
Yameveo/OrderApi/Model/Order/Api.php
@akira28
Estensione M2ePro - wsdl[…] <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> <complexType name="salesOrderEntity"> <all> <element name="ebay" type="typens:ebayOrder" minOccurs="0" maxOccurs="1"/> </all> </complexType> <complexType name="ebayOrder"> <all> <element name="ebay_order_id" type="xsd:string" minOccurs="0" maxOccurs="1"/> <element name="items" type="typens:ebayOrderItems" minOccurs="0" /> […] </all> </complexType> <complexType name="ebayOrderItems"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:ebayOrderItem[]" /> </restriction> </complexContent> </complexType> <complexType name=“ebayOrderItem"> […] <element name="buy_it_now_price" type="xsd:string" minOccurs="0" maxOccurs=“1"/> […] </complexType> […]
Yameveo/OrderApi/etc/wsdl.xml
Nuova call API
@akira28
Estensione RmaApi
• Configurazione del modulo
• Codice PHP
• WSDL
@akira28
RmaApi - config<config> <modules> <Yameveo_RmaApi> <version>1.0</version> </Yameveo_RmaApi> </modules> <global> <models> <rma> <class>Yameveo_RmaApi_Model</class> </rma> </models> <helpers> <rma> <class>Yameveo_RmaApi_Helper</class> </rma> </helpers> </global> </config>
Yameveo/RmaApi/etc/config.xml
@akira28
RMA API api.xml<config> <api> <resources> <rma translate="title" module="rmaapi"> <model>rma/api</model> <title>Rma Resource</title> <acl>rma</acl> <methods> <info translate="title" module="rmaapi"> <title>Retrieve RMA information</title> <method>info</method> <acl>rma/info</acl> </info> </methods> <faults module="rmaapi"> <invalid_protocol> <code>106</code> <message>This operation available through SOAP v2 only.</message> </invalid_protocol> </faults> </rma> </resources> <resources_alias> <rma>rma</rma> </resources_alias> <v2> <resources_function_prefix> <rma>rma</rma> </resources_function_prefix> </v2> <acl> <resources> <rma translate="title" module="rmaapi"> <info translate="title" module="rmaapi"> <title>Retrieve RMA information</title> </info> </rma> </resources> </acl> </api> </config>
Yameveo/RmaApi/etc/api.xml
@akira28
RmaApi - codiceclass Yameveo_RmaApi_Model_Api extends Mage_Api_Model_Resource_Abstract { /** * Info on RMA * * @param string $incrementId * @return info */ public function info($incrementId) { $rma = Mage::getModel('enterprise_rma/rma') ->getCollection() ->addFieldToFilter('increment_id', $incrementId) ->getFirstItem(); $rmaData = $rma->getData(); foreach ($rma->getItemsForDisplay() as $item) { $rmaData['items'][] = $item->getData(); } $comments = Mage::getResourceModel('enterprise_rma/rma_status_history_collection') ->addFilter('rma_entity_id', $rma->getId()); foreach ($comments as $comment) { $rmaData['comments'][] = $comment->getData(); } $rmaData['shipping_label'] = $rma->getShippingLabel()->getData(); ! return $rmaData; }
Yameveo/RmaApi/Model/Api.php
@akira28
RmaApi - wsdl[…] <message name="rmaInfoRequest"> <part name="sessionId" type="xsd:string"/> <part name="rmaIncrementId" type="xsd:string"/> </message> <message name="rmaInfoResponse"> <part name="result" type="typens:rmaExportEntity"/> </message> [...] <portType name="{{var wsdl.handler}}PortType"> <operation name="rmaInfo"> <documentation>Info on RMA</documentation> <input message="typens:rmaInfoRequest"/> <output message="typens:rmaInfoResponse"/> </operation> </portType> <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> <operation name="rmaInfo"> <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> <input> <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding>
@akira28
RmaApi - wsdl<complexType name="rmaExportEntity"> <all> [...] <element name="customer_custom_email" type="xsd:string" minOccurs="0" maxOccurs="1"/> <element name="items" type="typens:rmaExportEntityItemsArray" minOccurs="1" maxOccurs="1"/> [...] </all> </complexType> <complexType name="rmaExportEntityItemsArray"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:rmaExportEntityItem[]"/> </restriction> </complexContent> </complexType> <complexType name="rmaExportEntityItem"> <all> [...] <element name="product_sku" type="xsd:string" minOccurs="0"/> [...] </all> </complexType>
Yameveo/RmaApi/etc/wsdl.xml
@akira28
@akira28
Cos’altro si può fare con le API
• Esportare ed importare ordini, prodotti, clienti
• Checkout via SOAP per applicazioni esterne
• Creare promozioni
• Gestire il CMS
• ….
• Le possibilità sono infinite!
@akira28
Magento Cron
• Cos’è
• Come funziona
• Come può risultare utile
• Come si crea un task
@akira28
Magento Cron!
• Il meccanismo Cron di Magento viene attivato periodicamente utilizzando un cronjob del sistema
• La chiamata viene avviata nel file di cron.php
• Il codice in cron.php invoca Mage_Cron_Model_Observer → dispatch(), che a sua volta provvederà a:
• eseguire le operazioni pianificate
• generare, se necessario, task da eseguire in futuro
• ripulire la history delle operazioni eseguite
@akira28
Utilizzi del cron• Export automatico
• Report ordini giornaliero
• Aggiornamento statistiche
• Invio mail per cart abbandonati
• …
@akira28
Creare un task cron - config
[…] <crontab> <jobs> <yameveo_export> <schedule> <cron_expr>0 2 * * *</cron_expr> </schedule> <run> <model>yameveo/observer::inventoryExport</model> </run> </yameveo_export> </jobs> </crontab> […]
Yameveo/Export/etc/config.xml
@akira28
Creare un task cron - codiceclass Yameveo_Export_Model_Observer extends Mage_Core_Model_Observer { /** * Cron method to export the complete product inventory to the configured ftp server */ public function inventoryExport() { $products = Mage::getModel(‘catalog/product’)->getCollection(); // build data to export foreach ($products as $product) { […] } $this->sendToFtp($data); } […] }
Yameveo/Export/Model/Observer.php
@akira28
Configurare cron da backend
[…] <settings translate="label" module=“yameveo_export"> […] <fields> <cron_settings translate="label comment" module="yameveo_export"> <label>How often do you want the cron to run?</label> <frontend_type>text</frontend_type> <sort_order>70</sort_order> <comment>Use Crontab Format (Eg. "0 4 * * *" for every day at 4 a.m.)</comment> <show_in_default>1</show_in_default> </cron_settings> </fields> </settings> […]
Yameveo/etc/system.xml
@akira28
Configurare cron da backend
[…] <crontab> <jobs> <yameveo_export> <schedule> <config_path>export_config/settings/cron_settings</config_path> </schedule> <run> <model>yameveo_export/observer::inventoryExport</model> </run> </yameveo_export> </jobs> </crontab> […]
Yameveo/Export/etc/config.xml
Volete vedere altro codice?
@akira28
@akira28
Risorse• www.yameveo.com
• github.com/Yameveo
• twitter.com/Yameveo
• alanstorm.com
• www.magentocommerce.com/api
Domande?
Grazie!www.yameveo.com !
@akira28 @Yameveo !
http://bit.ly/andreadepirro