Silex/Symfony Form - form_errors(form) doesn't work in twig - symfony-forms

I think this is a easy one.
I have a Silex application, with Symfony Form (with Validator).
This is a portion of my form:
return $this->factory->createBuilder(FormType::class)
->add('holidayId', HiddenType::class, array())
->add('firstName', TextType::class, array(
'label' => 'Il tuo nome'
))
->add('lastName', TextType::class, array(
'label' => 'Il tuo cognome'
))
->add('email', EmailType::class, array(
'label' => 'La tua email',
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email()
),
'invalid_message' => 'Indirizzo email non valido',
))
->add('phone', TextType::class, array(
'label' => 'Cellulare',
'constraints' => array(
new Assert\NotBlank(),
new Assert\Regex("/[\d\-\ ]+/"),
new Assert\Length(array('min' => 5, 'max'=>20))
)
))
->add('city', ChoiceType::class, array(
'placeholder' => 'Seleziona una città',
'choices' => $cities,
))
->add('age', NumberType::class, array(
'label' => 'Età',
'constraints' => array(
new Assert\NotBlank(),
new Assert\Range(array('min'=>18, 'max'=>100))
)
))
->add('gender', ChoiceType::class, array(
'label' => 'Sesso',
'choices' => array(
'Uomo' => 0,
'Donna' => 1
),
'expanded' => true,
'constraints' => array(
new Assert\NotBlank(),
new Assert\Choice(array(0, 1))
)
))
->add('privacy', ChoiceType::class, array(
'choices' => array(
'Dichiaro di aver preso visione della privacy policy e autorizzo il trattamento dei dati personali per le finalità di cui ai punti a) b) c) della stessa.' => 1,
),
'expanded' => true,
'multiple' => true
))
->add('marketing', ChoiceType::class, array(
'choices' => array(
'Presto il consenso per l’utilizzo e la comunicazione dei miei dati a terzi da parte di P&R Eventi e Vacanze s.r.l. per finalità promozionali relative ai servizi turistici e per la ricezione di offerte commerciali.' => 1,
),
'expanded' => true,
'multiple' => true,
'required' => false
))
->add('send', SubmitType::class, array(
'label' => 'INVIA RICHIESTA',
'attr' => array('class' => 'btn btn-corporate btn-lg btn-block'),
))
->getForm();
Which returns an instance of Form.
On my controller I have:
$form = $requestType->getForm();
$form->handleRequest($request);
if($form->isValid()){
$data = $form->getData();
// .....
return $app->redirect('/thank-you');
}
The validation works fine, it redirects me when the form is valid.
On my twig view I render the form:
{{ form_start(form) }}
{{ form_errors(form) }}
<div class="form-group">
{{ form_label(form.firstName) }}
{{ form_widget(form.firstName, {'attr': {'class': 'form-control'}}) }}
</div>
<div class="form-group">
{{ form_label(form.lastName) }}
{{ form_widget(form.lastName, {'attr': {'class': 'form-control'}}) }}
</div>
<div class="form-group">
{{ form_label(form.email) }}
{{ form_widget(form.email, {'attr': {'class': 'form-control'}}) }}
</div>
...
The form_errors method doesn't show anything if the form isn't valid. Is ever BLANK ....
What's wrong?
Thank you in advance!
M.

I think that form doesn't contain childs errors by default
Add errors output for each element
<div class="form-group">
{{ form_label(form.firstName) }}
{{ form_errors(form.firstName) }}
{{ form_widget(form.firstName, {'attr': {'class': 'form-control'}}) }}
</div>
Or add special type for this form and change builder to pass all errors to view
namespace Form;
class Edit extends AbstractType
{
public function buildView(FormView $view, FormInterface $form, array $options)
{
parent::buildView($view, $form, $options);
$view->vars = array_replace($view->vars, array(
'errors' => $form->getErrors(true)
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder
->add('holidayId', HiddenType::class, array())
->add('firstName', TextType::class, array(
'label' => 'Il tuo nome'
))
...
}
}
....
$form = $app['form.factory']->create(\Form\Edit::class, [], []);

Related

Zend 2 module.config with constraints with model/controller not retrieveing record

I am learning Zend 2 and have an issue i cannot seem to get around. Im sure it is something simple but i cannot pinpoint it. What i am trying to do is list records by state_id and also view a record from the list. Showing only one of the views. When i bring up /Blog/view/1 I get a message that says: Could not find row 0. This shows up with the current link and if i take the /1 off. So it is not even looking at the record number. I suspect it may be in routing but not sure. thanks
This is what i have:
Module.config
'router' => array(
'routes' => array(
'blog' => array(
'type' => 'Literal',
'options' => array(
'route' => '/Blog',
'defaults' => array (
'module' => 'Blog',
'controller' => 'BlogController',
'action' => 'index',
), // defaults end
), // options end
'may_terminate' => true,
'child_routes' => array(
'list' => array(
'type' => 'segment',
'options' => array(
'route' => '/list[/:state_id]',
'defaults' => array (
'action' => 'list',
), //defaults end
'constraints' => array(
'state_id' => '[0-9]+',
) // constraints end
), // options end
), // view end
'view' => array(
'type' => 'segment',
'options' => array(
'route' => '/view[/:post_id]',
'defaults' => array(
'action' => 'view',
), // defaults end
'constraints' => array(
'post_id' => '[0-9]+',
) // constraints end
), // options end
), // post end
) // child route end
), // blog end
) // routes end
) // router end
); // return array end
Model:PostTable.php
public function getPosts($post_id)
{
$post_id = (int) $post_id;
$rowset = $this->tableGateway->select(array('post_id' => $post_id));
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not find row $post_id");
}
return $row;
}
View:
<h1><?php echo $this->escapeHtml($title); ?></h1>
<table class="table">
<tr>
<th>Title</th>
<th>View</th>
<th>Comments</th>
<th>Post Date</th>
</tr>
<?php foreach ($list as $posts) : ?>
<tr>
<td><?php echo $this->escapeHtml($posts->post_title);?></td>
<td><?php echo $this->escapeHtml($posts->num_views);?></td>
<td><?php echo $this->escapeHtml($posts->num_comments);?></td>
<td><?php echo $this->escapeHtml($posts->post_date);?></td>
</tr>
<?php endforeach; ?>
Edit: 06/06/2016 Added View Action.
public function viewAction()
{
return new ViewModel(array(
'list' => $this->getPostsTable()->getPosts(),
));
}
Also here is the getPostTable Action:
public function getPostsTable()
{
if (!$this->postsTable) {
$sm = $this->getServiceLocator();
$this->postsTable = $sm->get('Blog\Model\PostsTable');
}
return $this->postsTable;
}
You need to provide the post ID into the getPosts() method in the controller. The following is according to your PostTable's getPosts() method.
public function viewAction()
{
// Get the post ID from the route, /Blog/view/1
$post_id = $this->params()->fromRoute('post_id');
$list = $this->getPostsTable()->getPosts($post_id);
$view = new ViewModel(array(
'list' => $list,
));
return $view;
}

ZF2 Adding filters with element definition

I am trying to add filters and validators with element definition. But so far it is not working. Here is my controller class code.
public function validateAction() {
$testVals = Array ('question1' => 'value1' );
$formMaker = $this->getServiceLocator ()->get ( 'ttForm\Maker' );
$form = $formMaker->generateForm();
$form->setData($testVals);
if ($form->isValid()){
echo "Valid form";
}
else{
print_r($form->getMessages());
echo "Invalid form";
}
die;
}
This is form class code
public function generateForm (){
$element = array (
'options' => array(
'label' => "First Name :",
),
'attributes' => array(
'required' => 'required',
'type' => 'text'
),
'name' => 'firstName',
'filters' => array(
array('name' => 'Zend\Filter\StringTrim'),
),
'validators' => array(
array(
'name' => 'not_empty',
)),
);
$form = new Form();
$form->add($element);
return $form;
}
As you can see in form class, I have attached filters and validators with element definition, it does not work. Looking at docs, it seems like we can do so. Can anybody point out missing link? Thanks.

Zend Framework 2, Event Manager, SharedManager, Form Init

I have event added to onBootstrap()
$e->getApplication()->getEventManager()->getSharedManager()->attach('\Application\Form\Presentation\Edit', 'init', function($e) {
exit(print_r('<pre>') . var_dump($e));
}, 1);
How I can run this event after call form method init ?
I have solution,
In onBootstrap()
$services = $e->getApplication()->getServiceManager();
$sharedEventManager = $e->getApplication()->getEventManager()->getSharedManager();
$sharedEventManager->attach('PresentationEdit','init', function($event) use ($services) {
$form = $event->getTarget();
$form->add(array(
'type' => '\Zend\Form\Element\Text',
'name' => 'title2',
'attributes' => array(
'type' => 'text',
'class' => 'form-control',
'autocomplete' => 'off',
),
'options' => array(
'label' => 'presentation.title',
)
));
}, 100);
In form:
use Zend\EventManager\EventManager;
In init method:
$event = new EventManager('PresentationEdit');
$event->trigger('init', $this);
It works, but is this the correct approach?

extending zfcuser with custom radio fields

i am using ZFcuser with zendframework 2 and want to extend the registration form to enable me to add a radio field.
i followed the tutorial here
it works ok and i am able to render and obtain the values for imput tags. the problem comes when i try to render a radio button. it only renders one of the values.
here is my code:
public function onBootstrap(MVCEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$em = $eventManager->getSharedManager();
$em->attach(
'ZfcUser\Form\RegisterFilter',
'init',
function($e)
{
$filter = $e->getTarget();
$filter->add(array(
'name' => 'accept',
'required' => FALSE
));
}
);
// custom form fields
$em->attach(
'ZfcUser\Form\Register',
'init',
function($e)
{
/* #var $form \ZfcUser\Form\Register */
$form = $e->getTarget();
$form->add(
array(
'name' => 'username',
'options' => array(
'label' => 'Username',
),
'attributes' => array(
'type' => 'text',
),
)
);
$form->add(array(
'type' => 'Zend\Form\Element\radio',
'name' => 'terms',
'options' => array(
'label' => 'Accept Terms',
'value_options' => array(
'1' => 'Yes',
'0' => 'No',
),
),
));
}
);
$zfcServiceEvents = $e->getApplication()->getServiceManager()->get('zfcuser_user_service')->getEventManager();
$zfcServiceEvents->attach('register', function($e) {
$form = $e->getParam('form');
$user = $e->getParam('user');
the HTML
the html from this output only render 1 input tag; i.e
<input type="radio" value="" name="terms">
however, i need to render two radio buttons; one for the yes, and one for the no
does anyone have any ideas how to do this; i really appreciate your help
This is a limitation of the current ZfcUser(v. 1.x), but is something that will be fixed in the coming version(v. 2.x).
In the meantime: overwrite the standard view with your own.

dynamic dropdown get in zf2?

I want to put a dropdown in my project which is made in zf2... I wasted all day but I only got a static dropdown, not dynamic. Can anyone help me with this problem??
UserForm.php
$this->add(array(
'name' => 'group_name',
'type' => 'select',
'attributes' => array(
'id'=>'group_name',
'class'=>'large',
'options' => array('1=>php','2'=>'java'),
),
'options' => array(
'label' => '',
),
));
Thanks in advance for your valuabe answer.
Try this:
$this->add(array(
'name' => 'group_name',
'type' => 'select',
'attributes' => array(
'id'=>'group_name',
'class'=>'large',
),
'options' => array(
'label' => '',
'value_options' => array(
'1' => 'php',
'2' => 'java'
),
),
));
This is what i did:
In my constructor for my form
$this->add(array(
'type' => 'Zend\Form\Element\Select',
'name' => 'color',
'options' => array(
'empty_option' => 'Select a Color',
'value_options' => self::getColors(),
'label' => 'Color',
),
));
In the form class yet, i created this method:
public static function getColors() {
// access database here
//example return
return array(
'blue' => 'Blue',
'red' => 'Red',
);
}
In my view script:
<div class="form_element">
<?php $element = $form->get('color'); ?>
<label>
<?php echo $element->getOption('label'); ?>
</label>
<?php echo $this->formSelect($element); ?>
</div>
Think about it from a abstract level.
You have one Form
The Form needs Data from the outside
So ultimately your Form has a Dependency. Since we've learned from the official docs, there's two types of Dependency-Injection aka DI. Setter-Injection and Constructor-Injection. Personally(!) i use one or the other in those cases:
Constructor-Injection if the dependency is an absolute requirement for the functionality to work
Setter-Injection if the dependencies are more or less optional to extend already working stuff
In the case of your Form, it is a required dependency (because without it there is no populated Select-Element) hence i'll be giving you an example for Constructor-Injection.
Some action of your controller:
$sl = $this->getServiceLocator();
$dbA = $sl->get('Zend\Db\Adapter\Adapter');
$form = new SomeForm($dbA);
That's all for the form. The population now happens inside your Form. This is only an example and may need some fine-tuning, but you'll get the idea:
class SomeForm extends \Zend\Form
{
public function __construct(\Zend\Db\Adapter\Adapter $dbA)
{
parent::__construct('my-form-name');
// Create all the form elements and stuff
// Get Population data
$popData = array();
$result = $dbA->query('SELECT id, title FROM Categories', $dbA::QUERY_MODE_EXECUTE)->toArray();
foreach ($result as $cat) {
$popData[$cat['id'] = $cat['title'];
}
$selectElement = $this->getElement('select-element-name');
$selectElement->setValueOptions($popData);
}
}
Important: I HAVE NO CLUE ABOUT Zend\Db the above code is only for how i think it would work going by the docs! This is the part that would need some optimization probably. But all in all you'll get the idea of how it's done.
In your controller you can do something like below;
On my first example assuming that you have a Group Table. Then we're going to fetchAll the data in group table;
We need the id and name to be display in select options;
public function indexAction()
{
$groupTable = new GroupTable();
$groupList = $groupTable->fetchAll();
$groups = array();
foreach ($groupList as $list) {
$groups[$list->getId()] = $list->getName();
}
$form = new UserForm();
$form->get('group_name')->setAttributes(array(
'options' => $groups,
));
}
OR
in this example the grouplist is hardcoded;
public function indexAction()
{
$groupList = array('1' => 'PHP', '2' => 'JAVA', '3' => 'C#');
$groups = array();
foreach ($groupList as $id => $list) {
$groups[$id] = $list;
}
$form = new UserForm();
$form->get('group_name')->setAttributes(array(
'options' => $groups,
));
}
Then in your view script;
<?php
$form = $this->form;
echo $this->formRow($form->get('group_name'));
?>
Or you can right a controller helper, you may check this link http://www.resourcemode.com/me/?p=327
Just came across the same problem and had to take a look into zf2 source.
Here's a more OOP solution:
Inside the form constructor:
$this->add(array(
'name' => 'customer',
'type' => 'Zend\Form\Element\Select',
'attributes' => array(
'options' => array(
0 => 'Kunde',
)
),
'options' => array(
'label' => 'Kunde'
)));
inside the controller:
$view->form = new SearchForm();
$customers = $view->form->get('customer')->getValueOptions();
$customers[] = 'Kunde1';
$customers[] = 'Kunde2';
$customers[] = 'Kunde3';
$customers[] = 'Kunde4';
$view->form->get('customer')->setValueOptions($customers);

Resources