Как оптимизировать преобразование active-record в json

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
maxomato
Сообщения: 5
Зарегистрирован: 2016.03.07, 15:10
Откуда: Воронеж

Как оптимизировать преобразование active-record в json

Сообщение maxomato »

Здравствуйте!

У нас есть active-record модель с большим количеством релейшенов.

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

class Product extends ActiveRecord
{
	public function fields()
	{
		return   [
			'id',
			'prices',
			'producer'
		];
		
	}
	
	public function getProducer()
	{
		return $this->hasOne(Producer::class, ['product_id' => 'id']);
	}
	
	public function getPrices() {
		return $this->onePrice + $this->twoPrice;
	}
}
Отдаём её на фронт устанавливая

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

	Yii::$app->response->format = Response::FORMAT_JSON;
в контроллере.

Записей в БД очень много и запрос очень тормозит. Хотя сам запрос к БД выполняется быстро.
Полагаю, что много времени тратится на создание моделей.

Попробовали использовать Product::find()->asArray(), всё действительно заработало быстро, но выводятся все поля из БД без учёта
полей, указанных в методе fields, что нам очень нужно.
Также при этом не вызываются методы, типа getPrices, которые выполняют предобработку данных перед отправкой на фронт.

Есть ли какое-либо решение этой проблемы? Чтобы и данные быстро отдавались и можно было пользоваться и полями fields и
методами типа getPrices?
Т.е. пользоваться объектами, но при этом чтобы запрос был быстрым?

yiiliveext
Сообщения: 909
Зарегистрирован: 2019.08.13, 01:49

Re: Как оптимизировать преобразование active-record в json

Сообщение yiiliveext »

Смотрите в сторону yii\rest\Serializer, там уже есть нужный вам функционал, можете либо отнаследоваться, либо посмотреть как сделано.
По getPrice(), если это предобработчик цены из базы, то подключайте его в afterFind().

Аватара пользователя
ElisDN
Сообщения: 5495
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Как оптимизировать преобразование active-record в json

Сообщение ElisDN »

Жадную загрузку Product::find()->with('producer') используете?

yiiliveext
Сообщения: 909
Зарегистрирован: 2019.08.13, 01:49

Re: Как оптимизировать преобразование active-record в json

Сообщение yiiliveext »

ElisDN писал(а):
2020.01.24, 12:25
Жадную загрузку Product::find()->with('producer') используете?
Это не решит проблемы с fields, а вот так поможет и с автозагрузкой связей тоже. C getPrice() в afterFind() я, кстати, погорячился, здесь это излишне, можно сделать проще.

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

$models = Product::find()->all();
foreach ($models as $i => $model) {
            if ($model instanceof Arrayable) {
                $models[$i] = $model->toArray($fields, $expand);
            } elseif (is_array($model)) {
                $models[$i] = ArrayHelper::toArray($model);
            }
        }
В модели Product

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

public function fields()
{
    return [
        'id' => 'id',
        'name' => 'name',
        'price' =>  function ($model) {
            return $model->getPrice($model->price);
        },
        'myRelationFieldNameForAPI' => 'myRelation'
    ];
}

public function getMyRelation()
{
   //...
}

maxomato
Сообщения: 5
Зарегистрирован: 2016.03.07, 15:10
Откуда: Воронеж

Re: Как оптимизировать преобразование active-record в json

Сообщение maxomato »

ElisDN писал(а):
2020.01.24, 12:25
Жадную загрузку Product::find()->with('producer') используете?
Да, используем. Но когда используем asArray() это действительно не решает проблемы с fields, и с полями типа getPrice. Релейншены же возвращаются нормально.

Вопрос по участку кода.
yiiliveext писал(а):
2020.01.24, 12:50

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

$models = Product::find()-all();
foreach ($models as $i => $model) {
            if ($model instanceof Arrayable) {
                $models[$i] = $model->toArray($fields, $expand);
            } elseif (is_array($model)) {
                $models[$i] = ArrayHelper::toArray($model);
            }
        }
Здесь же будет выполняться только первая ветка if, ведь ActiveRecord имеет Arrayable интерфейс и мы переходим к следующему объекту в foreach. Тогда зачем вторая ветка if?
Последний раз редактировалось maxomato 2020.01.24, 14:16, всего редактировалось 1 раз.

yiiliveext
Сообщения: 909
Зарегистрирован: 2019.08.13, 01:49

Re: Как оптимизировать преобразование active-record в json

Сообщение yiiliveext »

maxomato писал(а):
2020.01.24, 13:32
Вопрос по участку кода.
yiiliveext писал(а):
2020.01.24, 12:50
Здесь же будет выполняться только первая ветка if, ведь ActiveRecord имеет Arrayable интерфейс и мы переходим к следующему объекту в foreach. Тогда зачем вторая ветка if?
Верно, она не нужна, просто скопировал кусок кода с сериализатора.

maxomato
Сообщения: 5
Зарегистрирован: 2016.03.07, 15:10
Откуда: Воронеж

Re: Как оптимизировать преобразование active-record в json

Сообщение maxomato »

ок, спасибо. Посмотрю тогда в сторону Serializer

Ответить