#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
}
Возможно, для некоторых из вас это хорошая отправная точка 🙂 На данный момент я использую это, но, возможно, есть и другой подход к этому.