Condividi!

Magento è una piattaforma, o meglio un vero e proprio framework, CONFIGURATION BASED, basato, cioè, sulla sua configurazione.

E’ bene fissare un concetto sin dall’inizio: in Magento, la parola CONFIGURAZIONE equivale ad un vero e proprio “ecosistema”, e non ha nulla a che fare col concetto classico di configurazione di una applicazione php, in cui molto spesso il discorso si riduce ad un unico, piccolo file, che gestisce, al massimo, i parametri di connessione al database e qualche variabile globale.

In Magento, la configurazione è una delle colonne portanti dell’intero sistema. Può contare sull’impiego di un arsenale di classi dedicate, contenenti metodi fondamentali per la vita dell’intero sistema, utilizzati dall’inizio alla fine del processo request-response, tra cui:

  • Mage_Core_Model_Config_Base (estende la classe Varien_Simplexml_Config)
  • Mage_Core_Model_Config (estende la classe Mage_Core_Model_Config_Base)
  • Mage_Core_Model_Config_Data (estende la classe Mage_Core_Model_Abstract)
  • Mage_Core_Model_Config_Element (estende la classe Varien_Simplexml_Element che estende SimpleXMLElement)
  • Mage_Core_Model_Config_Options (estende la classe Varien_Object)
  • Mage_Core_Model_Config_System (estende la classe Mage_Core_Model_Config_Base)

Prima di entrare nel dettaglio, è bene dare un occhiata ad una piccola lista di concetti legati alla singola classe mage_core_model_config, giusto per capire sin da subito l’importanza che ricopre all’interno di Magento:

  • E’ composta da circa 50 metodi pubblici20 metodi protetti e circa 20 proprietà.
  • Viene istanziata in prossimità dell’inizializzazione dell’applicazione
  • Si occupa di:
    • Caricare i file di configurazione xml di base app/ etc/local.xml e app/ etc/config.xml
    • Caricare tutti i file di configurazione dei moduli attivi
    • Caricare i dati di connessione al database
    • Collaborare attivamente, attraverso un enorme “lavoro sporco”, con i factory methods al fine di istanziare correttamente Models, Blocks ed Helpers

Vediamo, dunque, da dove inizia il processo di creazione dell’oggetto correlato.

Istanziamento nella classe Mage

L’istanziamento avviene all’interno del metodo run() della classe Mage, attraverso il metodo _setConfigModel() della stessa classe Mage

    public static function run($code = '', $type = 'store', $options = array())
    {
        try {
           ...
            self::$_app    = new Mage_Core_Model_App();
           ...
            self::$_events = new Varien_Event_Collection();
            self::_setIsInstalled($options);
            self::_setConfigModel($options);
            self::$_app->run(array(
                'scope_code' => $code,
                'scope_type' => $type,
                'options'    => $options,
            ));
           ...
        }

Il metodo _setConfigModel(), dopo aver controllato che non ci siano modelli di configurazione alternativi, istanzia un nuovo oggetto della classe Mage_Core_Model_Config, memorizzandolo all’interno della variabile protetta $_config della classe Mage.
In questo modo, l’oggetto sarà accessibile staticamente, ovunque nella piattaforma, attraverso la semplice chiamata al metodo statico Mage::getConfig(), che consente di reperire la proprietà, altrimenti protetta, _config.
E’ da qui, dunque, che nasce l’istanza della classe Mage_Core_Model_Config, consegnandoci l’oggetto che ci accompagnerà lungo tutto l’arco di vita dell’applicazione.

protected static function _setConfigModel($options = array())
    {
        if (isset($options['config_model']) && class_exists($options['config_model'])) {
            ...
        } else {
            $alternativeConfigModel = null;
        }

        if (!is_null($alternativeConfigModel) && ($alternativeConfigModel instanceof Mage_Core_Model_Config)) {
            self::$_config = $alternativeConfigModel;
        } else {
            self::$_config = new Mage_Core_Model_Config($options);
        }
    }

Caricamento delle configurazioni

NOTA: La classe Mage_Core_Model_Config estende la classe Mage_Core_Model_Config_Base, la quale a sua volta estende la classe Varien_Simplexml_Config. Quest’ultima, insieme ad altre classi che estendono la classe SimpleXML (nativa PHP), mettono a disposizione una serie di metodi che permettono di manipolare file XML e leggerne/scriverne agevolmente i contenuti. Dunque, negli script legati alla gestione delle configurazioni in Magento, si noterà un largo uso di metodi, appunto, legati strettamente alla manipolazione di file XML. Qualora non si sia particolarmente esperti in tali pratiche, sarà sufficiente consultare la documentazione ufficiale di PHP per apprenderne le metodiche principali.

All’interno della classe Mage_Core_Model_Config sono tre i metodi utilizzati per caricare e gestire le configurazioni:

  • metodo loadBase(): si occupa di caricare la configurazione di base all’interno dei file app/ etc/local.xml e app/ etc/config.xml
  • metodo loadModules(): si occupa di caricare tutte le configurazioni dei moduli attivi attraverso i singoli file app/code/<<codepool>>/<<namespace>>/<<modulename>>/ etc/config.xml
  • metodo loadDb(): si occupa di caricare le configurazioni memorizzate all’interno del database, nella tabella core_config_data

Analizziamo, uno alla volta, i metodi sopra elencati.

Analisi del metodo loadBase()

Seguendo il flusso di inizializzazione dell’applicazione, il metodo loadBase() viene richiamato attraverso i seguenti steps:

  1. La classe Mage_Core_Model_App esegue il metodo run()
  2. Il metodo run() richiama il metodo baseInit()
  3. Il metodo baseInit() richiama il metodo _initBaseConfig()
  4. Il metodo _initBaseConfig() richiama il metodo loadBase() dell’istanza dell’oggetto CONFIG

A questo punto, siamo all’interno del metodo loadBase().

public function loadBase()
    {
        $etcDir = $this->getOptions()->getEtcDir();
        $files = glob($etcDir.DS.'*.xml');
        $this->loadFile(current($files));
        while ($file = next($files)) {
            $merge = clone $this->_prototype;
            $merge->loadFile($file);
            $this->extend($merge);
        }
        if (in_array($etcDir.DS.'local.xml', $files)) {
            $this->_isLocalConfigLoaded = true;
        }
        return $this;
    }

Ecco la “traduzione testuale” del codice sopra riportato.

  1. Viene recuperato il percorso verso la directory “etc” che contiene i file local.xml e config.xml. Il path è memorizzato all’interno dell’array _data nell’oggetto Mage_Core_Model_Config_Options ( richiamato col metodo getOptions() ).
  2. Viene creato un array $files che conterrà i percorsi dei file. La funzione glob() qui usata, infatti, cicla la directory $etcDir alla ricerca di qualsiasi file abbia un estensione “.xml”, escludendo tutto il resto.
    Normalmente, dunque, verranno recuperati i paths dei file local.xml e config.xml
  3. A questo punto, attraverso il metodo loadFile(), inizia la fase di caricamento dei file, partendo dal primo all’interno dell’array.
    Il metodo loadFile() è il cuore di questo processo, ed il meccanismo alla sua base è di fondamentale importanza per comprendere in che modo, in linea generale, Magento “prende” un file xml qualsiasi e lo trasforma in un oggetto facilmente gestibile in termini di lettura e scrittura. Si consiglia,  a riguardo, di leggere l’apposita nota a fondo pagina sui metodi loadFile() e loadString() della classe Varien_SimpleXML_Config.
    ATTENZIONE: 
    è bene sapere sin da subito che il file config.xml appena caricato e trasformato in un oggetto di tipo Mage_Core_Model_Config_Element viene “salvato” nella proprietà interna _xml.
  4. All’interno del ciclo while avviene l’importantissima operazione di merging, cioè di unione dei due file config.xml e local.xml affinchè venga restituito un unico file contenente un’unica configurazione! In sostanza, ecco cosa avviene:
    1. Viene creato uno scheletro sul quale poter memorizzare temporaneamente il secondo file di configurazione, clonando l’oggetto Mage_Core_Model_Config_Base, referenziato nella proprietà _prototype, e salvando tale scheletro nella variabile $merge;
    2. Si effettua il caricamento temporaneo del nuovo file di configurazione all’interno della variabile $merge, nella proprietà interna _xml
    3. Il metodo extend(), a questo punto, provvede ad unire ed integrare le due configurazioni, estendendo il contenuto della proprietà _xml dei singoli oggetti, cioè quello temporaneo e quello già esistente.
  5. A questo punto, se il file local.xml era presente nella cartella etc (come accade dopo l’installazione), viene settata su true una proprietà flag che consentirà a Magento di sapere che non c’è bisogno di far partire il processo di installazione. Il file local.xml, infatti, viene generato proprio all’installazione di Magento.

Bene, cosa accade ora?!
Il metodo loadBase(), molto semplicemente, restituisce la sua parte di lavoro all’oggetto Mage_Core_Model_App, memorizzando il tutto nella proprietà _xml della proprietà _config.

L’immagine, che mostra lo stato del sistema dopo che il metodo baseInit() ( e quindi il metodo loadBase ) è già stato eseguito, chiarisce molto meglio il concetto:

 

Risultato finale del metodo loadBase()

Risultato finale del metodo loadBase()

Nota: I metodi loadFile() e loadString()

/**
     * Imports XML file
     *
     * @param string $filePath
     * @return boolean
     */
    public function loadFile($filePath)
    {
        if (!is_readable($filePath)) {
            //throw new Exception('Can not read xml file '.$filePath);
            return false;
        }

        $fileData = file_get_contents($filePath);
        $fileData = $this->processFileData($fileData);
        return $this->loadString($fileData, $this->_elementClass);
    }

Il metodo loadFile(), in questo caso, si occupa semplicemente di processare il file situato al path passatogli come argomento e di memorizzarne il contenuto sotto forma di stringa all’interno della variabile $fileData. Immaginate dunque il contenuto del file local.xml o config.xml trasformato in stringa e stanziato nella variabile $fileData.
Ora, questo metodo utilizzato singolarmente non porta ad alcun risultato apprezzabile. Ciò che si desidera è sapere come e dove il file di configurazione viene processato, memorizzato e reso successivamente accessibile sotto forma di oggetto.
A questo scopo, viene richiamato il metodo loadString().

    /**
     * Imports XML string
     *
     * @param  string $string
     * @return boolean
     */
    public function loadString($string)
    {
        if (is_string($string)) {
            $xml = simplexml_load_string($string, $this->_elementClass);

            if ($xml instanceof Varien_Simplexml_Element) {
                $this->_xml = $xml;
                return true;
            }
        } else {
            Mage::logException(new Exception('"$string" parameter for simplexml_load_string is not a string'));
        }
        return false;
    }

Questo metodo si occupa di processare la stringa passatagli come argomento trasformandola, appunto, DA STRINGA AD OGGETTO di tipo Varien_Simplexml_Element il tutto attraverso la funzione simple_xml_string.

Successivamente, questo nuovo oggetto che contiene la configurazione corrente, viene memorizzato nella proprietà interna _xml dell’oggetto corrente.

L’immagine in basso mostra esattamente come il file config.xml e tutti i suoi tags vengano trasformati in singoli oggetti Mage_Core_Model_Config_Element e, qualora un tag contenga effettivamente del testo, questo viene restituito sottoforma di proprietà di tipo stringa.

Caricamento file di configurazione attraverso il metodo loadString della classe Varien_SimpleXML_Config
Caricamento file di configurazione attraverso il metodo loadString della classe Varien_SimpleXML_Config