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
orderitem
class 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