2015-05-11 42 views
8

我正在尝试创建一个干净的服务层,其中服务层作用于一个或多个存储库,并且每个存储库都在其自己的雄辩模型上运行。如何从服务层分离雄辩?

例如,我可以具有:

ForumService 
    | 
    +-- PostRepo extends PostInterface 
    |  | 
    |  +-- Post (Eloquent) 
    | 
    +-- UserRepo extends UserInterface 
     | 
     +-- User (Eloquent) 

每个服务定义它经由ioc需要的依赖。所以,像这样:

// MessageService 
// .. 
public function __construct(UserInterface $userRepository, 
          MessageInterface $messageRepository) { 
    // .. 
} 

我的仓库通过其绑定在各自的服务供应商解决,如:

class UserRepositoryServiceProvider extends ServiceProvider 
{ 
    public function register() 
    { 
     $this->app>bind(
      'App\Models\Repositories\User\UserInterface', 
      'App\Models\Repositories\User\UserRepository'); 
    } 
} 

这一切工作就好了。每个服务都可以获得它需要的存储库。

为了使服务层不受任何依赖于雄辩的影响,任何留下回购的东西都是一个简单的,不可变的数据对象。

在日常语言要点:

  • 只有回购的谈话,以自己的模式直接
  • 回购回归简单的,一成不变的,数据对象
  • 服务行动,以配合多种回购的一起和现在简化的对象返回到控制器,最终还是视图。

然而我不能想出的服务或回购层干净的模式associate雄辩模型给对方。

鉴于Post模型具有belongsTo(User::class)关系,我如何在Post存储库层干净地创建该关系。

我曾尝试:

public function associate($authorId) 
{ 
    $post->author()->associate($authorId); 
} 

associate期望一个user雄辩的对象,而不仅仅是一个ID。我可以这样做:

public function associate($authorId) 
{ 
    $post->from()->associate($userRepo->findEloquent($authorId)); 
} 

但我觉得我正在浮出水面模型,进入一个不应该作用于其上的回购。

+0

那么您还有什么问题吗?或者答案是你问的? –

回答

2

最简单的办法:

public function assignToAuthor($postId, $authorId) 
{ 
    $post = $this->find($postId); // or whatever method you use to find by id 

    $post->author_id = $authorId; 
} 

现在,上面意味着你知道关系的外键author_id。为了抽象的,它只是一个位,使用此:

public function assignToAuthor($postId, $authorId) 
{ 
    $post = $this->find($postId); 

    $foreignKey = $post->author()->getForeignKey(); 

    $post->{$foreignKey} = $authorId; 
} 

记住,你仍然需要save$post模式,但我想你已经知道了。


根据您的实现的简单的,不可改变的,数据对象你使用,你也可以让传递对象,而不是原始的ID。线之间的东西:

public function assignToAuthor($postId, $authorId) 
{ 
    if ($postId instanceof YourDataOject) { 
     $postId = $postId->getId(); 
    } 

    if ($authorId instanceof YourDataOject) { 
     $authorId = $authorId->getId(); 
    } 

    // ... 
} 
2

我在这带来了一些理智这种情况对我过去所做的是什么做的事情类似于你在你的第二个associate方法做,并与Eloquent前缀的仓库,所以在事件中,我使用的东西,除了Eloquent,我只是创建了一个新的仓库实现。

所以在这种情况下,我最终会得到class EloquentUserRepository implements UserInterface。我通常最终会得到一些公共方法,这些方法只返回原语,并且可能还有一些私有方法,这些方法会与Eloquent耦合,因此我最终做的是将这些公共方法放到AbstractUserRepository中,或者如果它更有意义,保持代码干爽。

2

这真的取决于情况,我对这些行为以及我的知识库有很多想法。

我的建议是干脆不使用“联想”功能,你可以简单地做:

$post->user_id = $userID; 
$post->save(); 

**当然,你需要确保与ID的用户存在。

A)可以与“associatingUser” B)你可以做你喜欢使用的UserRepositoryInterface, 我看不出有什么问题,添加接口作为依赖做了一个特殊的服务之外做。

选项A:

class AssociateUserToPost { 

private $userRepo; 
private $postRepo; 

public function __construct(UserRepoInterface $userRepo, PostRepoInterface $postRepo) { 
    $this->userRepo = $userRepo; 
    $this->postRepo = $postRepo; 
} 

public function associate($userId, $postId) { 
    $user = $this->userRepo->getUser($userId); 
    if (! $user) 
     throw new UserNotExistException(); 

    $post = $this->postRepo->getPost($postId); 
    if (! $post) 
     throw new PostNotExistException(); 

    $this->postRepo->AttachUserToPost($postId, $userId); 
} 

} 

选项B(不太一样,代码只是坐在在不同的地方)

class PostRepository implements PostRepoInterface { 

private $userRepo; 

public function __construct(UserRepoInterface $userRepo) { 
    $this->userRepo = $userRepo; 
} 

public function associate($userId, $postId) { 
    $user = $this->userRepo->getUser($userId); 
    if (! $user) 
     throw new UserNotExistException(); 

    $post = $this->getPost($postId); 
    if (! $post) 
     throw new PostNotExistException(); 

    $this->AttachUserToPost($postId, $userId); 
} 

} 
0

水合!

我假设在post服务中调用findEloquent的另一个原因看起来很糟糕,因为您可能已经在控制器中检索到该数据。简而言之,您可以访问Eloquent用于将原始查询结果转换为功能完备的模型的相同方法。

$userData = array(
    // simple, immutable data 
); 

$userCollection = User::hydrate(array($userData)); 

$userModel = $userCollection->first(); 
0

我想你实际上需要一个额外的层,就是我所说的管理者。这将包含所有的业务逻辑,并且只能用于接口。在引擎盖下,它会调用服务(每个知道使用特定的资源/模型)