2015-05-11 5 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 красноречивого объекта, а не просто идентификатор. Я мог бы сделать:

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 модели, но я полагаю, вы уже знаете, что.


В зависимости от вашей реализации простых, неизменный, объект данных, что вы используете, вы можете также разрешить прохождение объектов вместо сырых идентификаторов. Что-то между линиями:

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 или черту, если это имеет больше смысла, чтобы сохранить код DRY.

2

Это действительно зависит от ситуации, у меня было много мыслей об этих действиях, а также о моих репозиториях.

То, что я хотел бы предложить, чтобы просто не использовать «ассоциировать» функцию, вы можете просто сделать:

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

**, конечно, нужно, чтобы убедиться, что пользователь с таким идентификатором не существует.

A) Вы можете сделать это снаружи с помощью специального сервиса для «associatingUser» B) Вы можете сделать это, как вы делали с помощью UserRepositoryInterface, я вижу никаких проблем при добавлении интерфейса в качестве зависимости.

Вариант А:

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

Гидратация!

Я предполагаю, что другая причина, вызывающая findEloquent в почтовом сервисе, кажется icky - это потому, что вы, возможно, уже получили эти данные в контроллере. Проще говоря, вы можете получить доступ к тому же методу, который использует Eloquent для преобразования исходных результатов запроса в полностью функционирующие модели.

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

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

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

Я думаю, что вам действительно нужен дополнительный слой, это то, что я называю менеджером. Это будет содержать всю бизнес-логику и будет работать только с интерфейсами. Под капотом он будет называть сервисы (каждый из которых знает, что нужно работать с определенным ресурсом/моделью)

Смежные вопросы