Может войдёшь?
Черновики Написать статью Профиль

Шаблон проектирования "Репозиторий" в действии

перевод

Две недели назад я обсуждал статью «Два шаблона проектирования, которые сделают ваши приложения лучше». После этого появился огромный интерес к демонстрации шаблона «Репозиторий» в действии. Сегодня мы посмотрим, как репозиторий подходит для Laravel Faq Page.

Просто говоря, репозиторий — это абстрактный слой между каким-либо хранилищем и вашим приложением или бизнес-логикой. Это примерно то же, как если бы вы могли подойти к полке для книг и взять нужные из них одним движением руки. Итак, давайте посмотрим на задачи, которые мы хотим решить взаимодействием между хранилищем данных или слоем постоянного хранилища.

  1. Выборка всех заданных вопросов
  2. Создание пустого вопроса для связывания формы в представлении
  3. Страничный вывод запросов
  4. Создание и хранение вопроса
  5. Выборка вопросов по первичному ключу
  6. Обновление вопроса с первичным ключом и некоторым массивом данных
  7. Удаление вопроса по первичному ключу

Если вы уже знакомы с Laravel, то у вас, вероятно, появится вопрос: «что не так с Eloquent?». Единственное не совсем стандартное его использование снаружи от модели — обновление вопроса по первичному ключу и атрибутам.

Однако я скрыл несколько требований. Первое — наши вопросы используют пакет Eloquent Rankable и наши коллекции выборок должны быть отсортированы по важности. Второе — страничный вывод должен быть только для отвеченных вопросов. Таким образом, мы думаем о репозитории как о методе исключения специфической логики базы данных из наших контроллеров. (Что, несомненно, делает Тейлора очень счастливым.)

Для начала мы создадим интерфейс для именования наших методов и их аргументов. Этот интерфейс позже будет реализован в нашем хранилище, использующем Eloquent. В src/Rtablada/LaravelFaq/Repositories/FaqRepository.php создадим следующее.

PHP
<?php namespace Rtablada\LaravelFaq\Repositories;

interface 
FaqRepository
{
  public function 
all($columns = array('*'));

  public function 
newInstance(array $attributes = array());

  public function 
paginate($perPage 15$columns = array('*'));

  public function 
create(array $attributes);

  public function 
find($id$columns = array('*'));

  public function 
updateWithIdAndInput($id, array $input);

  public function 
destroy($id);
}

Имена функций были выбраны по двум причинам. Первое, имена методов четко показывают действия, которые они совершают, и аргументы, которые могут им понадобиться. Кроме того, мы уже знакомы с API Eloquent, поэтому реализация будет понятна и проста.

Теперь давайте реализуем наш репозиторий в %%(t)src/Rtablada/LaravelFaq/Repostiories/FaqRepositoryEloquent.php:

PHP
<?php namespace Rtablada\LaravelFaq\Repositories;

use 
Rtablada\LaravelFaq\Faq;
use 
Config;

class 
FaqRepositoryEloquent implements FaqRepository
{
  protected 
$faqModel;

  public function 
__construct(Faq $faqModel)
  {
      
$this->faqModel $faqModel;
  }

  public function 
newInstance(array $attributes = array())
  {
      if (!isset(
$attributes['rank'])) {
          
$attributes['rank'] = 0;
      }
      return 
$this->faqModel->newInstance($attributes);
  }

  public function 
paginate($perPage 0$columns = array('*'))
  {
      
$perPage $perPage ?: Config::get('laravel-faq::pagination.length');
      return 
$this->faqModel->rankedWhere('answered'1)->paginate($perPage$columns);
  }

  public function 
all($columns = array('*'))
  {
      return 
$this->faqModel->rankedAll($columns);
  }

  public function 
create(array $attributes)
  {
      return 
$this->faqModel->create($attributes);
  }

  public function 
find($id$columns = array('*'))
  {
      return 
$this->faqModel->findOrFail($id$columns);
  }

  public function 
updateWithIdAndInput($id, array $input)
  {
      
$faq $this->faqModel->find($id);
      return 
$faq->update($input);
  }

  public function 
destroy($id)
  {
      return 
$this->faqModel->destroy($id);
  }
}

Как вы видите, мы использовали синтаксис ranked* из Eloquent Rankable в некоторых наших методах. Этот синтаксис в нашем контроллере ограничит свободу тому, кто хочет создать «плоскую» файловую версию пакета. Это так же убирает логику из нашего контроллера, что и является основной целью нашей абстракции. Теперь, если мы захотим что-то изменить в логике получения записей из БД, нам не потребуется искать обращения к ней во всех наших контроллерах и изменять их.

Наконец, в src/Rtablada/LaravelFaq/LaravelFaqServiceProvider.php мы должны добавить связывания и сказать Laravel, что всякий раз, когда мы запрашиваем экземпляр PHPFaqRepository, мы на самом деле хотим использовать реализацию PHPFaqRepositoryEloquent. Мне нравится выносить связывания в отдельные методы — это позволяет впоследствии изменять логику, которая не загромождает функцию загрузки PHPboot. В boot добавим следующее:

PHP
$this->bootRepositories();

И далее создадим функцию PHPbootRepositories:

PHP
public function bootRepositories()
{
  
$this->app->bind('Rtablada\LaravelFaq\Repositories\FaqRepository',
                   
'Rtablada\LaravelFaq\Repositories\FaqRepositoryEloquent');
}

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

Как вы считаете, полезен ли этот материал? Да Нет

Комментарии (2)

Manzadey

Паттер Репозиторий не используется для добавления или обновления записей. Для этого существует Паттерн «Сервисный Слой».

Lai

Это не совсем так, в Репозитории осуществляется хранение логики моделей (а уже в модели определяется, будет ли это бд, файл, и т.д.). К примеру, передаем данные модели и указываем, что нужно сохранить пользователя и его профиль, а модель сохранит куда нужно.
В Сервисном Слое мы реализуем бизнес-логику хранения. К примеру, передаем данные репозиторию пользователя и говорим, что хотим сохранить его. А еще передаем другому репозиторию данные отзыва пользователя и также говорим сохранить его. И т.д.

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.