Sto finendo un grande progetto usando Laravel 4 e ho dovuto rispondere a tutte le domande che mi stai ponendo in questo momento. Dopo aver letto tutti i libri di Laravel disponibili su Leanpub e un sacco di ricerche su Google, ho trovato la seguente struttura.
- Una classe Eloquent Model per tabella databile
- Una classe di repository per modello eloquente
- Una classe di servizio che può comunicare tra più classi di repository.
Quindi diciamo che sto costruendo un database di film. Avrei almeno le seguenti classi di modello eloquente:
- Film
- Studio
- Direttore
- Attore
- Revisione
Una classe di repository incapsulerebbe ogni classe del modello eloquente e sarebbe responsabile delle operazioni CRUD sul database. Le classi del repository potrebbero assomigliare a questa:
- MovieRepository
- StudioRepository
- DirectorRepository
- ActorRepository
- ReviewRepository
Ogni classe di repository estenderebbe una classe BaseRepository che implementa la seguente interfaccia:
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);
}
Una classe Service viene utilizzata per incollare più repository insieme e contiene la vera "logica di business" dell'applicazione. I controller comunicano solo con le classi di servizio per le azioni Crea, Aggiorna ed Elimina.
Quindi, quando voglio creare un nuovo record di film nel database, la mia classe MovieController potrebbe avere i seguenti metodi:
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.
}
Sta a te determinare come POST i dati ai tuoi controller, ma diciamo che i dati restituiti da Input :: all () nel metodo postCreate () hanno un aspetto simile a questo:
$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'
)
Poiché MovieRepository non dovrebbe sapere come creare record Attore, Regista o Studio nel database, useremo la nostra classe MovieService, che potrebbe essere simile a questa:
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;
}
Quindi quello che ci resta è una bella e sensata separazione delle preoccupazioni. I repository riconoscono solo il modello eloquente che inseriscono e recuperano dal database. I controller non si preoccupano dei repository, si limitano a trasferire i dati che raccolgono dall'utente e li passano al servizio appropriato. Il servizio non si preoccupa di come i dati che riceve vengono salvati nel database, si limita a trasferire i dati rilevanti che sono stati forniti dal controller ai repository appropriati.