Estou finalizando um grande projeto usando o Laravel 4 e tive que responder a todas as perguntas que você está fazendo no momento. Depois de ler todos os livros disponíveis do Laravel no Leanpub e toneladas de Google, criei a seguinte estrutura.
- Uma classe Eloquent Model por tabela de dados
- Uma classe de Repositório por Modelo Eloquent
- Uma classe de serviço que pode se comunicar entre várias classes de repositório.
Então, digamos que estou construindo um banco de dados de filmes. Eu teria pelo menos as seguintes classes do Modelo Eloquent:
- Filme
- Estúdio
- Diretor
- Ator
- Reveja
Uma classe de repositório encapsularia cada classe do Modelo Eloquent e seria responsável pelas operações de CRUD no banco de dados. As classes de repositório podem ter a seguinte aparência:
- MovieRepository
- StudioRepository
- DirectorRepository
- ActorRepository
- ReviewRepository
Cada classe de repositório estenderia uma classe BaseRepository que implementa a seguinte interface:
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);
}
Uma classe de serviço é usada para colar vários repositórios e contém a "lógica de negócios" real do aplicativo. Os controladores se comunicam apenas com as classes de serviço para as ações Criar, Atualizar e Excluir.
Portanto, quando eu quero criar um novo registro de filme no banco de dados, minha classe MovieController pode ter os seguintes métodos:
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.
}
Depende de você determinar como você envia os dados para seus controladores, mas digamos que os dados retornados por Input :: all () no método postCreate () sejam algo como:
$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'
)
Como o MovieRepository não deve saber como criar registros de ator, diretor ou estúdio no banco de dados, usaremos nossa classe MovieService, que pode ser algo assim:
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;
}
Então, o que nos resta é uma separação agradável e sensata de preocupações. Os repositórios conhecem apenas o modelo Eloquent que eles inserem e recuperam do banco de dados. Os controladores não se importam com os repositórios, apenas entregam os dados que coletam do usuário e os transmitem ao serviço apropriado. O serviço não se importa como os dados recebidos são salvos no banco de dados, apenas entrega os dados relevantes que foram fornecidos pelo controlador aos repositórios apropriados.