Prestashop 1.7 renderform by admincontroller error - forms

for my module i need to generate a form with helper. I found nothing with my error on the web so... I post again something...
Here my AdminYoutubeHomeController
<?php
class AdminYoutubeHomeController extends ModuleAdminController
{
public function __construct()
{
$this->bootstrap = true;
$this->display = 'view';
parent::__construct();
$this->meta_title = $this->l('Youtube');
if (!$this->module->active) {
Tools::redirectAdmin($this->context->link->getAdminLink('AdminHome'));
}
}
public function renderView()
{
/**
* If values have been submitted in the form, process.
*/
if (((bool)Tools::isSubmit('submitYoutubeHomeModule')) == true) {
$this->postProcess();
}
$this->context->smarty->assign([
'youtube_dir', _PS_MODULE_DIR_.'youtubehome',
'youtube_embeded' => "https://www.youtube.com/embed/",
'youtubeLink' => Configuration::get('YOUTUBEHOME_LINK_VIDEO')
]);
return $this->context->smarty->fetch(_PS_MODULE_DIR_.'youtubehome/views/templates/admin/youtubehome.tpl').$this->renderForm();
}
/**
* Create the form that will be displayed in the configuration of your module.
*/
public function renderForm()
{
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$helper->module = $this;
$helper->name_controller = $this->module->name;
$helper->default_form_language = $this->context->language->id;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0);
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitYoutubeHomeModule';
$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false)
.'&configure='.$this->module->name.'&tab_module='.$this->module->tab.'&module_name='.$this->module->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->tpl_vars = array(
'fields_value' => $this->getConfigFormValues(), /* Add values for your inputs */
'languages' => $this->context->controller->getLanguages(),
'id_language' => $this->context->language->id,
);
return $helper->generateForm(array($this->getConfigForm()));
}
/**
* Create the structure of your form.
*/
public function getConfigForm()
{
return array(
'form' => array(
'legend' => array(
'title' => $this->l('Settings'),
'icon' => 'icon-cogs',
),
'input' => array(
array(
'col' => 3,
'type' => 'text',
'prefix' => '<i class="icon icon-youtube-play"></i>',
'desc' => $this->l('Enter your youtube end link'),
'name' => 'YOUTUBEHOME_LINK_VIDEO',
'label' => $this->l('Link'),
),
),
'submit' => array(
'title' => $this->l('Save'),
),
),
);
}
/**
* Set values for the inputs.
*/
public function getConfigFormValues()
{
return array(
'YOUTUBEHOME_LINK_VIDEO' => Configuration::get('YOUTUBEHOME_LINK_VIDEO'),
);
}
/**
* Save form data.
*/
public function postProcess()
{
$form_values = $this->getConfigFormValues();
foreach (array_keys($form_values) as $key) {
Configuration::updateValue($key, Tools::getValue($key));
}
}
}
And here the error
My tpl file is in modules/youtubehome/views/templates/admin/youtubehome.tpl
I don't want to override the default form. Do you think i have doing something wrong ?
EDIT POST
Here it's the error with ps_version

try with :
$this->setTemplate('module:youtubehome/views/templates/admin/youtubehome.tpl');
Regards

Related

Taxonomy list dependent on choice from another taxonomy list, drupal 8

I have a taxonomy option list make where I choose say Toyota.
I want the second taxonomy option list with the models of Toyota only (Eg. Corolla, hilux etc...).
When I choose Benz the second list will then contains C-Class, ML, etc...
I have created the entity vehicle from google examples on xampp localhost, windows 10.
In my vehicle form I'm able to populate the first list. But the second appears empty.
Here is my code. Please help:
public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
$options = array();
$tax = "make";
$terms = \Drupal::entityManager()->getStorage('taxonomy_term')->loadTree($tax, $parent = 0, $max_depth = NULL, $load_entities = FALSE);
foreach ($terms as $term) {
$options[] = $term->name;
}
$form['make'] = array(
'#type' => 'select',
'#title' => t('Make'),
'weight' => 0,
'#options' => $options,
'#ajax' => array(
'callback' => [$this, 'changeOptionsAjax'],
'wrapper' => 'model_wrapper',
),
);
$form['model'] = array(
'#type' => 'select',
'#title' => t('Model'),
'weight' => 1,
'#options' => $this->getOptions($form_state),
'#prefix' => '<div id="model_wrapper">',
'#suffix' => '</div>',
);
return $form;
}
public function getOptions(FormStateInterface $form_state) {
$options = array();
if ($form_state->getValue('make') == "Benz") {
$tax="benz";
}
elseif ($form_state->getValue('make') == "BMW") {
$tax="bmw";
}
elseif ($form_state->getValue('make') == "Toyota") {
$tax="toyota";
}
else {
$tax="title";
// title is just another taxonomy list I'm using as default if make is not found
}
$terms = \Drupal::entityManager()->getStorage('taxonomy_term')->loadTree($tax, $parent = 0, $max_depth = NULL, $load_entities = FALSE);
foreach ($terms as $term) {
$options[] = $term->name;
}
return $options;
}
public function changeOptionsAjax(array &$form, FormStateInterface $form_state) {
return $form['model'];
}
Here I give you a working sample based on your example VehiculesForm.php:
I took the liberty to rename some variable for better readability.
<?php
namespace Drupal\example\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
/**
* VehiculesForm.
*/
class VehiculesForm extends FormBase {
/**
* The term Storage.
*
* #var \Drupal\taxonomy\TermStorageInterface
*/
protected $termStorage;
/**
* {#inheritdoc}
*/
public function __construct(EntityTypeManagerInterface $entity) {
$this->termStorage = $entity->getStorage('taxonomy_term');
}
/**
* {#inheritdoc}
*/
public static function create(ContainerInterface $container) {
// Instantiates this form class.
return new static(
// Load the service required to construct this class.
$container->get('entity_type.manager')
);
}
/**
* {#inheritdoc}
*/
public function getFormId() {
return 'vehicules_form';
}
/**
* {#inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
$brands = $this->termStorage->loadTree('make', 0, NULL, TRUE);
$options = [];
if ($brands) {
foreach ($brands as $brand) {
$options[$brand->getName()] = $brand->getName();
}
}
$form['brand'] = array(
'#type' => 'select',
'#title' => $this->t('brand'),
'#options' => $options,
'#ajax' => array(
'callback' => [$this, 'selectModelsAjax'],
'wrapper' => 'model_wrapper',
),
);
$form['model'] = array(
'#type' => 'select',
'#title' => $this->t('Model'),
'#options' => ['_none' => $this->t('- Select a brand before -')],
'#prefix' => '<div id="model_wrapper">',
'#suffix' => '</div>',
'#validated' => TRUE,
);
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Send'),
];
return $form;
}
/**
* {#inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
}
/**
* {#inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
}
/**
* Called via Ajax to populate the Model field according brand.
*
* #param array $form
* An associative array containing the structure of the form.
* #param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* #return array
* The form model field structure.
*/
public function selectModelsAjax(array &$form, FormStateInterface $form_state) {
$options = [];
$vocabulary = 'title';
switch ($form_state->getValue('brand')) {
case 'Benz':
$vocabulary = 'benz';
break;
case 'BMW':
$vocabulary = 'bmw';
break;
case 'Toyota':
$vocabulary = 'toyota';
break;
}
$models = $this->termStorage->loadTree($vocabulary, 0, NULL, TRUE);
if ($models) {
foreach ($models as $model) {
$options[$model->id()] = $model->getName();
}
}
$form['model']['#options'] = $options;
return $form['model'];
}
}
Also, I suggest you to make some improvments on you code such:
Don't use a switch but link your taxonomies with a reference fields.
Add validation to ensure security (check we don't spoof your field for example) !!
Don't use the brandname but the ID. Avoid $options[$brand->getName()] = $brand->getName(); and use something like $options[$brand->id()] = $brand->getName();.
Hope it will help you !

InputFilter "setRequired" not working for html5 multiple

I'm having hard time with a weird behaviour of fileinput.
This is my form:
namespace Frontend\Form;
use NW\Form\Form;
use Zend\InputFilter;
use Zend\Form\Element;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
class EnrollStructure extends Form implements ServiceManagerAwareInterface
{
protected $sm;
public function __construct($name=null) {
parent::__construct("frmEnrollStructure");
$this->setAttribute("action", "/registrazione_struttura/submit")
->setAttribute('method', 'post')
->setAttribute("id", "iscrizione_struttura")
->setAttribute("class", "form fullpage");
$this->addInputFilter();
}
public function init()
{
$structureFs = $this->sm->get('Structure\Form\Fieldsets\Structure');
$structureFs->setUseAsBaseFieldset(true);
$structureFs->remove("id")
->remove("creationTime")
->remove("latLon");
$file = new Element\File("images");
$file->setAttribute('multiple', true);
$this->add($structureFs)->add($file);
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Iscriviti',
'id' => 'sbmtEnrollStructure',
'class' => 'submit_btn'
),
));
$this->setValidationGroup(
array(
'structure' =>
array(
'companyname',
'vatNumber',
'addressStreet',
'addressZip',
'addressCity',
'addressRegion',
'fax',
'publicPhone',
'publicEmail',
'website',
'status',
'ownerNotes',
'category',
'subcategory',
"facilities",
"agreeOnPolicy",
"agreeOnPrivacy",
"subscribeNewsletter",
"contact" => array("name", "surname", "email", "role", "phone"),
),
"images"
));
}
/**
* Set service manager
*
* #param ServiceManager $serviceManager
*/
public function setServiceManager(ServiceManager $serviceManager)
{
$this->sm = $serviceManager;
}
public function addInputFilter()
{
$inputFilter = new InputFilter\InputFilter();
// File Input
$fileInput = new InputFilter\FileInput('images');
$fileInput->setRequired(true);
$fileInput->getValidatorChain()
->attachByName('filesize', array('max' => "2MB"))
->attachByName('filemimetype', array('mimeType' => 'image/png,image/x-png,image/jpg,image/jpeg'))
->attachByName('fileimagesize', array('maxWidth' => 2048, 'maxHeight' => 2048));
$inputFilter->add($fileInput);
$this->setInputFilter($inputFilter);
}
}
Basically, I mainly use a fieldset which contains most of the data I request to the user, plus a File input field.
This is the Fieldset Structure: (most important parts..)
use Zend\Form\Element;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Validator\Identical;
use Zend\Validator\NotEmpty;
use Zend\Validator\Regex;
use Zend\Validator\StringLength;
class Structure extends Fieldset implements InputFilterProviderInterface, ServiceManagerAwareInterface
{
protected $sm;
public function __construct()
{
parent::__construct('structure');
}
public function init()
{
$this->setHydrator(new DoctrineHydrator($this->_entityManager(),'Structure\Entity\Structure'));
$this->setObject($this->sm->getServiceLocator()->get("Structure_Structure"));
$id = new Element\Hidden("id");
$name = new Element\Text("companyname");
$name->setLabel("Ragione Sociale");
...........
}
public function getInputFilterSpecification()
{
return array
(
"id" => array(
"required" => false,
),
"companyname" => array(
"required" => true,
"validators" => array(
array('name' => "NotEmpty", 'options' => array("messages" => array( NotEmpty::IS_EMPTY => "Inserire la ragione sociale")))
),
),
.....
}
}
This is my controller:
public function submitAction()
{
try {
$this->layout("layout/json");
$form = $this->getForm('Frontend\Form\EnrollStructure');
//$form->addInputFilter();
$structure = $this->getServiceLocator()->get("Structure_Structure");
$viewModel = new ViewModel();
$request = $this->getRequest();
if ($request->isPost())
{
$post = array_merge_recursive
(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
$form->setData($post);
if ($form->isValid())
{
$structure = $form->getObject();
$contact = $structure->getContact();
$this->getServiceLocator()->get('Structure_ContactService')->save($contact);
$files = $request->getFiles()->toArray();
if(isset($files['images']))
{
$count = 3;
foreach($files['images'] as $pos => $file)
{
$fpath = $this->getServiceLocator()->get('RdnUpload\Container')->upload($file);
if(!empty($fpath))
{
if(--$count ==0) break;
$asset = $this->getServiceLocator()->get("Application_AssetService")->fromDisk($fpath, $file['name']);
$this->getServiceLocator()->get("Application_AssetService")->save($asset);
$structure->addImage($asset);
}
}
}
$this->getServiceLocator()->get('Structure_StructureService')->save($structure);
$retCode = RetCode::success(array("iscrizione_struttura!" => array("form_submit_successfull")), true);
}
else
{
$messages = $form->getMessages();
if(empty($messages))
$retCode = RetCode::error(array("iscrizione_struttura" => array("need_at_least_one_file" => "missing file")), true);
else
$retCode = RetCode::error(array("iscrizione_struttura" => $messages), true);
}
$viewModel->setVariable("retcode", $retCode);
return $viewModel;
}
} catch(Exception $e)
{
throw $e;
}
}
The strange thing is that if i remove from the field "images" the "multiple" attribute everything works fine, causing the form not to validate and i get this message:
[images] => Array
(
[fileUploadFileErrorFileNotFound] => File was not found
)
While, if i set the attribute multiple, and the user does not upload a file i get no error, but the form gets invalidated (this is the reason for this "bad" code in my controller:)
$messages = $form->getMessages();
if(empty($messages))
$retCode = RetCode::error(array("iscrizione_struttura" => array("need_at_least_one_file" => "missing file")), true);
else
$retCode = RetCode::error(array("iscrizione_struttura" => $messages), true);
I found the problem was caused by the Jquery form plugin, without it it works fine. :( In case somebody needs, I think the correct action code can be found here (I haven't tryied it anyway)
https://github.com/cgmartin/ZF2FileUploadExamples/blob/master/src/ZF2FileUploadExamples/Controller/ProgressExamples.php

$form->isValid says it is invalid, but my form does not show any error message - Zend Framework 2

Im having a problem with the addAction in my CRUD application. On the controller the logic does not pass the $form->isValid() verification but the form does not show any error message.
I tried with this (Thanks Sam):
foreach($form->get('product')->getElements() as $el)
{
echo $el->getName()." = ".$el->getValue()." > ".$el->getMessages()." <br/>";
}
That only show the name and value of the field, but not the error message.
I've tried letting the form totally blank and it fire "Value is required and can't be empty" error messages, but then, i fill each field one by one until i don't get more error messages but the form still invalid.
My form has a Product Fieldset as a base fieldset and a submit button. Inside Product Fieldset i have an ID field, a name field, a price field and a Brand Fieldset. Inside my Brand Fieldset i have a id field. Like this:
ProductForm:
class ProductForm extends Form
{
public function init()
{
// we want to ignore the name passed
parent::__construct('product');
$this->setName('product');
$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'product',
'type' => 'Administrador\Form\ProductFieldset',
'options' => array(
'use_as_base_fieldset' => true
),
));
$this->add(array(
'name' => 'submit',
'type' => 'Submit',
'attributes' => array(
'value' => 'Add',
'id' => 'submitbutton',
),
));
}
}
ProductFieldset:
class ProductFieldset extends Fieldset implements ServiceLocatorAwareInterface
{
protected $serviceLocator;
function __construct($name = null)
{
parent::__construct('product_fieldset');
$this->setHydrator(new ArraySerializableHydrator());
$this->setObject(new Product());
}
public function init()
{
$this->add(array(
'name' => 'id',
'type' => 'Hidden',
));
$this->add(array(
'name' => 'name',
'type' => 'Text',
'options' => array(
'label' => 'Name',
),
));
$this->add(array(
'name' => 'price',
'type' => 'Text',
'options' => array(
'label' => 'Price',
),
));
$this->add(array(
'name' => 'brand',
'type' => 'BrandFieldset',
));
}
public function setServiceLocator(ServiceLocatorInterface $sl)
{
$this->serviceLocator = $sl;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
}
BrandFieldset:
class BrandFieldset extends Fieldset
{
function __construct(BrandTable $brandTable)
{
parent::__construct('brand_fieldset');
//$this->setHydrator(new ClassMethodsHydrator(false))->setObject(new Brand());
$this->setHydrator(new ArraySerializableHydrator());
$this->setObject(new Brand());
$brandSelectOptionsArray = $brandTable->populateSelectBrand();
$this->add(array(
'name' => 'id',
'type' => 'Select',
'options' => array(
'label' => 'Brand',
'empty_option' => 'Please select a brand',
'value_options' => $brandSelectOptionsArray,
),
));
}
}
This is my new Form statement in the addAction:
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
Inside my model 'Product' i have the inputFilters, required filter for 'id' field, required filter for 'name' field. And for the Brand field i created other inputFilter and added it to the main inputFilter:
$brandFilter->add($factory->createInput(array(
'name' => 'id',
'required' => true,
'filters' => array(
array('name' => 'Int'),
),
)));
$inputFilter->add($brandFilter, 'brand');
The weird behavior is that my editAction works fine and has the same logic.
Is it there any form of echoing an internal error message from the form, something that helps me to understand WHY the form is not valid.
EDIT 2013-06-01
Here is my full Controller:
class ProductController extends AbstractActionController
{
protected $productTable;
protected $brandTable;
public function indexAction()
{
return new ViewModel(array(
'products' => $this->getProductTable()->fetchAll(),
));
}
public function addAction()
{
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
$form->get('submit')->setValue('Add');
$request = $this->getRequest();
if ($request->isPost()) {
$product = new Product();
$product->brand = new Brand();
$form->setInputFilter($product->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$product->exchangeArray($form->getData());
$this->getProductTable()->saveProduct($product);
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
}
return new ViewModel(array(
'form' => $form,
));
}
public function editAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('product', array(
'action' => 'add'
));
}
// Get the Product with the specified id. An exception is thrown
// if it cannot be found, in which case go to the index page.
try {
$product = $this->getProductTable()->getProduct($id);
}
catch (\Exception $ex) {
return $this->redirect()->toRoute('product', array(
'action' => 'index'
));
}
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
$brand = $this->getBrandTable()->getBrand($product->brand);
$product->brand = $brand;
$form->bind($product);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($product->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getProductTable()->saveProduct($form->getData());
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
public function deleteAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('product');
}
$request = $this->getRequest();
if ($request->isPost()) {
$del = $request->getPost('del', 'No');
if ($del == 'Yes') {
$id = (int) $request->getPost('id');
$this->getProductTable()->deleteProduct($id);
}
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
return array(
'id' => $id,
'product' => $this->getProductTable()->getProduct($id)
);
}
public function getProductTable()
{
if (!$this->productTable) {
$sm = $this->getServiceLocator();
$this->productTable = $sm->get('Administrador\Model\ProductTable');
}
return $this->productTable;
}
public function getBrandTable()
{
if (!$this->brandTable) {
$sm = $this->getServiceLocator();
$this->brandTable = $sm->get('Administrador\Model\BrandTable');
}
return $this->brandTable;
}
}
My case was I passed wrong input filter. isValid returns false, but $form->getMessages() is empty. Form OrderForm had the following:
$form->setInputFilter(new \Application\Form\UserInputFilter($er));
When I changed UserInputFilter to OrderInputFilter it works.
Well, I got the answer :D
This is how the addAction should be:
public function addAction()
{
$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');
$form->get('submit')->setValue('Add');
$product = new Product();
$product->brand = new Brand();
$form->bind($product); // I need to bind the product to the form to pass the isValid() validation
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($product->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$product = $form->getData();
$this->getProductTable()->saveProduct($product);
// Redirect to list of products
return $this->redirect()->toRoute('product');
}
}
return new ViewModel(array(
'form' => $form,
));
}
Apparently i needed to bind and empty product object to the form to be able to pass the isValid() validation. After that i retrieve a product object from the $form->getData().
You can also do: $form->setBindOnValidate(false);

Symfony2: How to add form constraint for a field in bind PRE_SET_DATA depending on the data

I have a form in Symfony 2 with basically two fields:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('contactType', 'select', array( 'choices' => $contactTypes ))
->add('value', 'text');
}
Then I added an EventSubscriber that listens to the FormEvents::PRE_SET_DATA event. What I actually want to do, is to change the way of validation depending on the value of contactType (numeric values from 1 to 4, which stand for email, mobile, fixed line and fax).
I followed this tutorial http://symfony.com/doc/current/cookbook/form/dynamic_form_generation.html
but I can't figure out, how to add a constraint to the value field.
Can anyone help me? Thanks a lot in advance.
Instead of adding validation constraints dynamically in event subscriber (not sure if this is even possible), you can set groups to field's validation constraints and determine validation groups based on submitted data.
A function to create the form from the controller :
<?php
// ...
class DefaultController extends Controller
{
/**
*
* #param \Clicproxy\DeltadocCabBundle\Entity\Mark $mark
* #param \Clicproxy\DeltadocCabBundle\Entity\Tag $tag
* #return Form
*/
private function createTagForm(Mark $mark, Tag $tag)
{
$form = $this->createForm(new TagType(), $tag, array(
'action' => $this->generateUrl('tag_new', array('slug' => $this->slugify($mark->getName()))),
'method' => 'POST',
));
foreach ($mark->getFields() as $field)
{
$form->add($this->slugify($field->getName()), $field->getFormType(), $field->getOptions());
}
$form->add('submit', 'submit', array('label' => 'crud.default.save'));
return $form;
}
// ...
The code in the entity (type, constraints, ...) :
<?php
// ...
/**
* Field
*
* #ORM\Table()
* #ORM\Entity
* #UniqueEntity({"name", "mark"})
*/
class Field
{
// ...
/**
*
* #return array
*/
public function getOptions()
{
$options = array('label' => $this->getName(), 'mapped' => FALSE);
$options['required'] = $this->getType() != 'checkbox';
if ('date' == $this->getType())
{
$options['attr']['class'] = 'datepicker'; // 'input-group date datepicker';
$options['attr']['data-date-format'] = 'dd/mm/yyyy';
$options['attr']['data-date-autoclose'] = true;
}
if ('choice' == $this->getType())
{
$choices = array();
foreach ($this->getChoices() as $choice)
{
$choices[$choice->getValue()] = $choice->getName();
}
asort($choices);
$options['choices'] = $choices;
}
$options['constraints'] = $this->getValidationConstraint();
return $options;
}
public function getValidationConstraint ()
{
$validation_constraint = array();
if ('number' == $this->getType()) {
if (0 < $this->getMaximum()) {
$validation_constraint[] = new LessThanOrEqual (array(
'message' => 'entity.field.number.lessthanorequal', // {{ compared_value }}
'value' => $this->getMaximum()
));
}
if (0 < $this->getMinimum()) {
$validation_constraint[] = new GreaterThanOrEqual(array(
'message' => 'entity.field.number.greaterthanorequal', // {{ compared_value }}
'value' => $this->getMinimum()
));
}
} elseif ('text' == $this->getType ()) {
if (0 < $this->getMaximum()) {
$validation_constraint[] = new Length(array(
'min' => $this->getMinimum() > 0 ? $this->getMinimum() : 0,
'max' => $this->getMaximum() > 0 ? $this->getMaximum() : 0,
'minMessage' => 'entity.field.text.minMessage', // {{ limit }}
'maxMessage' => 'entity.field.text.maxMessage',
'exactMessage' => 'entity.field.text.exactMessage',
));
}
} elseif ('date' == $this->getType()) {
}
return $validation_constraint;
}
// ...
All this code work actually.
With this you have a solution to generate a form on the fly with constraints.

The Choice constraint expects a valid callback

I updated Symfony2 to 2.1 and when I trying submit form I am getting error:
The Choice constraint expects a valid callback
source code from form type class:
$builder->add('type', 'choice',
array(
'expanded' => true,
'multiple' => false,
'choice_list' => new TypeChoices(),
'required' => true,
)
)
TypeChoices class:
class TypeChoices implements ChoiceListInterface {
public static $choices = array(
'full-time' => 'Full time',
'part-time' => 'Part time',
'freelance' => 'Freelance',
);
public static function getChoiceNameByValue($value)
{
return self::$choices[$value];
}
public function getChoices()
{
return self::$choices;
}
public static function getTypeChoicesKeys()
{
return array_keys(self::$choices);
}
public static function getPreferredChoiceKey()
{
return 'full-time';
}
}
Could someone give me any advice?
Maybe you could try to extend the SimpleChoiceList class, this way:
ChoiceList code:
class TypeChoices extends SimpleChoiceList
{
public static $choices = array(
'full-time' => 'Full time',
'part-time' => 'Part time',
'freelance' => 'Freelance',
);
/**
* Constructor.
*
* #param array $preferredChoices Preffered choices in the list.
*/
public function __construct(array $preferredChoices = array()) // PASS MORE ARGUMENT IF NEEDED
{
parent::__construct(
static::$choices,
$preferredChoices
);
}
}
Form type code:
->add('type', 'choice', array(
'choice_list' => new TypeChoices(),
...
))