I'm trying to add a Select2 input using the GenemuFormBundle as described in the "Use jQuery Select2 with Ajax" doc. Adding a jQuery Select2 Field following the jQuery Select2 Field documentation works just fine.
But the documentation on how to implement an Ajax-loading Select2 form is very inconclusive. If I unterstand the doc correctly, it aims to create the same as mentioned in the Select2 documentation. This is exactly the thing I'd like to create. I added hidden field as well as the required JavaScript, but the only thing that I get is a Variable "id" does not exist in xBundle:x:new.html.twig at line x.
Form builder (taken directly form the mentioned doc):
...
->add('field_name', 'genemu_jqueryselect2_hidden', array(
'configs' => array(
'multiple' => true // Wether or not multiple values are allowed (default to false)
)
))
->add('field_name', 'genemu_jqueryselect2_entity', array(
'class' => 'xBundle:Entity',
'property' => 'foo',
))
View (also taken directly form the doc):
{% block stylesheets %}
{{ form_stylesheet(form) }}
{% endblock %}
{% block javascript %}
{{ form_javascript(form) }}
{% endblock %}
{% block genemu_jqueryselect2_javascript %}
<script type="text/javascript">
$field = $('#{{ id }}');
var $configs = {{ configs|json_encode|raw }};
// custom configs
$configs = $.extend($configs, {
query: function (query) {
var data = {results: []}, i, j, s;
for (i = 1; i < 5; i++) {
s = "";
for (j = 0; j < i; j++) {s = s + query.term;}
data.results.push({id: query.term + i, text: s});
}
query.callback(data);
}
});
// end of custom configs
$field.select2($configs);
</script>
{% endblock %}
I just struggled with this exact issue and thought I would throw in my own findings for anyone that happens to stumble across this. I did find a solution, but I would probably still recommend just going with the ZenStruckFormBundle recommended by Doug because it seems to actually be designed to work as a solution for a select2 field type that loads via ajax and relates back to an entity.
The real reason this doesn't work is that the the genemu_jqueryselect2_* types for the GenemuFormBundle do not implement a data transformer that will work with an entity when you need an ajax-loading select2 field. It doesn't seem like it was ever designed to work this way. When you use the genemu_jqueryselect2_hidden type and have the “multiple’ config option set to true, then it adds an ArrayToStringTransformer. This will not work with an entity.
To fix this you need to make a new form field type and define that its parent is genemu_jqueryselect2_hidden then make a few customizations. It would look something like this…
namespace Acme\DemoBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Acme\DemoBundle\Form\DataTransformer\EntityCollectionToIdTransformer;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class EntityCollectionSelectorType extends AbstractType
{
/**
* #var ObjectManager
*/
protected $om;
/**
* #param ObjectManager $om
*/
public function __construct(ObjectManager $om)
{
$this->om = $om;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new EntityCollectionToIdTransformer($this->om, $options['configs']['entity']);
$builder->resetViewTransformers();
$builder->addModelTransformer($transformer);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'invalid_message' => 'The selected entity does not exist',
'required' => true,
'auto_initialize' => false,
'configs' => array('multiple' => true),
'error_bubbling' => false,
));
}
public function getParent()
{
return 'genemu_jqueryselect2_hidden';
}
public function getName()
{
return 'entity_collection_selector';
}
}
Then you will also need to add the new data transformer used in the above form field type, so that it can translate the values between the form field and the entity…
namespace Acme\DemoBundle\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Doctrine\ORM\PersistentCollection;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\Collections\ArrayCollection;
class EntityCollectionToIdTransformer implements DataTransformerInterface
{
/**
* #var ObjectManager
*/
private $om;
/**
* #var string The Doctrine entity type to use
*/
private $entityType;
/**
* #param ObjectManager $om
*/
public function __construct(ObjectManager $om, $entityType)
{
$this->om = $om;
$this->entityType = $entityType;
}
/**
* Transforms a collection of entities to a comma separated string
*
* #param ArrayCollection $entities
* #return string
*/
public function transform($entities)
{
if (null == $entities || empty($entities)) {
return '';
}
$results = '';
foreach ($entities as $entity) {
$results .= $entity->getId() . ',';
}
$results = trim($results, ' ,');
return $results;
}
/**
* Transforms a string of comma separated IDs to a PersistentCollection for Doctrine
*
* #param string $values
* #return PersistentCollection|ArrayCollection
* #throws TransformationFailedException if entity is not found.
*/
public function reverseTransform($values)
{
if (!$values) {
return new ArrayCollection();
}
$values = explode(',', $values);
$collection = array();
foreach ($values as $id) {
$item = $this->om->getRepository($this->entityType)->findOneById($id);
if (!is_null($item)) {
$collection[] = $item;
}
else {
throw new TransformationFailedException(sprintf(
'An entity with ID "%s" does not exist!',
$value
));
}
}
return new PersistentCollection($this->om, $this->entityType, new ArrayCollection($collection));
}
}
Now make sure you define your new field type in your config for your services…
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
...
<parameter key="acme_demo.form.type.entity_collection_selector.class">Acme\DemoBundle\Form\Type\EntityCollectionSelectorType</parameter>
...
</parameters>
<services>
...
<service id="acme_demo.form.type.entity_collection_selector"
class="%acme_demo.form.type.entity_collection_selector.class%">
<argument type="service" id="doctrine.orm.default_entity_manager" />
<tag name="form.type" alias="entity_collection_selector" />
</service>
...
</services>
</container>
Now you can use it as such…
$builder->add('customers', 'entity_collection_selector', array(
'configs' => array('entity' => 'AcmeDemoBundle:Customer')
));
Related
Im working on a project where I'm using some Symfony Components. My problem is how to make the Form Component's validation of Forms use AnnotationMapping to find the constraints.
SetUp:
global $loader; //composer - autoload
AnnotationRegistry::registerLoader([$loader, 'loadClass']);
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator();
$formFactory = Forms::createFormFactoryBuilder()
[...]
->addExtension(new ValidatorExtension($validator))
->getFormFactory();
Entity
/**
* #ORM\Entity
* #ORM\Table(name="..")
*/
class Conductor extends AbstractEntity {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string")
*/
protected $pattern;
[...]
}
Building the Form
$builder = $App->getFormFactory()->createBuilder(FormType::class, $entity_data);
foreach ($fields as $field) {
$builder->add(
$field,
null,
[
"attr" => array("class" => "..."),
]
);
}
$builder->getForm();
FormSubmit / Validation
if($request->isMethod('POST')) {
$formTable = $this->createFormTable( array() );
$form = $formTable->buildForm($entity);
$form->submit($this->dataMapper->formDataFromPost());
/*
$entity = $this->dataMapper->mapFromPost();
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator();
*/
if($form->isValid()) {
[...]
} else {
[...]
}
}
Im trying to make the NotBlank() Constraints work. But my form passes the validation in any case. If I use a new validator and validate with it, it will show me the correct Errors. But the Form->isValid() function does not. Maybe it is not configured correctly to use AnnotationMapping? Thank you very much in advance for tipps or solutions!
Problem localization
The form handleRequest / submit and validation are working as expected!
The form does not have any constraints!!
-> Mapping the Constraints from Annotation is not happening / working.
I did find a similar question: Why does Symfony form not validate my DTO with constraint annotations?
I wasn't able to find a solution to enable the mapping that should happen inside the FormComponent with the ValidatorExtension.
But I did find a functional workaround. My approach is to get the Constraints from the readPropertyMetadata function of the validator:
use Symfony\Component\Validator\Validation;
public function buildForm(AbstractEntity $entity) {
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator();
$fields = [*ENTITY PRPERTIES*];
$classMeta = $validator->getMetadataFor($entity);
foreach ($fields as $field) {
$metadata = $classMeta->getPropertyMetadata($field);
if(is_array($metadata) && count($metadata) > 0) {
$constraints = $classMeta->getPropertyMetadata($field)[0]->constraints;
} else {
$constraints = [];
}
$builder->add(
$field,
null,
[
"attr" => array("class" => "..."),
"constraints" => $constraints
]
);
}
}
As now the constraints are added to the form the validation finally works as expected.
I've an use case where i need some default conditional logic on my dynamic form build in Symfony 5.
Let me try to explain what my use case is and my problem with a simple form.
For example i've a form Product with two fields:
Part (choiceType => left, right)
Length (numberType)
On change all fields (:input) are being submitted through an Ajax request.
I've two controller methods one for visiting the page (form is being build), the other
is being called for rendering the form through the ajax request (handle conditional logic).
For the conditional logic part the following needs te be done
When part is left, default length needs to be 50
When part is right, default length needs to be 100
user could change default data
Setting the default data on length based on left or right is not the problem.
When left is selected, default length becomes 50. When changing the value to 55 (form is being submitted through every change) it becomes 50 again.
This behaviour is logic, but how could the default data been overwritten?
Above situation could also been described as give user default data with option to change it
form type
<?php
// ... namespace, use statments
class ProductType extends AbstractType
{
/**
* {#inheritDoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('part', ChoiceType::class, array(
'choices' => array(
'Left' => 'left',
'Right' => 'right',
)
));
$builder->add('length', NumberType::class);
$builder->addEventListener(FormEvents::POST_SET_DATA, function(FormEvent $event) use ($options)
{
$form = $event->getForm();
if(null === $product = $event->getData()) {
return;
}
switch($product->getPart()) {
case 'left': $defaultLength = 50; break;
case 'right': $defaultLength = 100; break;
default: $defaultLength = 0;
}
$form->get('length')->setData($defaultLength);
});
}
/**
* {#inheritDoc}
*/
public function getName(): string
{
return 'product';
}
/**
* {#inheritDoc}
*/
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(array(
'data_class' => Product::class,
'translation_domain' => 'forms',
));
}
}
controller
// src/Controller/ProductController.php
// ... namespace, use statments
namespace App\Controller;
class ProductController extends AbstractController
{
public function productAction(Request $request): Response
{
$product = new Product();
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$product = $form->getData();
dd($product);
}
return $this->render('product_view.html.twig', array(
'form' => $form->createView()
));
}
public function productConfigureAjaxAction(Request $request): Response
{
$product = new Product();
$part = $request->request->get('product')['part'] ?? null;
$product->setPart($part);
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
// product_form.html.twig is an separated file and included in product_view.html.twig
// by making the form separated is could been used for an ajax response
return $this->render('product_form.html.twig', array(
'form' => $form->createView()
));
}
}
I've extended Symfony's EntityType as UserChooserType for use with my User entity and Select2. The choice list for the UserChooserType comes from an ldap query (via an ajax call), not a Doctrine query. So the field starts out blank.
The User entity is related to many different entities across my application. But if I want the UserChooserType to load with a current the selected User I have to add a listener to every form that uses it. e.g.:
class SiteType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$siteAdminOpts = array('label' => 'entity.site.admin', 'required'=>false);
//opts for the UserChooserType
$builder
->add('siteName', FT\TextType::class, array('label' => 'entity.site.name'))
->add('siteAdmin', UserChooserType::class, $siteAdminOpts )
//must be added to every form type that uses UserChooserType with mod for the datatype that $event->getData() returns
->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
$site = $event->getData();
$form = $event->getForm(); //SiteType
if($user = $site->getSiteAdmin()) $siteAdminOpts['choices'] = array($user);
$form->add('siteAdmin', UserChooserType::class, $siteAdminOpts);
});
}
//etc.
tldr;
I'd like to either:
set UserChooserType's choices option to the selected user in UserChooserType::configureOptions(), or
move ->addEventListener(...) into UserChooserType::buildForm().
Any idea how it might be done?
Here is the UserChooserType:
class UserChooserType extends AbstractType
{
/**
* #var UserManager
*/
protected $um;
/**
* UserChooserType constructor.
* #param UserManager $um
*/
public function __construct(UserManager $um){
$this->um = $um; //used to find and decorate User entities. It is not a Doctrine entity manager, but it uses one.
}
/**
* #inheritDoc
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
if (!$data) return;
$user = $this->um->getUserByUserName($data);
if(!$user->getId()) $this->um->saveUser($user); //create User in db, if it's not there yet.
});
$builder->resetViewTransformers(); //so new choices aren't discarded
$builder->addModelTransformer(new CallbackTransformer(
function ($user) { //internal storage format to display format
return ($user instanceof User) ? $user->getUserName() : '';
},
function ($username) { //display format to storage format
return ($username) ? $this->um->getUserByUserName($username) : null;
}
));
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'class' => 'ACRDUserBundle:User',
'label' => 'ldap.user.name',
'choice_label' => function($user, $key, $index){
$this->um->decorateUser($user);
$label = $user->getDetail('displayName');
return $label ? $label : $user->getUserName();
},
'choice_value' => 'userName',
'choices' => [],
'attr' => array(
'class' => 'userchooser',
'placeholder' => 'form.placeholder.userchooser'
)
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'my_userchooser';
}
/**
* #inheritDoc
*/
public function getParent() {
return EntityType::class;
}
}
This helped me out:
https://symfony.com/doc/current/reference/forms/types/entity.html#using-choices
Here is how I used it (again with select 2):
public function buildForm(FormBuilderInterface $builder, array $options)
{
/** #var ProductCollection $productCollection */
$productCollection = $builder->getData();
$builder
->add('products', EntityType::class,
[
'class' => Product::class,
'required' => FALSE,
'expanded' => FALSE,
'multiple' => TRUE,
'choices' => $productCollection->getProducts(), // We only preload the selected products. The rest come from api.
'attr' => [
'data-toggle' => 'select',
'data-options' => json_encode([
'ajax' => [
'url' => '/admin/product/autocomplete',
'dataType' => 'json'
]
])
],
'choice_label' => function (Product $product) {
return $product->getName();
},
'choice_attr' => function (Product $product) {
return [
'data-avatarsrc' => $product->getImage()->getUrl(),
'data-caption' => $product->getSkus()->first()->getSku(),
];
},
]
)
;
}
And here is my JS for the init of the select2 (copy/paste):
function() {
var elements = document.querySelectorAll('[data-toggle="select"]');
function templateResult(element) {
let avatarsrc, caption;
if (element.id && element.avatarsrc) {
avatarsrc = element.avatarsrc
caption = element.caption ? ' ' + element.caption : ''
}
else if (element.element) {
avatarsrc = element.element.dataset.avatarsrc ? element.element.dataset.avatarsrc : ''
caption = element.element.dataset.caption ? ' ' + element.element.dataset.caption : ''
}
if (!avatarsrc) {
return element.text + caption
}
let wrapper = document.createElement("div");
return wrapper.innerHTML = '<span class="avatar avatar-xs mr-3 my-2"><img class="avatar-img rounded-circle" src="' + avatarsrc + '" alt="' + element.text + '"></span><span>' + element.text + '</span><span class="badge badge-soft-success ml-2">' + caption + '</span>', wrapper
}
jQuery().select2 && elements && [].forEach.call(elements, function(element) {
var select, additionalOptions, select2options;
additionalOptions = (select = element).dataset.options ? JSON.parse(select.dataset.options) : {};
select2options = {
containerCssClass: select.getAttribute("class"),
dropdownCssClass: "dropdown-menu show",
dropdownParent: select.closest(".modal") ? select.closest(".modal") : document.body,
templateResult: templateResult,
templateSelection: templateResult
}
$(select).select2({...select2options, ...additionalOptions})
})
}(),
Some remarks first:
The field name UserChooserType is a bit elaborated. UserType is shorter and just as clear, and fits the Symfony naming conventions better
I wouldn't extend UserChooserType from EntityType. Doc says EntityType is specifically dedicated to entities coming from Doctrine. It adds magic so that the field is easily configured around Doctrine: transformers, automatic fetching of choices from the DB, etc. If your users are fully defined in the LDAP, I would instead recommend extending ChoiceType and populate your choices from the LDAP directly.
Coming back to your problem, what you want here is to leverage the almighty power of dependency injection, by declaring your field type as a service. After having done that, instead of:
$builder->add('siteAdmin', UserChooserType::class, $siteAdminOpts)
You will do (assuming you chose the form name user_chooser_type):
$builder->add('siteAdmin', 'user_chooser_type', $siteAdminOpts)
You need to inject the security.token_storage service into your field type. This is the service that holds the current user's information, you can access it like this:
$user = $securityTokenStorage->getToken()->getUser();
With this the population of the default value can happen at the field type level instead of its parent.
Using this, you could also add the LDAP choices at field type level too, by injecting a service able to communicate with the LDAP.
It should finally noted that all default symfony field types are also declared as services.
EDIT:
Previous answer is beside the point.
In Symfony, I'm not aware of any possible simple way to modify the choice list of a choice/entity field after it has been created. I don't think there is, and actually I might have done the same as you to tackle the issue you're describing.
My opinion is that you're already doing what needs to be done in this case.
If you're really motivated though, I think it might just be possible to move the event listener in the form type like this:
->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) use ($options) {
if ($form->hasParent()) {
$data = $event->getData();
$form = $event->getForm();
$method = 'get' . ucfirst($form['action_name']);
if($user = $data->$method()) $siteAdminOpts['choices'] = array($user);
$form->getParent()->add($options['form_name'], UserChooserType::class, $siteAdminOpts);
}
});
Something like that. Not sure how that would work though.
I'm still interested in seeing if anyone comes up with a clean solution.
Good morning everyone! Is a form of.
Class ReleasesType:
$builder
->add('doid', 'text')
->add('dourl', 'text')
->add('artists', 'entity', array(
'class' => 'MReleaseCoreBundle:Artists',
'property' => 'name',
'expanded' => true ,
'multiple' => true
));
Сonnection with them one-to-many:
Class 'Artists':
/**
* #ORM\OneToMany(targetEntity="ReleasesArtists" , mappedBy="artists" , cascade={"all"})
* */
private $da;
public function __construct() {
$this->da = new \Doctrine\Common\Collections\ArrayCollection();
}
Class 'ReleasesArtists':
/**
* #ORM\ManyToOne(targetEntity="Releases", inversedBy="da")
* #ORM\JoinColumn(name="releases_id", referencedColumnName="id")
* */
private $releases;
/**
* #ORM\ManyToOne(targetEntity="Artists", inversedBy="da")
* #ORM\JoinColumn(name="artists_id", referencedColumnName="id")
* */
private $artists;
And of course the entity 'Releases':
/**
* #ORM\OneToMany(targetEntity="ReleasesArtists" , mappedBy="releases", cascade={"all"} , orphanRemoval=true)
*/
private $da;
public function getArtists() {
$artists = new ArrayCollection();
foreach($this->da as $p) {
$artists[] = $p->getArtists()->getName();
}
return $artists;
}
public function addDa($da) {
$this->da[] = $da;
}
public function setArtists($artists) {
foreach($artists as $p) {
$po = new \MRelease\CoreBundle\Entity\ReleasesArtists();
$po->setReleases($this);
$po->setArtists($p);
$this->addDa($po);
}
}
Connection is working correctly, all outputs. But does not "checked". In what may be the problem?
Thanks!
Into your controller, where you build and output your form, you have to do something like this
public function myFooAction(Request $request, $releasesId)
{
$repo = $this->getDoctrine()->getManager()->getRepository('YourBundleName:Releases');
$releasesObject = $repo->findOneById($releasesId);
$form = $this->createForm(new ReleasesType(), $releasesObject);
return $this->render('YourBundle::TemplateToRender, array('form'=>$form);
}
What happen here, and why is working?
I've made some assumptions as you don't provide any controller code. First of all, I assume that you have an action like myFooAction() where you do form operation and I suppose, also, that you pass to this action an id for load object from DB and tie it to your form - if I understood correctly your question.
So, first line of action is for retrieve repository for this object. Once you've got repo, you can fetch your object (second line). On third line I use Symfony2 form's facility and "connect" object to his form type: with this, all values contained into this object will be reported into your form (so checkboxes will have correct value). Last line is for render form.
Obviously, your action logic could be different but concept expressed here could be replicated with "different" implementation everywhere.
I develop new type, but I don't know how I can test it.
Assert annotation is not load and validations is not called.
Could any one please help me?
class BarcodeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->
add('price');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Bundles\MyBundle\Form\Model\Barcode',
'intention' => 'enable_barcode',
));
}
public function getName()
{
return 'enable_barcode';
}
}
A have following model for storing form data.
namepspace Bundles\MyBundle\Form\Model;
class Barcode
{
/**
* #Assert\Range(
* min = "100",
* max = "100000",
* minMessage = "...",
* maxMessage = "..."
* )
*/
public $price;
}
I develop some test like this, the form didn't get valid data but it is valid! (Because annotation is not applied)
I try adding ValidatorExtension but I dont know how can I set constructor paramaters
function test...()
{
$field = $this->factory->createNamed('name', 'barcode');
$field->bind(
array(
'price' => 'hello',
));
$data = $field->getData();
$this->assertTrue($field->isValid()); // Must not be valid
}
Not sure why you need to unit-test the form. Cant You unit test validation of Your entity and cover controller with your expected output?
While testing validation of entity You could use something like this:
public function testIncorrectValuesOfUsernameWhileCallingValidation()
{
$v = \Symfony\Component\Validator\ValidatorFactory::buildDefault();
$validator = $v->getValidator();
$not_valid = array(
'as', '1234567890_234567890_234567890_234567890_dadadwadwad231',
"tab\t", "newline\n",
"Iñtërnâtiônàlizætiøn hasn't happened to ", 'trśżź',
'semicolon;', 'quote"', 'tick\'', 'backtick`', 'percent%', 'plus+', 'space ', 'mich #l'
);
foreach ($not_valid as $key) {
$violations = $validator->validatePropertyValue("\Brillante\SampleBundle\Entity\User", "username", $key);
$this->assertGreaterThan(0, count($violations) ,"dissalow username to be ($key)");
}
}
Functional test. Given that you generate a CRUD with app/console doctrine:generate:crud with routing=/ss/barcode, and given that maxMessage="Too high" you can:
class BarcodeControllerTest extends WebTestCase
{
public function testValidator()
{
$client = static::createClient();
$crawler = $client->request('GET', '/ss/barcode/new');
$this->assertTrue(200 === $client->getResponse()->getStatusCode());
// Fill in the form and submit it
$form = $crawler->selectButton('Create')->form(array(
'ss_bundle_eavbundle_barcodetype[price]' => '12',
));
$client->submit($form);
$crawler = $client->followRedirect();
// Check data in the show view
$this->assertTrue($crawler->filter('td:contains("12")')->count() > 0);
// Edit the entity
$crawler = $client->click($crawler->selectLink('Edit')->link());
/* force validator response: */
$form = $crawler->selectButton('Edit')->form(array(
'ss_bundle_eavbundle_barcodetype[price]' => '1002',
));
$crawler = $client->submit($form);
// Check the element contains the maxMessage:
$this->assertTrue($crawler->filter('ul li:contains("Too high")')->count() > 0);
}
}
Include this line must be in Model and try it after include look like your model.
/* Include the required validators */
use Symfony\Component\Validator\Constraints as Assert;
namespace Bundles\MyBundle\Form\Model;
class Barcode
{
/**
* #Assert\Range(
* min = "100",
* max = "100000",
* minMessage = "min message here",
* maxMessage = "max message here"
* )
*/
public $price;
}