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

#php #laravel

Вопрос:

Я не уверен, возможно ли это или нет, но если это так, это сэкономит мне много дубликатов кода. У меня есть много заданий в очереди, которые обрабатывают импорт данных csv. Мне нужно отслеживать изменения, которые были внесены в эти импортные данные, и кто внес эти изменения. Я внедрил наблюдателей для каждой модели, и я могу регистрировать изменения, но я не могу получить пользователя, который импортировал данные, так как изменения происходят в задании, поставленном в очередь. Само задание знает о пользователе, так как я передаю пользователя заданию, но я не могу понять, как передать пользователя наблюдателю. У кого-нибудь есть какие-нибудь идеи о том, как это сделать?

Я использую пакет Laravel Excel для обработки импорта, и этот пакет также интегрирует постановку заданий в очередь. Вот код из задания импорта:

 class QueuedImport implements ToCollection, WithChunkReading, ShouldQueue
{
    use Importable;

    private $user;
    private $client;

    public function __construct($user, $client)
    {
        $this->user = $user; // this is the logged in user
        $this->client = $client;
    }

    public function collection(Collection $rows)
    {
        //each row updates a model, which triggers the update event in the observer
        $this->importRows($rows, $this->client, $this->user);

    }

    public function chunkSize(): int
    {
        return 500;
    }

    //....
}
 

А вот событие обновления наблюдателя:

 public function updated(MyModel $model)
    {
        $original = $model->getOriginal();
        $user = auth()->user();
        foreach ($model->getChanges() as $key => $value) {
            AppHistory::create([
                'user_id' => $user->id ?? null,
                'model_id' => $model->id,
                'field' => $key,
                'old_value' => $original[$key],
                'new_value' => $value
            ]);
        }
    }
 

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

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

Ответ №1:

Я не очень доволен этим решением, но, может быть, это сработает.

Возможно, вам захочется реализовать события laravel excel с Auth помощью фасада.

 use Auth;
use MaatwebsiteExcelConcernsWithEvents;

class QueuedImport implements ToCollection, WithChunkReading, ShouldQueue, withEvents
{
    use Importable;

    private $user;
    private $client;

    public function __construct($user, $client)
    {
        $this->user = $user; // this is the logged in user
        $this->client = $client;
    }

    public function collection(Collection $rows)
    {
        //each row updates a model, which triggers the update event in the observer
        $this->importRows($rows, $this->client, $this->user);

    }

    public function chunkSize(): int
    {
        return 500;
    }

    public function beforeImport()
    {
        Auth::loginUsingId($this->user->id);
    }

    public function afterImport()
    {
        Auth::logout();
    }

    //....
}
 

Комментарии:

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

Ответ №2:

Лучшее, что я мог придумать, не было идеальным, но я не мог придумать другого способа сделать это. В итоге я добавил столбец в каждую из таблиц, которые я наблюдаю, updated_by . Поэтому, когда модель обновляется, я заполняю это поле текущим зарегистрированным пользователем. Затем у меня есть доступ к этому полю в наблюдателе через модель. Итак, вот что у меня сейчас в «наблюдателе»:

 public function updated(MyModel $model)
    {
        $original = $model->getOriginal();
        $user = $model->created_by; // <--- this is the new field I added
        foreach ($model->getChanges() as $key => $value) {
            AppHistory::create([
                'user_id' => $user,
                'model_id' => $model->id,
                'field' => $key,
                'old_value' => $original[$key],
                'new_value' => $value
            ]);
        }
    }