簡體   English   中英

獨立Applicatin中的Symfony驗證程序組件問題

[英]Symfony Validator Component issue in Standalone Applicatin

我意識到也許我無法利用Symfony中的Validator Component的方式。 這是主意。

我有一個名為Package的類,目前只有一個名為namespace的屬性。 通常,我會在Package類中包含ClassMetadata和要驗證的任何約束對象。 但是,我的想法是,與其說那樣做,不如讓我的主題保持整潔,只對它必須負責的事情負責。

下面是我編寫的一個類,並將其稱為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 : [];
   }

  }

盡管我不確定約束的用法,因為大多數參考文獻都使用注解,但我不能忽略這一部分。 我也知道由於這個原因我的測試失敗。 但是,我的問題是我的設計,因為我沒有添加Validation對象用來構建驗證的靜態函數。 我的方法映射位於單獨的類中,而不是約束位於實際對象中的方法映射。

這個想法是要在我的對象上強制分離關注點單一責任 下面的圖表准確地描述了我要實現的目標:

在此處輸入圖片說明

我已經編寫了如下的測試:

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

在上面,我傳遞了一個數組而不是一個字符串,這會使我的測試失敗,因為永遠不可能有一個以數組形式存在的名稱空間-至少不是我要實現的名稱空間。

問題在於我的PackageValidator對象中的getViolations方法,因為我沒有將主題傳遞到驗證過程的上下文之外,該驗證過程在主題本身內部定義了主題元數據,然后在獲取驗證者對象時引用了對象的元數據,因此驗證錯誤。

總而言之,Package沒有loadMetadata方法,而是PackageValidator。 如何在不污染我要使用元數據功能驗證的每個對象的情況下實現這一目標?

以下是我從PHPUnit獲得的信息:

SimplexTest \\ Validate \\ Package \\ PackageValidatorTest :: testIfValidatorInterfaceWorks Symfony \\ Component \\ Validator \\ Exception \\ RuntimeException:無法自動驗證“ NULL”類型的值。 請提供一個約束。

您可以使用yml或xml配置向您的對象添加約束。

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

為此,您可以在Bundle配置目錄中創建一個名為validation.yml的文件。 添加以下內容以驗證您的對象:

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

這是使您不認為對自己的對象負責的事情脫離所述對象的一種方法。 它還消除了對您創建的每個對象的自定義驗證器類的需求。 您可以簡單地利用框架已經提供的驗證器服務。

編輯

好的,我想我已經找到了您可能正在尋找的東西:您可以創建一個MetadataFactory以所需的方式加載Metadata 這里有幾個示例: https : //github.com/symfony/validator/tree/master/Mapping/Factory

它基本上可以歸結為一個Factory類,該類返回您在其中附加約束的MetadataInterface實例。 這意味着您可以讓Factory從任何內容讀取元數據。 例如,您可以執行以下操作:

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;
    }
}

然后,在PackageValidator您要做的就是:

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 : [];
    }

}

希望這更符合您的需求。

正如您所說的,我遵循了您的建議。 我唯一需要更改的是PackageMetadataFactory內部的hasMetadaFor方法實現。 下面是我寧願檢查屬性是否存在的方式。

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

您建議的其他所有內容都可以正常運行。 下面是我的測試功能。

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

測試失敗,因為名稱空間不能為數字。 通過執行OrderPackage :: class傳遞OrderPackage的完全限定的類名,將驗證對象。

非常感謝您的建議。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM