ZF2 and Fieldset/Form usage - Unexpected Behavior - php

I am trying to create a simple login form with an email field and password field. I am running into issues when trying to display individual fields in my view. The Album tutorial on Zends' website didn't use a FIELDSET and the Blog tutorial only used echo $this->formCollection($form);. So I assumed there wouldn't be much of a difference, and everything I find online suggests there isn't a difference in syntax. Everything I have seems to match up to the Blog and Album tutorials on Zends' website respectively as far as I can tell.
The error does not occur if I move my field definitions to my FORM class (bypassing the FIELDSET) or if I dump all of the fields using:
echo $this->formCollection($form);
This is the error I am getting:
No element by the name of [USER_LOGIN] found in form
I am trying to display a single field using:
echo $this->formRow($form->get('USER_LOGIN'));
Here is the result of the formCollection call:
(*NOTE: I tried using "login-fieldset[USER_LOGIN]" in the $form->get() call and got the same behavior)
<fieldset>
<fieldset>
<label>
<span>Username</span>
<input type="text" name="login-fieldset[USER_LOGIN]" value="">
</label>
<label>
<span>Password</span>
<input type="password" name="login-fieldset[USER_PWD]" value="">
</label>
</fieldset>
<input type="submit" name="submit" value="Login">
</fieldset>
Here is the relevant code:
CSAdmin\Controller\LoginController:
namespace CSAdmin\Controller;
use Zend\View\Model\ViewModel;
use Zend\Form\FormInterface;
class LoginController extends AdminController
{
protected $loginService;
protected $loginForm;
public function __construct(
\CSAdmin\Service\LoginServiceInterface $loginService,
FormInterface $loginForm) {
parent::__construct();
$this->loginService = $loginService;
$this->loginForm = $loginForm;
}
public function indexAction()
{
array_push($this->layoutVars['customStyles'], 'css/admin/form.css');
array_push($this->layoutVars['customStyles'], 'css/admin/styles.css');
$request = $this->getRequest();
$login = $this->loginService->findUser($this->params('USER_LOGIN'));
$this->loginForm->bind($login);
if ($request->isPost()) {
//Nothing here yet
}
//Override view to use predefined Admin Views
$view = new ViewModel(array('data'=>$this->data,
'form'=>$this->loginForm
));
$view->setTemplate('CSAdmin/login/login.phtml'); // path to phtml file under view folder
//Set the Admin Layout
$layout = $this->layout();
$layout->setVariable('layout', $this->layoutVars);
$layout->setTemplate('layout/CSAdmin/login.phtml');
//Render Page
return $view;
}
}
CSAdmin\Form\LoginForm:
namespace CSAdmin\Form;
use Zend\Form\Form;
use Zend\Stdlib\Hydrator\ClassMethods;
use \CSAdmin\Model\User;
class LoginForm extends Form
{
public function __construct($name = null, $options = array())
{
parent::__construct($name, $options);
$this->setHydrator(new ClassMethods(false));
$this->setObject(new User());
$this->add(array(
'name' => 'login-fieldset',
'type' => 'CSAdmin\Form\LoginFieldset',
'options' => array(
'use_as_base_fieldset' => true
)
));
$this->add(array(
'type' => 'submit',
'name' => 'submit',
'attributes' => array(
'value' => 'Login'
)
));
}
}
CSAdmin\Form\LoginFieldset:
namespace CSAdmin\Form;
use Zend\Form\Fieldset;
use Zend\Stdlib\Hydrator\ClassMethods;
use \CSAdmin\Model\User;
class LoginFieldset extends Fieldset
{
public function __construct($name = null, $options = array())
{
parent::__construct($name, $options);
$this->setHydrator(new ClassMethods(false));
$this->setObject(new User());
$this->add(array(
'type' => 'text',
'name' => 'USER_LOGIN',
'options' => array(
'label' => 'Username'
)
));
$this->add(array(
'type' => 'password',
'name' => 'USER_PWD',
'options' => array(
'label' => 'Password'
)
));
}
}

You need to get the field set then the element so try:
echo $this->formRow($form->get('login-fieldset')->get('USER_LOGIN');

Related

How to load select option from database in zf2

I Have been following zf2 guide for blog I have created everything Controller, Factory, Form, Mapper, Model, Service, view etc
In my form I have a select element
$this->add(array(
'type' => 'select',
'name' => 'roleId',
'attributes' => array(
'id' => 'roleId',
'options' => array(
'1' => 'Admin',
'2' => 'Manager',
),
),
'options' => array(
'label' => 'Role',
),
));
Now in this form I want to load the option for the role from the database.
I tried loading the option by creating a simple function, which can be accessed in the element as below, but Am not able to fetch the result. I have already created Controller, Factory, Form, Mapper, Model, Service and view, Where I can do CRUD operation on Role.
$this->add(array(
'type' => 'select',
'name' => 'roleId',
'attributes' => array(
'id' => 'roleId',
'options' => $this->getAllRoles(),
),
'options' => array(
'label' => 'Role',
),
));
public function getAllRoles()
{
$roles = $this->getServiceLocator()->get('Admin\Service\RoleService');
$allRoles = $this->getAllTheRoles();
return $allroles;
}
Can anybody guide me how can I load all the Roles in option as listed in the IndexAction following Blog Post with ID and Name of the Role.
You could create a reusable form element that is pre-populated with the roles. To do so you must register the service with the form element manager in module.config.php.
return [
'form_elements' => [
'factories' => [
'RoleSelect' => 'MyModule\Form\Element\RoleSelectFactory',
],
],
];
There is not need to extend the standard select class as the changes are configuration only. This is best done in a factory class.
namespace MyModule\Form\Element;
use Zend\Form\Element\Select;
class RoleSelectFactory
{
public function __invoke($formElementManager, $name, $rname)
{
$select = new Select('role_id');
$select->setOptions(['label' => 'Role']);
$select->setAttributes(['id' => 'role_id']);
$serviceManager = $formElementManager->getServiceLocator();
$roleService = $serviceManager->get('Admin\Service\RoleService');
$options = [];
foreach($roleService->getAllTheRoles() as $role){
$options[$role->getId()] => $role->getName();
}
$select->setValueOptions($options);
return $select;
}
}
Adding the element within a form can then be updated to use the name of the service we registered.
$this->add([
'name' => 'role_id'
'type' => 'RoleSelect',
]);
One important point to remember is that the form using this element must be created using the $formElementManager->get('FormWithRoleSelect').
Finally found out the simple way to do this, Am really not sure if this is the correct way.
Added the Role service in the User Controller
Code in my userController.php
use Admin\Service\RoleServiceInterface;
class UserController extends AbstractActionController
{
/**
* #var \Admin\Service\UserServiceInterface
*/
protected $userService;
protected $roleService;
protected $userForm;
public function __construct(
UserServiceInterface $userService,
RoleServiceInterface $roleService,
FormInterface $userForm
)
{
$this->userService = $userService;
$this->roleService = $roleService;
$this->userForm = $userForm;
}
public function addAction()
{
$request = $this->getRequest();
$roles = $this->roleService->findAllRoles();
foreach ($roles as $role) {
if($role->getStatus() == 1) {
$allRoles[$role->getId()] = $role->getName();
}
}
$this->userForm->__construct(null, array('roleOptions'=>$allRoles));
}
}
My UserControllerFactory.php
<?php
namespace Admin\Factory;
use Admin\Controller\UserController;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class UserControllerFactory implements FactoryInterface
{
/**
* Create service
*
* #param ServiceLocatorInterface $serviceLocator
*
* #return mixed
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$realServiceLocator = $serviceLocator->getServiceLocator();
$userService = $realServiceLocator->get('Admin\Service\UserServiceInterface');
$roleService = $realServiceLocator->get('Admin\Service\RoleServiceInterface');
$userInsertForm = $realServiceLocator->get('FormElementManager')->get('Admin\Form\UserForm');
return new UserController(
$userService,
$roleService,
$userInsertForm
);
}
}
Finally the UserForm.php
<?php
namespace Admin\Form;
use Zend\Form\Form;
use Admin\Model\User;
use Zend\Stdlib\Hydrator\ClassMethods;
use Zend\Form\Element\Select;
class UserForm extends Form
{
public function __construct($name = null, $options = array())
{
$roleOptions = array();
if($options) {
$roleOptions = $options['roleOptions'];
}
parent::__construct($name, $options);
$this->setHydrator(new ClassMethods(false));
$this->setObject(new User());
$this->add(array(
'type' => 'hidden',
'name' => 'id'
));
$this->add(array(
'type' => 'select',
'name' => 'roleId',
'attributes' => array(
'id' => 'roleId',
'options' => $roleOptions
),
'options' => array(
'label' => 'Role',
),
));
}
}
This way using service manager I was successfully able to load the data in my for Select option.
Call getAllRoles() inside the controller then You can pass your custom array as parameter for form when you create form object. In form __construct function you can retrieve that array and set like this
'options' => $roles,

Fields in a form behave like "required", although they are not

I am trying to set up an edit form for an entity (Place) in my app. For this purpose I have written the form (PlaceForm), fieldset (PlaceFieldset), .phtml pages and functions in the controller. Since I am new in zf2, I have concentrated on the tutorlias on their homepage. I have seen that from validation is provided by the framework but in my case it is not necessary. None of the fields added in the fieldset have not the required attribute, however when I submit the form under all empty fields I get the message "Value is required and can't be empty" although it is actually not required. I do not want to create a wall of code in this question, so I will start with the function from the controller. If there is someone who would like to help me with this issue, just let me know and I will update any other part of the code (form, fieldset etc.) Thx in advance.
...
public function editPlaceAction() {
$id = $this->params()->fromRoute('id');
$uiServiceProvider = $this->getServiceLocator()->get('FamilyTree\Service\UiServiceProvider');
$placeArray = $uiServiceProvider->fetchSinglePlaceById($id);
$place = new Places($placeArray);
$form = new PlaceForm();
$form->bind($place);
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
var_dump($place);
}
}
$view = new ViewModel(array(
'form' => $form,
'title'=>"Edit place"
));
$view->setTemplate("family-tree/family-tree-maintenance/editPlace");
return $view;
}
...
and here you can see how my Fieldset looks like
<?php
namespace Places\Form;
use Zend\Form\Fieldset;
class PlaceFieldset extends Fieldset {
public function __construct() {
parent::__construct('place');
$this->add(array(
'name' => 'id',
'type' => 'Hidden',
));
$this->add(array(
'name' => 'name',
'type' => 'Text',
'options' => array(
'label' => 'Name',
),
));
$this->add(array(
'name' => 'admUnit1',
'type' => 'Text',
'options' => array(
'label' => 'AdmUnit1',
),
));
}
}

ZF2 - No element by the name of .. found in Form

My zend framework 2 project concerns an online restaurant Menu and I am trying to make a form to add Pizzas to database. But something is wrong with my code. The form won't show up, instead this error shows up:
No element by the name of [pizza_name] found in form
Please help me to find what's wrong with my code.
Here are my files:
addPizzaForm.php:
<?php
namespace Pizza\Form;
use Zend\Form\Form;
use Pizza\Form\AddPizzaForm;
use Pizza\Model\Pizza;
class AddPizzaForm extends Form
{
public function construct() {
parent:: construct('addpizzaform');
$this->add(array(
'name' => 'pizza_name',
'type' => 'text',
'options' => array(label => 'Pizza name')));
$this->add(array(
'name' => 'ingredients',
'type' => 'textarea',
'options' => array(label => 'Ingredients')));
$this->add(array(
'name' => 'small_price',
'type' => 'text',
'options' => array(label => 'Small price')));
$this->add(array(
'name' => 'big_price',
'type' => 'text',
'options' => array(label => 'Big price')));
$this->add(array(
'name' => 'family_price',
'type' => 'text',
'options' => array(label => 'Family price')));
$this->add(array(
'name' => 'party_price',
'type' => 'text',
'options' => array(label => 'Party price')));
$this->add(array(
'name' => 'add_pizza',
'type' => 'submit',
'attributes' => array(
'value' => 'Add New Pizza',
'id' => 'submitbutton')));
}
}
add.phtml view:
<?php
echo $this->headTitle('Add new Pizza');
?>
<div class="row">
<div class="col-md-8"> <h1> Add new Pizza </h1>
</div>
<?php
$form = $this->form;
$form->setAttribute('action', $this->url('pizza',array('action'=>'add')));
$form->prepare();
echo $this->form()->openTag($form);
echo $this->formRow($form->get('pizza_name')) . "</br>";
echo $this->formRow($form->get('ingredients')) . "</br>";
echo $this->formRow($form->get('small_price')) . "</br>";
echo $this->formRow($form->get('big_price')) . "</br>";
echo $this->formRow($form->get('family_price')) . "</br>";
echo $this->formRow($form->get('party_price')) . "</br>";
echo $this->formRow($form->get('add_pizza')) . "</br>";
echo $this->form()->closeTag();
?>
PizzaController.php:
<?php
namespace Pizza\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Pizza\Form\AddPizzaForm;
use Pizza\Model\Pizza;
class PizzaController extends AbstractActionController {
protected $pizzaTable;
public function addAction()
{
$add_form = new AddPizzaForm();
$request = $this->getRequest();
if($request->isPost())
{
$pizza = new Pizza();
$add_form->setInputFilter($pizza->getInputFilter());
$add_form->setData($request->getPost());
if($form->isValid())
{
$pizza->exchangeArray($form->getData());
$this->getPizzaTable()->save($pizza);
}
return $this->redirect()->toRoute('pizza');
}
return array('form' => $add_form);
}
public function getPizzaTable()
{
if( !$this->pizzaTable)
{
$sm = $this->getServiceLocator();
$this->pizzaTable = $sm->get('Pizza\Model\PizzaTable');
}
return $this->pizzaTable;
}
}
Welcome to stackoverflow!
You're getting that strange errors because there are FOUR important details that needs attention.
A - Your construct() method in AddPizzaForm has wrong name and signature. You have to rename construct to __construct change contents something like below:
class AddPizzaForm extends Form
{
public function __construct($name = null, $options = array() )
{
$formName = is_null($name) ? 'addpizza-form' : $name;
parent::__construct($formName, $options);
}
}
B - Create an init() method in your form and add your form elements inside that. This detail is clearly stated in official documentation:
If you are creating your form class by extending Zend\Form\Form, you
must not add the custom element in the __construct but rather in the init() method.
So, in your case:
class AddPizzaForm extends Form
{
// constructor etc..
public function init()
{
$this->add(array(
'name' => 'pizza_name',
'type' => 'text',
'options' => array(label => 'Pizza name')
)
);
// ... add other for elements ...
}
}
C. Finally, in your controller, you're trying to instantiate your form manually:
$add_form = new AddPizzaForm();
This is also bad practice. You need to get your AddPizzaForm instance from ServiceManager. This detail also stated in documentation:
You must not directly instantiate your form class, but rather get an
instance of it through the Zend\Form\FormElementManager.
To do that, introduce your AddPizzaForm in module.config.php like below:
'form_elements' => array(
'invokables' => array(
'add-pizza-form' => 'Pizza\Form\AddPizzaForm',
)
)
And grab it in your controller like this:
$add_form = $this->getServiceLocator()->get('FormElementManager')->get('add-pizza-form');
D - The last thing is; please read most of the documentation first before making some experiments. Reading documentation is most important step to getting better in any language or framework.
Hope it helps. Happy coding!

ZF2 Form, how to add a custom validator [duplicate]

This question already has answers here:
Zend Framework 2 Custom Validators for Forms
(5 answers)
Closed 9 years ago.
How can i add a custom validator to a ZF2 form?
I would like to add a custom validator to a zf2 form element or the form class itself to validate multiple elements against each other.
use Zend\Form\Form;
class MyForm extends Form {
public function init()
{
// Add some elements
$this->add(
$this->getFormFactory()->create(...);
}
// How can i add a custom validator here to the form or element?
}
}
My Current Solution
is very simpe but effective, the form class or the fieldset has has to implement the interface Zend\InputFilter\InputFilterProviderInterface
Now i can add something like this:
use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;
use \PayrollAccountingValidator;
class MyForm extends Form implements InputFilterProviderInterface {
public function init()
{
$this->getFormFactory()->create(
array(
'name' => 'salary',
'type' => 'Zend\Form\Element\Number',
'attributes' => array(
'min' => 0,
'step' => 1
),
'options' => array(
'label' => _('Salary?')
)
));
}
public function getInputFilterSpecification ()
{
return array(
'salary' => array(
'validators' => array(
new PayrollAccountingValidator($this)
)
)
);
}
}
What I would do:
Create the form
Create a input filter with a dependency of the validator
Add the validator to the field in the filter
Set the filter to the form in a factory.
Example
Form:
Here we merely add the elements to the form.
class SomeForm extends Form {
public function __construct() {
parent::__construct('someform');
$this->add(array(
'type' => 'Zend\Form\Element\Textarea',
'name' => 'somelement',
'options' => array(
'label' => 'Message',
)
));
}
}
Filter:
Here we create the filter for the releveant elements in the above form. We add the validator passed in at instantiation when creating the input filter:
namespace SomeModule\Form;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
class SomeFormFilter implements InputFilterAwareInterface {
protected $customValidator;
protected $inputFilter;
public function __construct($customValidator) {
$this->customValidator = $customValidator;
}
public function setInputFilter(InputFilterInterface $inputFilter) {
throw new \Exception("Not used");
}
public function getInputFilter() {
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$factory = new InputFactory();
$inputFilter->add(
$factory->createInput(
array(
'name' => 'somelement',
'required' => true,
'filters' => array(array(
'name' => 'StringTrim')
),
'validators' => array(
$this->customValidator
),
)
)
);
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
}
Module.php
We can now create a factory for the form to manage the filters validator dependency and apply the filter to the form:
public function getServiceConfig() {
return array(
'factories' => array(
'someForm' => function($sm) {
$form = new SomeForm();
$validator = new CustomValidator() // or $validator = $sm->get('CustomValidator');
$formFilter = new SomeFormFilter($validator);
$form->setInputFilter($formFilter->getInputFilter());
return $form;
},
),
);
}
You will obviosly need to make sure you use the correct namespaces in your Module.php or provide the FQCN's.
Now you can get this form, fully configured in you controller with one line of code:
$form = $this->getServiceLocator()->get('SomeForm');
If you have any more questions feel free to ask.

Magento: Admin form action not correct

I want to add a new form to the edit customer page, so far so good, using rewrites to customer_edit_tabs i was able to add a tab and my admin form to the page. Code looks like this.
protected function _beforeToHtml()
{
$this->addTab('extraoptions', array(
'label' => Mage::helper('customer')->__('Extra options'),
'class' => 'ajax',
'url' => $this->getUrl('module/adminhtml_tabs/info', array('_current' => true)),
));
This adds my tab corrently. From there the link on the tabs controller:
public function infoAction()
{
$this->_init();
$this->getResponse()->setBody(
$this->getLayout()->createBlock('module/adminhtml_tabs_edit')->toHtml()
);;
}
This links to my form container on Block/Adminhtml/Tabs/Edit.php
class Namespace_Module_Block_Adminhtml_Tabs_Edit extends Mage_Adminhtml_Block_Widget_Form_Container{public function __construct()
{
parent::__construct();
$this->_objectId = 'id';
$this->_mode = 'edit';
$this->_blockGroup = 'module';
$this->_controller = 'adminhtml_tabs';
$this->_updateButton('save', 'label', Mage::helper('module')->__('Save'));
}
public function getHeaderText()
{
return Mage::helper('module')->__('Extra Options');
}
}
My Block/Adminhtml/Tabs/Edit/Form.php
class Namespace_Module_Block_Adminhtml_Tabs_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
{
public function __construct()
{
parent::__construct();
}
protected function _prepareForm()
{
$form = new Varien_Data_Form(array(
'id' => 'info_form',
'action' => $this->getUrl('module/adminhtml_tabs/save', array('id' => $this->getRequest()->getParam('id'))),
'method' => 'post',
'enctype' => 'multipart/form-data'
)
);
$fieldset = $form->addFieldset('extra_options', array('legend' => Mage::helper('module')->__('Extra Options Fieldset')));
$fieldset2->addField('extra', 'text', array(
'name' => 'zip',
'title' => Mage::helper('module')->__('extra'),
'label' => Mage::helper('module')->__('extra data'),
'maxlength' => '250',
'required' => false,
));
$form->setUseContainer(true);
}
protected function _prepareLayout()
{
return parent::_prepareLayout();
}
Everything is fine, I have a new button below the default save customer buttons, but this save button does not update the action, so if i click it, it goes to the default customer/edit/save action, it does not tell me the method does not exist which it should. My guess is that there is something wrong with the container but i have tried three tutorials with little differences to no avail, hope someone can help and even maybe someone will find my code helpful.
In this line of code:
'action' => $this->getUrl('module/adminhtml_tabs/save')
You are telling Magento to look for a module named module, a controller aliased adminhtml_tabs, and a saveAction() method within that file.
You need to figure out where you want to send the user when a save needs to be performed, and then place it there (e.g. the route to your controller->saveAction() method).
I decided to create a new button to save with a custom action. On the container:
$this->_addButton('save', array(
'label' => Mage::helper('adminhtml')->__('Save Extras'),
'onclick' => 'document.myform.submit();',
'class' => 'save',
),-1,5);
This did the trick.

Categories