Kończę duży projekt przy użyciu Laravel 4 i musiałem odpowiedzieć na wszystkie pytania, które teraz zadajesz. Po przeczytaniu wszystkich dostępnych książek Laravel w Leanpub i mnóstwie google, wymyśliłem następującą strukturę.
- Jedna klasa Eloquent Model na tabelę datowalną
- Jedna klasa repozytorium na model elokwentny
- Klasa usług, która może komunikować się między wieloma klasami repozytorium.
Powiedzmy, że tworzę bazę danych filmów. Miałbym przynajmniej następujące klasy Eloquent Model:
- Film
- Studio
- Dyrektor
- Aktor
- Przejrzeć
Klasa repozytorium hermetyzowałaby każdą klasę modelu elokwentnego i byłaby odpowiedzialna za operacje CRUD w bazie danych. Klasy repozytorium mogą wyglądać następująco:
- MovieRepository
- StudioRepository
- DirectorRepository
- ActorRepository
- ReviewRepository
Każda klasa repozytorium rozszerzyłaby klasę BaseRepository, która implementuje następujący interfejs:
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);
}
Klasa Service służy do sklejania ze sobą wielu repozytoriów i zawiera prawdziwą „logikę biznesową” aplikacji. Kontrolery komunikują się tylko z klasami usług w przypadku akcji tworzenia, aktualizowania i usuwania.
Więc kiedy chcę utworzyć nowy rekord filmu w bazie danych, moja klasa MovieController może mieć następujące metody:
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.
}
Do Ciebie należy określenie, w jaki sposób POST przekazujesz dane swoim kontrolerom, ale powiedzmy, że dane zwrócone przez Input :: all () w metodzie postCreate () wyglądają mniej więcej tak:
$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'
)
Ponieważ MovieRepository nie powinno wiedzieć, jak tworzyć rekordy aktora, reżysera lub studia w bazie danych, użyjemy naszej klasy MovieService, która może wyglądać mniej więcej tak:
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;
}
Pozostaje więc przyjemne, rozsądne oddzielenie obaw. Repozytoria znają tylko model elokwentny, który wstawiają i pobierają z bazy danych. Administratorzy nie dbają o repozytoria, po prostu przekazują zebrane od użytkownika dane i przekazują je do odpowiedniej usługi. Serwis nie dba o to, w jaki sposób otrzymane dane są zapisywane w bazie danych, po prostu przekazuje odpowiednie dane, które otrzymała od administratora do odpowiednich repozytoriów.