#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
]);
}
}