2016-05-26 7 views
0

Ich bin mir bewusst, dass vielleicht die Art und Weise, wie ich die Validator-Komponente von Symfony verwenden möchte, nicht möglich ist. Hier ist die Idee.Symfony Validator Komponente Problem in Standalone-Anwendung

Ich habe eine Klasse namens Package, die nur eine Eigenschaft namens Namespace hat. Normalerweise würde ich die ClassMetadata und alle Constraint-Objekte, die ich validieren möchte, in meine Package-Klasse aufnehmen. Meine Idee ist jedoch, dass ich statt dessen lieber mein Thema sauber halte und nur für die Dinge verantwortlich bin, für die es verantwortlich sein muss.

Unten finden Sie eine Klasse schrieb ich und es nennen PackageValidater:

<?php 
use Symfony\Component\Validator\Constraints as Assert; 
use Symfony\Component\Validator\Mapping\ClassMetadata; 
use Symfony\Component\Validator\Validation; 

class PackageValidator 
{ 
    protected $subject; 

    public function PackageValidator($subject){ 
    $this->subject = $subject; 
    } 

    public static function loadMetadata(){ 
    $metadata->addPropertyConstraint('namespace', new new Assert\Type(['type' => 'string'])); 
    } 

    public function getViolations(){ 
    $validator = Validation::createValidatorBuilder() 
     ->addMethodMapping('loadMetadata') 
     ->getValidator(); 

    $violations = $validator->validate($this->subject); 

    return !empty($violations) ? $violations : []; 
    } 

    } 

Trotz der Tatsache, dass ich über die Verwendung meiner Einschränkung bin nicht sicher, da die meisten Referenz Anmerkungen verwendet und ich, können wir nicht ignorieren, dass Teil. Ich bin mir auch der Tatsache bewusst, dass mein Test aufgrund dieser Tatsache fehlschlägt. Mein Problem liegt jedoch in meinem Design, da ich die statische Funktion, die das Validierungsobjekt zum Erstellen der Validierung verwendet, nicht hinzugefügt habe. Anstatt meiner Methode zuzuordnen, wo sich Constraints in dem tatsächlichen Objekt befinden, befindet es sich in einer separaten Klasse.

Die Idee ist, Durchsetzung von Bedenken und einzige Verantwortung auf meine Objekte zu erzwingen. Unten ist ein Diagramm, das genau das, was zeigt ich zu erreichen versuche:

enter image description here

ich meinen Test wie unten gezeigt geschrieben haben:

$packageValidator = new PackageValidator(new Package([0 => 'test'])); 
$this->assertTrue(true, empty($packageValidator->getViolations())); 

Above Ich habe in einem Array anstelle eines String übergeben Das würde meinen Test zum Scheitern bringen, weil es niemals einen einzigen Namespace in einer Array-Form geben kann - zumindest nicht in dem, was ich versuche zu erreichen. Das Problem tritt mit meiner Methode getViolations im PackageValidator-Objekt auf, weil ich mein Thema nicht außerhalb des Kontextes meines Validierungsprozesses übergebe, der die Subjektmetadaten innerhalb des Subjekts selbst definiert, wenn das Validatorobjekt mit dem Verweis auf das Objekt abgerufen wird Die Metadaten des Subjekts erhalten die Validierungsfehler.

Alles in allem Package hat keine loadMetadata-Methode, aber PackageValidator. Wie kann ich dies ermöglichen, ohne jedes Objekt zu belasten, das ich mit der Metadatenfunktion validieren möchte?

Unten ist das, was ich von PHPUnit erhalten:

SimplexTest \ Validate \ Package \ PackageValidatorTest :: testIfValidatorInterfaceWorks Symfony \ Component \ Validator \ Exception \ Runtime: Kann nicht Validate Werte vom Typ "NULL" automatisch. Bitte geben Sie eine Einschränkung an.

Antwort

1

Sie können die XML- oder XML-Konfiguration verwenden, um Ihrem Objekt Abhängigkeiten hinzuzufügen.

http://symfony.com/doc/current/book/validation.html#the-basics-of-validation

Sie tun dies, indem Sie eine Datei validation.yml in Ihrem Bundle Konfigurationsverzeichnis genannt zu schaffen.Fügen Sie den folgenden Inhalt Ihres Objekts zu überprüfen:

Some\Name\Space\Package: 
    properties: 
     name: 
      - NotBlank: ~ 

, dass ein Weg, die Dinge halten Sie keine Verantwortung für Ihr Objekt aus dem Objekt betrachten. Darüber hinaus entfällt die Notwendigkeit einer benutzerdefinierten Validierungsklasse für jedes von Ihnen erstellte Objekt. Sie können einfach den Validator-Service nutzen, der bereits vom Framework bereitgestellt wird.

bearbeiten

Okay Ich glaube, ich etwas herausgefunden Sie vielleicht suchen: Sie MetadataFactory erstellen Metadata, wie Sie wollen zu laden. Es gibt ein paar Beispiele hier: https://github.com/symfony/validator/tree/master/Mapping/Factory

Es läuft im Grunde auf eine Factory-Klasse, die eine Instanz MetadataInterface zurückgibt, wo Sie Ihre Einschränkungen anhängen. Dies bedeutet, dass Sie die Factory Metadaten von allem lesen lassen können. Sie könnten zum Beispiel so etwas wie folgt aus:

use Symfony\Component\Validator\Constraints as Assert; 
use Symfony\Component\Validator\Mapping\ClassMetadata; 
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; 
use Your\Package; 

class PackageMetadataFactory implements MetadataFactoryInterface 
{ 
    /** 
    * Create a ClassMetaData object for your Package object 
    * 
    * @param object $value The object that will be validated 
    */ 
    public function getMetadataFor($value) 
    { 

     // Create a class meta data object for your entity 
     $metadata = new ClassMetadata(Package::class); 

     // Add constraints to your metadata 
     $metadata->addPropertyConstraint(
      'namespace', new Assert\Type(['type' => 'string'])); 

     // Return the class metadata object 
     return $metadata; 
    } 

    /** 
    * Test if the value provided is actually of type Package 
    * 
    * @param object $value The object that will be validated 
    */ 
    public function hasMetadataForValue($value) 
    { 
     return $value instanceof Package::class; 
    } 
} 

Dann in Ihrem PackageValidator alles, was Sie tun müssen, ist:

use Symfony\Component\Validator\Mapping\ClassMetadata; 
use Symfony\Component\Validator\Validation; 
use Your\PackageMetadataFactory; 

class PackageValidator 
{ 
    protected $subject; 

    public function PackageValidator($subject) { 
     $this->subject = $subject; 
    } 

    public function getViolations() { 
     $validator = Validation::createValidatorBuilder() 
      ->setMetadataFactory(new PackageMetadataFactory()) 
      ->getValidator(); 

     $violations = $validator->validate($this->subject); 

     return !empty($violations) ? $violations : []; 
    } 

} 

Hoffentlich ist mehr im Einklang, was Sie suchen.

+0

Danke @ Bloodline ... Vielleicht habe ich vergessen zu erwähnen, dass dieses Setup für eine Anwendung ist, die nicht in Symfony selbst ist. Ich bin mir der Verwendung der Komponente in Symfony sehr bewusst, aber nicht, wenn ich sie außerhalb verwende. Ich wollte auch nicht Xml, Yml und oder Annotations verwenden, um meine Constraints zu verbinden, sondern habe stattdessen ein Abject, das dafür verantwortlich ist, jedes Objekt zu validieren, das ich validieren möchte. Hoffnung, die Sinn macht. Nochmals vielen Dank für Ihre Antwort. – Maximum86

+0

@LuyandaSiko Ja, es macht jetzt Sinn. Ich habe nicht realisiert, dass Sie nicht den gesamten Rahmen nutzen. Wie ich es in den Dokumenten sehe, sagt 'addMethodMapping' dem Validator, welche Methode für den '$ Subjekt', den Sie validieren, aufgerufen wird, also bezweifle ich, dass das funktioniert. Ich werde darüber nachdenken und zu dir zurückkommen, wenn ich dir etwas einfallen lasse, damit dein Design funktioniert. –

+0

Danke. Ich habe versucht, die addMethodFactory für die Validierung zu verwenden, aber das ist fehlgeschlagen. Ich habe beschlossen, diesen Teil meiner Logik zu unterbrechen und zu anderen überzugehen, in der Hoffnung, später darauf zurückzukommen. Es wäre toll, wenn Sie einen Weg finden würden, bevor ich es tue, weil ich denke, dass diese Komponente großartig ist, außer dass sie nicht offen für eine andere Verwendung ist (ohne XML, YML oder Anmerkungen), außer dem Hinzufügen der Zuordnungsmethode für Einschränkungen innerhalb des zu validierenden Objekts. Für mich ist das wirklich ein Kick in den Bauch, es sei denn ich verpasse etwas an der gesamten Komponente. Danke für Ihre Hilfe. – Maximum86

0

Ich habe Ihren Vorschlag oben, wie Sie es formuliert haben, gefolgt. Das einzige, was ich ändern musste, war die Implementierung der hasMetadaFor-Methode in der PackageMetadataFactory. Im Folgenden schaue ich eher nach der Existenz von Immobilien.

public function hasMetadataFor($value){ 
return property_exists(Package::class, $value); 
} 

Alles andere, wie Sie vorgeschlagen, funktioniert perfekt. Unten ist meine Testfunktion.

$validator = new PackageValidator(new OrderPackage(125787618)); 
$this->assertSame(true, $validator->validates()); 

Der Test schlägt fehl, da der Namespace keine Zahlen sein kann. Wenn Sie den vollständig qualifizierten Klassennamen des OrderPackage übergeben, indem Sie OrderPackage :: class ausführen, wird das Objekt überprüft.

Vielen Dank für Ihren Rat.

+0

Ich bin froh, dass es für dich geklappt hat :) Ich habe selbst etwas gelernt, also profitieren wir alle, haha: D –

+1

Ja.Ich war so nah dran, nur dass ich nicht wirklich darauf eingehen konnte. Ich wusste jedoch, dass dies möglich ist und dies ist für mich der eleganteste Weg, ohne Extras zu verwenden und sicherzustellen, dass die Logik der Validierung eines Objekts vom zu validierenden Objekt isoliert ist. Das war die größte Errungenschaft und ich hätte es nicht ohne Hilfe tun können. Vielen Dank – Maximum86

Verwandte Themen