Мне нравится шаблон репозитория, но во многих случаях он слишком утомителен. Мы используем этот шаблон, потому что он дает нам возможность разорвать зависимость между нашими контроллерами и/или кодом служебного слоя и ORM (обычно Eloquent). К сожалению, это обычно приводит к написанию большого количества лишнего кода. Во время работы над новым проектом я решил поработать над (частичным) решением моих бед с шаблоном репозитория. Я использовал комбинацию полиморфизма, наследования и динамического программирования, чтобы задействовать полезные части шаблона, ограничивая при этом шаблонные. ==Обзор== Основная идея шаблона заключается в создании репозиториев, которые реализуют стандартный интерфейс %%RepositoryInterface%%, который охватывает стандартные методы Eloquent нестатическим бесфасадным способом. Это значит, что мы можем использовать инверсию зависимостей, увеличивая тестируемость нашего приложения. Кроме того, поскольку наш код слоя данных будет скрыт за репозиториями, мы можем изолировать изменения запросов и/или бизнес-логики в этом слое. Но реализации только функций Eloquent недостаточно. Мне также хотелось бы добавить для репозиториев возможность реализации собственных функций модели. Чтобы сделать это, мы предоставляем каждому репозиторию интерфейс модели, в который мы можем вставить функции модели. Наконец, вся шаблонная часть скрыта за классом %%AbstractRepository%%, от которого наследуют все репозитории. Мы ограничиваем шаблонную часть, используя динамическое программирование для определения модели Eloquent, которую необходимо вызвать на этапе выполнения. ==Реализация== ===RepositoryInterface=== В интерфейсе репозитория мы определяем все стандартные методы Eloquent. Сигнатуры соответствующих методов в интерфейсе и в %%(t)Illuminate\Database\Eloquent\Model%% должны точно совпадать. .(alert) **Примечание**: некоторые методы Eloquent были удалены для простоты. Чтобы вернуть их, просто используйте описанный ниже шаблон. %% modelClassName}::where", array($username)); return $where->get(); } } %% ===AbstractRepository=== Наконец, %%AbstractRepository%% выполняет динамическую реализацию различных методов Eloquent. %% modelClassName}::create", array($attributes)); } public function all($columns = array('*')) { return call_user_func_array("{$this->modelClassName}::all", array($columns)); } public function find($id, $columns = array('*')) { return call_user_func_array("{$this->modelClassName}::find", array($id, $columns)); } public function destroy($ids) { return call_user_func_array("{$this->modelClassName}::destroy", array($ids)); } } %% ===Пример использования=== Ниже приведены два примера использования. В первом используется метод Eloquent %%find%% для получения одной записи. Во втором используется наш метод %%findByUsername%% для поиска пользователя. %% find(1)->name; // вывод количества пользователей, у которых username = johnsmith echo count($repo->findByUsername('johnsmith')); %% ==Заключение== Такой подход позволяет получить преимущества использования слоя репозитория, не требуя написания большого количества шаблонного кода. Стандартный процесс добавления новых репозиториев **прост**. * Если нам нужны только стандартные функции Eloquent, мы создаем пустой интерфейс (%%SomethingRepositoryInterface%%), который наследует от %%RepositoryInterface%%. Затем мы создаем класс %%SomethingRepository%%, реализуем %%SomethingRepositoryInterface%%, наследуем от %%AbstractRepository%% и добавляем свойство %%$modelClassName%%. * Если нам надо добавить методы, специфичные для модели, мы следуем алгоритму из предыдущего шага, а затем добавляем сигнатуры пользовательских методов в %%SomethingRepositoryInterface%%, и конкретные реализации этих методов в %%SomethingRepository%%.