Как создать сложный виртуальный столбец в Eloquent Model? - PullRequest
0 голосов
/ 06 февраля 2019

Этот вопрос относится к этому , но я слишком сильно упростил свою реальную проблему.Итак, я создал отдельный вопрос:

У меня есть две таблицы.Один интервал хранения в днях, связанный с именем, таким как bimonthly = 15, и один другой, перечисляющий периодические действия и связанный с интервалом.

Я хотел бы перечислить следующие периодические действия, которые просты в чистом SQL:

SELECT *, DATE_ADD(updated_at, INTERVAL days DAY) AS next_action 
FROM periodic_actions 
INNER JOIN intervals ON interval_id = intervals.id
HAVING next_action > NOW()

Вот мои таблицы:

CREATE TABLE `intervals` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NULL,
  `days` INT NULL,
  PRIMARY KEY (`id`));

CREATE TABLE `periodic_actions` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `interval_id` INT NOT NULL,
  `name` VARCHAR(45) NULL,
  `updated_at` TIMESTAMP NOT NULL,
  PRIMARY KEY (`id`));

И содержание интервалов:

+----+----------+------+
| id | name     | days |
+----+----------+------+
|  1 | daily    |    1 |
|  2 | monthly  |   30 |
|  3 | annually |  365 |
+----+----------+------+

Я хотел бы создать такой же запрос с Eloquent, где я могу использовать where для моего виртуального столбца next_action:

Action::orderBy('next_action', 'asc')
    ->where('next_action', '>', Carbon::now())
    ->get()

Ближайший, который я имеюне могу спрятаться в мою модель:

Action::join('intervals', 'interval_id', '=', 'intervals.id')
    ->select(['*', DB::RAW('DATE_ADD(updated_at, INTERVAL days DAY) AS next_action')])
    ->havingRaw(DB::RAW('next_action > NOW()'))->get();

Конечно, у меня есть эта база Модель:

class Action extends Model
{
    protected $table = 'periodic_actions';

    public function interval() 
    {
        return $this->belongsTo(Interval::class);
    }
}

1 Ответ

0 голосов
/ 06 февраля 2019

Решение 1. Использование глобальной области для добавления поля в операторы выбора

Единственная проблема с виртуальными столбцами - Eloquent попытается обновить их, если вы не запретите это,Вы можете исключить его из массива $ fillable и использовать глобальную область действия в своей модели для добавления виртуального столбца, что-то вроде:

protected static function boot()
{
    parent::boot();

    static::addGlobalScope('next_action', function (Builder $builder) {
        $builder->addSelect(DB::raw('DATE_ADD(updated_at, INTERVAL days DAY) AS next_action'));
    });
}

Вы должны иметь в виду, чтоэто соединит вашу модель с MySQL, поскольку используемые вами функции даты не будут работать в базах данных, таких как sqlite.

Решение 2. Использование представления MySQL

Обычното, что я делаю, когда у меня есть несколько вычисляемых полей, создает представление MySQL.Создайте представление со всеми вычисляемыми полями, которые вы хотите, затем вы можете создать новую модель Eloquent для этого представления, не беспокоясь об областях запросов.

Единственное предостережение: вы, конечно, не можете использовать create / update/ delete для этой модели, но если вы используете модель только для отображения, это не должно быть проблемой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...