I have form with some attributes:
class ToraForm extends Form
{
public function __construct($name = null)
{
parent::__construct('tora');
$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'id',
'attributes' => array(
'type' => 'hidden',
),
));
$this->add(array(
'name' => 'name',
'attributes' => array(
'type' => 'text',
'required' => true,
),
'options' => array(
'label' => 'name',
),
));
}
but I want add drop-down list with data taken from another model. How to do it?
There are several different approaches you can take. Ultimately your Form has a dependency, which needs to be injected. I have written an in-depth blog-post about the three most common use-cases for Form-Dependencies for a Select-List.
Zend\Form\Element\Select and Database-Values
My BlogPost covers the following scenarios:
Zend\Form\Element\Select via DbAdapter
Zend\Form\Element\Select via TableGateway
DoctrineModule\Form\Element\DoctrineObject via Doctrine2
Here i will demonstrate only the DbAdapter approach without much explanation. Please refer to my blogpost for the in-depth explanations.
public function formDbAdapterAction()
{
$vm = new ViewModel();
$vm->setTemplate('form-dependencies/form/form-db-adapter.phtml');
$dbAdapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
$form = new DbAdapterForm($dbAdapter);
return $vm->setVariables(array(
'form' => $form
));
}
Then the respective Form Class:
class DbAdapterForm extends Form
{
protected $dbAdapter;
public function __construct(AdapterInterface $dbAdapter)
{
$this->setDbAdapter($dbAdapter);
parent::__construct('db-adapter-form');
$this->add(array(
'name' => 'db-select',
'type' => 'Zend\Form\Element\Select',
'options' => array(
'label' => 'Dynamic DbAdapter Select',
'value_options' => $this->getOptionsForSelect(),
'empty_option' => '--- please choose ---'
)
));
}
// more later...
// Also: create SETTER and GETTER for $dbAdapter!
}
And last but not least the DataProvider function:
public function getOptionsForSelect()
{
$dbAdapter = $this->getDbAdapter();
$sql = 'SELECT t0.id, t0.title FROM selectoptions t0 ORDER BY t0.title ASC';
$statement = $dbAdapter->query($sql);
$result = $statement->execute();
$selectData = array();
foreach ($result as $res) {
$selectData[$res['id']] = $res['title'];
}
return $selectData;
}
My use is like that:
Class Useful{
/**
* All languages
* #return array
*/
public static function getLanguages(){
return array(
'fr_DZ'=>'Algeria - Français',
'es_AR'=>'Argentina - Español',
'en_AU'=>'Australia - English',
'nl_BE'=>'België - Nederlands',
'fr_BE'=>'Belgique - Français',
'es_BO'=>'Bolivia - Español',
'bs_BA'=>'Bosna i Hercegovina - Hrvatski',
...
);
}
}
After I use like that:
$this->add(array(
'type' => 'Zend\Form\Element\Select',
'name' => 'languages',
'attributes'=>array(
'multiple'=>"multiple",
),
'options' => array(
'label' => 'My languages I speak',
'description' => '',
'value_options' => Useful::getLanguages()
),
));
Related
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.
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 have a form with two dates, start and stop. I have a validator for start and I want to validate stop and also that stop is after start. But the after validation only makes sense if start is valid.
isValid($value, $context = null) could be passed the other values in the context variable, but then I have to do the start check again.
So is there a possibility to check the result of the start validation in the stop validator's isValid() function?
You can use Callback
Or just write your own validator
------ Edit - my proposed answer - Input filter with callback or validator ------
I do that like this.
First create a filter with all params:
namespace MyGreatNameSpace\Filter;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\Factory as InputFactory;
class MyDateFilter extends InputFilter
{
public function __construct($myGreatClass)
{
$factory = new InputFactory();
$this->add($factory->createInput(array(
'name' => 'start_date',
'required' => true,
'validators' => array(
array(
'name' => 'Date',
'options' => array(
'format' => '2000-10-10',
),
)
),
)));
$this->add($factory->createInput(array(
'name' => 'end_date',
'required' => true,
'validators' => array(
array(
'name' => 'Date',
'options' => array(
'format' => '2000-10-10',
),
),
array(
'name' => 'Callback',
'options' => array(
'callback' => array($myGreatClass, 'isDateNewer'),
'messages' => array(
'callbackValue' => "The end date is Older then the start date",
),
),
),
),
)));
} // End of __construct
}
Create the callback function
public function isDateNewer($date, $params)
{
$date2 = $params['start_date'];
if ($date > $date2) { // Over simplistic
return TRUE;
}
}
Implant in the controller (I used services to pull the form/filter class)
// Get the form / validator objects from the SM
$form = $this->getServiceLocator()->get('date_form');
$filter = $this->getServiceLocator()->get('date_filter');
// Inject the input filter object to the form object, load the form with data and bind the result to the model
$form->setInputFilter($filter);
$form->setData($post);
$form->bind($myModel); // (if you wish to bind the data to whatever)
if (!$form->isValid()) {
return $this->forward()->dispatch.... (or whatever)
}
Another slightly diffrent way (though cleaner) is to write a validator. Check the Zend\Validator\Identical (note the token)
array(
'name' => '\Application\Validator\myNewNamedValidator',
'options' => array(
'token' => 'start_date',
'messages' => array(
'older' => "The end date is Older then the start date",
),
),
),
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 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);