2016-02-13 4 views
9

Sagen wir, ich habe dieses Modell. (Ich habe es zu Demonstrationszwecken sehr einfach.)Modellvalidierung in PHP, die eine Interaktion mit der Datenbank erfordert

class User 
{ 
    public $id; 
    public $email; 
    public $password; 
    public $errors = []; 

    public function isValid() 
    { 
     if (strpos($this->email, '@') === false) { 
      $this->errors['email'] = 'Please enter an email address'; 
     } 
     // ... 

     return !$this->errors; 
    } 
} 

Und lassen Sie uns sagen, ich habe dieses DAO zum Abrufen, Hinzufügen, Aktualisieren und Löschen von Benutzern.

class UserDAO 
{ 
    public function getUsers() { ... } 

    public function getUserById($id) { ... } 

    public function addUser(User $user) { ... } 

    public function updateUser(User $user) { ... } 

    public function deleteUser($id) { ... } 

    public function isEmailUnique($email) { ... } 
} 

Wenn ich eine Form verarbeiten, das tue ich normalerweise etwas wie folgt aus:

$userDAO = new UserDAO(); 
$user = new User(); 
$user->email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL); 
$user->password = filter_input(INPUT_POST, 'password'); 

if ($user->isValid()) { 
    if ($userDAO->addUser($user)) { 
     // ... 
    } else { 
     // ... 
    } 
} else { 
    // do something with $user->errors 
} 

Nun lassen Sie uns Teil meiner Benutzervalidierung sagen sollte, zu überprüfen, ob E-Mail eindeutig zuzuordnen sind, wie kann ich es machen Teil des Benutzermodells? Also, wenn $user->isValid() aufgerufen wird, überprüft es auch, ob die E-Mail eindeutig ist? Oder mache ich das alles falsch?

Aus meinem schwachen Verständnis von DAOs sind DAOs für alle Interaktionen mit der Datenbank verantwortlich. Wie kann ich das Modell von innen mit der Datenbank arbeiten lassen?

+1

Die Antwort von S.Lott hilft dir wahrscheinlich http://StackOverflow.com/a/198032/3904215. Und hier eine Beschreibung von tutorialspoint: http://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm – AMartinNo1

Antwort

2

Meine Empfehlung lautet: Berücksichtigen Sie bei der Validierung Ihres Modells User nicht die Eindeutigkeit Ihrer E-Mail-Adresse. Eindeutigkeit ist ein UserDAO Problem, kein User Problem.

Wenn die User sich selbst validieren kann, sollte es in der Lage sein, dies in Isolation zu tun; seine Validierung sollte sich nicht auf externe Interaktionen beziehen.

Es kommt nur darauf an, ob die E-Mail-Adresse eindeutig ist oder nicht, wenn Sie versuchen, sie in die Datenbank einzufügen. In Anbetracht der Möglichkeit von mehreren gleichzeitigen Benutzern ist es theoretisch möglich, die Eindeutigkeit der Adresse zu überprüfen und es nicht mehr eindeutig zu dem Zeitpunkt zu sein, zu dem Sie versuchen, es einzufügen.

Ich denke, die einfachste und zuverlässige Möglichkeit, dies zu tun, ist eine einzigartige Einschränkung für E-Mail-Adresse in Ihrer Datenbank hinzufügen, dann in Ihrer addUser() Methode, nur try, um es hinzuzufügen. Wenn Ihre Datenbank Ihnen sagt, dass es nicht eindeutig ist, dann wissen Sie, dass es nicht eindeutig ist. Sie können nicht wirklich vorher wissen.

+0

Danke. Du hast recht. Ich übertreibe mein Design umsonst. – Mikey

1

Ich denke, dass Validierung in diesem Fall ein Teil der Anwendungslogik ist, da Sie Daten benötigen, die nicht im Modell gespeichert sind. Daher ist es besser, die Validierungslogik in einer anderen Controller-Funktion zu implementieren.

Darüber hinaus gibt es eine ähnliche Frage mit der ähnlichen Antwort bereits: Best Place for Validation in Model/View/Controller Model?

0

Die UserDAO Klasse muss eine Methode userExists genannt implementieren. Diese Methode prüft nur, ob die E-Mail-Adresse bereits existiert. Es überprüft dies in der BD, so dass sein Platz in der UserDAO-Klasse ist. Es muss eine private Methode sein und addUser verwendet es, um einen korrekten Wert oder false/null zurückzugeben

1

Halten Sie die User Klasse, wie es ist, es ist ein guter Bürger für sich.

würde ich die Methode isEmailUniqueprivatenmachen (iff es nur dafür verwendet wird) und prüfen Sie durch die Existenz eines User mit dieser E-Mail innerhalb addUser. Auf der anderen Seite würde dies die Verantwortung der Logik auf die DAO ziehen. (Siehe: Responsibilities and use of Service and DAO Layers)

Also, wenn Sie das Verhalten von isValid zu überprüfen, ändern, wenn der Benutzer bereits auf die Datenbank ist, würden Sie Ihr Design zu brechen sein.

0

Ich denke, Sie können DAO als Argument für die Validierungsfunktion verwenden.

Aber möglicherweise besser Weg ist DAO in Ihrem Benutzermodell verwenden. Fügen Sie die private Variable $ dao hinzu und initialisieren Sie sie im Konstruktor. Und implementieren Sie alle Methoden zum Hinzufügen/Bearbeiten/Löschen von Operationen in der Modellklasse.

1

Ein Weg, um dies zu realisieren, wäre die Methode Benutzer entfernen :: IsValid vollständig zugunsten alles vorbei es in seinem Konstruktor benötigt, von dort die Validierung ausgeführt wird:

class User 
{ 
    public function __construct($email) { 
     if (strpos($email, '@') === false) { 
      throw new \InvalidArgumentException("Invalid email"); 
     } 

     $this->email = $email; 
    } 
} 

Wenn Sie denken, darüber, was macht einen Benutzer gültig? Wenn dies eine gültige E-Mail-Adresse ist, vergewissern Sie sich, dass Sie eine übergeben, wenn Sie das Benutzerobjekt erstellen. Das macht Ihr Benutzerobjekt immer gültig.

Ein besserer Weg, dies zu gewährleisten, ein ValueObject Verwendung wäre, die diese Validierungslogik kapselt, so dass Sie es in anderen Objekten verwenden können, viel Redundanz und vorformulierten Code zu vermeiden:

class Email 
{ 
    public function __construct($email) 
    { 
     if (strpos($email, '@') === false) { 
      throw new \InvalidArgumentException("Invalid email"); 
     } 

     $this->email = $email; 
    } 
} 

class User 
{ 
    public function __construct(Email $email) 
    { 
     $this->email = $email; 
    } 
} 

class ProspectiveUser 
{ 
    public function __construct(Email $email) 
    { 
     $this->email = $email; 
    } 
} 

Jetzt in Bezug auf, Wenn Sie einen Benutzer mit der Datenbank validieren, können Sie das in Ihrem DAO perfekt einkapseln. Das DAO kann die Überprüfung durchführen, um sicherzustellen, dass der Benutzer nicht bereits in der Datenbank ist, was den DAO-Benutzer davon unabhängig macht, abgesehen von der Tatsache, dass es wissen sollte, wie der Fall eines Fehlers behandelt wird, wenn der Benutzer bereits in der DB existiert :

class UserDAO 
{ 
    public function recordNewUser(User $user) 
    { 
     if ($this->userExists()) { 
      throw new UserAlreadyExistsException(); 
     } 

     $this->persist($user); 
     $this->flush($user); 
    } 

    private function userExists(User $user) 
    { 
     $user = $this->findBy(['email' => $user->getEmail()]); 

     return !is_null($user); 
    } 
} 

Wie Sie sehen können, die DAO bietet Ihnen eine Schnittstelle für einen neuen Benutzer zu speichern, aber diese Operation fehlschlagen, wenn die Einschränkung der E-Mail Einzigartigkeit nicht erfüllt ist.

1

Ich würde alle Validierungsprobleme aus der User Klasse nehmen und in die Controller-Ebene wechseln (die beispielsweise UserDAO anrufen kann, um die E-Mail-Eindeutigkeit zu überprüfen). Am besten ist es User Klasse einfach als Entity-Klasse zu halten und all die anderen Sachen in anderen Klassen setzen - sonst wird es wachsen und in den Zustand wachsen, die nicht mehr wartbar ist :)

auch zu prüfen: https://en.wikipedia.org/wiki/Single_responsibility_principle