Symfony2 – Auf Servicecointainer im Validator zugreifen

In der letzten Zeit arbeite ich verstärkt mit dem Symfony2 Framework. Bei dem letzten Projekt kam es zu der Gegebenheit, dass ich aus dem einer eigenen Validatorklasse auf Parameter in der parameters.yml zugreifen musste. Das klappt aber nur mit dem Umweg über den Servicecontainer.

Die Validatorklasse

Ich nehme mal an, man schreibt sich eine eigenen Validator. Dieser besteht normalerweise aus zwei Dateien:

<?php
// src/Acme/DemoBundle/Validator/Contrainsts/UpperCase.php
namespace Acme\DemoBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class UpperCase extends Constraint
{
    public $message = 'The string "%string%" is not in uppercase format.';

    public function validatedBy()
    {
        return 'uppercasevalidator';
    }
}

Diese Klasse gibt an sich nur die Fehlermeldung aus. Auf die Funktion „validateBy()“ komme ich später zurück.

Nun brauchen wir noch den eigentlichen Validierungscode, den wir in der folgenden Datei ablegen:


<?php 
//src/Acme/DemoBundle/Validator/Contrainsts/UpperCaseValidator.php
namespace Acme\DemoBundle\Validator\Constraints; 
use Symfony\Component\Validator\Constraint; 
use Symfony\Component\Validator\ConstraintValidator; 

class UpperCaseValidator extends ConstraintValidator {     

    public function validate($value, Constraint $constraint)     {
         if (!$this->ctype_upper($value) && $this->container-getParameter('validator.active')) {
            $this->context->addViolation($constraint->message, array('%string%' => $value));
        }
    }

    protected $container;

    public function __construct($container){
        $this->container = $container;
    }

}

Das Beispiel ist zwar etwas doof gewählt, aber wir nehmen mal an, dass man unbedingt im Validator auf Parameter aus der „parameters.yml“ zugreifen muss.

Die Konfiguration

Nach ein wenig Recherche bin ich auf eine Lösung des Problems gestoßen, welche ich nun gerne mit euch teilen möchte.

Um zum Ziel zu gelangen, muss man in der „app/config/config.yml“ einen neuen Bereich einführen:

services:
    validator.unique.test:
        class: "Acme\DemoBundle\Validator\Constraints\UpperCaseValidator"
        arguments: [@service_container]
        tags:
            - { name: validator.constraint_validator, alias: uppercasevalidator }

Das wichtige dabei ist, dass

  • Die Pfadangabe unter „class“ keine Tippfehler enthält
  • Der „alias“-Parameter genauso heißt, wie die Rückgabe der Funktion „validateBy()“.

Ansonsten sollte der Rest des Codes soweit verständlich sein. Die Konfiguration übergibt der Validator-Klasse den Servicecontainer als Argument, und diesen fangen wir im Konstruktor auf. Danach können wir den ganz normal innerhalb des Validators nutzen.

~Sebastian