Je suis en train de finaliser un grand projet en utilisant Laravel 4 et j'ai dû répondre à toutes les questions que vous posez actuellement. Après avoir lu tous les livres Laravel disponibles sur Leanpub et fait des tonnes de recherches sur Google, j'ai mis en place la structure suivante.
- Une classe de modèle Eloquent par table de base de données
- Une classe de dépôt par modèle Eloquent
- Une classe de service qui peut communiquer entre plusieurs classes de dépôt.
Donc disons que je construis une base de données de films. J'aurais au moins les classes de modèle Eloquent suivantes :
- Film
- Studio
- Réalisateur
- Acteur
- Critique
Une classe de dépôt encapsulerait chaque classe de modèle Eloquent et serait responsable des opérations CRUD sur la base de données. Les classes de dépôt pourraient ressembler à ceci :
- DepotFilm
- DepotStudio
- DepotRealisateur
- DepotActeur
- DepotCritique
Chaque classe de dépôt étendrait une classe BaseRepository qui implémente l'interface suivante :
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);
}
Une classe de service est utilisée pour assembler plusieurs dépôts et contient la vraie "logique métier" de l'application. Les contrôleurs communiquent uniquement avec les classes de service pour les actions de création, de mise à jour et de suppression.
Donc quand je veux créer un nouveau enregistrement de Film dans la base de données, ma classe MovieController pourrait avoir les méthodes suivantes :
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();
}
// Le nouveau film a été enregistré avec succès. Faites ce que vous avez à faire ici.
}
C'est à vous de déterminer comment vous envoyez des données POST à vos contrôleurs, mais disons que les données renvoyées par Input::all() dans la méthode postCreate() ressemblent à ceci :
$data = array(
'movie' => array(
'title' => 'Iron Eagle',
'year' => '1986',
'synopsis' => 'Quand le père de Doug, un pilote de l'Air Force, est abattu par des MiGs appartenant à un État du Moyen-Orient radical, personne ne semble capable de le sortir. Doug trouve Chappy, un colonel de l'Air Force intrigué par l'idée d'envoyer deux chasseurs pilotés par lui-même et Doug pour secourir le père de Doug après avoir bombardé la base MiG.'
),
'actors' => array(
0 => 'Louis Gossett Jr.',
1 => 'Jason Gedrick',
2 => 'Larry B. Scott'
),
'director' => 'Sidney J. Furie',
'studio' => 'TriStar Pictures'
)
Puisque le MovieRepository ne devrait pas savoir comment créer des enregistrements Acteur, Réalisateur ou Studio dans la base de données, nous utiliserons notre classe MovieService, qui pourrait ressembler à ceci :
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'];
// Dans un exemple plus complet, vous voudriez probablement mettre en œuvre des transactions de base de données et effectuer une validation des données en utilisant la classe Laravel Validator ici.
// Créez le nouvel enregistrement de film
$movie = $this->movieRepository->create($movieData);
// Créez les nouveaux enregistrements d'acteur et associez-les à l'enregistrement de film
foreach($actors as $actor)
{
$actorModel = $this->actorRepository->create($actor);
$movie->actors()->save($actorModel);
}
// Créez l'enregistrement du réalisateur et associez-le à l'enregistrement de film
$director = $this->directorRepository->create($directorData);
$director->movies()->associate($movie);
// Créez l'enregistrement du studio et associez-le à l'enregistrement de film
$studio = $this->studioRepository->create($studioData);
$studio->movies()->associate($movie);
// Supposons que tout a fonctionné. Dans le monde réel, vous devrez implémenter des vérifications.
return true;
}
Il nous reste donc une belle et sensée séparation des préoccupations. Les dépôts ne sont conscients que du modèle Eloquent qu'ils insèrent et récupèrent de la base de données. Les contrôleurs se désintéressent des dépôts, ils transmettent simplement les données collectées auprès de l'utilisateur et les passent au service approprié. Le service ne se soucie pas comment les données qu'il reçoit sont enregistrées dans la base de données, il transmet simplement les données pertinentes qui lui ont été données par le contrôleur aux dépôts appropriés.