Как виртуализировать поля в ActiveRecord ?

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Аватара пользователя
MetaDriver
Сообщения: 43
Зарегистрирован: 2014.04.21, 20:53
Откуда: Казань

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение MetaDriver »

zelenin писал(а):вы же не выбираете эти поля в запросе, вот они и нулевые - ->select('n,fn')
Ага, смешно. Это то понятно. Но их вообще не должно быть в ответе - поскольку "я же их не выбираю.." :)
В коротком случае объявления всё именно так и происходит.
--
Забавно, то точно такие же ответы приходят при пустом селекте ( return $this->hasOne(Pamjatnik::ClassName(), ['id' => 'id_pamjatnik'])->select(''); )
// И при длинной и при короткой форме объявления "fields()"
При короткой форме сервер возвращает поля 'name', 'n' и 'fn' , при длинной соответственно все поля, причём 'name', 'n' и 'fn' заполненные, а остальные == 'null'.
Понятно, что поля 'n' и 'fn' всегда извлекаются (для вычисления 'name'), но непонятно зачем это происходит при пустом селекте... :) :)
---
UPD
Был слегка неправ (в выделенных местах), каюсь. // не в той модели запросил пустой селект..
Поведение слегка проясняется. При пустом селекте возвращаются все поля объекта (заполненные). И это плохо - например для программного формирования содержимого селекта. По моей наивной логике, пустой селект должон возвращать пустой ответ. Разве нет?
Eсли селект не пуст - интереснее.
При выборе любых полей кроме n и fn, в поле name возвращается null. Если выбирается n или fn (но не оба) - вычислимое поле вычисляется как если бы незапрошенное поле было равно null. Если оба - вычисляется правильно.
В принципе поведение логичное, но на мой вкус неправильное... Мне зачем на клиенте лишние данные? Я бы хотел получить только поле name без довесков в виде fn и n. К тому же этот пример вычислимого поля весьма примитивен, есть (по замыслу) более сложные (требующие больше входных данных). И какой смысл отправлять их все клиенту? Идея была - экономить траффик и память на клиенте (таблиц у меня уже сейчас 33 штуки, а буде больше - около семидесяти)....
Последний раз редактировалось MetaDriver 2014.08.31, 18:07, всего редактировалось 5 раз.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение zelenin »

выбираете вы поля из базы, а нулевыми отображаются атрибуты модели.
Аватара пользователя
MetaDriver
Сообщения: 43
Зарегистрирован: 2014.04.21, 20:53
Откуда: Казань

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение MetaDriver »

zelenin писал(а):выбираете вы поля из базы, а нулевыми отображаются атрибуты модели.
Это так. Но на мой взгляд поведение как минимум должно быть одинаковым при короткой форме объявления fields() и при длинной. Они ж вроде как эквивалентны. И там и сям возвращаются массивы, и ежли я чего-нить понял в PHP, то абсолютно одинаковые. Но при этом возврат сервера разный. Сие непонятно а посему вызывает беспокойство своей непредсказуемостью. :) И, кстати, возврат при короткой форме мне нравится куда больше - таки более компактный и осмысленный.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение zelenin »

при "длинной" форме у вас заполняются все атрибуты модели. если вы что-то не извлекли селектом из базы, то атрибуты заполняются null. При "короткой" вы переназначаете атрибуты и выводите только некоторые.
Какое поведение вам кажется нелогичным?
Аватара пользователя
MetaDriver
Сообщения: 43
Зарегистрирован: 2014.04.21, 20:53
Откуда: Казань

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение MetaDriver »

zelenin писал(а):при "длинной" форме у вас заполняются все атрибуты модели. если вы что-то не извлекли селектом из базы, то атрибуты заполняются null. При "короткой" вы переназначаете атрибуты и выводите только некоторые.
Какое поведение вам кажется нелогичным?
Мне кажется нелогичной разница в поведении короткой и длинной формы объявления fields(), поскольку с точки зрения синтаксиса PHP они эквивалентны - в обоих случаях возвращают абсолютно одинаковые массивы. В чём тут прикол?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение zelenin »

MetaDriver писал(а):
zelenin писал(а):при "длинной" форме у вас заполняются все атрибуты модели. если вы что-то не извлекли селектом из базы, то атрибуты заполняются null. При "короткой" вы переназначаете атрибуты и выводите только некоторые.
Какое поведение вам кажется нелогичным?
Мне кажется нелогичной разница в поведении короткой и длинной формы объявления fields(), поскольку с точки зрения синтаксиса PHP они эквивалентны - в обоих случаях возвращают абсолютно одинаковые массивы. В чём тут прикол?
а. мы об ответе rest api сейчас говорим или об обычном подходе?
Аватара пользователя
MetaDriver
Сообщения: 43
Зарегистрирован: 2014.04.21, 20:53
Откуда: Казань

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение MetaDriver »

zelenin писал(а):
MetaDriver писал(а):
zelenin писал(а):при "длинной" форме у вас заполняются все атрибуты модели. если вы что-то не извлекли селектом из базы, то атрибуты заполняются null. При "короткой" вы переназначаете атрибуты и выводите только некоторые.
Какое поведение вам кажется нелогичным?
Мне кажется нелогичной разница в поведении короткой и длинной формы объявления fields(), поскольку с точки зрения синтаксиса PHP они эквивалентны - в обоих случаях возвращают абсолютно одинаковые массивы. В чём тут прикол?
а. мы об ответе rest api сейчас говорим или об обычном подходе?
REST-api. А что, есть разница? Короткая/длинная форма "fields()" приводят к различным возвратам результатов моделями, контроллеры и вьюхи вроде как не при делах. Допускаю, что при обычном использовании Yii (генерация страниц) разницу практически не заметно. Однако при rest-подходе она вылезла неприятным боком. Как бы не пришлось встревать в фильтрацию JSON-ответов. Совсем чегой-то не хочется как-то... :shock: :)
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение zelenin »

поехали заново: где чего вы прописываете, что получаете и что хотите получить с кусками кода, а не придуманной терминологией.
Аватара пользователя
MetaDriver
Сообщения: 43
Зарегистрирован: 2014.04.21, 20:53
Откуда: Казань

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение MetaDriver »

zelenin писал(а):поехали заново: где чего вы прописываете, что получаете и что хотите получить с кусками кода, а не придуманной терминологией.
Ок. Будут конкретные подробности и код. Только давайте уже завтра (то бишь сегодня после обеда).
// Я спать вырубаюсь уже. Силы на исходе и внимание отупело совсем.
Спасибо за помощь.
Аватара пользователя
MetaDriver
Сообщения: 43
Зарегистрирован: 2014.04.21, 20:53
Откуда: Казань

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение MetaDriver »

Выспался. Пообедал. Пошевелил мозгом.
Резюмо:
От виртуализации полей на Yii пока откажусь. Буду делать это на фронтенде на ангуляре.
Не то что бы "такой хоккей нам не нужен!", нужен, но не в такой реализации. Никаких претензий разработчикам, просто мои ожидания от выборки (select'ом) только нужных полей (включая, если нужно, виртуальные) оказались завышенными. При текущей реализации, без дополнительной самописной фильтрации виртуализация на Yii только увеличит траффик. В то время как я надеялся на уменьшение.
Возможно я со временем созрею для написания своей 'RestActiveRecord' (от которой буду наследоваться при создании REST-моделей), которая будет обладать нужными мне характеристиками.
Поскольку эти самые "нужные характеристики" вполне разумны, а посему наверняка нужны не только мне, я чуть позже поточнее сформулирую свои соображения и выложу здесь - возможно они заинтересуют разработчиков Yii.
А пока остановился на том, чтобы просто добавить дополнительные extraFields к реляциям (для выборки ограниченного набора полей из чужой модели).
Такой подход позволить экономить траффик и достаточно удобен для клиентов сервиса. Примерно так:

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

   public function getPamjatnik()  // добывает все поля "памятника"
   {
      return $this->hasOne(Pamjatnik::ClassName(), ['id' => 'id_pamjatnik']);
   }

   public function getPamjatnik_names()  // выбирает только поля с названиями
   {
      return $this->hasOne(Pamjatnik::ClassName(), ['id' => 'id_pamjatnik'])->select('n,fn');
   }
Ну ещё могу упомянуть, что довольно удобно использовать функции фиелдс() и эктраФиелдс() для формирования алиасов полей - это позволит сократить длину Get-запросов, а заодно js-код запросов на клиенте. Выглядит примерно так:

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

   public function extraFields()
   {
      return [
         'era_1',
         'p_v_1' => 'period_vremeni_1',
         't_drob_1' => 'tip_drobleniya_1',
         'era_2',
         'p_v_2' => 'period_vremeni_2',
         't_drob_2' => 'tip_drobleniya_2',
         'epokha',
         'klt_prndl' => 'kulturnaya_prinadlezhnost',
         'per_kult' => 'period_kultury',
         'pam' => 'pamjatnik',
         'pam_n'=>'pamjatnik_names',
      ];
   }
Кодирование обычное - слева алиас, справа значение атрибута.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение zelenin »

прочел. Еще раз скажу: ты просто не понимаешь смысл происходящего, не видишь разницу между fields/extraFields/атрибутами модели/полями таблицы. Поэтому: а) не можешь сделать желаемое, б) не можешь описать желаемое, т.к. "плаваешь" в терминологии.
Аватара пользователя
MetaDriver
Сообщения: 43
Зарегистрирован: 2014.04.21, 20:53
Откуда: Казань

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение MetaDriver »

zelenin писал(а):прочел. Еще раз скажу: ты просто не понимаешь смысл происходящего, не видишь разницу между fields/extraFields/атрибутами модели/полями таблицы.
Ой, да ладно! :) Тебе это померещилось. Если будет легче, я просто поправлю ту фразу, которая заставляет тебя так думать.
Нуно было просто вместо "доставляется в качестве extraField" читать "доставляется в качестве содержимого extraField".
Теперь лучше? ;)
Поэтому: а) не можешь сделать желаемое, б) не можешь описать желаемое, т.к. "плаваешь" в терминологии.
Соответственно выводы неправильные.
а) У меня всё работает. Если чё. :P :)
б) Описать желаемое способен вполне замечательно. Чуть позже выложу свои пожелания. // я об этом уже упомянул. возможно завтра.
Основное пожелание - виртуальные поля должны при запросах быть неотличимы от "реальных". Например, точно так-же откликаться на селект. В текущей реализации это не так. (как и почему приблизительно представляю)
А претензий к разработчикам у меня нет. // Мало ли чего там какой-то привереда хочет... Хочет - пусть сам и делает... :)
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение zelenin »

в селекте выбираются поля таблицы, а поля модели - надстройка над атрибутами модели.
Мне мерещится уже четвертую страницу.
Аватара пользователя
MetaDriver
Сообщения: 43
Зарегистрирован: 2014.04.21, 20:53
Откуда: Казань

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение MetaDriver »

Мне мерещится уже четвертую страницу.
Это нормально. Люди вообще любят глючить. Скрашивают таким образом унылые будни...
ОК, давай я тоже поумничаю немного. Сформулирую пока сырые соображения о желаемом положении дел.
zelenin писал(а):в селекте выбираются поля таблицы, а поля модели - надстройка над атрибутами модели.
Ага. В это всё и дело. И я нахожу в этом неувязочку.
Давай по порядку. Базовая идея моделирования данных - создание удобной прослойки между хранилищем данных и интерфейсом пользователя. Одна из функций - (1) создание единого интерфейса к различным хранилищам.
// С этой функцией ActiveRecord справляется на ура. Переключение на другой тип хранилища лёгкое и безболезненное.
Но это не предел мечтаний. Позволю себе помечтать дальше. Модель может иметь дополнительные возможности. Одна из которых - (2) виртуальные поля. Содержимое таких полей не имеет точного аналога в полях базы данных, но может быть вычислено из значений нескольких полей. Если такое преобразование происходит с потерей информации - оно необратимо, и такие поля могут быть доступны только для чтения. Если преобразование без потерь - оно теоретически обратимо и может реализоваться в виде виртуальных полей доступных как по чтению, так и по записи.
// Эта возможность реализована частично
Возможны ещё навороты. Один из них весьма привлекателен для меня. Это - (3) унификация интерфейса при запросах как к реальным, так и к виртуальным полям. В этом случае, запросы не должны тупо перекодироваться в запросы к базе данных, они должны довольно интеллектуально компилироваться в запросы нижнего уровня (к DB), а затем, после получения ответов фильтровать/преобразовывать их к формату "внешних" высокоуровневых запросов.
// Эта возможность не реализована.
Другими словами. Я хочу, чтоб моя модель данных имела собственный язык запросов, возможно похожий на нынешний (но необязательно), причём на уровне внешнего интерфейса пользователь не должен беспокоиться насчёт разницы между "реальными" и "виртуальными" полями. Он даже может не догадываться об их различной природе.
// Короче говоря, я не хочу ничего сверх обычной идеи ООП - абстракция инкапсулированных данных.
Структура физических данных неважна (может даже сто раз переделываться). Т.е. "всё для юзера" : интерфейс модели прописан - бери, работай и не беспокойся об физическом устройстве данных.
Как-то так.
Последний раз редактировалось MetaDriver 2014.09.01, 22:34, всего редактировалось 2 раза.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение zelenin »

понял.
частично можно решить проблему, добавив в модель методы, диначимески меняющие состав fields

Модель:

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

private $fields;

public function fields()
{
return $this->fields;
}

public function withName()
{
array_merge($this->fields,['name' => '...']);
return $this;
} 
Контроллер:

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

$query = Model::find();
if (Yii::$app->getRequest->get('newFieldName')) {
$query->withName();
}
$model = $query->all(); 
хотя так работать не будет, т.к. в query будет Query. Но накостылить можно
Аватара пользователя
MetaDriver
Сообщения: 43
Зарегистрирован: 2014.04.21, 20:53
Откуда: Казань

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение MetaDriver »

zelenin писал(а):понял.
частично можно решить проблему, добавив в модель методы, диначимески меняющие состав fields
Модель:

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

private $fields;

public function fields()
{
return $this->fields;
}

public function withName()
{
array_merge($this->fields,['name' => '...']);
return $this;
} 
О!. Это таки ближе к телу. Я примерно так и собираюсь. Сделать различные наборы полей в виде готовых возвратов из соответствующих функций. Их может быть несколько - в соответствии с типовыми наборами данных в юзерских запросах.
Только заниматься я этим буду не сейчас, а ближе к зиме, или даже к весне. Причин две. Во первых к тому времени как раз прояснятся "типовые пользовательские наборы". Сейчас пока проект в процессе доработки, интерфейс не утрясся ещё. Ну а во вторых, к тому времени я буду лучше разбираться в устройстве и возможностях PHP и Yii. :) У меня пока крайне мало опыта веб программирования вообще, а уж PHP тем более. Фактически это первый коммерческий проект в котором я взялся сам делать PHP-бакэнд. До этого только разминался и практиковался в основном на локалке. А к зиме я оботрусь, слегка заматерею ну и ..там посмотрим.
Мне и не до того сейчас - на фронтэнде работы до чёртиков. Хотя мне нравится, увлекательная штука этот ангуляр, что ни задачка - новая головоломка. :lol: Зато когда сделаешь чёньть умное.. непередаваемое осчусчение...:roll: наверное так чувствуют себя шнобелевские лауреаты.... :lol:
Контроллер:

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

$query = Model::find();
if (Yii::$app->getRequest->get('newFieldName')) {
$query->withName();
}
$model = $query->all(); 
хотя так работать не будет, т.к. в query будет Query. Но накостылить можно
Таки да. Именно так работать не будет. И да, накостылить можно. Скорее всего придётся делать свой VirtualActiveQuery, который и будет обслуживать искомую VirtualActiveRecord.
В прынцыпе интересная задачка. Только попозже. // ежли только кто-то другой до меня не сделает. чему я буду только рад.
de1phi
Сообщения: 145
Зарегистрирован: 2013.12.23, 20:02

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение de1phi »

а почему бы не актуализировать данные в afterFind()?
Аватара пользователя
MetaDriver
Сообщения: 43
Зарегистрирован: 2014.04.21, 20:53
Откуда: Казань

Re: Как виртуализировать поля в ActiveRecord ?

Сообщение MetaDriver »

de1phi писал(а):а почему бы не актуализировать данные в afterFind()?
Задачку можно решать "по большому" и "по маленькому". Если "по маленькому" - то я примерно так сейчас и делаю, только "afterFind" у меня работает на JS на фронтэнде. :)
А если "по большому", то нужно делать на Yii какую-то виртуальную прослойку между клиентом и сервисом, и там всё несколько сложнее - нужно обрабатывать внешние запросы, преобразовывая их во внутренние запросы к ActiveRecord, а затем (после обработки) преобразовывать их к "внешнему формату", ожидаемому клиентом. Можно это сделать тупо в контроллере (например при помощи поведений), но мне представляется такое решение стратегически ущербным, желательно решать универсально, т.е. на уровне модели (наша цель - "толстые модели / тонкие контроллеры" ;)). Как-то так.
Ответить