Сравните 2 строки таблицы с Laravel - PullRequest
0 голосов
/ 22 сентября 2019

Я пытаюсь сравнить 2 строки в базе данных, используя Laravel Eloquent Models.

У меня есть модель с именем History, которая запускается регулярно каждый час и вставляет вновь найденные данные в таблицу history.

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

Различия могутбуквально один столбец, но мне нужно знать разницу, поэтому я знаю, отправлять ли клиенту электронное письмо или нет.

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

Я также видел метод с именем isDirty.

Я не знаю, можно ли будет выбрать самые последние и затем передать данные предыдущих строк?

Столбцы могут быть добавлены в будущем, поэтому я хочу автоматизировать их.

Это мой текущий метод / модель:

class History extends Model
{
    public function hasIndescrepencies()
    {
       $current = $this->query()->orderBy('updated_at', 'DESC')->first();
        $previous = $this->query()->where('id', '<', $current->id)->orderBy('updated_at', 'DESC')->first();
    }
}

1 Ответ

0 голосов
/ 22 сентября 2019

Учитывая, что вы хотите сделать это только на одной модели, сравнивая строки current и previous в этой таблице, вот как я бы решил это:

<?php

class History extends Model
{
    public function hasIndescrepencies(): bool
    {
        $current = $this->query()->orderBy('updated_at', 'DESC')->first();
        $previous = null;
        if ($current) {
            $previous = $this->query()->orderBy('updated_at', 'DESC')->where('id', '!=', $current->id)->first();
        }

        if ($current && $previous) {

            $current = $current->toArray();
            $previous = $previous->toArray();

            $ignoreColumns = array_flip(['id', 'created_at', 'updated_at']);

            $currentDataKeys = array_filter(array_keys($current), function($key) use($ignoreColumns) {
                return !array_key_exists($key, $ignoreColumns);
            });

            $currentData = [];
            foreach ($currentDataKeys as $currentDataKey) {
                $currentData[$currentDataKey] = $current[$currentDataKey];
            }

            $previousDataKeys = array_filter(array_keys($previous), function($key) use($ignoreColumns) {
                return !array_key_exists($key, $ignoreColumns);
            });

            $previousData = [];
            foreach ($previousDataKeys as $previousDataKey) {
                $previousData[$previousDataKey] = $previous[$previousDataKey];
            }

            return !empty(array_diff($currentData, $previousData))

        }

        return false;
    }
}

Объяснение:

  1. Вы загружаете самую последнюю обновленную строку, а затем предыдущая строка выбирается так же, как текущая, без учета идентификатора текущей строки.
  2. Если первая и вторая строки существуют, то вы продолжаете делатьчек.эта таблица может начинаться только с одной строки или вообще без строк.
  3. Затем получить пару значений ключ => для текущей и предыдущей строки (исключая определенные столбцы, такие как id, creation_at & updated_at- потому что они будут другими, даже если базовые данные строки могли не измениться)
  4. Затем сравните массив diff и посмотрите, существует ли что-то

Вот как я это подтвердилработает с использованием чистого массива php:

$current = [
    'id' => 1,
    'name' => 'bob',
    'age' => 21,
    'created_at' => '2019-01-01 00:00:00',
    'updated_at' => '2019-01-02 00:00:00',
];

$previous = [
    'id' => 2,
    'name' => 'bob',
    'age' => 20,
    'created_at' => '2019-01-03 00:00:00',
    'updated_at' => '2019-01-04 00:00:00',
];

$ignoreColumns = array_flip(['id', 'created_at', 'updated_at']);

$currentDataKeys = array_filter(array_keys($current), function($key) use($ignoreColumns) {
    return !array_key_exists($key, $ignoreColumns);
});

$currentData = [];
foreach ($currentDataKeys as $currentDataKey) {
    $currentData[$currentDataKey] = $current[$currentDataKey];
}

$previousDataKeys = array_filter(array_keys($previous), function($key) use($ignoreColumns) {
    return !array_key_exists($key, $ignoreColumns);
});

$previousData = [];
foreach ($previousDataKeys as $previousDataKey) {
    $previousData[$previousDataKey] = $previous[$previousDataKey];
}

var_dump(array_diff($currentData, $previousData));

Результат var_dump должен выглядеть примерно так:

array(1) {
  ["age"]=>
  int(21)
}

Это правильно, поскольку единственное, что отличается от текущего и предыдущего, былозначение ключа возраста.

Надеюсь, это поможет.

...