Come anticipato nell’ultimo articolo sui profili d’importazione ed esportazione avanzati vedremo un’applicazione pratica, un modulo per l’esportazione delle categorie.
Cosa ci serve per esportare i dati delle categorie? Riprendendo i concetti spiegati nello scorso articolo avremo bisogno di un “Adapter” personalizzato che ci servirà a ottenere i dati delle categorie dal database e di un “Parser” personalizzato che prenda i dati caricati dall’Adapter e li traduca in un formato leggibile dal Parser di default di Magento che si occuperà di creare il CSV. Non creeremo un “Mapper” personalizzato, dato che quello già presente in Magento è più che sufficiente per il nostro scopo.
Partiamo dalla struttura base di un modulo per Magento, definiamo il Model aggiungendo le righe necessarie al file config.xml.
[code type=”xml”]
[/code]
Ora creiamo le due nostre classi Adapter e Parser:
- Artera_Exportcategories_Model_Convert_Adapter_Categories che estenderà la classe Mage_Eav_Model_Convert_Adapter_Entity
- Artera_Exportcategories_Model_Convert_Parser_Categories che estenderà la classe Mage_Eav_Model_Convert_Parser_Abstract
Analizziamole singolarmente.
Adapter
Il nostro Adapter personalizzato servirà per un’esportazione, quindi avremo bisogno di implementare la funzione “load()” che si occuperà di estrarre dal database i dati delle categorie.
È da notare che è stata estesa la classe Mage_Eav_Model_Convert_Adapter_Entity al posto di Mage_Dataflow_Model_Convert_Adapter_Abstract, come mai? La risposta è molto semplice, stiamo lavorando con dati EAV di Magento, questa classe estende Mage_Dataflow_Model_Convert_Adapter_Abstract, fornendo una base per lavorare più facilmente con dati di questo tipo. Se un giorno avrete bisogno di un vostro modulo personalizzato che esporterà dei dati che avete creato e non seguiranno il modello EAV di Magento, il vostro Adapter dovrà estendere Mage_Dataflow_Model_Convert_Adapter_Abstract.
Come detto in precedenza la funzione principale di cui avremo bisogno è “load()”, vediamone l’implementazione:
[code type=”php”]
public function load()
{
$attrFilterArray = array();
$attrFilterArray [‘store_id’] = ‘eq’;
//applico eventuali filtri
parent::setFilter($attrFilterArray);
return parent::load();
}
[/code]
Per prima cosa impostiamo i filtri che vorremo applicare ai dati da esportare, creiamo quindi l’array “$attrFilterArray” che avrà questa struttura: ‘identificatore attributo’ = ‘operatore filtro’, nel nostro modulo avremo bisogno solo di un filtro per “store”, con cui utilizzeremo l’operatore di uguaglianza “eq”. Per ogni filtro che vogliamo inserire dovremo quindi specificare quale operatore verrà applicato. Gli operatori applicabili sono quelli che vengono utilizzati per filtrare le “Collection” in Magento.
Dopo aver definito i filtri chiameremo la funzione appartenente al padre della nostra classe “setFilter”, che genera automaticamente il codice per filtrare i dati della collezione.
Infine chiamiamo la funzione “load()” del padre. In essa è già implementato il processo per l’estrazione dei dati, quindi non abbiamo bisogno di scriverlo noi. Attenzione: quest’ultima frase vale solo se stiamo lavorando con dati EAV, mentre se lavoreremo con dati personalizzati dovremo implementarci il processo da soli.
La funzione “load()” resituirà un array contenente tutti gli ID delle categorie.
La nostra classe non si compone solo della funzione “load()”, infatti è stato necessario implementare altre funzioni per specificare che vogliamo estrarre i dati delle categorie.
[code type=”php”]
public function __construct()
{
$this->setVar(‘entity_type’, ‘catalog/category’);
if (!Mage::registry(‘Object_Cache_Category’))
{
$this->setCategory($this->_getCategoryModel());
}
}
[/code]
Nel costruttore indicheremo l’entità che andremo a elaborare, nel nostro caso “catalog/category”
[code type=”php”]
public function setCategory(Mage_Catalog_Model_Category $object)
{
$id = Mage::objects()->save($object);
Mage::register(‘Object_Cache_Category’, $id);
}
protected function _getCategoryModel()
{
if (is_null($this->_categoryModel)) {
$categoryModel = Mage::getModel(‘catalog/category’);
$this->_categoryModel = Mage::objects()->save($categoryModel);
}
return Mage::objects()->load($this->_categoryModel);
}
[/code]
Queste funzioni non sono strettamente necessarie per il funzionamento dell’esportazione, ma migliorano la performance sfruttando la sessione di Magento per evitare di eseguire le stesse query al database più volte.
Parser
Descritto l’Adapter” passiamo al Parser. Come già spiegato nel precedente articolo esso si occupa di prendere i dati estratti dall’Adapter, elaborarli e infine convertirli in un formato che permetta di salvarli in un file CSV.
Il primo passaggio per la creazione della classe è di estendere Mage_Eav_Model_Convert_Parser_Abstract. Anche in questo caso, come per l’Adapter, Magento ci viene in auto fornendoci una classe che implementa Mage_Dataflow_Model_Convert_Parser_Abstract per i dati EAV.
La funzione che si occupa dell’elaborazione dei dati è “unparse”, vediamone l’implementazione
[code type=”php”]
public function unparse()
{
$categoryIds = $this->getData();
foreach($categoryIds as $i => $cat_id)
{
//ciclo tutti gli id di categoria che ho ottenuto
$category = $this->getCategoryModel()
->setStoreId($this->getStoreId())
->load($cat_id);
//escludo Root
if($category->getLevel() == 0)
continue;
$position = Mage::helper(‘catalog’)->__(‘Line %d, Name: %s’, ($i+1), $category->getName());
$this->setPosition($position);
//genero l’array $row che verrà passato al parser IO per il salvataggio su csv
$row = array(
‘store_id’ => $category->getStoreId(),
‘entity_id’ => $category->getId(),
‘parent_id’ => $category->getParentId(),
‘path’ => $category->getPath(),
‘position’ => $category->getPosition(),
‘include_in_menu’ => $category->getIncludeInMenu(),
‘name’ => $category->getName(),
‘url_key’ => $category->getUrlKey(),
‘is_active’ => $category->getIsActive(),
‘display_menu’ => $category->getDisplayMode(),
‘description’ => $category->getDescription(),
‘meta_keywords’ => $category->getMetaKeywords(),
‘meta_description’ => $category->getMetaDescription(),
‘is_anchor’ => $category->getIsAnchor()
);
//landing page
$category_display = $category->getDisplayMode();
if($category_display == self::DISPLAY_BLOCK || $category_display == self::DISPLAY_BOTH)
{
$landing_id = $category->getLandingPage();
$row[‘landing_page’] = Mage::getModel(‘cms/block’)->load($landing_id)->getIdentifier();
}
//images
if($image = $category->getImage())
$row[‘image’] = $image;
if($thumbnail = $category->getThumbnail())
$row[‘thumbnail’] = $thumbnail;
//salvo la righa da passare al parser IO
$batchExport = $this->getBatchExportModel()
->setId(null)
->setBatchId($this->getBatchModel()->getId())
->setBatchData($row)
->setStatus(1)
->save();
}
return $this;
}
[/code]
I passaggi che esegue questa funzione sono:
- Recupera gli ID delle categorie che sono stati estratti dall’Adapter recuperandoli dalla sessione, dove erano stati salvati in attesa che il Parser inizi la sua esecuzione.
[code type=”php”]
$categoryIds = $this->getData();
[/code] - Esclude dalla esportazione la categoria “Root”.
[code type=”php”]
if($category->getLevel() == 0)
continue;
[/code] - Estrae i dati di ogni categoria e li converte in array, tipologia di dato che può essere salvata in un file CSV.
[code type=”php”]
$row = array(
‘store_id’ => $category->getStoreId(),
‘entity_id’ => $category->getId(),
‘parent_id’ => $category->getParentId(),
‘path’ => $category->getPath(),
‘position’ => $category->getPosition(),
‘include_in_menu’ => $category->getIncludeInMenu(),
‘name’ => $category->getName(),
‘url_key’ => $category->getUrlKey(),
‘is_active’ => $category->getIsActive(),
‘display_menu’ => $category->getDisplayMode(),
‘description’ => $category->getDescription(),
‘meta_keywords’ => $category->getMetaKeywords(),
‘meta_description’ => $category->getMetaDescription(),
‘is_anchor’ => $category->getIsAnchor()
);
[/code]
In questa fase è importante stare attenti ad alcuni campi particolari, dove i valori ottenuti dal Model non sono quelli che magari vogliamo avere sul file d’esportazione. Ognuno di questi casi deve essere trattato singolarmente, come vedremo in seguito. - Salviamo l’array nel “Batch” che il “Parser IO” leggerà per compilare il file CSV.
[code type=”php”]
$batchExport = $this->getBatchExportModel()
->setId(null)
->setBatchId($this->getBatchModel()->getId())
->setBatchData($row)
->setStatus(1)
->save();
[/code]
“Batch” non è altro che una tabella del database che viene compilata con tutte le righe interessate dall’esportazione o l’importazione, in parole povere è una tabella ponte che verrà poi utilizzata dalle prossime “action”, per recuperare i dati. Questa tabella viene svuotata ad operazione terminata.
Per quanto riguarda alcuni campi particolari, nel modulo ho gestito il campo “landing_page”, cioè il blocco statico che deve essere visualizzato nella pagina della categoria nel caso che sia impostata la visualizzazione della stessa in:“Solo blocco statico” o “Blocco statico e prodotti”.
[code type=”php”]
const DISPLAY_BLOCK = ‘PAGE’;
const DISPLAY_BOTH = ‘PRODUCTS_AND_PAGE’;
…
//landing page
$category_display = $category->getDisplayMode();
if($category_display == self::DISPLAY_BLOCK || $category_display == self::DISPLAY_BOTH)
{
$landing_id = $category->getLandingPage();
$row[‘landing_page’] = Mage::getModel(‘cms/block’)->load($landing_id)->getIdentifier();
}
[/code]
Nel Model della categoria la “landing_page” è salvata come l’identificatore numerico del blocco statico. Preferiremmo invece avere il codice letterale del blocco statico che risulta più consistente come dato, per esempio vogliamo in un futuro importare l’albero delle categorie su un’altra installazione di Magento, dove i blocchi statici hanno un ordine di creazione diverso da dove abbiamo esportato le categorie. In un caso simile gli identificatori numerici saranno sicuramente diversi e risulterebbe un’importazione errata delle impostazione delle categorie. Utilizzando l’identificatore letterale, nel caso che siano stati “chiamati” in modo diverso, basterà modificare il dato da backend, invece che intervenire direttamente nel database.
L’implementazione della logica è molto semplice, viene controllata la modalità di visualizzazione della categoria, se è “Solo blocco statico” o “Blocco statico e prodotti” viene estratto l’ID del blocco statico, caricato il Model dello stesso e estratto l’identificatore letterale.
Ho voluto inserire un controllo ulteriore sulle immagini associate alle categorie, dato che questi campi non vengono sempre valorizzati. La funzione controlla che per ogni riga esistano questi dati e in caso affermativo li salva:
[code type=”php”]
//images
if($image = $category->getImage())
$row[‘image’] = $image;
if($thumbnail = $category->getThumbnail())
$row[‘thumbnail’] = $thumbnail;
[/code]
Con questo abbiamo terminato l’implementazione del modulo, vediamo ora le azioni XML per il profilo d’esportazione che utilizzerà le classi appena create.
Azioni XML
Andiamo in Sistema > Importa/Esporta > Dataflow – Profili Avanzati. Clicchiamo su “Aggiungi Nuovo Profilo” e nell’area di testo scriviamo queste azioni:
Estrazione degli ID di categoria
[code type=”markup”]
[/code]
Richiamiamo la funzione “load” dell’Adapter del nostro modulo che estrarrà gli id delle categorie, filtrati per store.
Elaborazione dei dati delle categorie
[code type=”markup”]
[/code]
Richiamiamo la funzione “unparse” del Parser del nostro modulo. Essa utilizzando gli id ottenuti tramite l’Adapter elaborerà i dati delle categorie e li salverà nel Batch dedicato a questa esportazione.
Mappatura dell’intestazione del file CSV
[code type=”markup”]
[/code]
Anche se non abbiamo la necessita di mappare in modo particolare i nomi dei campi degli attributi della categoria, l’azione che richiama il Mapper deve comunque essere definita, dato che genera la prima riga, quella che contiene i nomi dei campi, del file CSV.
Conversione dei dati in formato CSV
[code type=”markup”]
true
[/code]
Utilizzando questo Parser standard di Magento i dati salvati nel Batch verranno convertiti nel formato più adatto per la creazione del file CSV.
Salvataggio file d’esportazione
[code type=”markup”]
file
var/export
[/code]
Viene creato e salvato il file CSV contenente i dati delle categorie da esportare.
Il modulo per l’esportazione dell’albero delle categorie potete trovarlo qui.