oop - 管理 Laravel 中的关系,遵循存储库模式

标签 oop laravel laravel-4 repository-pattern eloquent

在阅读了 T. Otwell 关于 Laravel 中良好设计模式的书后,在 Laravel 4 中创建应用程序时,我发现自己为应用程序上的每个表创建了存储库。

我最终得到了以下表结构:

  • 学生:学号、姓名
  • 类(class):id、姓名、teacher_id
  • 教师:ID、姓名
  • 作业:id、名称、course_id
  • 分数(充当学生和作业之间的枢纽):student_id、task_id、分数

我有存储库类,其中包含所有这些表的查找、创建、更新和删除方法。每个存储库都有一个与数据库交互的 Eloquent 模型。关系在 Laravel 文档的模型中定义:http://laravel.com/docs/eloquent#relationships .

创建新类(class)时,我所做的就是调用类(class)存储库上的 create 方法。该类(class)有作业,因此在创建作业时,我还想在分数表中为类(class)中的每个学生创建一个条目。我通过作业存储库来完成此操作。这意味着作业存储库与两个 Eloquent 模型(作业模型和学生模型)进行通信。

我的问题是:由于这个应用程序的大小可能会增加并且会引入更多的关系,因此与存储库中的不同 Eloquent 模型进行通信是否是一种好的做法,或者应该使用其他存储库来完成此操作(我的意思是从作业存储库)还是应该在 Eloquent 模型中一起完成?

此外,使用分数表作为作业和学生之间的枢纽是一个好的做法还是应该在其他地方完成?

最佳答案

我正在使用 Laravel 4 完成一个大型项目,并且必须回答您现在提出的所有问题。在阅读了 Leanpub 上所有可用的 Laravel 书籍并进行了大量的谷歌搜索之后,我想出了以下结构。

  1. 每个数据表一个 Eloquent Model 类
  2. 每个 Eloquent 模型一个存储库类
  3. 可以在多个 Repository 类之间进行通信的 Service 类。

假设我正在构建一个电影数据库。我至少有以下 Eloquent 模型类:

  • 电影
  • 工作室
  • 董事
  • Actor
  • 评论

存储库类将封装每个 Eloquent Model 类并负责数据库上的 CRUD 操作。存储库类可能如下所示:

  • 电影存储库
  • StudioRepository
  • DirectorRepository
  • ActorRepository
  • 评论存储库

每个存储库类都会扩展一个实现以下接口(interface)的 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);
}

服务类用于将多个存储库粘合在一起,并包含应用程序的真正“业务逻辑”。 Controller 与服务类通信以执行创建、更新和删除操作。

因此,当我想在数据库中创建新的电影记录时,我的 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 到 Controller 由您决定,但假设 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 、导演或工作室记录,因此我们将使用 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 模型。 Controller 不关心存储库,他们只是将从用户收集的数据移交给适当的服务。该服务并不关心它接收到的数据如何保存到数据库中,它只是将 Controller 提供的相关数据传递给适当的存储库。

关于oop - 管理 Laravel 中的关系,遵循存储库模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18817615/

相关文章:

oop - 模型失控

c - C 中的 "Dynamic Inheritance"

laravel - 属于ToMany多个外键,laravel

php - Laravel 从关系中提取字段

php - Paypal 自适应支付服务 550001 错误

javascript - ES6 OOP 从父类继承方法

oop - 将代码逻辑与实际数据结构分离。最佳实践?

php - Laravel 使用多少成本/回合进行哈希处理?

php - Laravel 4 权限

php - 自动为 $fillable 属性赋值 (Laravel 4)