Lumen возвращает информацию об удаленной записи, всегда получает ModelNotFoundException

#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 , я прав?