I'm trying to set a drop down to 'required' but the form still goes through. What am I doing wrong?
Here is the code:
this->exportForm = new sfForm();
$widgets['sheet_type'] = new sfWidgetFormDoctrineChoice(array('model' => 'ExportSheet', 'add_empty' => true));
$this->exportForm->setWidgets($widgets);
$this->exportForm->setValidators(array('sheet_type' => new sfValidatorDoctrineChoice(array('model' => 'ExportSheet', 'required' => true), array('required' => 'Please select a sheet type to export.') )));
UPDATE:
I've made the changes suggested.
actions.class.php:
$this->exportForm = new sfForm();
$this->exportForm->getWidgetSchema()->setNameFormat('exportForm[%s]');
$widgets['sheet_type'] = new sfWidgetFormDoctrineChoice(array('model' => 'ExportSheet', 'add_empty' => true));
$this->exportForm->setWidgets($widgets);
$this->exportForm->setValidators(array('sheet_type' => new sfValidatorDoctrineChoice(array('model' => 'ExportSheet', 'required' => true), array('required' => 'Please select a sheet type to export.') )));
if ($request->isMethod('post'))
{
$this->exportForm->bind($request->getParameter('exportForm'));
if ($this->exportForm->isValid())
{
...
}
}
Template:
<form method="post" action="<?php echo url_for('#export'); ?>">
<div id="export" style="display: block">
<?php echo $exportForm['sheet_type']->renderRow(); ?>
</form>
I can see when I submit that the echoing $request->getParameter('sheet_type') does return a value. If this is the case, why is the validation still failing?
There are 2 parts to validating a form ... the first is adding the validators the second is checking if its valid ....
take this example :
public function executeSomeaction(sfWebRequest $request)
{
// Define the form
this->exportForm = new sfForm();
$widgets['sheet_type'] = new sfWidgetFormDoctrineChoice(array('model' => 'ExportSheet', 'add_empty' => true));
$this->exportForm->setWidgets($widgets);
$this->exportForm->setValidators(array('sheet_type' => new sfValidatorDoctrineChoice(array('model' => 'ExportSheet', 'required' => true), array('required' => 'Please select a sheet type to export.') )));
// Deal with the request
if ($request->isMethod('post'))
{
$this->exportForm->bind($request->getParameter(<your form>));
if ($this->exporForm->isValid())
{
// Handle the form submission
// ...
$this->redirect('foo/bar');
}
}
}
Its only the second part within if ($request->isMethod('post')) that applies your validation and checks the user submitted data. See here in the symfony docs about handling forms with validation
If you use the following to add a naming schema for your form output then getting all of the results is easy ....
$this->exportForm->getWidgetSchema()->setNameFormat('exportForm[%s]');
then you can get use :
$this->exportForm->bind($request->getParameter('exportForm'));
this will then get the array with all of the field values in it and bind it to your form - ready for checking to see if its valid.
Update
you need to specify
$this->exportForm->getWidgetSchema()->setNameFormat('exportForm[%s]');
after
$this->exportForm->setWidgets($widgets);
as the setWidgets method resets the naming format
Related
I am using the great bundle https://github.com/misd-service-development/phone-number-bundle to store and retrieve phone number, but I have a problem when I want to pre-fill a form with it (not the same entity).
I have the following code in my Type
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use libphonenumber\PhoneNumberFormat;
use Misd\PhoneNumberBundle\Form\Type\PhoneNumberType;
class CreateAdType extends AbstractType
{
private $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
//Builds the form
public function buildForm(FormBuilderInterface $builder, array $options)
{
//Defines data
$user = $this->tokenStorage->getToken()->getUser();
$userEmail = is_object($user) ? $user->getEmail() : '';
$userPhone = is_object($user) ? $user->getPhone() : '';
//Defines fields
$builder
->add('phone', PhoneNumberType::class, array(
'label' => 'label.phone',
'disabled' => $disabled,
'widget' => PhoneNumberType::WIDGET_COUNTRY_CHOICE,
'country_choices' => array(
'FR',
),
))
->add('email', EmailType::class, array(
'label' => 'label.email',
'disabled' => $disabled,
'required' => true,
'attr' => array(
'placeholder' => 'placeholder.email',
'value' => $userEmail,
)))
;
}
public function finishView(FormView $view, FormInterface $form, array $options)
{
$view['phone']->children['number']->vars['data'] = '123456789';
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Ad',
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
// a unique key to help generate the secret token
'intention' => 'createAdForm',
));
}
public function getName()
{
return 'createAd';
}
}
The resulting html code is the following
<div class="form-group">
<label>Phone</label>
<div>
<div id="create_ad_phone" value="**THE_VALUE_APPEARS_HERE**">
<select id="create_ad_phone_country" name="create_ad[phone][country]">
<option value="FR" >France (+33)</option>
</select>
<input type="text" id="create_ad_phone_number" name="create_ad[phone][number]" value="**BUT_I_NEED_THE_VALUE_HERE**" />
</div>
</div>
</div>
This sets the value to the phone div, but not to the input phone_number, where I need it. Is there a way ?
Following in your form type, don't forget to use
...
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
...
public function finishView(FormView $view, FormInterface $form, array $options)
{
$view['phone']->children['number']->vars['value'] = $view['phone']->children['number']->vars['value'] ? $view['phone']->children['number']->vars['value'] : '+13008228232';
}
In you method add you can use choices for select
$builder
->add('phone', PhoneNumberType::class, array(
'widget' => PhoneNumberType::WIDGET_COUNTRY_CHOICE,
'country_choices' => array(
'FR',
),
'choices' => array('number' => $user->getPhone))
);
Are you rendering in twig template?
If so have you tried passing in "$user" object to twig template from controller, and then call the "getPhone" function in twig.
Like so, in your controller:
return $this->render('default/some_template.html.twig', array(
'form' => $form->createView(),
'user' => $user,
));
Then in your twig template somewhere:
{{ form_widget(form.phone, {'value' : user.getPhone}) }}
Try something like that to see if it works.
I haven't tried this - but it might work.
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.
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);
How can I check in symfony 1.4 if a value is a specific string.
In my html-code I enter a default-value:
<input ... value="Recipe name.">
My current form:
$recipename_value = 'Recipe name.';
$this->setWidgets(array(
'recipename' => new sfWidgetFormInputText(array(), array('size' => '40', 'maxlength' => '150',
'value' => $recipename_value,
$this->setValidators(array(
'recipename' => new sfValidatorString(array('max_length' => 150), array(
'required' => 'Please enter a recipe name.'
)),
The sfValidator should give an error message when the value is Recipe name. How can I do it in symfony? I read a lot about max_- & min_length and sfValidatorSchemaCompare, but nothing with string. Can somebody help me?
Thanks!
Gunnar
You can use postValidator
In your form class:
public function checkValue($validator, $values) {
if ($values['recipename']=="Recipe name."){
$message = 'Your message';
throw new sfValidatorError($validator, $message);
}
else{
return $values;
}
}
BUT , I think the true way for you is to use placeholder for your form field. You can read about it:
HTML5 placeholder Attribute
And plugin for IE:
jQuery HTML5 Placeholder Plugin
I'm building a simple form mailer in symfony using sfExtraForm plugin captcha. Everything works except sfValidator is not redirecting the user and showing an error when any field is invalid. The only thing I can think of is I did not generate the module. I built it from scratch.
I have to do the redirect manually. Is this because this is a sfForm and not an sfDoctrine Form? It is if the line if ($form->isValid()) returns false but without the associated redirect and error codes. Here is the program. Thanks:
Form:
<?php
class AdsForm extends sfForm
{
public function configure()
{
$this->setWidgets(array(
'name' => new sfWidgetFormInputText(),
'email' => new sfWidgetFormInputText(),
'phone' => new sfWidgetFormInputText(),
'fax' => new sfWidgetFormInputText(),
'attention' => new sfWidgetFormInputText(),
'message' => new sfWidgetFormInputText(),
'captcha' => new sfWidgetFormReCaptcha( array('public_key'=>self::PUBLIC_KEY)),
));
$this->widgetSchema->setNameFormat('ads[%s]');
$this->setValidators(array(
'name' => new sfValidatorString(array('max_length' => 50)),
'email' => new sfValidatorString(array('max_length' => 50)),
'phone' => new sfValidatorString(array('max_length' => 50)),
'fax' => new sfValidatorString(array('max_length' => 50)),
'attention' => new sfValidatorString(array('max_length' => 50)),
'message' => new sfValidatorString(array('max_length' => 255)),
'captcha' => new sfValidatorReCaptcha(array('private_key' => self::PRIVATE_KEY))
));
$this->widgetSchema->setLabels(array(
'name' => 'Your Name:*',
'email' => 'Your Email:*',
'phone' => 'Your Phone:*',
'fax' => 'Your Fax',
'attention' => 'Attention:*',
'message' => 'Mail Message:*',
'captcha' => 'Image Verification:*',
));
}
}
Action:
class adsActions extends sfActions
{
public function executeIndex(sfWebRequest $request)
{
$this->form=new adsForm();
}
public function executeSend(sfWebRequest $request){
$this->forward404Unless($request->isMethod(sfRequest::POST));
$form=new adsForm();
$captcha = array('recaptcha_challenge_field' => $request->getParameter('recaptcha_challenge_field'),'recaptcha_response_field' => $request->getParameter('recaptcha_response_field'),);
$form->bind(array_merge($request->getParameter('ads'), array('captcha' => $captcha)));
if ($form->isValid())
{
print_r($_REQUEST);
$ads=$this->getRequestParameter('ads');
print_r($ads);
$headers = 'From: '."\r\n" .
'Reply-To: no-reply#yellowexplorer.com' . "\r\n" .
'X-Mailer: PHP/' . phpversion();
//mail(' ******#yahoo.com','Yellow Explorer','An account has been created for you at yellowexplorer.com with a username of '.$this->username.'. Please click here to finish creating your account.',$headers);
}
else{
$this->redirect('/ads');
}
}
}
You're not seeing any errors because you're redirecting! To render form fields with their errors, you need to be rendering the actual form instance that you called bind on. Try changing $this->redirect('/ads') to $this->setTemplate('index').
Other potential changes (outside the scope of the question):
You can enforce the request method requirements of the send action at the routing level. Make the send route an sfRequestRoute and add the requirement { sf_method: post }.
Symfony has a built in mailer, sfMailer. Any reason you've decided not to use it?