Я закінчую великий проект, використовуючи Laravel 4, і мені довелося відповісти на всі запитання, які ви зараз задаєте. Прочитавши всі доступні книги Laravel у Leanpub та тонах Гугла, я придумав таку структуру.
- Один клас красномовної моделі на таблицю даних
- Один клас сховища за красномовною моделлю
- Клас обслуговування, який може спілкуватися між декількома класами репозиторію.
Тож скажімо, я будую базу даних про фільми. У мене були б принаймні такі класи красномовної моделі:
- Кіно
- Студія
- Директор
- Актор
- Огляд
Клас сховища інкапсулює кожний клас красномовної моделі та несе відповідальність за операції CRUD над базою даних. Класи сховища можуть виглядати приблизно так:
- MovieRepository
- StudioRepository
- ДиректорРепозитарій
- ActorRepository
- ReviewRepository
Кожен клас репозиторію розширить клас BaseRepository, який реалізує такий інтерфейс:
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);
}
Клас обслуговування використовується для склеювання декількох сховищ разом і містить реальну "ділову логіку" програми. Контролери спілкуються лише з класами обслуговування для дій "Створення, оновлення та видалення".
Отже, коли я хочу створити нову запис фільму в базі даних, мій клас MovieController може мати такі методи:
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.
}
Ви самі визначаєте, як ви надсилаєте дані POST своїм контролерам, але скажімо, дані, повернені методом Input :: all () у методі postCreate (), виглядають приблизно так:
$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'
)
Оскільки MovieRepository не повинен знати, як створювати записи Actor, Director або Studio в базі даних, ми будемо використовувати наш клас MovieService, який може виглядати приблизно так:
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;
}
Тож те, що нам залишилося, - це приємне, розумне розділення проблем. Репозиторіям відомо лише красномовна модель, яку вони вставляють та отримують із бази даних. Контролерам не важливо сховища, вони просто передають дані, які вони збирають від користувача, і передають їх у відповідну службу. Службі неважливо, як отримані ними дані зберігаються в базі даних, вона просто передає відповідні дані, які їх передав контролер у відповідні сховища.