• Jeder User im Forum verpflichtet sich zur Akzeptanz und zur Einhaltung dieser Regeln:
    1. Umgangston
      Ein angemessener höflicher Umgangston, ohne Beleidigungen, Beschimpfungen und aggressive Postings ist für jedes Mitglied Pflicht.
    2. Beiträge
      Jedes Mitglied sollte sich bemühen nur sinnvolle Beiträge zum Thema zu posten. Dabei ist unbedingt vorher zu prüfen, ob das Thema vorher schon einmal diskutiert wurde und daher fortgesetzt werden kann
      • Suchfunktion benutzen!
      • offizielle Doku lesen!
    3. Haftung
      Jeder Beitragsersteller übernimmt die alleinige Verantwortung seiner Inhalte.
    4. Werbung
      Wir erlauben keine Beiträge, Signaturen, Private Nachrichten oder eMails an Benutzer, die Werbung enthalten. Ausgenommen
      sind Stellengesuche /-angebote, welche ausschließlich im Forum "Stellengesuche" veröffentlicht werden dürfen.
    5. Verstöße
      Regelwidrige Beiträge sollten dem Team gemeldet werden. Nach deren Überprüfung werden wir schnellstmöglich
      entsprechend handeln.
    6. Authorität
      Den Anweisungen der Team-Mitglieder (Administratoren und Moderatoren) sind in diesem Forum Folge zu leisten.
      Bei Fragen oder Beschwerden bitte an diese wenden.
    Wir möchten Euch darauf aufmerksam machen, dass es bei Verstößen gegen einen oder mehreren der oben genannten
    Punkte dem Team frei steht entsprechend zu handeln. Dies kann z.B. das Löschen eines Beitrags, das Ausschliessen bzw.
    Sperren von Mitgliedern oder aber lediglich eine Verwarnung sein.

    In diesem Zusammenhang sollte erwähnt werden, dass das Forum automatisch die IP-Adresse jedes Beitrag-Erstellers
    speichert. Bei schweren Vergehen, behalten wir es uns vor, die IP-Adresse zur Strafverfolgung weiterzugeben.
  • Willkommen im Zend Framework Forum

    ZF1 Zend Framework 1 + ZF2 Zend Framework 2

    Das Zend Framework Forum ist seit 2006 die erste Anlaufstelle für Zend Framework Entwickler in Deutschland. Mit über 70.000 Beiträgen und einer steigenden Nutzerzahl bietet das Forum hilfreiche Themen und ZF-Tutorials für professionelle Entwickler, fortgeschrittene Programmierer sowie Zend Framework Einsteiger.
    Wenn dies Dein erster Besuch in der Zend Framework Community ist, lies bitte zuerst die Hilfe - FAQ durch. Du musst Dich registrieren, bevor Du Beiträge verfassen kannst. Klicke oben auf 'Registrieren', um die Registrierung zu starten. Du kannst auch jetzt schon Beiträge lesen. Hier im Forum findest Du die Zend Framework Hilfe, die Du suchst!

    Grüße an alle Zend Framework Entwickler. Das Team vom Zend Framework Forum!

    Drupal Agentur

Frage zur Vorgehensweise mit Factories

michga93

New member
Hallo zusammen,

ich würde gerne von euch erfahren, ob die folgende Vorgehensweise in Bezug auf Factories und Models so okay ist oder ob es einen "besseren Weg nach Rom" gibt :)
Alle meine Models erben von der Klasse AbstractModel. Diese Klasse dient in erster (und einziger) Linie dazu, häufig benötigte Services zu kapseln und meinen Models zur Verfügung zu stellen:

PHP:
<?php
namespace Application\Model;

use Doctrine\ORM\EntityManager;
use Zend\Mvc\Plugin\FlashMessenger\FlashMessenger;
class AbstractModel {
  
  protected $_entityManager;
  
  protected $_flashMessenger;
  
  protected function getEntityManager() : EntityManager {
    return $this->_entityManager;
  }
  
  public function setEntityManager(EntityManager $entityManager) {
    $this->_entityManager = $entityManager;
  }
  
  protected function getFlashMessenger() : FlashMessenger {
    return $this->_flashMessenger;
  }
  
  public function setFlashMessenger(FlashMessenger $flashMessenger) {
    $this->_flashMessenger = $flashMessenger;
  }
}
Gesetzt werden diese Services über die Factories der einzelnen Models, wie hier das Beispiel der RegisterModelFactory:

PHP:
<?php
namespace User\Factory\Model;

use Interop\Container\ContainerInterface;
use User\Model\RegisterModel;
use Zend\ServiceManager\Factory\FactoryInterface;
use Doctrine\ORM\EntityManager;

class RegisterModelFactory implements FactoryInterface {

  public function __invoke(ContainerInterface $containerInterface, $requestedName, array $options = null) {
    $registerEmailModel = $containerInterface->get(RegisterEmailModel::class);
    $registerModel = new RegisterModel($registerEmailModel);
    $registerModel->setEntityManager($containerInterface->get(EntityManager::class));
    $registerModel->setFlashMessenger($containerInterface->get('ControllerPluginManager')->get('flashmessenger'));
    return $registerModel;
  }
}
Die Services, welche ich nur in den einzelnen Models benötige, setze ich hingegen über den Konstruktor des Models, wie in der Factory zu sehen ist. Diese werden dann in einzelnen Klassenvariablen gehalten:

PHP:
<?php
namespace User\Model;

use Zend\Stdlib\Parameters;
use Application\Model\AbstractModel;

class RegisterModel extends AbstractModel {

  private $_registerEmailModel;

  public function __construct(RegisterEmailModel $registerEmailModel) {
    $this->_registerEmailModel = $registerEmailModel;
  }

  public function createUser(Parameters $post) : bool {}

  private function _getRegisterEmailModel() : RegisterEmailModel {
    return $this->_registerEmailModel;
  }
}
Technisch läuft alles einwandfrei, aber ich würde gerne Eure Meinung zu meiner Vorgehensweise hören :)

Dankeschön und viele Grüße
Michael
 

Kaiuwe

Super-Moderator
ich würde gerne von euch erfahren, ob die folgende Vorgehensweise in Bezug auf Factories und Models so okay ist oder ob es einen "besseren Weg nach Rom" gibt
Ich kann leider nicht erkennen, welche Aufgabe dein Datenmodell übernimmt. Scheinbar werden Zuständigkeiten und Aufgaben in den Klassen vermischt. Wieso steht in jeder Klasse der „Entity Manager“ von Doctrine zur Verfügung? Die Abhängigkeit zum „Flash Messenger“ ist sogar falsch, denn es ist ein Kontroller-Plugin und hat ausserhalb eines Kontrollers nichts verloren. Zusätzlich bindest du damit dein Datenmodell an das ZF und hier konkret an das MVC-Muster. Auch werden falsche Bezeichnungen verwendet, denn „$post“ in der Methode „RegisterModel::createUser“ setzt scheinbar voraus, dass es sich die HTTP-Methode „POST“ handelt. Dies wird wiederum auch noch an „Zend\Stdlib\Parameters“ gebunden, wieder die Abhängigkeit zum ZF und MVC.
Das pauschale zur Verfügung stellen von Funktionalitäten, egal ob dies benötigt werden oder nicht, ist grundsätzlich falsch. Das konkrete Problem, welches eine Klasse lösen soll, scheint damit nicht genau definiert zu sein. Die Idee des Datenmodells liegt nicht darin eine Klasse zu erstellen, welche alle Probleme löst. Daher ist auch der Name „Model“ für eine einzelne Klasse nicht korrekt.
Du hast hier zwar nur einen kleinen Auszug gegeben, aber die Problematik zieht sich durch alle deine Klassen, wenn diese die Klasse „Application\Model\AbstractModel“ erweitern.

Übrigens stimmt die Methodensignatur deiner Fabrik nicht ganz. (siehe im Interface)
 

michga93

New member
Autsch, mit soviel hatte ich nicht gerechnet aber dafür habe ich ja den Thread geöffnet - Danke schonmal für deine Antwort! :)

Ich kann leider nicht erkennen, welche Aufgabe dein Datenmodell übernimmt. Scheinbar werden Zuständigkeiten und Aufgaben in den Klassen vermischt. Wieso steht in jeder Klasse der „Entity Manager“ von Doctrine zur Verfügung?
Die Models beinhalten in erster Linie die CRUD Funktionalität der einzelnen Doctrine-Entities. Beispielsweise enthält das UserModel die Methoden getUserById(), editUser(), deleteUser(), usw. Aus diesem Grund wird der EntityManager auch über das AbstractModel zur Verfügung gestellt.

Die Abhängigkeit zum „Flash Messenger“ ist sogar falsch, denn es ist ein Kontroller-Plugin und hat ausserhalb eines Kontrollers nichts verloren.
Kann ich definitiv nachvollziehen, allerdings wusste ich es ehrlich gesagt nicht besser, da in einer einzelnen Model-Methode mehrere Flash-Messages erstellt werden müssen (Beispiel beim Anlegen eines Benutzers: Benutzer wurde erfolgreich angelegt [success] und Benutzer konnte nicht angelegt werden [error]). Der korrekte Weg ist wahrscheinlich, die Messages in einer lokalen Model - Variable zu speichern und dann im Controller auf diese zuzugreifen und in den FlashMessenger "zu schmeißen", richtig?

Zusätzlich bindest du damit dein Datenmodell an das ZF und hier konkret an das MVC-Muster. Auch werden falsche Bezeichnungen verwendet, denn „$post“ in der Methode „RegisterModel::createUser“ setzt scheinbar voraus, dass es sich die HTTP-Methode „POST“ handelt. Dies wird wiederum auch noch an „Zend\Stdlib\Parameters“ gebunden, wieder die Abhängigkeit zum ZF und MVC.
Für dieses Projekt ist derzeit nichts anderes geplant, als auf das MVC zu setzen (Keine Pipelines). Mir ist gerade noch nicht bewusst, was daran falsch ist, außer das bei einem Einsatz von Pipelines der Code nicht wiederverwendet werden kann.

Übrigens stimmt die Methodensignatur deiner Fabrik nicht ganz.
Da der Parameter $containerInterface $container heißen müsste, richtig?


Nochmal herzlichen Dank für deine Antwort und deine künftigen Antworten :)
Michael
 

Kaiuwe

Super-Moderator
Die Models beinhalten in erster Linie die CRUD Funktionalität der einzelnen Doctrine-Entities. Beispielsweise enthält das UserModel die Methoden getUserById(), editUser(), deleteUser(), usw. Aus diesem Grund wird der EntityManager auch über das AbstractModel zur Verfügung gestellt.
Das ist doch über die Repositories von Doctrine bereits geregelt. Brauchst du hier eigene Funktionalitäten, dann geht das ebenfalls über Doctrine. (siehe in der Doku unter „Custom Repositories“)
Damit ist auch gleich der Name „Model“ aus deinen Klassen entfernt. ;)

Der korrekte Weg ist wahrscheinlich, die Messages in einer lokalen Model - Variable zu speichern und dann im Controller auf diese zuzugreifen und in den FlashMessenger "zu schmeißen", richtig?
Auch hier bringt Doctrine bereits etwas mit: „Events“. Bei der Verarbeitung innerhalb von Doctrine werden verschiedene Ereignisse ausgelöst. An diese Ereignisse kann man Zuhörer (Klassen) anheften und jeder Art von eigenen Aktionen ausführen. Zum Beispiel an den „Flash Messenger“ die gewünschten Nachrichten übergeben oder Mails versenden, Protokoll führen usw.
Damit hast du wiederum eine Entkopplung innerhalb des Systems umgesetzt. (siehe ebenfalls beim Entwurfsmuster „Beobachter“)
In der Doctrine-Dokumentation findest du alles unter „Events“ und für deinen Fall unter „Implementing Event Listeners“.

Für dieses Projekt ist derzeit nichts anderes geplant, als auf das MVC zu setzen (Keine Pipelines).
Selbst wenn du weiterhin auf das MVC-Muster setzt, hast du eine Abhängigkeit zum ZF. Oder eine eine Abhängigkeit zu einer bestimmten Version einer Komponente. Ich erinnere an die Wechsel von ZF1 zu ZF2 und von ZF2 zu ZF3.

…außer das bei einem Einsatz von Pipelines der Code nicht wiederverwendet werden kann.
Kann dir leider hier nicht folgen. Was soll man nicht wiederverwenden können? Wenn du mit „Pipelines“ auf „Middleware“ abzielst, dann ist genau der umgekehrte Fall korrekt: du erhöhst die Wiederverwendbarkeit.

Da der Parameter $containerInterface $container heißen müsste, richtig?
Daumen hoch!
 

michga93

New member
Klasse, danke für die zahlreichen Informationen!! Damit kann ich den Code sicher so abändern, dass es auch im Sinne des Erfinders ist :)
 
Oben