php - Getting specific model instance based on attribute data yii2 -
i have following table
orderitem(id, service_item_id, special_service_item_id,...)
in orderitem class specified relation
class orderitem extends activerecord { ... public function getserviceitems() { return $this->hasmany(serviceitem::classname(), ['id' => 'special_item_id']); } public function getspecialitems() { return $this->hasmany(specialitem::classname(), ['id' => 'service_item_id']); } ... } by way can proper instances of serviceitems:
$order = order::findone([123]); //an array of serviceitems $serviceitems = $order->serviceitems; //an array of specialitems $specialitems = $order->specialitems; but want extend specialitem, in fact specialitem extended serviceitem. items saved in same table, have calculate values in way when have specialitem.
sure can add 1 column extra_speacial_item_id , define relationgetextraspecialitem(), think not way. (what if want extend more , more?)
however found there mechanism in yii/ yii2 called single table inheritance @ answer, overwrite instantiate() method of baseactiverecord (source). in other answer use factorymethod. how should implement it? thoughts were:
class serviceitem extends activerecord { public function instantiate($attributes){ switch($attributes['class_name']){ case specialitem::classname(): $class = specialitem::classname(); break; case extraspecialitem::classname(): $class = extraspecialitem::classname(); break; default: $class = get_class($this); } $model = new $class(null); return $model; } } if i'm getting right, have place new children of serviceitem in instantiate() method. should alter table to:
order(pk_id, fk_service_item_id, class_name, ...)
now can access items in 2 ways:
only use method
getserviceitems()$order = order::findone([123]); //an array of mixed servicetypes, depending on class_name field $serviceitems = $order->serviceitems;modify relations in
orderitemclass orderitem extends activerecord { ... public function getserviceitems() { return $this->hasmany(serviceitem::classname(), ['id' => 'special_item_id']) ->where(['class_name' => serviceitem::classname()]); } public function getspecialitems() { return $this->hasmany(specialitem::classname(), ['id' => 'service_item_id']) ->where(['class_name' => specialitem::classname()]); } public function getextraspecialitems() { return $this->hasmany(extraspecialitems::classname(), ['id' => 'service_item_id']) ->where(['class_name' => extraspecialitems::classname()]); } ... }accessing items above:
$order = order::findone([123]); //an array of serviceitems $serviceitems = $order->serviceitems; //an array of specialitems $specialitems = $order->specialitems; //an array of extraspecialitems $extraspecialitems = $order->extraspecialitems;
is there (better) way of getting instance of model or these suitable soulutions? way of overwriting instantiate() method correct?
another way
order_item table many_many item_type table. item_type(id, type,other_stuffs). (type = service, special, etc)
the junction table order_item_type (or something) have order_item_id , item_type_id primary composite key.
then
class orderitem extends activerecord { public function getorderitemtypes() { return $this->hasmany(orderitemtype::classname(), ['order_item_id' => 'id']); } public function getserviceitems() { return $this->hasmany(item::classname(), ['id' => 'item_id']) ->via('orderitemtypes') ->where("type = service"); } public function getspecialitems() { return $this->hasmany(item::classname(), ['id' => 'item_id']) ->via('orderitemtypes') ->where("type = special"); } } or like
class orderitem extends activerecord { public function getorderitemtypes() { return $this->hasmany(orderitemtype::classname(), ['order_item_id' => 'id']); } public function getitemtypes($type = null) { return $this->hasmany(item::classname(), ['id' => 'item_id']) ->via('orderitemtypes') ->filterwhere(['type' => $type]); //not sure if can this, looks cool. if not, i'm sure mean. } } benefits of database design normalization, , flexibility.
Comments
Post a Comment