Magento Tutorial: Wie man Increment Models nutzt, um IDs zu generieren (oder SKUs)

Hast du dich je gefragt, wie Magento die increment_id Werte für Bestellungen, Rechnungen etc. generiert und wie man diesen Mechnismus nutzen oder erweitern kann? Vielleicht hast du die eav_entity_store Tabelle entdeckt, die die jeweils letzte increment id pro Entity-Typ und Store enthält, wobei je Store ggf. ein unterschiedlicher Präfix verwendet wird:

mysql> select * from eav_entity_store;
+-----------------+----------------+----------+------------------+-------------------+
| entity_store_id | entity_type_id | store_id | increment_prefix | increment_last_id |
+-----------------+----------------+----------+------------------+-------------------+
|               1 |              5 |        1 | 1                | 100000090         |
|               2 |              6 |        1 | 1                | 100000050         |
|               3 |              8 |        1 | 1                | 100000027         |
|               4 |              7 |        1 | 1                | 100000005         |
|               5 |              1 |        0 | 0                | 000000011         |
|               6 |              5 |        2 | 2                | 200000001         |
|               7 |              5 |        3 | 3                | 300000002         |
|               8 |              8 |        3 | 3                | 300000001         |
|               9 |              6 |        3 | 3                | 300000001         |
+-----------------+----------------+----------+------------------+-------------------+
9 rows in set (0.00 sec)

In diesem Artikel erkläre ich, wie dieses System für andere Entities genutzt werden kann.

Zunächst mal, die Standard-Methode funktioniert nur mit EAV Entities, nur mit einem Attribut pro Entity und dessen Name muss increment_id sein. Ich erkläre gleich aber noch, wie diese Beschränkungen umgangen werden können.

Standard-Verwendung

Das increment_id Attribut sollte das Backend-Model eav/entity_attribute_backend_increment haben, und die Entity selbst benötigt zusätzliche Konfiguration:

Entity Setup

Beispiel: Setup Script
$installer->installEntities(array(
            'your_entity' => array(
                'entity_model' => 'your/entity_resource',
                'table' => 'your_entity_table',
                'increment_model' => 'eav/entity_increment_numeric',
                'increment_per_store' => 0,
                'increment_pad_length' => 8,
                'increment_pad_char' => '0',
                'attributes' => array(
                    'increment_id', array(
                        'type'      => Varien_Db_Ddl_Table::TYPE_TEXT,
                        'backend'   => 'eav/entity_attribute_backend_increment,
                    ),
                    // ... other attributes
                ),
            ),
        ));

Werfen wir einen Blick auf die relevanten Felder:

  • increment_model: Das Model, das verantwortlich dafür ist, die increment_ids zu generieren. Entweder eav/entity_increment_numeric (Fortlaufende Nummern) , eav/entity_increment_alphanum (Fortlaufender Buchstaben+Zahlencode) oder ein eigenes Model. Mehr zu benutzerdefinierten Increment Models weiter unten.
  • increment_per_store: (Standard: 0) 0 = Die increment_id ist global für diese Entity, 1 = Die increment_id wird je Store inkrementiert. Man kann für jeden Store View ein eigenes Präfix bestimmen (siehe unten).
  • increment_pad_length: (Standard: 8) Die Mindestlänge der ID. Kürzere IDs werden links mit increment_pad_char aufgefüllt (Standard: “0”).
Hinweise:
  1. Für bereits vorhandene Entities kann updateEntityType statt installEntityType genutzt werden.
  2. Ist die increment_id als Feld in der Entity-Tabelle gespeichert, nutze static als Typ.

Präfix je Store

Setzt man im Entity-Setup “increment_per_store” auf “1”, bekommen die increment_ids standardmäßig die store_id als Präfix. Setzt man es auf “0” (global), ist das Präfix “0”. Um andere Präfixe aufszusetzen, nutze das Mage_Eav_Model_Entity_Store Model. Die zugehörige Datenbank-Tabelle eav_entity_store, die ich zu Anfang gezeigt habe, wird automatisch mit einem Eintrag proe Entity und Store View befüllt, wenn “increment_per_store” gesetzt ist, sonst mit einem Eintrag pro Entity, welcher die store_id 0 hat.
Die Tabelle enthält den Präfix genauso wie die letzte increment_id (beides sollte vom Increment Model genutzt werden, um die nächste ID zu bestimmen).

Beispiel: Setzen von last_id und prefix für das Product Model
        $productEntityType = Mage::getModel('eav/entity_type')
            ->loadByCode(Mage_Catalog_Model_Product::ENTITY);
        $entityStoreConfig = Mage::getModel('eav/entity_store')
            ->loadByEntityStore($productEntityType->getId(), 0);
        $entityStoreConfig->setEntityTypeId($productEntityType->getId())
            ->setStoreId(0)
            ->setIncrementPrefix($prefix)
            ->setIncrementLastId($lastId)
            ->save();

In diesem Beispiel wird das globale Präfix (store=0) für die Product Entity auf $prefix gesetzt und die last_id auf $lastId. Üblicherweise würde dieser Code nur einmal durch ein Setup Script aufgerufen werden und einmal pro Store nachdem ein Store angelegt wurde. Beachte, dass die automatisch generierten Einträge erstellt werden, sobald eine neue increment_id für den jeweiligen Store View angefragt wird und noch kein Eintrag existiert. Der Code dazu befindet sich in Mage_Eav_Model_Entity_Type::fetchNewIncrementId():

Core Code:
    public function fetchNewIncrementId($storeId = null)
    {
    ...
        if (!$entityStoreConfig->getId()) {
            $entityStoreConfig
                ->setEntityTypeId($this->getId())
                ->setStoreId($storeId)
                ->setIncrementPrefix($storeId)
                ->save();
        }
    ...
    }

Sonderfall: Beliebiges Attribut

Schauen wir uns das Backend Model an, sehen wir dass es prüft, ob das Objekt neu ist (also noch keine ID hat) und in dem Fall das Erstellen der increment_id an das Entity Resource Model selbst delegiert:

Core code
/**
 * Entity/Attribute/Model - attribute backend default
 *
 * @category   Mage
 * @package    Mage_Eav
 * @author      Magento Core Team <core@magentocommerce.com>
 */
class Mage_Eav_Model_Entity_Attribute_Backend_Increment extends Mage_Eav_Model_Entity_Attribute_Backend_Abstract
{
    /**
     * Set new increment id
     *
     * @param Varien_Object $object
     * @return Mage_Eav_Model_Entity_Attribute_Backend_Increment
     */
    public function beforeSave($object)
    {
        if (!$object->getId()) {
            $this->getAttribute()->getEntity()->setNewIncrementId($object);
        }

        return $this;
    }
}

Wie man sieht, bekommt das Entity Resource Model keine Informationen über das Attribut selbst und tatsächlich, setNewIncrementId ist hart kodiert, das Attribut code>increment_id zu nutzen (getIncrementId() and setIncrementId()):

Core code

    /**
     * Set new increment id to object
     *
     * @param Varien_Object $object
     * @return Mage_Eav_Model_Entity_Abstract
     */
    public function setNewIncrementId(Varien_Object $object)
    {
        if ($object->getIncrementId()) {
            return $this;
        }

        $incrementId = $this->getEntityType()->fetchNewIncrementId($object->getStoreId());

        if ($incrementId !== false) {
            $object->setIncrementId($incrementId);
        }

        return $this;
    }

Es gibt zwei Wege, diese Einschränkung zu überwinden:

  1. setIncrementId() und getIncrementId() in der eigenen Entity implementieren, so dasss sie auf das tatsächliche Attribut zugreifen
  2. Das Backend Model erweitern und beforeSave() überschreiben, um die generierte increment_id anschließend dem eigentlichen Attribut zuzuweisen. assign the generated increment id to the actual attribute afterwards. Eine einfache Version könnte so aussehen:
    class Your_Awesome_Model_Entity_Attribute_Backend_Increment extends
            Mage_Eav_Model_Entity_Attribute_Backend_Increment
    {
        public function beforeSave($object)
            parent::beforeSave($object);
            $object->setData($this->getAttribute()->getName(), $object->getIncrementId());
            return $this;
        }
    }

Sonderfall: Nicht-EAV-Models

Wie du wahrscheinlich weißt, sind Bestellungen, Rechnungen etc. keine EAV Entities 1 aber sie haben dennoch Einträge in der entity_type Tabelle und nutzen increment_ids. Wenn die das können, kannst du es auch, also mal sehen wie es für Bestellungen gemacht wurde:

Der entity type wird wie eine echte EAV Entity registriert:

Core Code: Setup Script
/**
 * Install eav entity types to the eav/entity_type table
 */
$installer->addEntityType('order', array(
    'entity_model'          => 'sales/order',
    'table'                 => 'sales/order',
    'increment_model'       => 'eav/entity_increment_numeric',
    'increment_per_store'   => true
));

Weil es kein EAV-Attribut gibt, das das Backend Model nutzen könnte, muss das setzen der increment_id vom Order Model selbst ausgelöst werden:

Core Code: Order Model
    protected function _beforeSave()
    {
    ...
        if (!$this->getIncrementId()) {
            $incrementId = Mage::getSingleton('eav/config')
                ->getEntityType('order')
                ->fetchNewIncrementId($this->getStoreId());
            $this->setIncrementId($incrementId);
        }
    ...
    }

Und das war’s!

Benutzerdefinierte Increment Models

Du kannst eine beliebige Klasse, die Mage_Eav_Model_Entity_Increment_Interface implementiert, als Increment Model spezifizieren. Vorsicht: Dieses Interface gibt an, nur eine Methode zu benötigen, getNextId(), doch mindestens die folgenden Setter werden ebenfalls aufgerufen:

  • setPrefix
  • setPadLength
  • setPadChar
  • setLastId
  • setEntityTypeId
  • setStoreId

Ja, Magento hat nicht viel Liebe für Interfaces übrig… Also, wenn du dein eigenes Increment Model implementieren willst, solltest du als mindestes von Varien_Object erben, besser von Mage_Eav_Model_Entity_Increment_Abstract, welches bereits die Präfix- und Padding-Logik bereitstellt.

In der Methode getNextId() wirst du dann die nächste increment_id generieren, basierend auf der letzten, die dort via $this->getLastId() verfügbar ist.

Vollständiges Beispiel: AutoSKU

Ein reales Beispiel ist meine AutoSKU Extension, die automatisch Produkt-SKUs zuweist. Um dies zu erreichen, habe ich ein Increment Model für die catalog_product Entity definiert, das Backend Model für SKU geändert, das Attribut auf “nicht benötigt” gesetzt und es nicht editierbar gemacht. Schau es dir im Github Repository an, um die Implementierungs-Details zu sehen:

https://github.com/schmengler/AutoSKU

4 Replies to “Magento Tutorial: Wie man Increment Models nutzt, um IDs zu generieren (oder SKUs)”

  1. Hi There,

    I just tried installing this, but got an error message about the setup – I have placed an issue on GitHub with full details.

    Looks like a nice plugin, if I can get it working.

    Thanks

    James

  2. Hello,

    I am using your AutoSKU successfully work.but i want to modify SKU generate number.
    your generate S100 I want KOM_1000.
    how to do this.

    Thank you

    1. You have to change the format directly in MySQL: Go to the table eav_entity_store and look for the entry with increment_prefix = 'S'. Change it to ‘KOM_’ and also set ‘increment_last_id’ to a higher number if you want to start at 1000.

Comments are closed.