xepozz / yii2-api-model-presenter
The API model presenter.
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 0
Open Issues: 0
Type:yii2-extension
Requires
- yiisoft/yii2: ~2.0.0
Requires (Dev)
- phpunit/phpunit: ^5.0
This package is auto-updated.
Last update: 2024-10-15 10:31:40 UTC
README
Установка
composer req xepozz/yii2-api-model-presenter
Описание
При работе с API приходится отдавать свойства объектов в виде примиивой структуры JSON или XML.
В Yii2 заложен механизм отображения моделей, как JSON или XML.
Выглядит это так:
class User extends \yii\db\ActiveRecord { public $firstName; public $lastName; public function fields() { return [ 'id' => 'id', 'name' => function() { return $this->firstName . ' ' . $this->lastName; }, ]; } }
Проблемы
-
Первая проблема навязанного подхода в том, что модель засоряется знаниями о том, в какую структуру она будет преобразована при сериализации.
-
Вторая проблема появляется тогда, когда есть наследование моделей.
Пример:
Существуетcommon\models\User
,api\modules\chat\models\User
,api\modules\forum\models\User
(крайне не советую разводить такой зоопарк) Все хорошо, если отдавать непосредственно ту модель, которую хотите отобразить. Но если какой-то модуль отдаетcommon\models\User
, вместоapi\modules\chat\models\User
, то приходится идти на хитрости, чтобы отдать нужную структуру в апи. Хитрость обычно такая:/** @var $model \common\models\User */ $model = $someService->getMyUser(); return \api\modules\chat\models\User::findOne($model->id);
Или наоборот, когда нужно вывести структуру описанную в
common\models\User
, вместо той, что заложена вapi\modules\chat\models\User
./** @var $model \api\modules\chat\models\User */ $model = $someService->getMyUser(); return \common\models\User::findOne($model->id);
Выглядит, как костыль на костыле, если честно.
-
Третья проблема вытекает из предыдущей.
Если используются модели из пунка №2, то плохой программист захочет выводитьapi\modules\chat\models\Message
(которая унаследована отcommon\models\Message
), при выводе самой моделиapi\modules\chat\models\User
как связь.
Но вcommon\models\User
связь прописана наcommon\models\Message
, как быть? Одним пальцем руки происходит override модели в связи на ту, что лежит вapi/...
.
Решение
Способ борьбы с таким предлагаю такой:
Есть класс, в котором описывается всё поведение, которое будет отдаваться в API.
В данный класс можно загружать любой зоопарк моделей. Структура на выходе будет всегда одинаковая.
Пример
Пример простого использования проксирования объектов.
use Xepozz\Yii2ApiModelPresenter\ProxyPresenter; /** * @property \common\models\User $record */ class UserPresenter extends ProxyPresenter { protected function getFields(): array { return [ 'first_name', 'last_name', 'full_name' => function() { return sprintf('%s %s', $this->record->first_name, $this->record->last_name); } ]; } }
Пример более продвинутого использования.
Используем презентер связи для ее вывода.
use Xepozz\Yii2ApiModelPresenter\ProxyPresenter; /** * @property \common\models\User $record */ class UserPresenter extends ProxyPresenter { protected function getFields(): array { return [ // ... ]; } public function getExtraFields(): array { return [ 'messages' => 'chatMessages', ]; } protected function setUpChildDefinitions(): array { return [ 'chatMessages' => ChatMessagePresenter::class, ]; } }
Пример с вариантивным скрытие поля
use Xepozz\Yii2ApiModelPresenter\ProxyPresenter; /** * @property \common\models\User $record */ class UserPresenter extends ProxyPresenter { protected function getFields(): array { return [ 'id', 'status', 'last_visited_at', ]; } protected function getIgnoredFields(): array { return [ /** * Скрываем на "prod" откружении поле email. Используется только для разработки */ 'id' => YII_ENV_PROD, 'last_visited_at' => function() { /** * Если статус online, тогда не показываем это поле. */ return (bool) $this->record->status; }, ]; } }
Развитие
Буду рад всевозможным исправлениям, замечаниям и всевозможным дискуссиям по дальнейшему развитию библиотеки.
На текущий момент есть план со следующими задачами:
- Нужно написать тесты
- Написать более внятную документацию
- Перевести документацию на английский язык