ZF2 Nested Collection element has no value - php

I have created a form with nested Collection Customer(Form) -> Categories(Collection/Fieldset) -> Tags(Collection/Fieldset).
It's:
One(Customer) -> Many(Categories)
One(Catogrie) -> Many(Tags)
After bind the customer to the Form it looks like everything is working fine. The Hydrator get the object and the elements where created in Tags.
But in the View the Tag-Elements have no value...
I have checked the Hydrator for typos but everything is fine I copy/paste the index to make sure. When i var_dump the Tags-Collection the objects with value are binded.
I really dont know where the error is, thats why i dont enter some code here I think it would be to much. When you have an idea I can show you the code where you guess the error can be.
Greetings.
Tiega.
EDIT:
Okay I will try to do my best to give you readable code :)
class KontakteController extends AbstractActionController {
public function getKontaktAction()
{
$formManager = $this->serviceLocator->get('FormElementManager');
$kontaktForm = $formManager->get('KontakteManager\Form\KontakteForm');
$id = $this->params()->fromRoute('id');
$kontakt = $this->getKontakte()->getKontakt($id);
if (!$id || !$kontakt) {
return $this->redirect()->toRoute('kontakte', array(
'action' => 'addKontakt'
));
}
$kontakt->initFirmaKommunikation($this->getKommunikation());
$kontakt->initAdressen($this->getAdressen());
$kontakt->initAnsprechpartner($this->getKontakte());
$kontakt->initBankverbindungen($this->getBankverbindung());
$kontakt->initFirmaKategorien($this->getKontakteKategorie());
$kontakt->initPersonKategoiern($this->getKontakteKategorie());
$kontaktForm->bind($kontakt);
return new ViewModel(array(
'kontaktForm' => $kontaktForm,
'geloescht' => $kontakt->geloescht,
'tags' => $this->ladeTags(),
));
}
CustomerFieldset:
class KontakteForm extends Form implements InputFilterProviderInterface {
public function __construct()
{
parent::__construct('kontakt');
$this->setHydrator(new KontaktHydrator())
->setObject(new Kontakt());
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'firmaKategorien',
'options' => array(
'count' => 0,
'allow_add' => true,
'allow_remove' => true,
'should_create_template' => false,
'target_element' => array(
'type' => 'KontakteManager\Form\KontaktKategorieFieldset'
)
)
));
}
/**
* #return array
\*/
public function getInputFilterSpecification()
{
return array();
}
The CategorieFieldset:
class KontaktKategorieFieldset extends Fieldset {
public function __construct()
{
parent::__construct('kontakteKategorie');
$this->setHydrator(new KontaktKategorieFieldsetHydrator())
->setObject(new KontaktKategorie());
$this->add(array(
'name' => 'id',
'type' => 'Zend\Form\Element\Hidden',
'attributes' => array(
'class' => 'form-control',
),
));
$this->add(array(
'name' => 'bezeichnung',
'type' => 'Zend\Form\Element\Text',
'attributes' => array(
'class' => 'form-control',
),
'options' => array(
'label' => 'Kategorie',
),
));
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'tags',
'options' => array(
'count' => 0,
'allow_add' => true,
'allow_remove' => true,
'should_create_template' => false,
'target_element' => array(
'type' => 'KontakteManager\Form\TagFieldset'
)
)
));
}
And the TagFielset:
class TagFieldset extends Fieldset implements InputFilterProviderInterface {
public function __construct()
{
parent::__construct('Tag');
$this->setHydrator(new TagHydrator())
->setObject(new Tag());
$this->add(array(
'name' => 'id',
'type' => 'Zend\Form\Element\Hidden',
'attributes' => array(
'class' => 'form-control',
),
));
$this->add(array(
'name' => 'mehrsprachig',
'type' => 'Zend\Form\Element\Hidden',
'attributes' => array(
'class' => 'form-control',
),
'options' => array(
'label' => 'Mehrsprachig',
),
));
$this->add(array(
'name' => 'kategorieID',
'type' => 'Zend\Form\Element\Hidden',
'attributes' => array(
'class' => 'form-control',
),
));
$this->add(array(
'name' => 'bezeichnung',
'type' => 'Zend\Form\Element\Text',
'attributes' => array(
'class' => 'form-control',
'readonly' => 'readonly',
),
'options' => array(
'label' => 'Bezeichnung',
),
));
}
/**
* #return array
\*/
public function getInputFilterSpecification()
{
return array();
}
And the View code how i try to display the collections
<h5 class="text-primary"><strong>Kategorien</strong></h5>
<hr>
<?php foreach($kontaktForm->get('firmaKategorien') as $element): ?>
<div class="row">
<div class="col-lg-12">
<div class="col-lg-6">
<?php echo $this->formElement($element->get('bezeichnung')); ?>
</div>
<div class="col-lg-6">
<?php foreach($element->get('tags') as $tag): ?>
<?php echo $this->formElement($tag->get('bezeichnung')); ?>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endforeach; ?>
and here an example result:
<h5 class="text-primary"><strong>Kategorien</strong></h5>
<hr>
<div class="row">
<div class="col-lg-12">
<div class="col-lg-6">
<input type="text" name="firmaKategorien[0][bezeichnung]" class="form-control" value="Druckerei">
</div>
<div class="col-lg-6">
<input type="text" name="firmaKategorien[0][tags][0][bezeichnung]" class="form-control" readonly="readonly" value="">
<input type="text" name="firmaKategorien[0][tags][1][bezeichnung]" class="form-control" readonly="readonly" value="">
</div>
</div>

See if this will make any changes
$kontaktForm->bind($kontakt);
//Add this line
$kontaktForm->setData((Array)$kontakt);
Please post back the error you get

Related

Zend Framework 3 - Add and Remove new input element section using javascript

I want to add multiple school locations in zend-form on click of anchor tag or button.
So that zend form validation can be applied to all dynamically created fields
Please see attached image.I want to clone div with in red border in image
Below is SchoolController Class
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use School\Service\SchoolManager;
use Doctrine\ORM\EntityManager;
use Zend\View\Model\ViewModel;
use Application\Form\AddSchoolForm;
use School\Entity\School;
use School\Entity\SchoolLocation;
class SchoolController extends AbstractActionController {
/**
* Entity manager.
* #var Doctrine\ORM\EntityManager
*/
private $entityManager;
/**
* School manager.
* #var School\Service\SchoolManager
*/
private $schoolManager;
public function __construct($entityManager, $schoolManager) {
$this->entityManager = $entityManager;
$this->schoolManager = $schoolManager;
}
public function addAction() {
$form = new AddSchoolForm();
// Check if user has submitted the form
if ($this->getRequest()->isPost()) {
// Fill in the form with POST data
$data = $this->params()->fromPost();
$form->setData($data);
// Validate form
if ($form->isValid()) {
$reqData = array(
'name' => $data['name'],
'description' => $data['description'],
'active' => 1,
'school_location' => (object) array(
(object) array(
"apartment_number" => $data['apartment_number'],
"street_name" => $data['street_name'],
"city" => $data['city'],
"state" => $data['state'],
"pin" => $data['pin'],
"active" => 1)
)
);
$this->schoolManager->addSchool((object) $reqData);
} else {
print_r($form->getMessages());
die("not valid data");
$isLoginError = true;
}
}
return new ViewModel([
'form' => $form
]);
}
}
Below is AddSchoolForm Class:
<?php
namespace Application\Form;
use Zend\Form\Element;
use Zend\Form\Form;
use Zend\InputFilter\InputFilter;
/**
* This form is used to collect user's login, password and 'Remember Me' flag.
*/
class AddSchoolForm extends Form {
/**
* Constructor.
*/
public function __construct() {
// Define form name
parent::__construct('addschool-form');
// Set POST method for this form
$this->setAttribute('method', 'post');
$this->addElements();
$this->addInputFilter();
}
/**
* This method adds elements to form (input fields and submit button).
*/
protected function addElements() {
$this->add([
'attributes' => array(
'name' => 'name',
'type' => 'text',
'id' => 'name',
'class' => 'form-control',
'required' => 'required',
),
'options' => [
'label' => 'School Name',
],
]);
// Add "desc" field
$this->add([
'attributes' => array(
'name' => 'description',
'type' => 'text',
'id' => 'description',
'class' => 'form-control',
'required' => 'required',
),
'options' => [
'label' => 'Description',
],
]);
$this->add([
'type' => 'hidden',
'name' => 'active',
'value' => 1
]);
// Add "school location" field
$this->add([
'attributes' => array(
'name' => 'apartment_number',
'type' => 'text',
'id' => 'apartment_number',
'class' => 'form-control'
),
'options' => [
'label' => 'Apartment Number',
],
]);
$this->add([
'attributes' => array(
'name' => 'street_name',
'type' => 'text',
'id' => 'street_name',
'class' => 'form-control'
),
'options' => [
'label' => 'Street Name',
],
]);
$this->add([
'attributes' => array(
'name' => 'city',
'type' => 'text',
'id' => 'city',
'class' => 'form-control'
),
'options' => [
'label' => 'City',
],
]);
$this->add([
'attributes' => array(
'name' => 'state',
'type' => 'text',
'id' => 'state',
'class' => 'form-control'
),
'options' => [
'label' => 'State',
],
]);
$this->add([
'attributes' => array(
'name' => 'pin',
'type' => 'text',
'id' => 'pin',
'class' => 'form-control'
),
'options' => [
'label' => 'PIN',
],
]);
// Add the Submit button
$this->add([
'type' => 'submit',
'name' => 'submit',
'attributes' => [
'value' => 'Sign in',
'id' => 'submit',
],
]);
}
/**
* This method creates input filter (used for form filtering/validation).
*/
private function addInputFilter() {
// Create main input filter
$inputFilter = new InputFilter();
$this->setInputFilter($inputFilter);
// Add input for "email" field
$inputFilter->add([
'name' => 'name',
'required' => true,
'filters' => [
['name' => 'StringTrim'],
],
'validators' => [
[
'name' => 'StringLength',
'options' => [
'min' => 5,
'max' => 20
],
],
],
]);
$inputFilter->add([
'name' => 'description',
'required' => true,
'filters' => [
],
'validators' => [
[
'name' => 'StringLength',
'options' => [
'min' => 5,
'max' => 64
],
],
],
]);
}
}
Below is view file add.phtml
<script type="text/javascript">
function addSchoolLocation(){
$( ".schoolLocation" ).clone().appendTo( ".schoolLocation" );
}
</script>
<!-- Content Header (Page header) -->
<section class="content-header">
<ol class="breadcrumb">
<li><i class="fa fa-dashboard"></i> Home</li>
<li class="active">Add School</li>
</ol>
</section>
<!-- Main content -->
<section class="content">
<div class="row">
<!-- left column -->
<div class="col-md-12">
<!-- general form elements -->
<div class="box box-primary form-custome">
<div class="box-header with-border">
<h3 class="box-title">Add School <ul class="add-icon-new">
<li><i class="fa fa-angle-down"></i></li>
<li><a href="#" class="i-refresh"><i class="fa fa-refresh" aria-hidden="true"></i>
</a></li>
<li><i class="fa fa-times" aria-hidden="true"></i></li>
</ul>
</h3>
</div>
<h5 class="form-heading">School Information</h5>
<form role="form" method="post">
<div class="box-body">
<div class="form-group col-md-3 col-sm-6">
<?= $this->formLabel($form->get('name')); ?>
<?= $this->formElement($form->get('name')); ?>
</div>
<div class="form-group col-md-3 col-sm-6">
<?= $this->formLabel($form->get('description')); ?>
<?= $this->formElement($form->get('description')); ?>
</div>
<?= $this->formElement($form->get('active')); ?>
<h5 class="form-heading">School Location</h5>
<div class="schoolLocation">
<div class="form-group col-md-3 col-sm-6">
<?= $this->formLabel($form->get('apartment_number')); ?>
<?= $this->formElement($form->get('apartment_number')); ?>
</div>
<div class="form-group col-md-3 col-sm-6">
<?= $this->formLabel($form->get('street_name')); ?>
<?= $this->formElement($form->get('street_name')); ?>
</div>
<div class="form-group col-md-3 col-sm-6">
<?= $this->formLabel($form->get('city')); ?>
<?= $this->formElement($form->get('city')); ?>
</div>
<div class="form-group col-md-3 col-sm-6">
<?= $this->formLabel($form->get('state')); ?>
<?= $this->formElement($form->get('state')); ?>
</div>
<div class="form-group col-md-3 col-sm-6">
<?= $this->formLabel($form->get('pin')); ?>
<?= $this->formElement($form->get('pin')); ?>
</div>
</div>
<div>
Add School Location
Add School Location
</div>
<div class=" form-group col-sm-12">
<button class="save">Save</button>
<button class="reset">Reset</button>
</div>
</div>
</form>
</div>
</div>
</div>
<!-- /.row -->
</section>
<!-- /.content -->
I want to clone div with class schoollocation
Note*: I tried below solutions but nothing worked for me as those are not the solution for Zend Framework-3
Zend Framework - Add new input element using javascript
https://docs.zendframework.com/zend-form/collections/#form-collections
What you're looking for is the usage of Collections (which you linked) and Fieldsets.
You use a Fieldset to represent an Entity. In this example the Fieldset is Location, attached to School.
Also, the School as a One To Many relation with Location.
As such, you would have a SchoolFieldset class, which needs a Collection Element.
Below a very simplified example of the setup.
Backend
LocationFieldset
class LocationFieldset
{
public function init()
{
parent::init();
$this->add([
'name' => 'name',
'required' => true,
'type' => Text::class,
'options' => [
'label' => _('Name'),
],
]);
// ... Add whatever for Location
}
}
SchoolFieldset
class SchoolFieldset
{
/**
* #var LocationFieldset
*/
protected $locationFieldset;
public function __construct(LocationFieldset $locationFieldset)
{
$this->locationFieldset($locationFieldset);
}
public function init()
{
parent::init();
$this->add([
'name' => 'name',
'required' => true,
'type' => Text::class,
'options' => [
'label' => _('Name'),
],
]);
$this->add([
'type' => Collection::class,
'required' => true,
'name' => 'locations',
'options' => [
'label' => _('Locations'),
'count' => 1, // Initial amount of Fieldsets on-load
'allow_add' => true, // Allows creation of 0/multiple
'allow_remove' => true, // Allows removal
'should_create_template' => true, // Creates template in the HTML in a <span data-template="the whole html here"></span> -> JavaScript this bit for duplication/removal
'target_element' => $this->locationFieldset, // A pre-loaded Fieldset must be passed here, not just the FQCN as you would for including a Fieldset not in a Collection
],
]);
// ... Add whatever
}
}
SchoolForm
class SchoolForm extends CustomAbstractForm
{
public function init()
{
$this->add([
'name' => 'school',
'type' => SchoolFieldset::class,
'options' => [
'use_as_base_fieldset' => true,
],
]);
//Call parent initializer. (Default for me it adds a submit button)
parent::init();
}
}
Front-end
In the view of the form, I load a bit of JavaScript. It's based on the demo data given in the Zend Framework documentation.
Please note that those docs do not account for removal (so if you have HTML objects with id's 0-1-2 and you remove 1, it will count, come to 2 and create another 2, giving you 0-2-2 and thus an overwrite for the second one you already had).
The JavaScript I have in a project at the moment is this (sorry, cannot give you all of it, but this should get you started):
Buttons
var $addButton = $('<button type="button" data-action="add-fieldset" class="btn btn-primary">Add another</button>');
var $removeButton = $('<button type="button" data-action="remove-fieldset" class="btn btn-danger">Remove</button>');
Usage
$('body').on('click', 'button[type="button"][data-action="add-fieldset"]', function () {
addCollectionFieldset(this);
});
$('body').on('click', 'button[type="button"][data-action="remove-fieldset"]', function () {
removeCollectionFieldset(this);
});
function addCollectionFieldset(element) {
var $element = $(element);
var $fieldsetDataSpan = $element.siblings('span[data-name="fieldset-data"]');
var fieldsetCount = $fieldsetDataSpan.data('fieldset-count');
var escapedTemplate = $element.siblings('span[data-template]').data('template');
var $replaced = $(escapedTemplate.replace(/__index__/g, fieldsetCount));
$replaced.append($removeButton.clone());
$($replaced).insertAfter($element.siblings('fieldset:last'));
$('<hr>').insertBefore($element.siblings('fieldset:last'));
$fieldsetDataSpan.data('fieldset-count', fieldsetCount + 1); // Up the count by one fieldset
}
function removeCollectionFieldset(element) {
$(element).parent().remove();
}
Note: the "Remove" button is placed IN every Fieldset within the Collection. The "Add another" button is placed below the Collection.
How you solve that issue, is up to you.
View
<?= $this->form($form) ?>
<?php $this->inlineScript()->prependFile($this->basePath('js/form.js')) ?>
Controller action
public function addAction()
{
/** #var SchoolForm $form */
$form = $this->getSchoolForm();
/** #var Request $request */
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
/** #var School $school */
$school = $form->getObject();
$this->getObjectManager()->persist($school);
try {
$this->getObjectManager()->flush();
} catch (Exception $e) {
throw new Exception(
'Could not save. Error was thrown, details: ' . $e->getMessage(),
$e->getCode(),
$e->getPrevious()
);
}
return $this->redirectToRoute('schools/view', ['id' => $school->getId()]);
}
}
return [
'form' => $form,
'validationMessages' => $form->getMessages() ?: '',
];
}
ControllerFactory
class AddControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
/** #var ObjectManager $objectManager */
$objectManager = $container->get(EntityManager::class);
/** #var FormElementManagerV3Polyfill $formElementManager */
$formElementManager = $container->get('FormElementManager');
/** #var SchoolForm $schoolForm */
$schoolForm = $formElementManager->get(SchoolForm::class);
return new AddController($objectManager, $schoolForm);
}
}
FormFactory
class SchoolFormFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$objectManager = $container->get(EntityManager::class);
$translator = $container->get('MvcTranslator');
$inputFilterPluginManager = $container->get('InputFilterManager');
$inputFilter = $inputFilterPluginManager->get(SchoolFormInputFilter::class); // Did not show this one
/** #var SchoolForm $form */
$form = new SchoolForm();
$form->setObjectManager($objectManager);
$form->setTranslator($translator);
$form->setInputFilter($inputFilter);
return $form;
}
}
FormFactory
class SchoolFieldsetFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$objectManager = $container->get(EntityManager::class);
$translator = $container->get('MvcTranslator');
$fieldset = new SchoolFieldset();
$fieldsetObject = new School();
/** #var SchoolFieldset $fieldset */
$fieldset = new $fieldset($objectManager(), 'school');
$fieldset->setHydrator(
new DoctrineObject($objectManager())
);
$fieldset->setObject($fieldsetObject);
$fieldset->setTranslator($translator);
return $fieldset;
}
}
If you have a few moments to spare, I would advise you to check out more examples in a repo I created to help quickly create forms in ZF and ZF with Doctrine. The ReadMe with examples is here

Zend Framework 2 Repopulate form using validated values

I have a simple form class setup along with a filter. After submitting the form, if there's a validation error, the validation/filter works and I can dump the filtered values, but the form does not display the cleaned data. In particular, I am testing with StringTrim and StripTags. I can see the trimmed value, but the final form output still shows the original value submitted. How do I use the validated values instead when the form is repopulated?
An example:
Form data submitted string " asdf ".
Dumping form data, $regform->getData() : "asdf"
The above is expected, but the output in the view still shows the spaces: " asdf ".
I appreciate any input. Code is below. Thank you!
Controller code:
public function indexAction ()
{
$this->layout()->pageTitle = "Account Registration";
$regform = new RegForm($data=null);
if($this->request->isPost()){
$data = $this->post;
$regform->setData($data);
$ufilter = new RegFilter();
$regform->setInputFilter($ufilter->getInputFilter());
if($regform->isValid()){
$this->view->result = "ok";
}
else {
$this->view->result = "Not good";
}
var_dump($regform->getData());
}
$this->view->regform = $regform;
return $this->view;
}
RegForm.php
<?php
namespace GWMvc\Form;
use Zend\Form\Form;
use Zend\Form\Element;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;
use Zend\Session\Container;
class RegForm extends Form
{
public function __construct($data = null, $args = array())
{
parent::__construct('reg-form');
$this->setAttribute('class', 'form form-inline');
$this->setAttribute('role', 'form');
$this->setAttribute('method', 'post');
$this->setAttribute('action','/app/registration/index');
$this->add(array(
'name' => 'firstname',
'type' => 'Zend\Form\Element\Text',
'options' => array(
'label' => 'First Name:',
),
'attributes' => array('id' => 'firstname', 'type' => 'text',
'class' => 'regformitem regtextfield')));
$this->add(array(
'name' => 'lastname',
'type' => 'Zend\Form\Element\Text',
'options' => array(
'label' => 'Last Name:'
),
'attributes' => array('id' => 'lastname', 'type' => 'text',
'required' => true,'class' => 'regformitem regtextfield')));
$this->add(array(
'type' => 'Zend\Form\Element\Csrf',
'name' => 'csrf',
'options' => array(
'csrf_options' => array(
'timeout' => 600
)
)
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Submit',
'class' => 'btn btn-default',
),
));
}
}
RegFilter.php
<?php
namespace GWMvc\Form;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
class RegFilter implements InputFilterAwareInterface
{
public $username;
public $password;
protected $inputFilter;
public function setInputFilter(InputFilterInterface $inputFilter)
{
throw new \Exception("Not used");
}
public function getInputFilter()
{
if (!$this->inputFilter) {
$this->inputFilter = new InputFilter();
$this->factory = new InputFactory();
$this->inputFilter->add($this->factory->createInput(array(
'name' => 'firstname',
'required' => true,
'filters' => array(
array('name' => 'StringTrim'),
array('name' => 'StripTags'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 50,
),
),
),
)));
$this->inputFilter->add($this->factory->createInput(array(
'name' => 'lastname',
'required' => true,
'filters' => array(
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 50,
),
),
),
)));
}
return $this->inputFilter;
}
}
View Script:
<?php
$form = &$this->regform;
$form->prepare();
echo $this->form()->openTag($form);
echo $this->formElement($form->get('csrf'));?>
<div class="form" gwc="regitem">
<?php echo $this->formRow($form->get('firstname')); ?>
</div>
<div class="form" gwc="regitem">
<?php echo $this->formRow($form->get('lastname')); ?>
</div>
EDIT (SOLUTION)
As per the accepted answer below, it was this easy. Here's what I added.
$valid = $regform->isValid();
$regform->setData($regform->getData());
if($valid){
$this->view->result = "ok";
} else {
// not ok, show form again
}
I guess you have to do it manually:
if($regform->isValid()){
$regform->setData ($regform->getData ())->isValid ();
$this->view->result = "ok";
}

Remove model name from submitted form url (GET)

Here's my form
<?php $form=$this->beginWidget('booster.widgets.TbActiveForm',array(
'id'=>'listing-main-form',
'enableAjaxValidation'=>false,
'action'=>Yii::app()->createUrl('site/search'),
'method'=>'get',
)); ?>
<div class="form-group" style="padding-bottom:0px;border:none">
<label class="control-label" for="selecttype">Type</label>
<?php echo $form->dropDownListGroup(
$model,
'prp',
array(
'wrapperHtmlOptions' => array(
'class' => 'col-sm-5',
),
'widgetOptions' => array(
'data' => CHtml::listData(Type::model()->findAll(), 'id', 'type'),
'htmlOptions' => array('id'=>'selecttype'),
),
'label' => ''
)
); ?>
</div>
<div class="form-group">
<div id="resproperties">
<div class="resdv">
<?php echo $form->checkboxListGroup(
$model,
'rs',
array(
'widgetOptions' => array(
'data' =>CHtml::listData(ResourceCategory::model()->findAll(), 'id', 'res_category'),
),
'label' => ''
)
); ?>
</div>
</div>
............
............
When the form is submitted, I can read all the field's data fine. But the url appears with Model[field] for each fields and looks very ugly (see below). Is there any where I can remove the model name from there?
index.php?r=site/search&ItemModel[prp]=1&ItemModel[rs]=&ItemModel[rs][]=2&ItemModel[rs][]=3&ItemModel[rs][]=4&ItemModel[cm] ............
You can explicitly set input name.
...
'htmlOptions' => array(
'id'=>'selecttype',
'name' => 'fieldname'
)
...
Also you can override CHtml and CActiveForm classes.
In your array for each element, add
'name'=>'your_custom_name'
So...
<?php echo $form->dropDownListGroup(
$model,
'prp',
array(
'wrapperHtmlOptions' => array(
'class' => 'col-sm-5',
),
'widgetOptions' => array(
'data' => CHtml::listData(Type::model()->findAll(), 'id', 'type'),
'htmlOptions' => array('id'=>'selecttype'),
),
'label' => '',
'name' => 'customName'
)
); ?>

ZF2 - How to add a new Form in an existing Controller?

I have a login Form LoginForm.php with its Filter LoginFilter.php, that has a View /login/index.phtml, a Controller LoginController.php, two Factory LoginControllerFactory.php & LoginFormFactory.php and it is called in the config.module.php and works perfect. The Form is correctly displayed.
I have a ViewController.php that has a method idAction that shows a post by its id passed by parameter from the homepage in a View called /view/id.phtml. I want to display this Form I created within this View and I don't know how. First, I created the Form exactly as I created the login Form, but I realized that I already configured my id child-route, inside of view route with a Factory in module.config.php.
Then, I tried to set the form in the idAction method, exactly as I did in indexAction in LoginController.php Controller, but I'm receiving the following error: An exception was raised while creating "Rxe\Factory\ViewController"; no instance returned.
I will now show you what I did to try to display this new Form.
First, the Form itself:
class CommentForm extends Form
{
public function buildForm()
{
$this->setAttribute('method', 'POST');
$this->setAttribute('id', 'add-comment-form');
$this->add(array(
'name' => 'comment',
'type' => 'textarea',
'options' => array(
'label' => 'Category'
),
'attributes' => array(
'class' => 'form-control'
)
));
$this->add(array(
'name' => 'submit',
'type' => 'submit',
'attributes' => array(
'class' => 'btn btn-success',
'value' => 'Comment'
)
));
}
}
Form's CommentFormFactory.php calling its Filter and building the Form:
class CommentFormFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$form = new CommentForm();
$form->setInputFilter($serviceLocator->get('Rxe\Factory\CommentFilter'));
$form->buildForm();
return $form;
}
}
The ViewControllerFactory.php calling the CommentFormFactory.php, just like in LoginControllerFactory.php:
class ViewControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$serviceManager = $serviceLocator->getServiceLocator();
$viewController = new ViewController();
$viewController->setPostsTable($serviceManager->get('Rxe\Factory\PostsTable'));
$viewController->setCommentsTable($serviceManager->get('Rxe\Factory\CommentsTable'));
$viewController->setCommentForm($serviceManager->get('Rxe\Factory\CommentForm'));
return $viewController;
}
}
The ViewController.php, calling the form within its idAction's ViewModel:
class ViewController extends AbstractActionController
{
use PostsTableTrait;
use CommentsTableTrait;
private $commentForm;
function setCommentForm($commentForm)
{
$this->commentForm = $commentForm;
}
public function indexAction()
{
$category = $this->params()->fromRoute('category');
return new ViewModel(array(
'posts' => $this->postsTable->getPostsByCategory($category),
'categories' => $category
));
}
public function idAction()
{
$id = $this->params()->fromRoute('id');
$viewModel = new ViewModel(array(
'commentForm' => $this->commentForm,
'commentParams' => $this->params()->fromPost(),
'messages' => $this->flashMessenger()->getMessages(),
'posts' => $this->postsTable->getPostById($id),
'posts' => $this->commentsTable->getNumberOfCommentsByPost($id),
'comments' => $this->commentsTable->getCommentsByPost($id)
));
$viewModel->setTemplate('rxe/view/id.phtml');
if ($this->getRequest()->isPost()) {
$this->commentForm->setData($this->params()->fromPost());
if ($this->commentForm->isValid()) {
$this->flashMessenger()->addMessage('Thank you for your comment. :)');
} else {
$this->flashMessenger()->addMessage('Your comment wasn\'t sent.');
}
}
return $viewModel;
}
}
And finally my module.config.php
'controllers' => array(
'invokables' => array(
'Rxe\Controller\Index' => 'Rxe\Controller\IndexController',
'Rxe\Controller\View' => 'Rxe\Controller\ViewController',
'Rxe\Controller\Login' => 'Rxe\Controller\LoginController'
),
'factories' => array(
'Rxe\Factory\LoginController' => 'Rxe\Factory\LoginControllerFactory',
'Rxe\Factory\ViewController' => 'Rxe\Factory\ViewControllerFactory',
'Rxe\Factory\IndexController' => 'Rxe\Factory\IndexControllerFactory'
)
),
'service_manager' => array(
'factories' => array(
'Rxe\Factory\LoginForm' => 'Rxe\Factory\LoginFormFactory',
'Rxe\Factory\LoginFilter' => 'Rxe\Factory\LoginFilterFactory',
'Rxe\Factory\CommentForm' => 'Rxe\Factory\CommentFormFactory',
'Rxe\Factory\CommentFilter' => 'Rxe\Factory\CommentFilterFactory',
'Rxe\Factory\PostsTable' => 'Rxe\Factory\PostsTableFactory',
'Rxe\Factory\CategoriesTable' => 'Rxe\Factory\CategoriesTableFactory',
'Rxe\Factory\CommentsTable' => 'Rxe\Factory\CommentsTableFactory',
'Zend\Db\Adapter\AdapterService' => 'Zend\Db\Adapter\AdapterServiceFactory'
)
),
Please, let me know if you need me to show you more codes. Thank you in advance.
EDIT #1
If I remove the line that calls the Form in the ViewControllerFactory.php, I get the following error: Fatal error: Call to a member function prepare() on a non-object in /home/vol12_3/byethost4.com/b4_16354889/htdocs/module/Rxe/view/rxe/view/id.phtml on line 31
The id.phtml is:
<!-- Comment form -->
<div id="comment-form-area" class="col-xs-3">
<?php $this->commentForm->prepare() ?>
<?php echo $this->form()->openTag($this->commentForm); ?>
<div class="form-group comment-area">
<?php echo $this->formRow($this->commentForm->get('comment_content')); ?>
</div>
<div class="form-group">
<?php echo $this->formRow($this->commentForm->get('submit')); ?>
</div>
<?php echo $this->form()->closeTag(); ?>
</div>
<!-- /Comment form -->
Try removing these lines
'invokables' => array(
'Rxe\Controller\Index' => 'Rxe\Controller\IndexController',
'Rxe\Controller\View' => 'Rxe\Controller\ViewController',
'Rxe\Controller\Login' => 'Rxe\Controller\LoginController'
),
If it doesn't work, have a look at this tutorial how to create proper controller factories and pass dependencies. https://samsonasik.wordpress.com/2015/03/31/zend-framework-2-using-__invokepluginmanager-manager-in-services-factory/
An example how I build my forms:
namespace Admin\Form;
use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;
class ContentForm extends Form implements InputFilterProviderInterface
{
public function __construct()
{
parent::__construct("content");
}
public function init()
{
$this->setAttribute('method', 'post');
$this->add([
'type' => 'Zend\Form\Element\Text',
'name' => 'title',
'attributes' => [
'required' => true,
'size' => 40,
'id' => "seo-caption",
'placeholder' => 'Title',
],
'options' => [
'label' => 'Title',
],
]);
$this->add([
'type' => 'Zend\Form\Element\Text',
'name' => 'text',
'attributes' => [
'class' => 'ckeditor',
'rows' => 5,
'cols' => 80,
],
'options' => [
'label' => 'Text',
],
]);
}
public function getInputFilterSpecification()
{
return [
[
"name"=>"title",
"required" => true,
'filters' => [
['name' => 'StripTags'],
['name' => 'StringTrim'],
],
'validators' => [
['name' => 'NotEmpty'],
[
'name' => 'StringLength',
'options' => [
'encoding' => 'UTF-8',
'min' => 1,
'max' => 200,
],
],
],
],
[
"name"=>"text",
"required" => true,
'filters' => [
['name' => 'StripTags'],
['name' => 'StringTrim'],
],
'validators' => [
['name' => 'NotEmpty'],
[
'name' => 'StringLength',
'options' => [
'encoding' => 'UTF-8',
'min' => 1,
],
],
],
],
];
}
}
Than I create a Factory
namespace Admin\Factory\Controller;
use Admin\Controller\ContentController;
use Zend\Mvc\Controller\ControllerManager;
class ContentFormFactory
{
/**
* #{inheritDoc}
*/
public function __invoke(ControllerManager $controllerManager)
{
return new ContentController(
$controllerManager->getServiceLocator()->get('FormElementManager')->get('Admin\Form\ContentForm')
);
}
}
Inside module.config.php I have this code
'controllers' => [
'factories' => [
'Admin\Controller\Content' => "Admin\Factory\Controller\ContentFormFactory",
],
'invokables' => [
...
],
],
Please, show us some more code.

ERRORS Zend\InputFilter\Exception\RuntimeException

I am trying use zf2 to validate form, but have errors:
An error occurred
An error occurred during execution; please try again later.
Additional information:
Zend\InputFilter\Exception\RuntimeException
File:
C:\xampp\htdocs\ZEND\Users\Users\vendor\ZF2\library\Zend\InputFilter\Factory.php:395
Message:
Invalid validator specification provided; was neither a validator instance nor an array specification
Code:
<?php
namespace Users\Form;
use Zend\InputFilter\InputFilter;
class RegisterFilter extends InputFilter{
public function __construct(){
$this->add(array(
'name' => 'email',
'required' =>true,
'validators' => array(
'name' => 'EmailAddress',
'options' => array(
'domain' => true,
),
),
));
$this->add(array(
'name' => 'user',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringLength'),
),
'validators' => array(
array(
'options' => array(
'encoding' => 'UTF-8',
'min' => 6,
'max' => 32,
),
),
),
));
}
}
RegisterForm
<?php
namespace Users\Form;
use Zend\Form\Form;
class RegisterForm extends Form {
public function __construct($name = null){
parent::__construct('Register');
$this->setAttribute('method', 'post');
$this->setAttribute('enctype', 'multipart/form-data');
$this->add(array(
'name' => 'user',
'attributes' => array(
'type' => 'text',
'required' => 'required'
),
'options' => array(
'label' => 'UserName',
),
));
$this->add(array(
'name' => 'pwd',
'attributes' => array(
'type' => 'password',
'required' => 'required'
),
'options' => array(
'label' => 'Password',
)
));
$this->add(array(
'name' => 'cpwd',
'attributes' => array(
'type' => 'password',
'required' => 'required'
),
'options' => array(
'label' => 'Comfirm Password',
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Register',
),
));
$this->add(array(
'name' => 'email',
'attributes' => array(
'type' => 'email',
),
'options' => array(
'label' => 'Email',
),
'attributes' => array(
'required' => 'required',
),
'filters' => array(
array('name' => 'StringTrim')
),
'validators' => array(
array(
'name' => 'EmailAddress',
'options' => array(
'messages' => array(
\Zend\Validator\EmailAddress::INVALID_FORMAT => 'Email Address Format is invalid'
)
)
)
)
));
}
}
RegisterController
<?php
namespace Users\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Users\Form\RegisterForm;
use Users\Form\RegisterFilter;
class RegisterController extends AbstractActionController{
public function indexAction(){
$form = new RegisterForm();
$viewmodel = new ViewModel(array('form' => $form));
return $viewmodel;
}
public function processAction(){
if(!$this->request->isPost()){
return $this->redirect()-> toRoute(NULL,
array( 'controller' => 'register',
'action' => 'index',
));
}
$post = $this->request->getPost();
$form = new RegisterForm();
$inputFilter = new RegisterFilter();
$form->setInputFilter($inputFilter);
$form->setData($post);
if(!$form->isValid()){
$model = new ViewModel(array(
'error' => true,
'form' => $form,
));
$model ->setTemplate('users/register/index');
return $model;
}
return $this->redirect()->toRoute(NULL,array(
'controller' => 'register',
'action' => 'confirm',
));
}
public function confirmAction(){
$viewmodel = new ViewModel();
return $viewmodel;
}
}
index.phtml
<section class = 'register'>
<h2> Register </h2>
<?php if($this -> error): ?>
<p class='error'> have errors </p>
<?php endif ?>
<?php
$form = $this->form;
$form -> prepare();
$form -> setAttribute('action', $this->url(NULL,
array('controller' => 'Register', 'action' => 'process')));
$form -> setAttribute('method','post');
echo $this->form()->openTag($form);
?>
<dl class='zend_form'>
<dt><?php echo $this->formLabel($form -> get('user')) ;?> </dt>
<dd> <?php echo $this->formElement($form->get('user')) ;?>
<?php echo $this->formElementErrors($form->get('user')) ;?>
</dd>
<dt><?php echo $this->formLabel($form -> get('email'));?></dt>
<dd><?php echo $this->formElement($form-> get('email')) ;?>
<?php echo $this->formElementErrors($form -> get('email')) ;?>
</dd>
<dt><?php echo $this->formLabel($form -> get('pwd')) ;?></dt>
<dd><?php echo $this->formElement($form->get('pwd')) ;?>
<?php echo $this->formElementErrors($form->get('pwd')) ;?>
</dd>
<dt><?php echo $this->formLabel($form ->get('cpwd'));?></dt>
<dd><?php echo $this->formElement($form->get('cpwd'));?>
<?php echo $this->formElementErrors($form->get('cpwd'))?>
</dd>
<dd><?php echo $this->formElement($form->get('submit'));?>
<?php echo $this->formElementErrors($form->get('submit'));?>
</dd>
</dl>
<?php echo $this->form()->closeTag()?>
</section>
Your validator structure is wrong.
The validators key is expecting an array of validators. You are supplying the validator name and options directly.
Change this:
this->add(array(
'name' => 'email',
'required' =>true,
'validators' => array(
'name' => 'EmailAddress',
'options' => array(
'domain' => true,
),
),
));
To:
this->add(array(
'name' => 'email',
'required' =>true,
'validators' => array(
array(
'name' => 'EmailAddress',
'options' => array(
'domain' => true,
),
)
//Another validator here ..
),
));

Categories