Ich beende ein großes Projekt mit Laravel 4 und musste alle Fragen beantworten, die Sie gerade stellen. Nachdem ich alle verfügbaren Laravel-Bücher bei Leanpub und jede Menge Googeln gelesen hatte, kam ich auf die folgende Struktur.
- Eine eloquente Modellklasse pro datierbarer Tabelle
- Eine Repository-Klasse pro eloquentem Modell
- Eine Serviceklasse, die zwischen mehreren Repository-Klassen kommunizieren kann.
Nehmen wir also an, ich baue eine Filmdatenbank auf. Ich hätte mindestens die folgenden folgenden eloquenten Modellklassen:
- Film
- Studio
- Direktor
- Darsteller
- Rezension
Eine Repository-Klasse würde jede Eloquent Model-Klasse kapseln und für CRUD-Operationen in der Datenbank verantwortlich sein. Die Repository-Klassen könnten folgendermaßen aussehen:
- MovieRepository
- StudioRepository
- DirectorRepository
- ActorRepository
- ReviewRepository
Jede Repository-Klasse würde eine BaseRepository-Klasse erweitern, die die folgende Schnittstelle implementiert:
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);
}
Eine Service-Klasse wird zum Zusammenkleben mehrerer Repositorys verwendet und enthält die eigentliche "Geschäftslogik" der Anwendung. Controller kommunizieren nur mit Serviceklassen für Aktionen zum Erstellen, Aktualisieren und Löschen.
Wenn ich also einen neuen Movie-Datensatz in der Datenbank erstellen möchte, verfügt meine MovieController-Klasse möglicherweise über die folgenden Methoden:
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.
}
Es liegt an Ihnen, zu bestimmen, wie Sie Daten an Ihre Controller senden. Angenommen, die von Input :: all () in der postCreate () -Methode zurückgegebenen Daten sehen ungefähr so aus:
$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'
)
Da das MovieRepository nicht wissen sollte, wie Schauspieler-, Director- oder Studio-Datensätze in der Datenbank erstellt werden, verwenden wir unsere MovieService-Klasse, die ungefähr so aussehen könnte:
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;
}
Was uns also bleibt, ist eine nette, vernünftige Trennung der Bedenken. Repositorys kennen nur das Eloquent-Modell, das sie einfügen und aus der Datenbank abrufen. Controller interessieren sich nicht für Repositorys, sie geben lediglich die vom Benutzer gesammelten Daten weiter und geben sie an den entsprechenden Dienst weiter. Dem Dienst ist es egal, wie die empfangenen Daten in der Datenbank gespeichert werden. Er gibt lediglich die relevanten Daten, die er vom Controller erhalten hat, an die entsprechenden Repositorys weiter.