Добавление вычисляемого поля с данными из другой таблицы

Итак, у меня есть модель site(#id, name, start_date, end_date), которая может быть в pause(#id, site_id, start_date, end_date), и я хочу отслеживать паузы.

Я начал с добавления кнопки расширения в CRUD сайта, чтобы иметь возможность добавлять/удалять паузы. Работает как шарм.

Но теперь я хотел бы знать непосредственно в списке сайтов состояние каждого. Итак, я начал с добавления нового поля выражения и просто проверил, работает ли сайт или нет:

$this->addExpression('state')->set('if(site.end_date IS NULL,"In Progress", if(now() < site.end_date, "In Progress", "Ended"))');

Работает отлично! Но теперь я не могу придумать способ определить, находится ли сайт в паузе или нет, и на самом деле я не могу воспроизвести результат выше, используя addExpression()->set(function($m, $q) {});

Редактировать:

Таким образом, пример, приведенный DarkSide, работает как шарм, но теперь мне нужно смешать два результата в единственном поле state:

$this->addExpression('state')->set(function($model, $select)
 {
   // Is it ended ?
   $ended = $select->expr('if(site.date_ended IS NULL,"In Progress", if(now() < site.date_ended, "In Progress", "Ended"))');

   // Is it in pause ?
   $paused = $model->refSQL('Site_Pause')
                   ->count()
                   ->where('date_started', '<', $select->expr('now()'))
                   ->where('date_ended', '>', $select->expr('now()'));

  if ($paused > 0)
    return 'paused';
  return $ended;
 });

Поскольку $model->refSQL() возвращает объект DSQL, я не могу использовать операторы if. Должен ли я попытаться сделать однократный SQL-запрос или попробовать, как указано выше, использовать операторы if, получив результаты из объекта Dsql?


person Steff    schedule 30.01.2014    source источник


Ответы (2)


В Model_Site:

Плохой пример:

Я думаю, вы можете добавить все в методе subselect в set() как выражение, но это нехорошо и не рекомендуется.

$this->addExpression('paused')
    ->set("if( (SELECT 1 FROM pause WHERE pause.start_date<now() AND (pause.end_date IS NULL OR pause.end_date>now())), 'yes', 'no') ");

Лучший пример:

$this->addExpression('paused')->set(function($m, $q){
    return $m->refSQL('Pause') // Model_Pause
        ->where('start_date', '<', $q->expr('now()'))
        ->where('end_date', '>', $q->expr('now()')) // here you'll also need to use q->orExpr() to add case when end_date is null (see expression above in bad example)
        ->count()
        ;
);

Что-то подобное вы можете увидеть в моих моделях надстройки планировщика (last_status, last_run, next_status, next_run в Model_Task). Вот ссылка: https://github.com/DarkSide666/ds-addons/tree/master/Scheduler/lib/Model/Scheduler

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

person DarkSide    schedule 03.02.2014
comment
Спасибо, теперь я лучше понимаю использование $m и $q, см. отредактированный вопрос для последнего шага, которого я хотел бы достичь. - person Steff; 25.02.2014
comment
Я думаю, что вам следует попробовать сделать все в одном SQL, а затем вернуть его как DSQL. Вы можете попробовать внедрить один DSQL в другой DSQL в качестве подзапроса. Может быть, это может помочь. Сегодня вечером я немного сонный, чтобы сделать хороший пример этого :) - person DarkSide; 26.02.2014

Хорошо понял ! Я публикую здесь решение, если это кому-то нужно:

$this->addExpression('etat')->set(function($model, $select) { return ( $select->expr( 'IF ( site.date_ended IS NULL OR NOW() < site.date_ended, IF ( [f1] > 0, "Paused", "In Progress" ), "Ended" )' )->setCustom('f1', $model->refSQL('Site_Pause') ->count() ->where('date_started', '<', $select->expr('NOW()')) ->where('date_ended', '>', $select->expr('NOW()')) ) ); });

person Steff    schedule 26.02.2014