Страница 1 из 1

Как разделить массив полей в Model::fields() для разных случаев?

Добавлено: 2019.04.06, 12:31
MaximWeber
Задача
Предположим, есть REST-сервис, представленный двумя ресурсами: список записей, информация о записи. Нужно, чтобы список записей содержал только поля id и title, а информация о записи: id, title, text, image, author.

Как мне решить мою задачу наиболее красивым способом? Что посоветуете?

Как я пытаюсь это решить (ниже можно особо не читать)
Я знаю, что в url могу использовать get-параметр fields и в нем перечислить те поля, что меня интересуют. Но мне такой подход не нравится тем, что url становится не таким лаконичным, как бы мне хотелось.

В моделях Yii2 есть fields(), который используется сериализатором в контроллере и определяет список полей, которые следует вернуть клиенту. Для разделения списка полей для разных сценариев использования я решил воспользоваться полем scenario у модели. Это прекрасно работает ровно до того момента, пока я не использую ActiveDataProvider(), в который никаким способом этот сценарий я передать не могу.

В коде это выглядит как-то так:

Код: Выделить всё

class Post 
{
    const SCENARIO_INDEX = 'index';
    const SCENARIO_VIEW = 'view';

    public function fields()
    {
        $fields = parent::fields();

        if ($this->scenario === self::SCENARIO_INDEX) {
            $fields = ['id', 'title'];
        }
        if ($this->scenario === self::SCENARIO_VIEW) {
            $fields = ['id', 'title', 'text', 'image', 'author'];
        }

        return $fields;
    }
}

class PostController extends \yii\rest\Controller
{
    public function actionIndex()
    {
        return new ActiveDataProvider([
            'query' => Post::find(),
            // 'scenario' => Post::SCENARIO_INDEX, // Это так не работает :(
        ]);
    }
    
    public function actionView($id)
    {
        $post = Post::findOne((int) $id);
        if (!$post) {
            throw new NotFoundHttpException();
        }
        $post->scenario = Post::SCENARIO_VIEW;

        return $post;
    }
}

На ум мне пришли три решения:
1. Собственная реализация ActiveDataProvider с поддержкой сценариев.
2. Не использовать сценарии. Создать наследников Post (например, PostForIndex, PostForView), в которых переопределять fields() под мои нужды.
3. Не использовать сценарии. В контроллере задать get-параметры:
\Yii::$app->request->setQueryParams(['fields' => 'id, title']);

Re: Как разделить массив полей в Model::fields() для разных случаев?

Добавлено: 2019.06.03, 12:41
masson
MaximWeber писал(а):
2019.04.06, 12:31
class PostController extends \yii\rest\Controller
{
public function actionIndex()
{
return new ActiveDataProvider([
'query' => Post::find(),
// 'scenario' => Post::SCENARIO_INDEX, // Это так не работает :(
]);
}
А так разве не работает?

Код: Выделить всё

return new ActiveDataProvider([
    'query' => Post::find()->select(['id', 'title']),
]);