我正在使用Laravel 4完成一个大型项目,不得不回答您现在要问的所有问题。在精读Leanpub上所有可用的Laravel书和大量的Googling之后,我想到了以下结构。
- 每个数据表一个雄辩的模型类
- 每个雄辩模型一个存储库类
- 一个服务类,可以在多个存储库类之间进行通信。
假设我正在建立一个电影数据库。我至少将具有以下以下Eloquent Model类:
存储库类将封装每个Eloquent Model类,并负责数据库上的CRUD操作。存储库类可能如下所示:
- 电影资料库
- Studio存储库
- 总监资料库
- 演员库
- 评论库
每个存储库类都会扩展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);
}
Service类用于将多个存储库粘合在一起,并包含应用程序的真实“业务逻辑”。控制器仅与用于创建,更新和删除操作的服务类通信。
因此,当我想在数据库中创建新的Movie记录时,我的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.
}
由您决定如何将数据发布到控制器,但是让我们说由postCreate()方法中Input :: all()返回的数据看起来像这样:
$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;
}
因此,我们剩下的是很好的,明智的关注点分离。存储库只知道它们插入和从数据库检索的Eloquent模型。控制器不在乎存储库,它们只是传递从用户那里收集的数据并将其传递给适当的服务。该服务不在乎接收到的数据如何保存到数据库中,它只是将控制器提供的相关数据移交给相应的存储库。