![]() |
|
Snippets |
|
I needed to have many subclasses inherited from a main class.
To do that with propel, you need to have all your classes in one big table. I wanted to have separate tables.
Then I discovered the propel behaviors and it does that very well !
Let's see an example with a master class "element" and a subclass "subElement" :
The tables of the subclasses just need to have an "element_id" foreign key column, to be linked with the "element" master class table :
# schema.yml example propel: # master class element: _attributes: { phpName: Element } id: name: varchar(255) content: longvarchar created_at: # subclass with only the subclass properties and element_id foreign key column sub_element: _attributes: { phpName: SubElement } element_id: author: varchar(255)
Activate the behaviors in "project/config/propel.ini" (before building the model!):
propel.builder.AddBehaviors = true
Don't forget to rebuild the model, anytime you modify it :
>symfony propel-build-model
Create your behavior in "project/config/config.php" :
// get propel behavior lib require_once($sf_symfony_lib_dir.'/addon/propel/sfPropelBehavior.class.php'); // declare all the methods from of the master class "element", that you'll need in the subclasses sfPropelBehavior::registerMethods('ElementBehavior', array( array('ElementBehavior', 'setName'), array('ElementBehavior', 'getName'), array('ElementBehavior', 'setContent'), array('ElementBehavior', 'getContent'), array('ElementBehavior', 'setCreated'), array('ElementBehavior', 'getCreatedAt'), ) ); // Modify save() and delete() master class methods // SubElement->save() need to run Element->save()..., and so for SubElement->delete() sfPropelBehavior::registerHooks('ElementBehavior', array( ':save:pre' => array('ElementBehavior', 'preSave'), ':delete:pre' => array('ElementBehavior', 'preDelete'), ) );
Declare all these behavior methods in the master class model (here in "project/lib/model/Element.php") :
// declare this class after the element class class ElementBehavior { /* Properties Setters */ public function setName(BaseObject $object, $value) { if (!$object->getElement()) $object->setElement(new Element()); $object->getElement()->setName($value); } public function setContent(BaseObject $object, $value) { if (!$object->getElement()) $object->setElement(new Element()); $object->getElement()->setContent(value); } public function setCreatedAt(BaseObject $object, $value) { if (!$object->getElement()) $object->setElement(new Element()); $object->getElement()->setCreatedAt($value); } /* Properties Getters */ public function getId(BaseObject $object) { if (!$object->getElement()) $object->setElement(new Element()); return $object->getElement()->getId(); } public function getName(BaseObject $object) { if (!$object->getElement()) $object->setElement(new Element()); return $object->getElement()->getName(); } public function getContent(BaseObject $object) { if (!$object->getElement()) $object->setElement(new Element()); return $object->getElement()->getContent(); } public function getCreatedAt(BaseObject $object) { if (!$object->getElement()) $object->setElement(new Element()); return $object->getElement()->getCreatedAt(); } /* Element save method called just before SubElement save */ public function preSave(BaseObject $object) { // if element not null... if ($object->getElement()) { // save element in his table $object->getElement()->save(); // if new element, capture id if ($object->isNew()) $object->setElementId($object->getElement()->getId()); } } /* Element delete method called just before SubElement delete */ public function preDelete(BaseObject $object) { // if element not null and not new... if ($object->getElement() && !$object->getElement()->isNew()) { // delete element in his table $object->getElement()->delete(); } } }
add the "ElemenBehavior" to all your subclasses (here in" project/lib/model/SubElement.php") :
sfPropelBehavior::add('SubElement', array('ElementBehavior'));
That's all ! You can test it with a code like this :
// create subElement $test = new SubElement(); // test on element methods $test->setName('test'); $test->setContent('this is the big test !'); // test also SubElement methods $test->setAuthor('mr john smith'); // save in element table AND in sub_element table ! $test->save(); // capture subElement with id 1 $test = SubElementPeer :: retrieveByPk(1); // delete element and subElement in the two tables $test->delete(); // mix criteria for both class $c = new Criteria(); $c->add(ElementPeer :: ID, 1); $c->add(SubElementPeer :: AUTHOR, 'mr john smith'); // get a list of the subElements $subElements = SubElementPeer :: doSelectJoinElement(new Criteria());
each time you add a column or a method to the element model, you need to declare it in the behavior to be handled in the subclasses.
It's a way to go, may be there is a simplier way, but this works well for me...
I needed to have many subclasses inherited from a main class.
To do that with propel, you need to have all your classes in one big table. I wanted to have separate tables.
Then I discovered the propel behaviors and it does that very well !
Let's see an example with a master class "element" end a subclass "subElement" :
The tables of the subclasses just need to have an "element_id" foreign key column, to be linked with the "element" master class table :
# schema.yml example propel: # master class element: _attributes: { phpName: Element } id: name: varchar(255) content: longvarchar created_at: # subclass with only the subclass properties and element_id foreign key column sub_element: _attributes: { phpName: SubElement } element_id: author: varchar(255)
Activate the behaviors in "project/config/propel.ini" :
propel.builder.AddBehaviors = trueCreate your behavior in "project/config/config.php" :
// get propel behavior lib require_once($sf_symfony_lib_dir.'/addon/propel/sfPropelBehavior.class.php'); // declare all the methods from of the master class "element", that you'll need in the subclasses sfPropelBehavior::registerMethods('ElementBehavior', array( array('ElementBehavior', 'setName'), array('ElementBehavior', 'getName'), array('ElementBehavior', 'setContent'), array('ElementBehavior', 'getContent'), array('ElementBehavior', 'setCreated()'), array('ElementBehavior', 'getCreatedAt()'), ) ); // Modify save() and delete() master class methods // SubElement->save() need to run Element->save()..., and so for SubElement->delete() sfPropelBehavior::registerHooks('ElementBehavior', array( ':save:pre' => array('ElementBehavior', 'preSave'), ':delete:pre' => array('ElementBehavior', 'preDelete'), ) );
Declare all these behavior methods in the master class model (here in "project/lib/model/Element.php") :
// declare this class after the element class class ElementBehavior { /* Properties Setters */ public function setName(BaseObject $object, $value) { if (!$object->getElement()) $object->setElement(new Element()); $object->getElement()->setName($value); } public function setContent(BaseObject $object, $value) { if (!$object->getElement()) $object->setElement(new Element()); $object->getElement()->setContent(value); } public function setCreatedAt(BaseObject $object, $value) { if (!$object->getElement()) $object->setElement(new Element()); $object->getElement()->setDescription($value); } /* Properties Getters */ public function getId(BaseObject $object) { if (!$object->getElement()) $object->setElement(new Element()); return $object->getElement()->getId(); } public function getName(BaseObject $object) { if (!$object->getElement()) $object->setElement(new Element()); return $object->getElement()->getName(); } public function getContent(BaseObject $object) { if (!$object->getElement()) $object->setElement(new Element()); return $object->getElement()->getContent(); } public function getCreatedAt(BaseObject $object) { if (!$object->getElement()) $object->setElement(new Element()); return $object->getElement()->getCreatedAt(); } /* Element save method called just before SubElement save */ public function preSave(BaseObject $object) { // if element not null... if ($object->getElement()) { // save element in his table $object->getElement()->save(); // if new element, capture id if ($object->isNew()) $object->setElementId($object->getElement()->getId()); } } /* Element delete method called just before SubElement delete */ public function preDelete(BaseObject $object) { // if element not null and not new... if ($object->getElement() && !$object->getElement()->isNew()) { // delete element in his table $object->getElement()->delete(); } } }
add the "ElemenBehavior" to all your subclasses (here in" project/lib/model/SubElement.php") :
sfPropelBehavior::add('SubElement', array('ElementBehavior'));
That's all ! You can test it with a code like this :
// create subElement $test = new SubElement(); // test on element methods $test->setName('test'); $test->setContent('this is the big test !'); // test also SubElement methods $test->setAuthor('mr john smith'); // save in element table AND in sub_element table ! $test->save(); // capture subElement with id 1 $test = SubElementPeer :: retrieveByPk(1); // delete element and subElement in the two tables $test->delete(); // mix criteria for both class $c = new Criteria(); $c->add(ElementPeer :: ID, 1); $c->add(SubElementPeer :: AUTHOR, 'mr john smith'); // get a list of the subElements $subElements = SubElementPeer :: doSelectJoinElement(new Criteria());
each time you add a column or a method to the element model, you need to declare it in the behavior to be handled by the subclasses.
It's a way to go, may be there is a simplier way, but this works well for me...