2016-07-05 86 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():分隔符不能是字母数字或反斜杠' –