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?
Related
I'm just starting using PHPUnit with Zend and need little help to figure out how these tests should work.
I want to test if form return any error message if I do not pass any POST parameters.
The problem is that one field from my form is using Doctrine's DoctrineModule\Form\Element\ObjectSelect
...
$this->add(array(
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'name' => 'user',
'attributes' => array(
'id' => 'user-label',
),
'options' => array(
'object_manager' => $em,
'target_class' => 'Application\Entity\User',
'property' => 'username',
'label' => 'User:',
'display_empty_item' => true,
'empty_item_label' => '---',
'label_generator' => function($entity) {
return $entity->getUsername();
},
),
));
...
I get following error:
Fatal error: Call to a member function getIdentifierFieldNames() on null
I tried override this field with mocked object, however Zend doesn't allow objects in type, just class name (string), so this code doesn't work:
public function testIfFormIsValid()
{
$objectSelect = $this->getMockBuilder('DoctrineModule\Form\Element\ObjectSelect')
->disableOriginalConstructor()
->getMock();
$objectSelect->expects($this->any())
->method('getValueOptions')
->will($this->returnValue(array()));
$form = new \AppModuleComment\Form\Comment('form', array(
'em' => $this->em // Mocked object
));
$form->add(array(
'type' => $objectSelect,
'name' => 'user',
'attributes' => array(
'id' => 'user-label',
),
'options' => array(
'object_manager' => $this->em,
'target_class' => 'Application\Entity\User',
'property' => 'username',
'label' => 'User:',
'display_empty_item' => true,
'empty_item_label' => '---',
'label_generator' => function($entity) {
return $entity->getUsername();
},
),
));
$data = array(
'id' => null,
'user' => null
);
$form->setData($data);
$this->assertTrue($form->isValid(), 'Form is not valid');
}
What am I doing wrong? How should I test such code?
It seems you are testing functionality of Zend or Doctrine (or both) and not your own code. When you use libraries you should trust these libraries.
What happens is: Form\Form::add() uses Form\Factory::create() to create from the array an element. Form\Factory::create() uses Form\FormElementManager::get() to get an element from the given type.
Your type is an object and because Form\FormElementManager::get() can not handle objects your script will fail.
It seems you want to test that if post is empty Form::valid() calls ObjectSelect::valid() but this does not verify if the value is null. That's code from Doctrine / Zend not yours. Don't test it.
More interesting it gets when you want to mock the result of an select from within Doctrines ObjectSelect. But that's another question.
Please help me with Zend framework 2:)
I want to create a form with collection of fieldsets using Form Element Manager (absolutely like in official documentation).
My FormElementManager configuration:
'form_elements' => array(
'factories' => array(
'Admin\Form\TaskForm' => function($sm) {
$form = new TaskForm();
$doctrimeEntityManager = $sm->getServiceLocator()->get('Doctrine\ORM\EntityManager');
$form -> setEntityManager($doctrimeEntityManager);
$form -> init();
return $form;
},
'Admin\Form\TaskbrandFieldset' => function($sm) {
$doctrimeEntityManager = $sm->get('Doctrine\ORM\EntityManager');
$form = new TaskbrandFieldset();
$form->setEntityManager($doctrimeEntityManager);
return $form;
},
)
),
Admin\Form\TaskForm (only problem part):
namespace Admin\Form;
use Doctrine\ORM\EntityManager;
use Zend\Form\Form;
class TaskForm extends Form {
protected $entityManager;
public function init() {
$this->setAttribute('method', 'post');
// Id
$this->add(array(
'name' => 'id',
'attributes' => array(
'type' => 'hidden',
),
));
// My fieldset
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'taskbrands',
'options' => array(
'label' => 'Brand of the product',
'count' => 0,
'should_create_template' => true,
'allow_add' => true,
'target_element' => array(
'type'=>'Admin\Form\TaskbrandFieldset'
),
),
'attributes' => array(
'id' => 'addressFieldset'
)
));
}
}
Admin\Form\TaskbrandFieldset:
namespace Admin\Form;
use Admin\Entity\Taskbrand;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class TaskbrandFieldset extends Fieldset implements InputFilterProviderInterface, ServiceLocatorAwareInterface {
protected $entityManager;
protected $serviceLocator;
public function init() {
$this->setName('TaskbrandFieldset');
$this->setHydrator(new ClassMethodsHydrator(false))
->setObject(new Taskbrand());
$this->setLabel('Taskbrand');
$this->add(array(
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'name' => 'brand',
'options' => array(
'object_manager' => $this->getEntityManager(),
'target_class' => 'Module\Entity\Brand',
'property' => 'name',
),
));
}
}
And, finally, my controller:
$Task = $this->getServiceLocator()->get('Admin\Model\Task')->findByPk($id);
$formManager = $this->getServiceLocator()->get('FormElementManager');
$form = $formManager->create('Admin\Form\TaskForm');
$form->bind($Task);
The problem is that form Admin\Form\TaskForm instantiates in factory described in form_elements configuration section, but Admin\Form\TaskbrandFieldset does not. It just invokes.
Trying to understand this problem I found that Admin\Form\TaskForm and Admin\Form\TaskbrandFieldset instantiates with different instances of FormElementManager, first one have my config inside (including factories description), but second has nothing.
Please help me :)
The problem is in your controller. Use
$form = $formManager->get('Admin\Form\TaskForm');
instead of
$form = $formManager->create('Admin\Form\TaskForm');
Remember that you don't have to use $form->init(). It's automatically called, same like in zf1. There is a good tutorial on zf2 site
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
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 been trying all day to do multiple insert for the same form based on a number and i couldn't go any where with it. I hope someone here would be help me out...
am using admin generator on 1.4 doctrine. I have a form which i generated with only two fields. what am trying to do is, based on a number inserted the form will be repeated x number of times.
In the generator file I added a partial which placed a text field in the beginning of the form with default value of 1. If I choose 2 the form below gets duplicated twice..
Here is what i did to my form.. In action
class prizesActions extends autoPrizesActions
{
public function executeNew(sfWebRequest $request)
{
$this->form = $this->configuration->getForm(null, array('n' => 5));
$this->prizes = $this->form->getObject();
}
}
and in the PrizesForm, I wrote the following
class PrizesForm extends BasePrizesForm
{
public function configure()
{
$array = $this->getOptions();
for ($i = 0; $i < $array['n']; $i++) {
$this->setWidgets(array(
'id' => new sfWidgetFormInputHidden(),
'prize_no' => new sfWidgetFormInputText(),
'prize' => new sfWidgetFormInputText(),
'created_at' => new sfWidgetFormDateTime(),
'updated_at' => new sfWidgetFormDateTime(),
));
$this->setValidators(array(
'id' => new sfValidatorDoctrineChoice(array('model' => $this->getModelName(), 'column' => 'id', 'required' => false)),
'prize_no' => new sfValidatorInteger(array('required' => false)),
'prize' => new sfValidatorString(array('max_length' => 200, 'required' => false)),
'created_at' => new sfValidatorDateTime(),
'updated_at' => new sfValidatorDateTime(),
));
$this->widgetSchema->setNameFormat('prizes['.$i.'][%s]');
$this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
}
unset( $this['updated_at'],
$this['created_at']
);
}
}
I think the loop is working but its over writing the widgets at every entry and i cannot find other method to append instead. Any ideas?
Thanks,
Did you try embedForm()? Code below should give you an idea.
class PrizesForm extends BasePrizesForm
{
public function configure()
{
$this->setWidgets(array(
'id' => new sfWidgetFormInputHidden(),
'prize_no' => new sfWidgetFormInputText(),
'prize' => new sfWidgetFormInputText(),
'created_at' => new sfWidgetFormDateTime(),
'updated_at' => new sfWidgetFormDateTime(),
));
$this->setValidators(array(
'id' => new sfValidatorDoctrineChoice(array('model' => $this->getModelName(), 'column' => 'id', 'required' => false)),
'prize_no' => new sfValidatorInteger(array('required' => false)),
'prize' => new sfValidatorString(array('max_length' => 200, 'required' => false)),
'created_at' => new sfValidatorDateTime(),
'updated_at' => new sfValidatorDateTime(),
));
$this->widgetSchema->setNameFormat('prizes[%s]');
}
}
class PrizesGroupForm extends sfForm
{
public function configure()
{
$array = $this->getOptions();
for ($i = 0; $i < $array['n']; $i++)
{
$this->embedForm('prizes_' . $i, new PrizesForm());
}
$this->widgetSchema->setNameFormat('prizes_group[%s]');
}
}