Отражает конечные точки как модель для Symfonys Serializer, также учитывает общие атрибуты ответа

#php #class #symfony #serialization #interface

#php #класс #symfony #сериализация #интерфейс

Вопрос:

Чего я хочу:

Я пытаюсь десериализовать ответ от использования вызова API в PHP. Для моих конечных точек мне нравится иметь модель, чтобы сериализатор мог творить чудеса.

Ответ:

 {
    "count": 123,
    "next": "string",
    "previous": "string",
    "limit": 123,
    "offset": 123,
    "results": 
      [
        {...},
        {...}
      ]

}
  

Теперь каждый ответ поставляется с одинаковыми «базовыми» атрибутами: count, limit, offset … и т.д. И затем в результатах каждый результат специфичен для конечной точки.

Например:

 {
    "id": 0,
    "name": "string",
    "handle": "string"
}
  

В Symfony я вызываю следующее:

 $this->serializer->deserialize($data, EndpointModel::class, 'json')
  

что должно дать мне:

 AppApiModelBaseModel {#541 ▼
  -count: 901
  -limit: 10
  -offset: 0
  -results: array:10 [▼
    0 => AppApiModelEndpointModel {#547 ▼
      -id: 3203
      -name: FooBar
    }
    1 => AppApiModelResultModel {#549 ▶}
    ...
  ]
}
  

Где я застрял:

Я создал BaseModel.php :https://hastebin.com/exagaworez.xml
И у меня есть EndpointModel.php :https://hastebin.com/tijinojixo.xml
Поэтому я вызываю это с:

 $this->serializer->deserialize($data, BaseModel::class, 'json')  
  

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

Как я мог бы добиться чего-то подобного?

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

Я использую Symfony, использую API с http_client и хочу преобразовать ответ с помощью сериализатора. Может быть, кто-нибудь может указать мне правильное направление или дать мне что-нибудь почитать 🙂

Заранее благодарю вас! Дайте мне знать, если вам нужна дополнительная информация

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

1. Чтобы убедиться, что я понял, вы на самом деле не вызываете ‘$this-> serializer-> deserialize ($data, EndpointModel::class, ‘json’)’ верно? вы вызываете $this-> serializer-> deserialize($data, BaseModel::class, ‘json’), и он должен внутренне десериализовать результаты в EndpointModel ? Кроме того, результаты могут содержать несколько типов объектов?

2. Да, правильно. Я заставил его работать с сериализатором Symfony, вызвав BaseModel и установив тип $results для EndpointModel. Таким образом, данные будут десериализованы правильно. И да, результаты могут содержать несколько типов или моделей разных конечных точек. Если я вызываю только базовую модель и передаю с ней «правильную» модель или если я вызываю EndpointModel, для меня это не имеет значения, не уверен, как сериализатор будет работать с этим 🙂 Но, конечно, что-то, что я могу выяснить

Ответ №1:

В итоге я получил следующую структуру, которая дает мне желаемый результат:

Поскольку мой ответ на большинстве конечных точек имеет те же свойства, я создал abstract class называемый BaseResponse :

 <?php


namespace AppApiResponse;


abstract class BaseResponse
{
    /**
     * @var int
     */
    private $count;

    /**
     * @var int
     */
    private $limit;

    /**
     * @var int
     */
    private $offset;


    /**
     * @return int
     */
    public function getCount(): int
    {
        return $this->count;
    }

    /**
     * @param int $count
     */
    public function setCount(int $count): void
    {
        $this->count = $count;
    }

    /**
     * @return int
     */
    public function getLimit(): int
    {
        return $this->limit;
    }

    /**
     * @param int $limit
     */
    public function setLimit(int $limit): void
    {
        $this->limit = $limit;
    }

    /**
     * @return int
     */
    public function getOffset(): int
    {
        return $this->offset;
    }

    /**
     * @param int $offset
     */
    public function setOffset(int $offset): void
    {
        $this->offset = $offset;
    }
}
  

Здесь я храню все общие значения моих ответов.

Затем я создаю, class который extends мой BaseResponse и заботится о конкретных свойствах или, в основном, о моих results , вот так:

 <?php


namespace AppApiResponse;


use AppApiModelCenterModel;

class CenterResponse extends BaseResponse
{

    /**
     * @var CenterModel
     */
    private $results;

    public function __construct(CenterModel ...$results)
    {
        $this->results = $results;
    }

    /**
     * @return array
     */
    public function getResults(): array
    {
        return $this->results;
    }

    /**
     * @param $results
     */
    public function setResults(CenterModel ...$results): void
    {
        $this->results = $results;
    }
}
  

и, наконец, я могу создать свою модель, которая содержит структуру моего конечного объекта. Таким образом, я могу отслеживать объект без необходимости касаться части ответа. Смотрите здесь:

 <?php


namespace AppApiModel;

/**
 * Class CenterModel
 * @package AppApiModel
 */
class CenterModel
{
    /**
     * @var string
     */
    private $name;

    /**
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @param string $name
     */
    public function setName(string $name): void
    {
        $this->name = $name;
    }
}
  

Таким образом, я могу отслеживать свои ответы и модели конечных точек без дублирования слишком большого количества строк кода.

Позже я использую сериализатор и вызываю CenterResponse для десериализации ответа. Вот так:

 $this->serializer->deserialize($data, CenterResponse::class, 'json');
  

Тогда результат будет примерно таким:

 Center.php on line 64:
AppApiResponseCenterResponse {#541 ▼
  -results: array:10 [▼
    0 => AppApiModelCenterModel {#547 ▼
      -name: "Center Name here"
    }
    1 => AppApiModelCenterModel {#549 ▶}
    2 => AppApiModelCenterModel {#581 ▶}
    3 => AppApiModelCenterModel {#621 ▶}
    4 => AppApiModelCenterModel {#623 ▶}
    5 => AppApiModelCenterModel {#624 ▶}
    6 => AppApiModelCenterModel {#625 ▶}
    7 => AppApiModelCenterModel {#626 ▶}
    8 => AppApiModelCenterModel {#627 ▶}
    9 => AppApiModelCenterModel {#628 ▶}
  ]
  -count: 901
  -limit: 10
  -offset: 0
}
  

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