2015-05-11 19 views
8

Ich versuche eine Clean-Cut-Service-Schicht zu erstellen, wobei die Service-Schicht auf einem oder mehreren Repositories agiert und jedes Repository auf seinem eigenen eloquenten Modell agiert.Wie eloquent von der Service-Schicht zu entkoppeln?

Zum Beispiel kann ich:

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

Jeder Dienst definiert es Abhängigkeiten über ioc erforderlich ist. Also, so etwas wie:

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

Das alles funktioniert ganz gut:

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

sind meine Repositories über ihre Bindungen in ihren jeweiligen Service-Provider, wie aufgelöst. Jeder Dienst erhält die erforderlichen Repositories.

Um die Serviceebene von jeder spezifischen Abhängigkeit von eloquent zu befreien, ist alles, was ein Repo verlässt, ein einfaches, unveränderliches Datenobjekt.

Schlüsselpunkte in der Alltagssprache:

  • Nur die direkt
  • , um ihre eigenen Modelle Rede Repo
  • Repo Rückkehr einfach, unveränderlich, Datenobjekte
  • Dienstleistungen mehrere Repo zusammen und Gegenwart binden handeln vereinfachte Objekte zurück zu den Controllern und schließlich zu den Ansichten.

jedoch Ich kann nicht mit einem sauberen Muster associate eloquent Modelle miteinander im Dienst oder Repo-Schicht kommen.

Angesichts der Post Modell hat eine belongsTo(User::class) Beziehung, wie ich diese Beziehung auf der Post Repository-Schicht sauber erstellen.

Ich habe versucht:

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

Aber associate erwartet eine user eloquent Objekt, nicht nur eine ID. Ich konnte tun:

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

Aber ich fühle mich wie ich ein beredtes Modell bis zu einem Repo am Belag, der nicht auf sie handeln sollte.

+0

Nun, haben Sie noch Fragen? oder die Antwort war, was du gefragt hast? –

Antwort

2

Der einfache Weg:

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

    $post->author_id = $authorId; 
} 

, Nun ist die oben Impliziert, dass Sie den Fremdschlüssel author_id der Relation kennen. Um zu abstrahieren es nur ein bisschen, verwenden Sie diese:

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

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

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

Verstand, dass Sie immer noch zu save brauchen die $post Modell, aber ich nehme an, Sie bereits wissen.


Je nach Implementierung des einfach, unveränderlich, Objektdaten, die Sie verwenden, können Sie erlauben auch die Objekte anstelle von Roh-IDs übergeben. Etwas zwischen den Linien:

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

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

    // ... 
} 
2

Was ich in der Vergangenheit, die für diese Situation etwas Vernunft gebracht hat, war, Dinge zu tun, was Sie tun, in Ihrer zweiten associate Methode und Präfix das Repository mit Eloquent so für den Fall, dass ich etwas anderes verwenden Eloquent, ich erstelle nur eine neue Implementierung des Repository.

In diesem Fall würde ich am Ende mit class EloquentUserRepository implements UserInterface enden. Normalerweise habe ich am Ende einige öffentliche Methoden, die nur Primitive und möglicherweise einige private Methoden aufnehmen und zurückgeben, die mit Eloquent gekoppelt wären. Also mache ich dann diese öffentlichen Methoden in eine AbstractUserRepository oder eine Eigenschaft, wenn es mehr Sinn macht. den Code DRY behalten.

2

Es hängt wirklich von der Situation ab, ich hatte viele Gedanken zu diesen Aktionen und auch zu meinen Repositories.

Was würde ich vorschlagen, ist, einfach nicht die „Associate“ Funktion zu verwenden, können Sie einfach tun:

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

** natürlich müssen Sie sicherstellen, dass der Benutzer mit dieser ID existiert.

A) Sie können es draußen für „associatingUser“ mit einem besonderen Service tun B) Sie können es tun, wie Sie mit der Verwendung der UserRepositoryInterface tun, Ich sehe kein Problem, die Schnittstelle als Abhängigkeit hinzufügen.

Eine Option:

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); 
} 

} 

Option B (ganz gleich, Code sitzt nur an verschiedenen Orten)

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

Trink!

Ich nehme an, dass ein weiterer Grund findEloQuent innerhalb des Post-Service scheint, scheint icky ist, weil Sie diese Daten bereits innerhalb des Controllers möglicherweise abgerufen haben. Einfach gesagt, können Sie auf dieselbe Methode zugreifen, die Eloquent verwendet, um rohe Abfrageergebnisse in voll funktionsfähige Modelle zu transformieren.

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

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

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

Ich denke, dass Sie tatsächlich eine zusätzliche Schicht benötigen, ist, was ich einen Manager nenne. Dies wird die gesamte Geschäftslogik enthalten und nur mit Schnittstellen funktionieren. Unter der Haube ruft es die Dienste an (jeder weiß, dass er mit einer bestimmten Ressource/einem bestimmten Modell arbeiten soll)