active-record
active-record copied to clipboard
Suggestion to add multi-level relations to ActiveRecord::extraFields()
Currrently there is no possibility to dynamically manage relations that should be included to respond in case when relation level is bigger than one. For example we have model Business and you can define Locations relation like this:
public function extraFields()
{
$fields = parent::fields();
$fields[]='locations';
return $fields;
}
And then you can include it to respond using ?expand="locations"
But if we want to include Locations together with related location Schedules, then that doesn't work.
I suggest to implement multi-level relations (using dot notation):
public function extraFields()
{
$fields = parent::fields();
$fields[]='locations';
$fields[]='locations.schedule';
return $fields;
}
And then it will be possible to use it this way: ?expand="locations, locations.schedule"
I think it would be nice, because it's very often needed to manage relation records that should be included to respond. Is it possible?
I thought about this. It's not trivial, especially if you also want to support selectively pick up certain fields from relations.
can't we delegate this to the extraFields method of the related model and use definitions from there?
How will the GET query parameter looks like? How to go from there to the method parameters?
can't we delegate this to the extraFields method of the related model and use definitions from there?
We do not need do that!
Please read this: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#autoloading
All we need is support expand or embed parameter.
I thought about this. It's not trivial, especially if you also want to support selectively pick up certain fields from relations.
From client side there is no feature to selectively pick up certain fields from relations in expand/embed. It will be overcoding.
From model side it can be easily handled like:
class Product extends ActiveRecord
{
public function extraFields()
{
return [
'price',
'quantity',
'categories' => ['id', 'title'], <- LOOK HERE
];
}
}
So query like GET /products?expand=price,categories will give you result:
{
"id": 1,
"title": "Foo",
"price": "$10",
"categories": [
{
"id": 1,
"title": "Bar"
},
{
"id": 2,
"title": "Baz"
}
}
}
+1
+1
+1
+1
+1
+1
+1
Where in code YII2 looks for "expand" parameter to choose which extra fields must be shown?
Where in code YII2 looks for "expand" parameter to choose which extra fields must be shown?
https://github.com/yiisoft/yii2/blob/master/framework/rest/Serializer.php#L159
+1
This problem make me cry, really! I want to get list of "items" with author. And in author I want to get Full name extra field. But it's not working at all. Expand not using custom fields.
+1
For the moment, I've worked around this problem by overruling the fields() call in my ActiveRecord model.
class MultiLevelActiveRecord extends \yii\db\ActiveRecord
{
public function fields()
{
$fields = parent::fields();
// Add multi-level expanded fields
$expandFields = explode(',', Yii::$app->request->getQueryParam('expand'));
foreach ($expandFields as $field)
{
if (strpos($field, strtolower($this->formName()).'.') === 0)
{
$fields[] = substr($field, strlen($this->formName()) + 1);
}
}
return $fields;
}
}
That enabled me to use:
?expand=category,author.name
But only based on exact modal names, and not based on relations. It's dirty, but does the job for me.
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1