Использование шаблона адаптера при использовании сторонних API и создании домена в Laravel - PullRequest
2 голосов
/ 26 апреля 2019

В моем проекте REST API Laravel я в основном использую сторонние API.Для этого у меня есть папка ' Services ', сгруппированная по API (Размещение, Планирование, Скидка и т. Д.) Для отправки правильных параметров в API и получения необработанных данных.

Мне нужноиспользовать шаблон адаптера здесь, потому что эти сторонние выходные данные должны быть отформатированы.

Позвольте мне привести пример.

У меня есть интерфейс EventDao ( Объект доступа к данным ) и один или несколько конкретных классов EventDao, таких как EventbriteDao.

У меня также есть адаптер для каждого конкретного DAO.Например: EvenbriteAdapter

У меня где-то будет некоторая бизнес-логика, поэтому мне нужен класс Event entity .Чтобы передать данные адаптера объекту, мне нужен класс EventDTO ( объект передачи данных )

Наконец, я могу вызвать eventDao (через интерфейс благодаря поставщикам услуг Laravel)

Я передаю его необработанный вывод на адаптер, затем вывод адаптера на объект.Тогда я могу вызвать один из методов класса сущностей.(После этого мне нужно преобразовать его в правильные данные json, но это простая часть.)

Я не понимаю, куда поместить другую логику CRUD, такую ​​как updateEvent, deleteEvent, getAll и т. д. Должен ли я вызывать их непосредственно в контроллере или создавать репозитории (шаблон )?Я в замешательстве.

Это был бы хороший подход или чрезмерная инженерия ?Потому что у меня есть 5-6 классов / интерфейсов, отличных от контроллера.

Другая проблема заключается в вызове EventbriteAdapter непосредственно в контроллере.Должен ли я иметь интерфейс для этого?В этом случае мне нужно будет связать интерфейсы сервиса и адаптера с его реализациями в AppServiceProvider.

Еще одна проблема, которую я испытываю, связана с коллекциями для блоков сущностей.Если я вызываю метод getAll (), я могу перебирать данные и создавать массив объектов, но мне это неудобно.Коллекции Laravel были бы полезны, но я хочу отделить прикладной уровень от домена.Что было бы хорошим решением для этого?

Вот примеры кодов для некоторых файлов, которые я упомянул:

interface EventAdapter
{
    public function getId();
    public function getName();
    public function getStartDate();
    public function getLocationName();
}



class EventbriteAdapter implements EventInterface
{
    private $raw;

    public function __construct(array $raw)
    {
        $this->raw = $raw;
    }

    public function getName()
    {
        return $this->raw['name'];
    }

    public function getStartDate()
    {
        return $this->raw['start'];
    }

    public function getLocation()
    {
        return $this->raw['venue']['name'].' '.$this->raw['venue']['address'];
    }
}


// Fetch event from Eventbrite (or other third-party)
$result = fetchEventFromEventbrite();

// Wrap event in adapter
$adapter = new EventbriteAdapter($result);

1 Ответ

2 голосов
/ 30 апреля 2019

Я не понимаю, куда поместить другую логику CRUD, такую ​​как updateEvent, deleteEvent, getAll и т. Д. Должен ли я вызывать их непосредственно в контроллере или создавать репозитории (шаблон репозитория)?Я в замешательстве.

Вы можете использовать шаблон шлюза для инкапсуляции всей логики взаимодействия со сторонним API.Шлюз может содержать методы для получения данных и их сохранения.Например:

interface EventGatewayInterface
{
    /**
     * Get an event by id
     * 
     * @param mixed $id unique identifier of an event
     * @return Event the event
     */
    public function getById($id);

    /**
     * Get all events
     *
     * @return Event[] list of events
     */
    public function getAll();

    /** 
     * Add an event
     *
     * @param Event $event the event which will be added
     */
    public function add(Event $event);

    /**
     * Update an event
     *
     * @param Event $event the event which will be updated  
     */
    public function update(Event $event);

    /**
     * Delete an event
     *
     * @param Event $event the event which will be removed
     */
    public function delete();
}

Это был бы хороший подход или чрезмерный инжиниринг?Поскольку у меня есть 5-6 классов / интерфейсов, отличных от контроллера.

На самом деле, вы используете шаблон адаптера для перевода одного представления (необработанное представление) в другое (представление объекта),Но шаблон Adapter используется для перевода одного программного интерфейса в совместимый программный интерфейс.Для преобразования представлений используется шаблон Mapper .Вы можете реализовать простой маппер, например:

class RawEventMapper
{
    /**
     * Map raw data to an event object
     * 
     * @param array $data raw data
     * @return Event the event object
     */
    public function map(array $data)
    {
        $event = new Event();
        $event->name = $data['name'];
        $event->startDate = $data['start'];
        $event->location = $data['venue']['name'].' '.$data['venue']['address'];
        return $event;
    }
}

и использовать его в Gateway для преобразования необработанных данных в объект.

class ConcreteEventGateway implement EventGatewayInterface
{
    /** @var RawEventMapper data mapper */
    protected $mapper;

    /**
     * Constructor
     *
     * @param RawEventMapper $mapper data mapper
     */ 
    public function __construct(RawEventMapper $mapper)
    {
        $this->mapper = $mapper;
    }

    /** @inheritdoc */
    public function getById($id)
    {
        // get raw data from 3rd party API
        return $this->mapper->map($raw);
    }
}

Коллекции Laravel были бы полезны, но яхочу отделить прикладной уровень от домена.Что было бы хорошим решением для этого?

Если вы хотите создать доменный слой, независимый от фреймворка, вам не следует использовать коллекцию Laravel.

...