Я заканчиваю большой проект с использованием Laravel 4, и мне нужно было ответить на все вопросы, которые вы задаете прямо сейчас. После прочтения всех доступных книг по Laravel на Leanpub и множества поисковиков в Google, я придумал следующую структуру.
- Один класс Eloquent Model для каждой таблицы данных
- Один класс репозитория для каждой модели Eloquent
- Класс службы, который может взаимодействовать между несколькими классами репозитория.
Допустим, я создаю базу данных фильмов. У меня были бы по крайней мере следующие классы Eloquent Model:
- Фильм
- студия
- директор
- Актер
- Обзор
Класс репозитория будет инкапсулировать каждый класс Eloquent Model и будет отвечать за операции CRUD в базе данных. Классы репозитория могут выглядеть так:
- MovieRepository
- StudioRepository
- DirectorRepository
- ActorRepository
- ReviewRepository
Каждый класс репозитория будет расширять класс BaseRepository, который реализует следующий интерфейс:
interface BaseRepositoryInterface
{
public function errors();
public function all(array $related = null);
public function get($id, array $related = null);
public function getWhere($column, $value, array $related = null);
public function getRecent($limit, array $related = null);
public function create(array $data);
public function update(array $data);
public function delete($id);
public function deleteWhere($column, $value);
}
Класс Service используется для объединения нескольких репозиториев и содержит реальную «бизнес-логику» приложения. Контроллеры только связываются с классами обслуживания для создания, обновления и удаления действий.
Поэтому, когда я хочу создать новую запись фильма в базе данных, мой класс MovieController может иметь следующие методы:
public function __construct(MovieRepositoryInterface $movieRepository, MovieServiceInterface $movieService)
{
$this->movieRepository = $movieRepository;
$this->movieService = $movieService;
}
public function postCreate()
{
if( ! $this->movieService->create(Input::all()))
{
return Redirect::back()->withErrors($this->movieService->errors())->withInput();
}
// New movie was saved successfully. Do whatever you need to do here.
}
Вам решать, как вы отправляете данные POST в свои контроллеры, но предположим, что данные, возвращаемые Input :: all () в методе postCreate (), выглядят примерно так:
$data = array(
'movie' => array(
'title' => 'Iron Eagle',
'year' => '1986',
'synopsis' => 'When Doug\'s father, an Air Force Pilot, is shot down by MiGs belonging to a radical Middle Eastern state, no one seems able to get him out. Doug finds Chappy, an Air Force Colonel who is intrigued by the idea of sending in two fighters piloted by himself and Doug to rescue Doug\'s father after bombing the MiG base.'
),
'actors' => array(
0 => 'Louis Gossett Jr.',
1 => 'Jason Gedrick',
2 => 'Larry B. Scott'
),
'director' => 'Sidney J. Furie',
'studio' => 'TriStar Pictures'
)
Поскольку MovieRepository не должен знать, как создавать записи Actor, Director или Studio в базе данных, мы будем использовать наш класс MovieService, который может выглядеть примерно так:
public function __construct(MovieRepositoryInterface $movieRepository, ActorRepositoryInterface $actorRepository, DirectorRepositoryInterface $directorRepository, StudioRepositoryInterface $studioRepository)
{
$this->movieRepository = $movieRepository;
$this->actorRepository = $actorRepository;
$this->directorRepository = $directorRepository;
$this->studioRepository = $studioRepository;
}
public function create(array $input)
{
$movieData = $input['movie'];
$actorsData = $input['actors'];
$directorData = $input['director'];
$studioData = $input['studio'];
// In a more complete example you would probably want to implement database transactions and perform input validation using the Laravel Validator class here.
// Create the new movie record
$movie = $this->movieRepository->create($movieData);
// Create the new actor records and associate them with the movie record
foreach($actors as $actor)
{
$actorModel = $this->actorRepository->create($actor);
$movie->actors()->save($actorModel);
}
// Create the director record and associate it with the movie record
$director = $this->directorRepository->create($directorData);
$director->movies()->associate($movie);
// Create the studio record and associate it with the movie record
$studio = $this->studioRepository->create($studioData);
$studio->movies()->associate($movie);
// Assume everything worked. In the real world you'll need to implement checks.
return true;
}
Итак, у нас осталось хорошее, разумное разделение проблем. Репозитории осведомлены только о модели Eloquent, которую они вставляют и извлекают из базы данных. Контроллеры не заботятся о репозиториях, они просто передают данные, которые они собирают от пользователя, и передают их соответствующей службе. Сервис не заботится о том, как данные, которые он получает, сохраняется в базе данных, он просто передает соответствующие данные, которые он предоставил контроллером, в соответствующие репозитории.