Zend Framework 2: Factory mit Optionen

Es ist Freitag und wie fast jeden Freitag soll es auch heute einen kleinen Tipp aus meinem Alltag geben. Aktuell arbeite ich sowohl mit dem Zend Framework 2 als auch mit dem Zend Framework 3. Im Zend Framework 2 war es mir bisher immer ein Rätsel, wie ich Optionen an eine Service Factory weiter geben kann. Diese Woche kam dann die Erleuchtung.
 

Was ist eine Factory?

Eine Factory ist wohl eines der am meisten benutzten Design Patterns in PHP. Eine Factory ist in den meisten Fällen eine simple Klasse, die eine Instanz einer anderen Klasse erzeugt und zurück gibt. Ein großer Vorteil der Factory ist, dass die Erzeugung eines Objektes allein in der Factory stattfindet. Ändert sich die Erzeugung dieses Objektes, muss man sie nicht an verschiedenen Stellen im Code selbst, sondern nur in der Factory ändern. Ein weiterer Vorteil ist, dass komplexe Initialisierungen in einer Factory abgehandelt werden können. So muss viel Code nur in der Factory anstatt an mehreren Stellen im Programm geschrieben werden. Man vermeidet also Aufwand.
 

Wie sieht so eine Factory im Zend Framework 2 aus?

Im Zend Framework spricht man von Services, die über die ganze Software verteilt durch den Service Manager abgerufen werden können. Diese Services sind nichts anderes als Klassen, die sich zum Beispiel um die Authentifizierung eines Users oder um den Zugriff auf eine Datenbanktabelle kümmern. In der Regel werden diese Services über eine Factory erzeugt und im Service Manager abgelegt.

Als Beispiel soll uns der PostCode Validator des Zend Framework 2 dienen. Diesen wollen wir über eine Factory mit dem entsprechenden Ländercode aufrufen. Dieser Ländercode wurde zuvor durch den User in einem Formular angegeben. Hier mal eine einfache Factory.

namespace Application\I18n\Validator\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class PostCodeValidatorFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $oServiceLocator){

    }
}

Mit dieser Factory würden wir lediglich den Validator ausliefern? Wie soll der Validator wissen, um welches Land es sich eigentlich handelt, um die Postleitzahl dann richtig zu validieren? Richtig. Wir benutzen Optionen für die Factory. Mit dem MutableCreationOptionsInterface, welches das Zend Framework 2 mitliefert, kann das ziemlich leicht erledigt werden. Hierzu erweitern wir unsere Factory ein wenig.

namespace Application\Form\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\MutableCreationOptionsInterface;

class PostCodeValidatorFactory implements FactoryInterface, MutableCreationOptionsInterface
{
    protected $options;

    public function setCreationOptions( array $aOptions )
    {
        $this->options = $aOptions;
    }

    public function createService(ServiceLocatorInterface $oServiceLocator){

    }
}

In einem Controller würden wir den Validator mit einem optionalen „country_code“ Parameter also wie folgt aufrufen:

$oForm = $oServiceManager->get('ValidatorManager')->get(
    PostCode::class,
    [ 'locale_code' => $this->params()->fromPost('country') ]
);

Die komplette Factory

Die komplette Factory inklusive der Initialisierung des PostCode Validators würde dann wie folgt aussehen.

namespace Application\Form\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\MutableCreationOptionsInterface;

use Zend\I18n\Validator\PostCode;

class PostCodeValidatorFactory implements FactoryInterface, MutableCreationOptionsInterface
{
    protected $options;

    public function setCreationOptions( array $aOptions )
    {
        $this->options = $aOptions;
    }

    public function createService(ServiceLocatorInterface $oServiceLocator){
        $oValidator = new PostCode($this->options['locale_code']);
        return $oValidator;
    }
}

Durch den Einsatz des MutableCreationOptionsInterface wird die setCreationOptions Methode in der Factory implementiert. Somit können wir auf alle Optionen für die Initialisierung des PostCode Validators zugreifen. In diesem Fall ist es die Locale Option, die das Land des Users aus einer zuvor getätigten Angabe in einem Formular beinhaltet. Hat der User also Deutschland als sein Heimatland angegeben, initialisieren wir hier den PostCode Validator also mit der de_DE Angabe und schon werden fünfstellige Postleitzahlen als richtig validiert.

Fazit

Sicherlich ist das Beispiel mit dem PostCode Validator ein wenig unglücklich gewählt, weil der PostCode Validator als Konstruktor Parameter ohnehin das locale Attribut entgegen nimmt. Dennoch veranschaulicht das Beispiel auf eine ganz einfache Art und Weise den Einsatz des MutableCreationOptionsInterface. Ich muss also Parameter nicht umständlich so lange an Konstruktoren übergeben, bis sie letztendlich an der richtigen Stelle angekommen sind. Ich habe dies mangels Wissen im Artikel über Validatoren mit Zugriff auf die Datenbank etwas umständlich beschrieben. Mit dem Einsatz von Optionen in der Factory wäre das sicherlich einfacher gegangen.

Haben wir also wieder was gelernt.
 
Bildquelle: Pixabay / CC0 Licence

Kommentar verfassen

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.