2016-07-05 123 views
2

你如何通過MoneyType Field驗證表單帖子?如何驗證Symfony表單輸入MoneyType?

這是夠糟糕的it uses input type="text" instead of type="number",但糟糕的是它什麼並不重要的輸入,像「ASDF」的反應總是:valid form posted.我怎樣才能得到有用的錯誤信息,指示用戶,他們需要把一個有效金額,如「43.21」

我在控制器試圖'error_bubbling' => true上添加選項,在樹枝視圖{{ form_errors(form) }},並通過$form->getErrors()作爲this answer建議,但那些總是空的,因爲不管是什麼,$form->isValid()總是返回true不管用戶輸入。


項目結構:

. 
├── composer.json 
├── composer.lock 
├── pub 
│   └── scratch.php 
├── vendor 
│   └── ... 
└── views 
    └── form.html.twig 

scratch.php

<?php require_once __DIR__.'/../vendor/autoload.php'; 
use Symfony\Component\Form\Forms; 
use Symfony\Component\Form\Extension\Core\Type\MoneyType; 
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationExtension; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\Translation\Translator; 
use Symfony\Bridge\Twig\Form\TwigRenderer; 
use Symfony\Bridge\Twig\Form\TwigRendererEngine; 
use Symfony\Bridge\Twig\Extension\FormExtension; 
use Symfony\Bridge\Twig\Extension\TranslationExtension; 

// the Twig file that holds all the default markup for rendering forms 
// this file comes with TwigBridge 
$defaultFormTheme = 'form_div_layout.html.twig'; 

$appVariableReflection = new \ReflectionClass('\Symfony\Bridge\Twig\AppVariable'); 
$vendorTwigBridgeDir = dirname($appVariableReflection->getFileName()); 
// the path to your other templates 
$viewsDir = realpath(__DIR__.'/../views'); 

$twig = new Twig_Environment(new Twig_Loader_Filesystem(array(
    $viewsDir, 
    $vendorTwigBridgeDir.'/Resources/views/Form', 
))); 
$formEngine = new TwigRendererEngine(array($defaultFormTheme)); 

$twig->addExtension(
    new FormExtension(new TwigRenderer($formEngine)) 
); 

$twig->addExtension(
    new TranslationExtension(new Translator('en')) 
); 

$formEngine->setEnvironment($twig); 

// create your form factory as normal 
$formFactory = Forms::createFormFactoryBuilder() 
    ->addExtension(new HttpFoundationExtension()) 
    ->getFormFactory(); 

$formBuilder = $formFactory->createBuilder(); 

$formBuilder->add("amount", MoneyType::class, [ 
    'currency' => 'USD', 
    'error_bubbling' => true 
]); 

$form = $formBuilder->getForm(); 

$request = Request::createFromGlobals(); 

$form->handleRequest($request); 

if ($form->isValid()) { 

    die('valid form posted.'); 

} 

$form->getErrors(true); 

echo $twig->render('form.html.twig', array(
    'form' => $form->createView(), 
)); 

form.html.twig

{{ form_start(form) }} 

    {{ form_errors(form) }} 

    {{ form_widget(form) }} 

    <input type="submit" /> 

{{ form_end(form) }} 

composer.json

{ 
    "require": { 
     "symfony/form": "^3.1", 
     "symfony/twig-bridge": "^3.1", 
     "symfony/translation": "^3.1", 
     "symfony/http-foundation": "^3.1" 
    } 
} 
+0

什麼是你的 'scratch.php' 文件的目的是什麼?爲什麼不使用控制器文件?我只是問,因爲'scratch.php'文件中有很多代碼似乎不是必需的......並且您也將它放在不是Symfony標準的pub文件夾下。也許你有這樣一個創建項目的原因 - 你能解釋一下嗎? –

+0

@AlvinBunk獨立最小,完整,可驗證的例子。我沒有使用這個框架,用Symfony測試水域,因爲這些組件被認爲是模塊化的。 –

+0

爲什麼不簡單地使用NumberType字段而不是MoneyType作爲用例? – Alsatian

回答

0

我想通了,我錯過了Validator component

use Symfony\Component\Validator\Validation; 

// Set up the Validator component 
$validator = Validation::createValidator(); 

然後,我需要將validator extension添加到表單工廠。

use Symfony\Component\Form\Extension\Validator\ValidatorExtension; 

// create your form factory as normal 
$formFactory = Forms::createFormFactoryBuilder() 
    ... 
    ->addExtension(new ValidatorExtension($validator)) 
    ... 

當然,這需要composer require symfony/validator

所以,我沒有需要

  • $form->getErrors(true)
  • 'error_bubbling' => true
  • {{ form_errors(form) }}

scratch.php

<?php require_once __DIR__.'/../vendor/autoload.php'; 
use Symfony\Component\Form\Forms; 
use Symfony\Component\Form\Extension\Core\Type\MoneyType; 
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationExtension; 
use Symfony\Component\Form\Extension\Validator\ValidatorExtension; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\Translation\Translator; 
use Symfony\Component\Validator\Validation; 
use Symfony\Bridge\Twig\Form\TwigRenderer; 
use Symfony\Bridge\Twig\Form\TwigRendererEngine; 
use Symfony\Bridge\Twig\Extension\FormExtension; 
use Symfony\Bridge\Twig\Extension\TranslationExtension; 

// the Twig file that holds all the default markup for rendering forms 
// this file comes with TwigBridge 
$defaultFormTheme = 'form_div_layout.html.twig'; 

$appVariableReflection = new \ReflectionClass('\Symfony\Bridge\Twig\AppVariable'); 
$vendorTwigBridgeDir = dirname($appVariableReflection->getFileName()); 
// the path to your other templates 
$viewsDir = realpath(__DIR__.'/../views'); 

$twig = new Twig_Environment(new Twig_Loader_Filesystem(array(
    $viewsDir, 
    $vendorTwigBridgeDir.'/Resources/views/Form', 
))); 
$formEngine = new TwigRendererEngine(array($defaultFormTheme)); 

$twig->addExtension(
    new FormExtension(new TwigRenderer($formEngine)) 
); 

$twig->addExtension(
    new TranslationExtension(new Translator('en')) 
); 

$formEngine->setEnvironment($twig); 

// Set up the Validator component 
$validator = Validation::createValidator(); 

// create your form factory as normal 
$formFactory = Forms::createFormFactoryBuilder() 
    ->addExtension(new HttpFoundationExtension()) 
    ->addExtension(new ValidatorExtension($validator)) 
    ->getFormFactory(); 

$formBuilder = $formFactory->createBuilder(); 

$formBuilder->add("amount", MoneyType::class, [ 
    'currency' => 'USD' 
]); 

$form = $formBuilder->getForm(); 

$request = Request::createFromGlobals(); 

$form->handleRequest($request); 

if ($form->isValid()) { 

    die('valid form posted.'); 

} 

$form->getErrors(true); 

echo $twig->render('form.html.twig', array(
    'form' => $form->createView(), 
)); 

form.html.twig

{{ form_start(form) }} 

    {{ form_widget(form) }} 

    <input type="submit" /> 

{{ form_end(form) }} 

composer.json

{ 
    "require": { 
     "symfony/form": "^3.1", 
     "symfony/twig-bridge": "^3.1", 
     "symfony/translation": "^3.1", 
     "symfony/http-foundation": "^3.1" 
     "symfony/validator": "^3.1" 
    } 
} 
0

你有一個或多個約束連接到你的表單字段是這樣的:

use Symfony\Component\Validator\Constraints\Regex; 

$formBuilder->add("amount", MoneyType::class, [ 
    'currency' => 'USD', 
    'error_bubbling' => true, 
    'constraints' => [ 
    new Regex(array('pattern'=>'/\d+(\.\d+)?/','message'=>'must be numeric')), 
    ] 
]); 

然後,如果違反約束消息「必須是數字」會顯示你的表單不會有效。

內置約束定義如下: http://symfony.com/doc/current/reference/constraints.html

驗證使用在此說明: http://symfony.com/doc/current/book/forms.html#using-a-form-without-a-class

+0

致命錯誤:帶有消息「選項」約束的'Symfony \ Component \ OptionsResolver \ Exception \ UndefinedOptionsException'未捕獲的異常' –

+0

'驗證器組件是否仍然存在此錯誤? – Alsatian

+0

感謝您檢查,但實際上這個答案存在很多問題。 1)你的'use'語句有一個錯字,應該是複數'Constraints'而不是單個'Constraint'。 2)它沒有捕獲字母字符 - 可能是因爲默認的MoneyType驗證器勝過它。 3)它失敗了一個有效的數量,比如「12.34」,並且它拋出一個PHP警告'preg_match():分隔符不能是字母數字或反斜槓' –