Magento-Models mit Mage::getModel() laden

Welche Models werden mit Mage::getModel() geladen? (c) batintherain@flickr.comModels sind das um und auf jedes Magento-Shops. Mit ihnen werden Daten geladen und gespeichert, zudem enthalten sie die Geschäftslogik des Shops. Daher muss jeder Entwickler zu Beginn lernen, wie er Models lädt und wo er die entsprechenden Klassen findet.

Magento verwendet für den Aufruf von Models eine eigene Methode. Wenn man den Quelltext durchforstet, stößt man ständig auf Code wie den folgenden:

$product = Mage::getModel('catalog/product');

Der erste Gedanke: was soll das?

[toc levels=3 title=“Inhalt“]

Der Sinn hinter Mage::getModel()

In Magento werden Model- und Block-Klassen nicht direkt geladen, wie man das von PHP kennt:

$product = new Mage_Catalog_Model_Product();

Der Grund ist, dass man die Möglichkeit haben soll, bestehende Klassen zu erweitern. Angenommen, ich muss in einem Shop Produkten eine neue Methode beibringen, dann erstelle ich eine eigene Klasse:

class Emzee_Catalog_Model_Product extends Mage_Catalog_Model_Product
{
    // neue Funktion
}

Jetzt müsste ich aber überall im Code den Aufruf

$product = new Mage_Catalog_Model_Product();

durch

$product = new Emzee_Catalog_Model_Product();

ersetzen, um die neue Methode nutzen zu können. Das schadet der Updatefähigkeit des Systems, weswegen man bei Magento Inc. (damals noch Varien) eine Alternative gesucht hat. Herausgekommen ist die Methode Mage::getModel(), der man ein bestimmtes Argument übergibt und die sich im Hintergrund um alles Weitere kümmert.

Wie Mage::getModel() funktioniert

Noch einmal zur Erinnerung, wie unser Beispiel-Aufruf aussieht:

$product = Mage::getModel('catalog/product');

Der Methode wird ‚catalog/product‚ übergeben. Magento-intern wird dieser String, der für Model- und Block-Klassen verwendet, als Klassen-Id (classId) bezeichnet. Sieht man sich verschiedene Klassen-Ids an, fällt einem auf:

  • Klassen-Ids bestehen aus mehreren Wörtern.
  • Es kommt ein Slash (bzw. Schrägstrich, „/“) in der Klassen-Id vor.
  • Manchmal sind Wörter durch Unterstriche („_“) unterteilt. Bei Magento-Core-Code kommen Unterstriche erst nach dem Slash vor, bei manchen Entwickler-Extensions aber auch schon vor dem Slash.

Einige Beispiele für solche Klassen-Ids sind catalog/product, cataloginventory/stock_item oder sales/billing_agreement.

Der Schrägstrich unterteilt die Klassen-Id in zwei Teile:

  • Der Teil vor dem Schrägstrich wird als Gruppe (group) bezeichnet.
  • Der Teil nach dem Schrägstrich ist die Klasse (class) – ja, das ist ziemlich zweideutig.

Die Methode nutzt die Information von Gruppe und Klasse, um einen vollständigen Klassennamen zusammenzusetzen und die PHP-Klasse zu laden.

Mage::getModel() findet die PHP-Klassen über so genannte Klassen-Ids. Die Klassen-Id setzt sich aus Gruppe (vor dem Schrägstrich) und Klasse (nach dem Schrägstrich) zusammen.

Den Klassennamen aus Gruppe und Klasse herauslesen

Um auf den kompletten Klassennamen zu kommen, muss man die Gruppe und die Klasse analysieren und die Ergebnisse zusammensetzen.

Gruppe

Die Gruppe heißt in Magento also zum Beispiel „catalog“, „cataloginventory“ oder „sales“. Sie ist dazu da, das Problem Mage_Catalog_Model_Product vs. Emzee_Catalog_Model_Product zu umgehen – der erste Teil des Klassennamens wird durch die Gruppe abstrahiert.

Die Sache läuft wie folgt: jedes Modul bzw. jede Extension kann in seiner Konfigurationsdatei (etc/config.xml des Moduls) Gruppen definieren und festlegen, wofür diese Gruppe steht. Sehen wir uns das am Beispiel von Mage::getModel(‚catalog/product‘) an.

Magento Inc. hat die Gruppennamen so gewählt, dass man sie leicht auf Module zurückführen kann. Heißt die Gruppe „catalog“, so wurde sie im Modul Mage_Catalog definiert, die Gruppe „sales“ wurde in Mage_Sales definiert und so weiter. In der Konfigurationsdatei von Mage_Catalog (app/code/core/Mage/Catalog/etc/config.xml) wird neben vielen anderen Dingen Folgendes definiert:

<?xml version="1.0"?>
<config>
    <!-- ... viele XML-Tags ... -->
    <global>
        <models>
            <catalog>
                <class>Mage_Catalog_Model</class>
                <resourceModel>catalog_resource_eav_mysql4</resourceModel>
            </catalog>
            <!-- ... viele XML-Tags ... -->
        </models>
        <!-- ... viele XML-Tags ... -->
    </global>
    <!-- ... viele XML-Tags ... -->
</config>

Zwei Tags sind für uns wichtig, um Mage::getModel() zu verstehen.

  1. <catalog>: dieser Tag unter <models> sagt uns: definiere etwas für eine Gruppe namens „catalog“.
  2. <class>: dieser Tag unterhalb von <catalog> sagt uns: die Gruppe „catalog“ steht für Mage_Catalog_Model.

Wann immer du die Gruppe „catalog“ siehst, denke dir stattdessen Mage_Catalog_Model. Der Clou bei der Sache: wenn man eine eigene Extension schreibt, kann man in config.xml Bezug auf diese Gruppe nehmen und Magento anweisen, für bestimmte Klassen Mage_Catalog_Model zu ignorieren und stattdessen woanders nachzusehen. Darauf wollen wir momentan aber nicht näher eingehen.

Die Gruppe wird in den XML-Konfigurationsdateien der Module/Extensions in der Node <config><global><models><[gruppenname]><class> definiert und steht z.B. für Mage_Catalog_Model. Dabei handelt es sich um den ersten Teil des vollständigen Klassennamens.

Klasse

Nachdem wir die „Gruppe“ kennengelernt haben, fehlt uns noch die Klasse. Die Gruppe hat den ersten Teil des vollständigen Klassennamens definiert und uns somit verraten, in welchem Model-Verzeichnis wir nach der Klassendatei suchen werden.

Bei der Klasse haben wir es nun einfacher. Wir ersetzen den ersten Buchstaben jedes Wortes durch einen Großbuchstaben.

  • product wird zu Product.
  • stock_item wird zu Stock_Item.
  • billing_agreement wird zu Billing_Agreement.

Bei der Klasse wird der erste Buchstabe jedes Wortes durch einen Großbuchstaben ersetzt. Die Klasse ergibt den zweiten Teil des Klassennamens.

Gruppe und Klasse zusammenführen

Für den vollständigen Klassennamen können wir nun das Ergebnis unserer Gruppen-Recherche mit dem Ergebnis der Klasse zusammenführen, indem wir die Teile mit einem Unterstrich verbinden:

  • catalog/product
    catalog = Mage_Catalog_Model
    product = Product
    catalog/product = Mage_Catalog_Model_Product
  • cataloginventory/stock_item
    cataloginventory = Mage_CatalogInventory_Model
    stock_item = Stock_Item
    cataloginventory/stock_item = Mage_CatalogInventory_Model_Stock_Item
  • sales/billing_agreement
    sales = Mage_Sales_Model
    billing_agreement = Billing_Agreement
    sales/billing_agreement = Mage_Sales_Model_Billing_Agreement

Verbinde das Ergebnis von Gruppe und Klasse mit einem Unterstrich, dann hast du den vollständigen Klassennamen gefunden.

Die PHP-Klasse finden

Möchte man sich die PHP-Klasse genauer ansehen, so muss man sie in der Dateistruktur erst einmal finden. Das ist zum Glück nicht mehr sehr schwer, sobald man den vollständigen Klassennamen hat.

Jedes Modul bzw. jede Extension ist in einem der Code-Pools core, community oder local abgelegt. Definiert wird der Code-Pool in den Konfigurationsdateien unter app/etc/modules, doch wir wollen uns heute mit einer Faustregel begnügen:

  • Magento-Standardmodule sind in app/code/core zu finden.
  • Extensions von Magento Connect sind in app/code/community zu finden.
  • Nicht über Magento Connect veröffentlichte Extensions sind unter app/code/local/ zu finden.

Jetzt müssen wir noch die Unterstriche durch Schrägstriche (Verzeichnisstrenner) ersetzen und .php anhängen, dann finden wir die jeweilige PHP-Klasse im Dateisystem:

  • catalog/product
    app/code/core/Mage/Catalog/Model/Product.php
  • cataloginventory/stock_item
    app/code/core/Mage/CatalogInventory/Model/Stock/Item.php
  • sales/billing_agreement
    app/code/core/Mage/Sales/Model/Billing/Agreement.php

Fragen?

Gibt es Model-Klassen, die ihr trotzdem nicht finden könnt? Gibt es offene Fragen zu dem Thema? Bitte in den Kommentaren melden!