Страница 1 из 1
Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.26, 19:06
Greengo86
Господа, никак не могу разобраться как мне в prepareDataProvider() в ViewAction вернуть модель автора и связные с ним книги
Код: Выделить всё
public function actions()
{
....
'view' => [
'class' => ViewAction::class,
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
],
];
...
}
Если делаю так, то возвращается всего один лишь автор без книг и ->with('books') не помагает.
Код: Выделить всё
class ViewAction extends \yii\rest\Action
{
public function run()
{
if ($this->checkAccess) {
call_user_func($this->checkAccess, $this->id);
}
return $this->prepareDataProvider();
}
protected function prepareDataProvider()
{
$requestParams = Yii::$app->getRequest()->getBodyParams();
if (empty($requestParams)) {
$requestParams = Yii::$app->getRequest()->getQueryParams();
}
/* @var $modelClass \yii\db\BaseActiveRecord */
$modelClass = $this->modelClass;
$query = $modelClass::find()->with('books');
$query->andWhere(['id' => '1']);
return Yii::createObject([
'class' => ActiveDataProvider::className(),
'query' => $query,
'sort' => [
'params' => $requestParams,
],
]);
}
}
Если так, то вернутся лишь книги -
Код: Выделить всё
$query = $modelClass::findOne($requestParams);
$books = $query->getBooks();
return Yii::createObject([
'class' => ActiveDataProvider::className(),
'query' => $books,
'sort' => [
'params' => $requestParams,
],
]);
Код: Выделить всё
public function getBooks()
{
return $this->hasMany(Book::class, ['author_id' => 'id']);
}
Как мне вернуть автора и в его теле его ответа его книги? Использовать другой провайдер? Пытался вынести в контроллер и отдавать через echo json_encode() ругается на то, что нет метода ->setHeader() по этой инструкции -
https://www.yiiframework.com/wiki/748/b ... -in-yii2-0
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.26, 19:36
ElisDN
Код: Выделить всё
public function getBooks()
{
return $this->hasMany(Book::class, ['author_id' => 'id']);
}
public function extraFields()
{
return ['books'];
}
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.26, 19:53
Greengo86
ElisDN писал(а): ↑2021.11.26, 19:36
Дмитрий, по прежнему только автор на выходе
Код: Выделить всё
public function getBooks()
protected function prepareDataProvider()
{
$requestParams = Yii::$app->getRequest()->getBodyParams();
if (empty($requestParams)) {
$requestParams = Yii::$app->getRequest()->getQueryParams();
}
/* @var $modelClass \yii\db\BaseActiveRecord */
$modelClass = $this->modelClass;
$query = $modelClass::find()->with('books');
$query->andWhere(['id' => '1']);
return Yii::createObject([
'class' => ActiveDataProvider::className(),
'query' => $query,
'sort' => [
'params' => $requestParams,
],
]);
}
Код: Выделить всё
class Author extends \yii\mongodb\ActiveRecord
{
public function behaviors()
{
return [
[
'class' => TimestampBehavior::class,
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
'value' => new Expression('NOW()'),
],
];
}
public static function primaryKey()
{
return ['id'];
}
public function attributes()
{
return ['_id', 'id', 'name', 'surname', 'birthday', 'bio', 'created_at', 'updated_at'];
}
public function rules()
{
return [
[['created_at', 'updated_at'], 'integer'],
[['name', 'surname', 'birthday'], 'required'],
];
}
public function getBooks()
{
return $this->hasMany(Book::class, ['author_id' => 'id']);
}
public function extraFields()
{
return ['books'];
}
public static function tableName()
{
return 'author';
}
public function attributeLabels()
{
return [
'created_at' => 'Created At',
'updated_at' => 'Updated At',
'name' => 'First Name',
'surname' => 'Surname Name',
'birthday' => 'Birthday',
'bio' => 'Bio',
];
}
}
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.26, 20:00
Greengo86
Также попробовал добавить в рест модель -
Код: Выделить всё
class Author extends \common\models\Author
{
public function fields()
{
$fields = parent::fields();
unset($fields['id'], $fields['created_at'], $fields['updated_at'], $fields['bio']);
return $fields;
}
public function extraFields()
{
return ['books'];
}
}
Результат тот же (((
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.27, 01:44
Greengo86
Вышел из положения, если можно это так назвать таким образом -
Код: Выделить всё
class Author extends \common\models\Author
{
public function fields(){
$fields = parent::fields();
$fields['books'] = function ($model) {
return $model->books;
};
return $fields;
}
public function extraFields()
{
return ['books'];
}
}
И выходит метод extraFields никакой роли не играет((( Оччч странно... Но что мне делать теперь с тем, что при каждом методе (этот GET) мне надо возвращать разный набор полей? В том числе и с books -
Код: Выделить всё
public function fields()
{
$fields = parent::fields();
unset($fields['id'], $fields['created_at'], $fields['updated_at'], $fields['author_id']);
return $fields;
}
Здесь ненужные мне поля заансетил, а как же мне тогда быть с книгами? Проверять в fields() какой именно метод из реквеста - оччч не хочется такого делать...
Но нет, конечно, это полная фигня, если не смогу управлять полями модели как мне нужно
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.27, 12:40
ElisDN
Greengo86 писал(а): ↑2021.11.27, 01:44
Но что мне делать теперь с тем, что при каждом методе (этот GET) мне надо возвращать разный набор полей?
Уберите fields() и указывайте нужные поля в GET-запросе ?expand=books
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.27, 13:19
Greengo86
ElisDN писал(а): ↑2021.11.27, 12:40
Greengo86 писал(а): ↑2021.11.27, 01:44
Но что мне делать теперь с тем, что при каждом методе (этот GET) мне надо возвращать разный набор полей?
Уберите fields() и указывайте нужные поля в GET-запросе ?filelds=id,name,books
Нет, к сожалению, в адресе, в урле могу указать указать только айдишник -
{stand}/authors/2
Есть вариант, да - удалить fields() и в select в query указать эти поля. Есть еще варианты?
Код: Выделить всё
return Yii::createObject([
'class' => ActiveDataProvider::className(),
'query' => Author::find()
->select(['id', 'name','surname'])
->where(['id' => $requestParams['id']]),
'sort' => [
'params' => $requestParams,
],
]);
И я так понял что extraFields() работает только, если указан параметр в expand в урле. Как-то тоже это можно обойти? Не указывать, но чтобы связная модель загружалась...
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.27, 13:39
ElisDN
Greengo86 писал(а): ↑2021.11.27, 13:19
Как-то тоже это можно обойти? Не указывать, но чтобы связная модель загружалась...
Либо указывать expand в адресе, либо для каждой выборки сделать отдельные классы-наследники со своим fields().
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.27, 17:11
rak
Greengo86 писал(а): ↑2021.11.27, 13:19
ElisDN писал(а): ↑2021.11.27, 12:40
Greengo86 писал(а): ↑2021.11.27, 01:44
Но что мне делать теперь с тем, что при каждом методе (этот GET) мне надо возвращать разный набор полей?
Уберите fields() и указывайте нужные поля в GET-запросе ?filelds=id,name,books
Нет, к сожалению, в адресе, в урле могу указать указать только айдишник -
{stand}/authors/2
Есть вариант, да - удалить fields() и в select в query указать эти поля. Есть еще варианты?
Код: Выделить всё
return Yii::createObject([
'class' => ActiveDataProvider::className(),
'query' => Author::find()
->select(['id', 'name','surname'])
->where(['id' => $requestParams['id']]),
'sort' => [
'params' => $requestParams,
],
]);
И я так понял что extraFields() работает только, если указан параметр в expand в урле. Как-то тоже это можно обойти? Не указывать, но чтобы связная модель загружалась...
есть вариант ещё такой костыль влепить
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.27, 17:35
Greengo86
ElisDN писал(а): ↑2021.11.27, 13:39
Greengo86 писал(а): ↑2021.11.27, 13:19
Как-то тоже это можно обойти? Не указывать, но чтобы связная модель загружалась...
Либо указывать expand в адресе, либо для каждой выборки сделать отдельные классы-наследники со своим fields().
Что-то совсем печально
Как по Вашему, Дмитрий, что правильнее и изяшнее с точки зрения архитектуры указывать поля в ActiveDataProvider в ->select() или штамповать модельки? Или на вкус и цвет у всех могут быть разные мнения
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.27, 17:41
Greengo86
rak писал(а): ↑2021.11.27, 17:11
Неужели для этого нет никакой настройки в urlManager? Ок, спасибо
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.27, 18:04
rak
Greengo86 писал(а): ↑2021.11.27, 17:41
rak писал(а): ↑2021.11.27, 17:11
Неужели для этого нет никакой настройки в urlManager? Ок, спасибо
https://www.yiiframework.com/doc/api/2. ... lts-detail
можно вот это попробовать
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.28, 17:46
Greengo86
ElisDN писал(а): ↑2021.11.27, 13:39
Greengo86 писал(а): ↑2021.11.27, 13:19
Как-то тоже это можно обойти? Не указывать, но чтобы связная модель загружалась...
Либо указывать expand в адресе, либо для каждой выборки сделать отдельные классы-наследники со своим fields().
Хм, ничего не понимаю! Сделал дочерние модели, но они не имеют нужного эффекта - приходит просто пустой массив - []
В контроллере
Код: Выделить всё
public function actions()
{
$actions = [
'index' => [
'class' => IndexAction::class,
'modelClass' => IndexAuthor::class,
'checkAccess' => [$this, 'checkAccess'],
],
];
return array_merge(parent::actions(), $actions);
}
Та самая дочерняя рестовая модель -
Код: Выделить всё
<?php
namespace frontend\models\rest;
class IndexAuthor extends Author
{
public function fields()
{
$fields = parent::fields();
// unset($fields['id'], $fields['_id'], $fields['created_at'], $fields['updated_at'], $fields['bio']);
$fields['books'] = function ($model) {
return $model->books;
};
return $fields;
}
}
Рестовая основная модель -
Код: Выделить всё
<?php
namespace frontend\models\rest;
class Author extends \common\models\Author
{
public function fields(){
return parent::fields();
}
}
Еcли изменить в actions modelClass на Author основную рестовую модель - данные возвращаются, а если IndexAuthor - ничего (( В дебаггере даже не доходит до брейпоинта до метода fields() класса IndexAuthor
Re: Подскажите как вернуть модель связную с другой в ActiveDataProvider
Добавлено: 2021.11.28, 19:36
Greengo86
Докопался до истины. Если делать дочерние модели, то по умолчанию выборка данных происходит из таблицы исходя из полученного из -
Код: Выделить всё
Inflector::camel2id(StringHelper::basename(get_called_class()), '_')
То есть по умолчанию выбирали из таблицы index_author, так как класс IndexAuthor! Для этого в моделе нужно вставить статический метод -
Код: Выделить всё
public static function collectionName()
{
return $model::tableName();
}