#php #laravel #serialization #lumen #lumen-5.3
#php #laravel #сериализация #lumen #lumen-5.3
Вопрос:
Я пытаюсь использовать Pusher с Lumen для отправки событий клиентам для обновления данных. Я создал очень простое событие:
class CarEvent extends Event implements ShouldBroadcast{
use SerializesModels;
public $car;
private $type;
public function __construct( Car $car, $type )
{
$this->car = $car;
$this->type = $type;
}
public function broadcastOn()
{
return ['car'];
}
public function broadcastAs()
{
return $this->type;
}
}
И я успешно запускаю его в своем контроллере, используя Event::fire(new CarEvent($car,"add"));
Внутри консоли Pusher я получаю событие ниже:
Моя проблема начинается, когда я пытаюсь отправить событие при удалении записи, ниже приведен мой код:
public function deleteCar($id){
$car = $this->cars->findOrFail($id);
$car->delete();
$oldCar = new Car;
$oldCar->id=$id;
Event::fire(new CarEvent($oldCar,"delete"));
return Response::deleted();
}
Это всегда дает ModelNotFoundException
результат, потому что модель с заданным идентификатором больше не существует, что верно.
Мой вопрос в том, как я могу запустить событие, которое сообщит, что автомобиль с определенным идентификатором удален. Я не хочу создавать другой класс, который будет расширять событие и будет использоваться только для удаления, я бы хотел использовать свой существующий класс CAREvent.
Мне нужно передать простой объект только с помощью свойства Id следующим образом:
Могу ли я создать объект Car и установить его Id
свойство и каким-то образом отключить получение rest, если данные из базы данных при сериализации модели?
Ответ №1:
Проблема возникает не при сериализации, а при отмене сериализации. Видите ли, ваше событие использует SerializesModels
признак. Этот признак имеет следующий метод:
protected function getRestoredPropertyValue($value)
{
if (! $value instanceof ModelIdentifier) {
return $value;
}
return is_array($value->id)
? $this->restoreCollection($value)
: (new $value->class)->newQuery()->useWritePdo()->findOrFail($value->id);
}
Этот признак сериализует модели как a ModelIdentifier
, который содержит только имя класса и идентификатор. При отмене сериализации модель извлекается заново из базы данных с использованием этой информации. В вашем случае удаления findOrFail
это приводит к сбою.
Я думаю, вы можете придумать решение, которое соответствует вашим потребностям сейчас. Этот, например, я думаю, должен работать для разных моделей; если вы знаете, что это нужно только для моделей автомобилей, вы можете сделать более простой.
protected function getRestoredPropertyValue($value)
{
if ($this->type == 'delete' amp;amp; $value instanceof ModelIdentifier) {
$model = (new $value->class);
$pk = $model->getQueueableId();
$model->$pk = $value->id;
return $model;
}
return parent::getRestoredPropertyValue($value);
}
Обновить
Вероятно, чище иметь отдельные события, как вы предлагаете. Все конструкторы должны получать модель автомобиля, а для случая удаления вы создаете простой объект с нужными вам атрибутами.
abstract class CarEvent extends Event implements ShouldBroadcast
{
use SerializesModels;
public $car;
protected $type;
public function __construct(Car $car)
{
$this->car = $car;
}
public function broadcastOn()
{
return ['car'];
}
public function broadcastAs()
{
return $this->type;
}
}
class AddCarEvent extends CarEvent
{
protected $type = 'add';
}
class DeleteCarEvent extends CarEvent
{
protected $type = 'delete';
public function __construct(Car $car)
{
$this->car = (object) ['id' => $car->id];
}
}
Комментарии:
1. Спасибо за ваш ответ. Для временного обходного пути я создал отдельное событие только для удаления, но ваше решение выглядит лучше. Могу ли я создать базовый класс событий, который будет расширен моим другим событием? У меня есть фон C # и начинается с Lumen. Как мне создать этот класс? Мне нужен способ указать тип и модель, например, универсальный класс в C #. В идеале я мог бы передать другую модель конструктору. Не могли бы вы добавить этот класс в свой ответ?
2. Извините за такую долгую задержку. Но у меня есть еще один связанный с этим вопрос. Могу ли я клонировать объект (в моем случае Car), чтобы мое событие возвращало не только идентификатор, но и полную модель. Я знаю, что должен объявить событие перед удалением car и после этого я должен его запустить, но на этот раз Car не будет в моей базе данных и . Я пытался создать clone непосредственно перед вызовом delete, но безуспешно. Я, вероятно, должен добавить модифицированную версию
getRestoredPropertyValue
. Как я должен изменить его, чтобы он возвращал элемент, который я передал событию, и не пытался получить его из базы данных? Может ли это быть универсальным для событий других типов?3. По сути, я хотел бы сериализовать модель, которая передается внутри конструктора моего события, и избежать (если возможно) запроса базы данных для новой модели (это не нужно, потому что я передаю ее внутри конструктора). Я немного читал о программном удалении, но я его не использую, поэтому любые сериализаторы, связанные с программным удалением, не будут работать.
4. @Misiu Хорошо, итак, вы просто хотите получить данные об автомобиле, без необходимости «обновлять» данные модели из базы данных или даже проверять их существование. Затем в конструкторе событий
$this->car = $car->toArray();
, чтобы вы сериализовали данные, а не сам объект Eloquent.5. @Спасибо за ответ, это почти то, что мне нужно. Если я удаляю, я бы хотел избежать проверки и обновления, но во всех остальных случаях (добавить, обновить) Я бы хотел сохранить нормальное поведение, поэтому, вероятно, я должен изменить
getRestoredPropertyValue
, я прав?