Symfony get query from form with some empty text areas - forms

I'd like to know if there is anyway to get a query result from the text areas that have been filled while some have not.
Example:
$form = $this->get('form.factory')->create(new UsersType(), new Users())
->add('firstname', 'text', array('required' => false, 'label' => 'First name '))
->add('lastname', 'text', array('required' => false, 'label' => 'Last name '))
;
$idm = $em->getRepository('MyBundle:Users')->findBy(
array('number' => $form->get('number')->getData(),
'firstname' => $form->get('firstname')->getData(),
'lastname' => $form->get('lastname')->getData()
));
I would like that it ignores the texts which have not been filled and execute a query only with the filled texts.
Thank you!

$lookups = array('number', 'firstname', 'lastname');
$queryArray = array();
foreach($lookups as $lookup){
$fieldData = $form->get($lookup)->getData();
if(!empty($fieldData)){
$queryArray[$lookup] = $fieldData;
}
}
if(sizeof($queryArray) > 0){
$idm = $em->getRepository('MyBundle:Users')->findBy($queryArray);
}

Related

symfony form not coming back valid, do i have form object issues?

i have tried various ways, but i cant get form to come back isValid() so i wanted to make sure i have this portion correct first.
<?php
namespace ABC\DeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller,
Sensio\Bundle\FrameworkExtraBundle\Configuration\Route,
Sensio\Bundle\FrameworkExtraBundle\Configuration\Template,
Sensio\Bundle\FrameworkExtraBundle\Configuration\Method,
Symfony\Component\HttpFoundation\Request,
Symfony\Component\HttpKernel\Exception\HttpException,
Symfony\Component\Form\FormBuilderInterface,
Symfony\Component\Form\Forms,
Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationExtension,
Symfony\Component\Form\Extension\Validator\ValidatorExtension,
Symfony\Component\Validator\Validation,
Symfony\Component\Validator\Constraints\Length,
Symfony\Component\Validator\Constraints\NotBlank,
Symfony\Component\Config\Definition\Exception\Exception,
Symfony\Component\HttpFoundation\Response,
ABC\CoreBundle\Controller\CoreController;
class DoSomethingController extends CoreController
{
protected $debug = FALSE;
public function doSomethingAction(Request $request)
{
/**
* build the form here
*
* Either use out custom build form object
* $form = $formFactory->createBuilder('form', $defaultData)
*
* Or alternatively, use the default formBuilder
* $form = $this->createFormBuilder($defaultData)
*/
$validator = Validation::createValidator();
$formFactory = Forms::createFormFactoryBuilder()
->addExtension(new HttpFoundationExtension())
->addExtension(new ValidatorExtension($validator))
->getFormFactory();
$defaultData = array(
'comment' => 'Type your comment here',
'name' => 'Type your name here',
'resources' => '{}',
'warning' => 'Warning, your still in debug mode on your controller.php'
);
//$form = $this->createFormBuilder($defaultData)
$form = $formFactory->createBuilder('form', $defaultData)
->setAction($this->generateUrl('do_something'))
->add("emails", 'text', array(
'label' => "Recipient's email address (separate with a comma)",
'constraints' => array(// constraints here
),
))
->add('comment', 'textarea', array(
'label' => "Leave a comment",
))
->add('name', 'text', array(
'label' => "Your name",
'constraints' => array(// constraints here
),
))
->add('email', 'email', array(
'label' => "Your email address",
'constraints' => array(// constraints here
),
))
->add('copy', 'checkbox', array(
'label' => "Send me a copy",
'required' => false,
))
->add('cancel', 'button', array(
'label' => "Cancel",
'attr' => array('class' => 'btn-branded'),
))
->add('save', 'submit', array(
'label' => "Email Resources",
'attr' => array('class' => 'btn-branded'),
));
//make resources visible by putting them into a text box
$resourceInputType = $this->debug ? 'text' : 'hidden';
$form->add('resources', $resourceInputType, array(
'constraints' => array(// constraints here
),
));
//add a visible warning input box, so we know were on debug, we don't want this released to live on debug.
$this->debug ? ($form = $form->add('warning', 'text')) : null;
$form .= $form->getForm();
//alternatively
//$form->bind($_POST[$form->getName()]);
//$form->handleRequest($request);
//validate
if ($form->isValid()) {
$data = $form->getData();
//run some data checks, then fire it off
$something = $this->DoSomething($data);
return $something;
//$return=array("responseCode"=>200, "data"=>$data);
// $return=json_encode($return); //json encode the array
// return new Response($return,200,array('Content-Type'=>'application/json'));//make sure it has the correct content type
}else
{
echo '<pre>';
var_dump('form is coming back as not isValid(), make sure debug is off, heres our errors list:<br>');
var_dump($form->getErrorsAsString());
echo '</pre>';
}
//its not a POST, or POST is invalid, so display the form
return $this->render($this->someTemplate, array(
'form' => $form->createView(),
));
}
}
1) Im a bit confused (oop wise) on the way to pass around this form object during conditional manipulation. Do i need to concatenate it when manipulating it or what does symfony offer to avoid this, or am i just passing the object around wrong? see this example to understand better this question. e.g. $form .= $form->getForm(); How would i properly concatenate this form object during manipulation, like i did when i used the ternary, to convine myself that when i pass this object around, its teh same object, and not a new one.
2) see any other problems that might be causing the breakage?
EDIT #Chausser
this is the latest code, streamlined a bit, that i am working with now using some apparently rare exmples found here http://api.symfony.com/2.5/Symfony/Component/Form/Forms.html. its still not coming back isValid() . Please compare my former, and new usage example of the form object.
<?php
/**
* #param Request $request
* #Route("/do/something", name="do_something", options={"expose"=true})
* #Method({"GET", "POST"})
* #return mixed
*/
public function doSomethingAction(Request $request)
{
$defaultData = array(
'comment' => 'Type your comment here',
'name' => 'Type your name here',
'resources' => '{}',
'warning' => 'Warning, your still in debug mode on your controller.php'
);
$resourceInputType = $this->debug ? 'text' : 'hidden';
$formFactory = Forms::createFormFactory();
$form = $formFactory
->createBuilder()
->setAction($this->generateUrl('do_something'))
->add("emails", 'text', array(
'label' => "Recipient's email address (separate with a comma)",
'constraints' => array(// constraints here
),
))
->add('comment', 'textarea', array(
'label' => "Leave a comment",
))
->add('name', 'text', array(
'label' => "Your name",
'constraints' => array(// constraints here
),
))
->add('email', 'email', array(
'label' => "Your email address",
'constraints' => array(// constraints here
),
))
->add('copy', 'checkbox', array(
'label' => "Send me a copy",
'required' => false,
))
->add('cancel', 'button', array(
'label' => "Cancel",
'attr' => array('class' => 'btn-branded'),
))
->add('save', 'submit', array(
'label' => "Email Resources",
'attr' => array('class' => 'btn-branded'),
))
->add('resources', $resourceInputType, array(
'constraints' => array(// constraints here
),
))
->getForm();
$form->handleRequest($request);
//validate
if ($form->isValid()) {
$data = $form->getData();
//run some data checks, then fire it off
$something = $this->DoSomething($data);
return $something;
//other options for returning
//$return=array("responseCode"=>200, "data"=>$data);
// $return=json_encode($something); //json encode the array
// return new Response($return,200,array('Content-Type'=>'application/json'));//make sure it has the correct content type
} else {
echo '<pre>';
var_dump('form is coming back as not isValid(), make sure debug is off, heres our errors list:<br>');
var_dump($form->getErrorsAsString());
echo '</pre>';
}
//its not a POST, or POST is invalid, so display the form
return $this->render($this->someTemplate, array(
'form' => $form->createView(),
));
}
EDIT
so now after my edits to get the form to not try and haldne the request, unless its teh POST request, not the GET request
if($request && $request->getMethod() == 'POST'){
$form->handleRequest($request);
//validate
if ($form->isValid()) {
$data = $form->getData();
//run some data checks, then fire it off
$something = $this->DoSomething($data);
return $something;
//other options for returning
//$return=array("responseCode"=>200, "data"=>$data);
// $return=json_encode($something); //json encode the array
// return new Response($return,200,array('Content-Type'=>'application/json'));//make sure it has the correct content type
} else {
echo '<pre>';
var_dump('form is coming back as not isValid(), make sure debug is off, heres our errors list:<br>');
var_dump($form->getErrorsAsString());
echo '</pre>';
}
}
which has led to the controller error mentioned below
Ok, it looks as if the validator extension, when used, was breaking, since the HttpFoundationExtension() wasnt being included. Apparently to use either the validator, or the factory builder (not sure which) it needs this extension as well.
working example, copied from initial example, with working parts added.
<?php
namespace ABC\DeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller,
Sensio\Bundle\FrameworkExtraBundle\Configuration\Route,
Sensio\Bundle\FrameworkExtraBundle\Configuration\Template,
Sensio\Bundle\FrameworkExtraBundle\Configuration\Method,
Symfony\Component\HttpFoundation\Request,
Symfony\Component\HttpKernel\Exception\HttpException,
Symfony\Component\Form\FormBuilderInterface,
Symfony\Component\Form\Forms,
Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationExtension,
Symfony\Component\Form\Extension\Validator\ValidatorExtension,
Symfony\Component\Validator\Validation,
Symfony\Component\Validator\Constraints\Length,
Symfony\Component\Validator\Constraints\NotBlank,
Symfony\Component\Config\Definition\Exception\Exception,
Symfony\Component\HttpFoundation\Response,
ABC\CoreBundle\Controller\CoreController;
class DoSomethingController extends CoreController
{
protected $debug = FALSE;
public function doSomethingAction(Request $request)
{
$validator = Validation::createValidator();
$builder = Forms::createFormFactoryBuilder()
->addExtension(new ValidatorExtension($validator))
->addExtension(new HttpFoundationExtension());
$defaultData = array(
'comment' => 'Type your comment here',
'name' => 'Type your name here',
'resources' => '{}',
'warning' => 'Warning, your still in debug mode on your controller.php'
);
$resourcesInputType = $this->debug ? 'text' : 'hidden';
$form = $builder->getFormFactory()
->createBuilder('form', $defaultData)
->setAction($this->generateUrl('do_something'))
->add("emails", 'text', array(
'label' => "Recipient's email address (separate with a comma)",
'constraints' => array(// constraints here
),
))
->add('comment', 'textarea', array(
'label' => "Leave a comment",
))
->add('name', 'text', array(
'label' => "Your name",
'constraints' => array(// constraints here
),
))
->add('email', 'email', array(
'label' => "Your email address",
'constraints' => array(// constraints here
),
))
->add('copy', 'checkbox', array(
'label' => "Send me a copy",
'required' => false,
))
->add('cancel', 'button', array(
'label' => "Cancel",
'attr' => array('class' => 'btn-branded'),
))
->add('save', 'submit', array(
'label' => "Email Resources",
'attr' => array('class' => 'btn-branded'),
))->add('resources', $resourcesInputType, array(
'constraints' => array( // constraints here
),
))
->getForm()
->handleRequest($request);
if ($form->isValid()) {
$data = $form->getData();
//run some data checks, then fire it off
$something = $this->DoSomething($data);
return $something;
}
// initial render
return $this->render($this->someTemplate, array(
'form' => $form->createView(),
));
}
}

Zend Framework validation: set element value to empty string when there is no data in POST

I'm sorry if my question is a bit dumb, but I have looked at other questions/Googled this and still didn't get it.
I have a form with default and custom elements:
class Form_Client extends Planner_Form {
public function init() {
$this->addPrefixPath('Planner_Form_Element', 'Planner/Form/Element', 'element');
$this->setAttrib('name', 'clientForm');
$this->addElement('text', 'phone', array(
'label' => 'Телефон',
'required' => true,
'filters' => array('Digits'),
'ng-model' => 'clientForm.phone',
));
$this->addElement('text', 'extra_phone_1', array(
'label' => 'Дополнительный телефон',
'required' => false,
'filters' => array(
array('Digits'),
),
'ng-model' => 'clientForm.extra_phone_1',
));
$this->addElement('text', 'name', array(
'label' => 'Имя',
'required' => false,
'ng-model' => 'clientForm.name',
));
$this->addElement('datetime', 'birthday', array(
'label' => 'Дата рождения',
'required' => false,
'ng-model' => 'clientForm.birthday',
));
I send form via AngularJs, and when I check it
if ($request->isPost()) {
$body = $this->getRequest()->getRawBody();
$data = Zend_Json::decode($body);
Zend_Debug::dump($data);
$form = new Form_Client();
if ($form->isValid($data)) {
$values = $form->getValues();
Zend_Debug::dump($values);
}
I get the following:
array(1) {
["phone"] => string(10) "9138521376"
}
array(4) {
["phone"] => string(10) "9138521376"
["extra_phone_1"] => string(0) ""
["name"] => NULL
["birthday"] => NULL
}
So my question is: why extra_phone_1 field gets empty string, and name gets NULL? Is it because of filter on extra_phone_1 field? If so, how can I set field value to empty string, when there is no data in POST for this field?
You are right, the value is'' due Digits filter and null without this filter.
To have a non-null value in the name field, for example, you can use the same technique and try to put the filter 'StringTrim'

how to set value from database in Zend Framework 1 in add form element

I have a form in Zend Framework 1. when I click on edit button I want to display values from databases in the form. but I don't know how to do it.
This is my form code:
// Add an email element
$this->addElement('text', 'orgname', array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators'=>Array(
'ViewHelper','Errors'
)
));
This is my controller:
public function editclientcompanyAction()
$form = new Application_Form_Companyform();
$form->addform();
$this->view->form = $form;
$request = $this->getRequest();
$editid=$request->getParam('id');
$edit_show = new Application_Model_Clientcompany;
$showdetails = $edit_show->editclient($editid);
$this->view->assign('datas', $showdetails);
How do I display database vlaues in my Zend Form?
There are two cases.
1) Populating form which has fields same like the database table fields : If you have the form which has same fields like the database fields, then you can populate them easily.
First you need to get the data from the database and then call the Zend_Form populate function passing the data as an associative array, where keys will be same like form fields names and values will be values for the form fields, as below in case of your form.
This will be in your controller
$data = array("orgname" => "Value for the field");
$form = new Application_Form_Companyform();
$form->populate($data);
Now send will automatically populate the form field orgname. You dont need to modify your form or set the value field in the addElement.
*2)Setting field value manually: * The second case is to set the value manually. First you will need to modify your form and add a constructor to it. Also in your form class you will need to create a property (if you have multiple fields, then you can create an array property or multiple properties for each field. This will be all up to you.). And then set the value key in the addElement. Your form should look like this
class Application_Form_Companyform extends Zend_Form
{
private $orgname;
public function __contruct($orgname)
{
$this->orgname = $orgname;
//It is required to call the parent contructor, else the form will not work
parent::__contruct();
}
public function init()
{
$this->addElement('text', 'orgname',
array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators'=>Array('ViewHelper','Errors'),
'value'=>$this->orgname
)
));
} //end of init
} //end of form
Now your controller, you will need to instantiate the form object passing the value of the orgname field like below
$form = new Application_Form_Companyform("This is the value for orgname");
And thats it.
I used such methods and it works like a charm. For your requirements, you may need to adjust the above sample code, as i did not checked it, but it will run fine for sure i hope :P
Thank you
Ok in either ZF1 or ZF2 just do this.
// Add an email element
$this->addElement('text', 'orgname',
array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators' => Array('ViewHelper','Errors'),
'value' => $showdetails->orgname
)
));
You might want to test first for null/empty values first though, you could use ternary operators for convenience:
// Add an email element
$this->addElement('text', 'orgname',
array(
'required' => true,
'filters' => array('StringTrim'),
'style' => array('width:220px'),
'decorators' => Array('ViewHelper','Errors'),
'value' => empty($showdetails->orgname)? null : $showdetails->orgname
)
));
Please have a look in my edit function at /var/www/html/zend1app/application/controllers/CountryController.php :
public function editAction() {
$data = $this->getRequest()->getParams();
$id = (int)$data['id'];
$options = array();
$country = $this->getCountryModel()->fetchRow("id=$id");
if(!$country)
{
throw new Exception("Invalid Request Id!");
}
$form = new Application_Form_Country();
$form->addIdElement();
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost())){
$data = new Application_Model_Country();
if($data->save($form->getValues()))
{
$message = array("sucess" => "Country has been updated!");
}
else {
$message = array("danger" => "Country could not be updated!");
}
$this->_helper->FlashMessenger->addMessage($message);
return $this->_helper->redirector('index');
}
}
$options = array (
'id' => $country->id,
'name' => $country->name,
'code' => $country->code
);
$form->populate( $options ); // data binding in the edit form
$this->view->form = $form;
}
and form class at /var/www/html/zend1app/application/forms/Country.php :
class Application_Form_Country extends Zend_Form
{
public function init()
{
// Set the method for the display form to POST
$this->setMethod('post');
// Add an email element
$this->addElement('text', 'name', array(
'label' => 'Enter Country Name:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
array('validator' => 'StringLength', 'options' => array(0, 20))
)
));
// Add the comment element
$this->addElement('text', 'code', array(
'label' => 'Enter Country Code:',
'required' => true,
'validators' => array(
array('validator' => 'StringLength', 'options' => array(0, 20))
)
));
// Add the submit button
$this->addElement('submit', 'submit', array(
'ignore' => true,
'label' => 'Save',
));
// And finally add some CSRF protection
$this->addElement('hash', 'csrf', array(
'ignore' => true,
));
}
public function addIdElement()
{
$this->addElement('hidden', 'id');
}
}
HTH

Drupal form option populate from loop

I want to populate select option from loop
$form['vote']['selected'] = array(
'#type' => 'select',
'#title' => 'Select',
'#name' => 'name',
);
foreach($loop as $row)
$form['vote']['selected']['#options'] = array($row->id => $row->name);
}
return $form;
Need some help?
This is the standard way to do it:
$options = array();
foreach($loop as $row)
$options[$row->id] = $row->name;
}
$form['vote']['selected'] = array(
'#type' => 'select',
'#title' => 'Select',
'#name' => 'name',
'#options' => $options
);
You might also look at the fetchAllKeyed method of the database query which is a handy shortcut to get data from the database into a keyed array suitable for select lists:
$options = db_query('SELECT id, name FROM {table}')->fetchAllKeyed();
The above will produce exactly the same as the foreach loop above.

How to verify password field in zend form?

In my form, I'm trying to verify that the user fills in the same value both times (to make sure they didn't make a mistake). I think that's what Zend_Validate_Identical is for, but I'm not quite sure how to use it. Here's what I've got so far:
$this->addElement('password', 'password', array(
'label' => 'Password:',
'required' => true,
'validators' => array(
'Identical' => array(What do I put here?)
)
));
$this->addElement('password', 'verifypassword', array(
'label' => 'Verify Password:',
'required' => true,
'validators' => array(
'Identical' => array(What do I put here?)
)
));
Do I need it on both elements? What do I put in the array?
For what its worth, support for comparing two identical form fields within a model was added to the 1.10.5 release. I wrote up a short tutorial on the matter, which you can access via the below link, but the bottom line is that the Zend_Validate_Identical validator has been refactored to accept a form field name as input. For instance, to compare the values of form fields pswd and confirm_pswd, you'll attach the validator to confirm_pswd like so:
$confirmPswd->addValidator('Identical', false, array('token' => 'pswd'));
Works like a charm.
See Validating Identical Passwords with the Zend Framework for a more complete example.
I can't test it at the moment, but I think this might work:
$this->addElement('password', 'password', array(
'label' => 'Password:',
'required' => true
));
$this->addElement('password', 'verifypassword', array(
'label' => 'Verify Password:',
'required' => true,
'validators' => array(
array('identical', true, array('password'))
)
));
After two days I found the right answer follow me step by step:
step 1:
create PasswordConfirmation.php file in root directory of your project with this path:
yourproject/My/Validate/PasswordConfirmation.php with this content below:
<?php
require_once 'Zend/Validate/Abstract.php';
class My_Validate_PasswordConfirmation extends Zend_Validate_Abstract
{
const NOT_MATCH = 'notMatch';
protected $_messageTemplates = array(
self::NOT_MATCH => 'Password confirmation does not match'
);
public function isValid($value, $context = null)
{
$value = (string) $value;
$this->_setValue($value);
if (is_array($context)) {
if (isset($context['user_password'])
&& ($value == $context['user_password']))
{
return true;
}
}
elseif (is_string($context) && ($value == $context)) {
return true;
}
$this->_error(self::NOT_MATCH);
return false;
}
}
?>
step 2:
Add two field in your form like this:
//create the form elements user_password
$userPassword = $this->createElement('password', 'user_password');
$userPassword->setLabel('Password: ');
$userPassword->setRequired('true');
$this->addElement($userPassword);
//create the form elements user_password repeat
$userPasswordRepeat = $this->createElement('password', 'user_password_confirm');
$userPasswordRepeat->setLabel('Password repeat: ');
$userPasswordRepeat->setRequired('true');
$userPasswordRepeat->addPrefixPath('My_Validate', 'My/Validate', 'validate');
$userPasswordRepeat->addValidator('PasswordConfirmation', true, array('user_password'));
$this->addElement($userPasswordRepeat);
now enjoy your code
class My_Validate_PasswordConfirmation extends Zend_Validate_Abstract
{
const NOT_MATCH = 'notMatch';
protected $_messageTemplates = array(
self::NOT_MATCH => 'Password confirmation does not match'
);
public function isValid($value, $context = null)
{
$value = (string) $value;
$this->_setValue($value);
if (is_array($context)) {
if (isset($context['password_confirm'])
&& ($value == $context['password_confirm']))
{
return true;
}
} elseif (is_string($context) && ($value == $context)) {
return true;
}
$this->_error(self::NOT_MATCH);
return false;
}
}
http://framework.zend.com/manual/en/zend.form.elements.html
$token = Zend_Controller_Front::getInstance()->getRequest()->getPost('password');
$confirmPassword->addValidator(new Zend_Validate_Identical(trim($token)))
->addFilter(new Zend_Filter_StringTrim())
->isRequired();
Use the above code inside the class which extends zend_form.
I was able to get it to work with the following code:
In my form I add the Identical validator on the second element only:
$this->addElement('text', 'email', array(
'label' => 'Email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array('EmailAddress')
));
$this->addElement('text', 'verify_email', array(
'label' => 'Verify Email:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array('EmailAddress', 'Identical')
));
And in the controller, just before calling isValid():
$validator = $form->getElement('verify_email')->getValidator('identical');
$validator->setToken($this->_request->getPost('email'));
I don't know if there is a more elegant way of doing this without having to add this code to the controller. Let me know if there is a better way to do this.
With Zend Framework 1.10 the code needed to validate the equality of two fields using Zend Form and Zend Validate is:
$form->addElement('PasswordTextBox',
'password',
array('label' => 'Password')
);
$form->addElement('PasswordTextBox',
'password_confirm',
array('label' => 'Confirm password',
'validators' => array(array('Identical', false, 'password')),
)
);
You can notice, in the validators array of the password_confirm element, that the Identical validator is passed as array, the semantics of that array is: i) Validator name, ii) break chain on failure, iii) validator options
As you can see, it's possible to pass the field name instead of retrieving the value.