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:
- Für bereits vorhandene Entities kann
updateEntityType
stattinstallEntityType
genutzt werden. - Ist die
increment_id
als Feld in der Entity-Tabelle gespeichert, nutzestatic
als Typ.
Präfix je Store
Setzt man im Entity-Setup “increment_per_store” auf “1”, bekommen die increment_id
s 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:
setIncrementId()
undgetIncrementId()
in der eigenen Entity implementieren, so dasss sie auf das tatsächliche Attribut zugreifen- Das Backend Model erweitern und
beforeSave()
überschreiben, um die generierteincrement_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_id
s. 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)”
Comments are closed.
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
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
You have to change the format directly in MySQL: Go to the table
eav_entity_store
and look for the entry withincrement_prefix = 'S'
. Change it to ‘KOM_’ and also set ‘increment_last_id’ to a higher number if you want to start at 1000.