Change name and id in form - forms

I would change my Return form
I create form with a loop inside my twig, and I would like to change the name and id fields
eg
<input type="text" id="foo_1" name="foo_1[title]" maxlength="255">
I want to add an index like I did for the id of the form {{loop.index}}
I might have to pass something to the constructor of my form, but I have not found anything that has helped me

For Now i do It:
My controller
foreach($fotos as $key => $foto){
$array_fotos[] = array(
"form" => $this->createForm(new \My\FotoBundle\Form\FotoType($key), $fotos[$key])->createView(),
);
}
In My FormType i do this
class FotoType extends AbstractType
{
protected $key;
public function __construct($chiave) {
$this->key = $chiave;
}
.....
public function getName()
{
return 'form_gestione_foto_'.$this->key;
}
}

Related

How to pass a Doctrine ObjectManager to a form through ZF2 FormElementManager

I would like to create custom form elements in ZF2, which requires FormElementManager. I am currently using Doctrine Hydrator in the form creation as shown in this tutorial. In this method, an ObjectManager object is created in the controller and passed to the new form when it is instantiated:
public function editAction()
{
// Get your ObjectManager from the ServiceManager
$objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
// Create the form and inject the ObjectManager
$form = new UpdateBlogPostForm($objectManager);
// …
the update form:
namespace Application\Form;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Form\Form;
class UpdateBlogPostForm extends Form
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('update-blog-post-form');
// The form will hydrate an object of type "BlogPost"
$this->setHydrator(new DoctrineHydrator($objectManager));
// Add the user fieldset, and set it as the base fieldset
$blogPostFieldset = new BlogPostFieldset($objectManager);
$blogPostFieldset->setUseAsBaseFieldset(true);
$this->add($blogPostFieldset);
// … add CSRF and submit elements …
// Optionally set your validation group here
}
}
the BlogPost fieldset:
namespace Application\Form;
use Application\Entity\BlogPost;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;
class BlogPostFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('blog-post');
$this->setHydrator(new DoctrineHydrator($objectManager))
->setObject(new BlogPost());
// … add fieldset elements …
}
// … public function getInputFilterSpecification() …
}
Unfortunately, in order to use ZF2's FormElementManager, the ZF2 manual says, "The second catch is that you must not directly instantiate your form class, but rather get an instance of it through the Zend\Form\FormElementManager;" so I have to get the form like this:
public function editAction()
{
$sl = $this->getServiceLocator();
$form = $sl->get('FormElementManager')->get('\Application\Form\UpdateBlogPostForm');
Is there a way to pass the ObjectManager object $objectManager to the form through FormElementManager, or is there a way to create the object within the form so the hydrator and the fieldset can use it?
DoctrineEntityHydratorFactory
A factory that creates the hydrator and injects the object manager.
namespace MyModule\Stdlib\Hydrator;
use DoctrineORMModule\Stdlib\Hydrator\DoctrineEntity;
class DoctrineEntityHydratorFactory
{
public function __invoke($hydratorPluginManager, $name, $requestedName)
{
$serviceManager = $hydratorPluginManager->getServiceLocator();
$objectManager = $serviceManager->get('Doctrine\ORM\EntityManager');
return new DoctrineEntity($objectManager);
}
}
BlogPostFieldset
A reusable fieldset that contains all the elements for a Blog post and uses the EntityHydrator to hydrate a BlogPost entity.
namespace MyModule\Form;
use Zend\Form\Fieldset;
class BlogPostFieldsetFactory
{
public function __invoke($formElementManager, $name, $requestedName)
{
$serviceManager = $formElementManager->getServiceLocator();
$hydrator = $serviceManager->get('HydratorManager')->get('DoctrineEntityHydrator');
$fieldset = new Fieldset('blog_post');
$fieldset->setHydrator($hydrator);
$fieldset->setObject(new BlogPost);
//... add fieldset elements.
$fieldset->add(['...']);
//...
return $fieldset;
}
}
UpdateBlogPostFormFactory
A factory to create the blog post update form. This attaches the fieldset and sets the use_as_base_fieldset option which allows it to use the fieldsets hydrator.
namespace MyModule\Form;
class UpdateBlogPostFormFactory
{
public function __invoke($formElementManager, $name, $requestedName)
{
$form = new Form('update_blog_post);
//...
$factory = new \Zend\Form\Factory($formElementManager);
$form->setFormFactory($factory);
$form->add([
'name' => 'blog_post',
'type' => 'BlogPostFieldset',
'options' => [
'use_as_base_fieldset' => true,
]
]);
//...
return $form;
}
}
You will also need to register the services with the required managers in module.config.php.
return [
'form_elements' => [
'factories' => [
'UpdateBlogPostForm' => 'MyModule\Form\UpdateBlogPostFormFactory',
'BlogPostFieldset' => 'MyModule\Form\BlogPostFieldsetFactory',
],
],
'hydrators' => [
'factories' => [
'DoctrineEntityHydrator' => 'MyModule\Stdlib\Hydrator\DoctrineEntityHydratorFactory',
],
],
];
So with the above you can request your form in the controller.
$form = $formElementManager->get('UpdateBlogPostForm');

Pass a value from controller to partial in ZF2

I want to pass some value from controller to view partial, basically, view partial is set using the placeholder in Application\Module.php, here is the code that does it.
<?php
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
use Zend\View\Renderer\PhpRenderer;
use Zend\View\Resolver;
use Zend\ServiceManager\ServiceManager;
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$eventManager->attach(\Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'initBreadcrumbAndActionButtonWidget'));
$moduleRouteListener->attach($eventManager);
$serviceManager = $e->getApplication()->getServiceManager();
}
public function initBreadcrumbAndActionButtonWidget(\Zend\Mvc\MvcEvent $e)
{
$serviceManager = $e->getApplication()->getServiceManager();
$config = $serviceManager->get('config');
$viewHelperManager = $this->getViewHelperManager($e->getApplication()->getServiceManager());
$partialHelper = $viewHelperManager->get('partial');
$partial = $partialHelper('widgets/breadcrumb', array(
'config' => $config,
'actionButtons' => $config['action-buttons']
));
$placeHolder = $viewHelperManager->get('placeholder');
$placeHolder('widgets/breadcrumb')->set($partial);
}
public function getViewHelperManager($serviceManager)
{
$stack = new Resolver\TemplatePathStack(array('script_paths' => array(__DIR__ . '/view/')));
$resolver = new Resolver\AggregateResolver();
$resolver->attach($stack);
$renderer = new PhpRenderer();
$renderer->setResolver($resolver);
$viewHelperManager = $serviceManager->get('ViewHelperManager');
return $viewHelperManager;
}
public function getConfig()
{
return array_merge_recursive(
include __DIR__ . '/config/module.config.php',
);
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}
It is all working good till here, however now i want to pass a value from controller to the partial widgets/breadcrumb, after several attempt i thought implementing a ViewHelper could be a solution, and i implemented following view helper.
<?php
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
class Variable extends AbstractHelper
{
protected $data;
public function __invoke()
{
return $this;
}
public function set($identifier, $data)
{
$this->data[$identifier] = $data;
return $this;
}
public function get($identifier)
{
return $this->data[$identifier];
}
}
In controller i assign the value to ViewHelper like this.
$viewHelperManager = $this->getServiceLocator()->get('ViewHelperManager');
$variable = $viewHelperManager->get('variable');
$variable->set('stack', 'overflow');
And in partial, to access the value i use the get method.
$this->variable()->get('stack');
Now my problem is that get() is rendered first hence the value set in controller has no effect.
My question is how can i make the set() gets rendered first so i can have the value in partial, or if there is any better approach of passing the value to partial please suggest.
Thanks.
Baaah, i called the view helper in wrong action, it worked when i moved the $variable->set('stack', 'overflow'); in the action where i wanted the value to pass.
Not sure if there can be a better solution, but this does the job for me to pass the value after i found no way in ZF2 that satisfies my requirement.

zendframework 2 Doctrine 2 my post form is not returning the values

i am a little baffled by this;
my post forms is not populating the values received from the returned post values; i suspect the problem is arising from my getJobId() in my jobsort class values;
below is my form:
public function jobSortAction()
{
$form = new CreateJobSortForm($this->getEntityManager());
$jobSort = new JobSort();
$form->setInputFilter($jobSort->getInputFilter());
$id= 11;
$jobSort->setId($id);
$form->bind($jobSort);
if ($this->request->isPost()) {
//$post = $this->request->getPost();
$form->setData($this->request->getPost());
//var_dump($post);
//var_dump($jobSort);
if ($form->isValid()) {
$this->getEntityManager()->persist($jobSort);
$this->getEntityManager()->flush();
}
}
return array('form' => $form);
}
below is the var_dumped values of the 'return post values' and the Jobsort() object. You will note that the returned post values has values for both the Id and the JobId
object(Zend\Stdlib\Parameters)[168]
public 'JobSort' =>
array (size=2)
'jobId' => string '5' (length=1)
'id' => string '11' (length=2)
public 'submit' => string 'Submit' (length=6)
object(Workers\Entity\JobSort)[394]
protected 'inputFilter' => null
protected 'id' => int 11
protected 'jobId' => null
protected 'workerservicelist' => null
yet, when i populate the values, it does not seem to record the values for the jobId
below is my jobsort entity class:
class JobSort
{
protected $inputFilter;
/**
* #ORM\Id
*
* #ORM\Column(name="user_id", type="integer")
*/
protected $id;
/**
* #ORM\Column(name="jobId", type="integer")
*/
protected $jobId;
public function setId($id)
{
return $this->id = $id;
}
public function getId()
{
return $this->id;
}
public function setJobId($jobId)
{
return $this->jobId = $jobId;
}
public function getJobId( )
{
return $this->jobId;
}
is there any advice or suggestions on what i need to do to find out why the values are not been populated
warm regards
Andreea
by the way; the form actually works when i had the Id of CLASS jobsort set to
#ORM\GeneratedValue(strategy="AUTO")
the problem started when i took it out and set it to manual
Hello again
here is my form:
this is the error message i received;
An exception occurred while executing 'INSERT INTO worker_main_jobsort (user_id, jobId) VALUES (?, ?)' with params [11, null]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'jobId' cannot be null
here is my form:
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Form\Form;
use Workers\Form\Fieldset\JobSortFieldset;
class CreateJobSortForm extends Form
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('create-Job-post-form');
// The form will hydrate an object of type "BlogPost"
$this->setHydrator(new DoctrineHydrator($objectManager, 'Workers\Entity\JobSort'));
// Add the user fieldset, and set it as the base fieldset
$JobSortFieldset = new JobSortFieldset($objectManager);
$JobSortFieldset->setUseAsBaseFieldset(true);
$this->add($JobSortFieldset);
// Optionally set your validation group here
// … add CSRF and submit elements …
$this->add(array(
'name' => 'submit',
'type' => 'Submit',
'attributes' => array(
'value' => 'Submit',
'id' => 'submitbutton',
),
));
// Optionally set your validation group here
}
}
and here is the fieldset class:
class JobSortFieldset extends Fieldset
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('JobSort');
$id= 10;
$this->setHydrator(new DoctrineHydrator($objectManager, 'Workers\Entity\JobSort'))
->setObject(new JobSort());
}
}
this addition is in response to rafaame solution;
i amended my form as recommended; however it still not working. i think the issue now is that Rafaame solution is in regarding to zendDB save method, but i am using doctrine persis**t and **flush method . i accordingly get the following error message;
Call to undefined method Workers\Entity\JobSort::save()
below is my amended form:
public function jobSortAction()
{
$form = new CreateJobSortForm($this->getEntityManager() );
$jobSort = new JobSort();
if($this->request->isPost())
{
$form->setData($this->request->getPost());
if ($form->isValid())
{
$entity = $form->getData();
$model = new JobSort();
$model->save($entity);
// $this->getEntityManager()->persist( $model);
// $this->getEntityManager()->flush();
}
}
return array('form' => $form);
}
in response to Rafaame question about what problems i had,the message that i am now receiving is this:
**
EntityManager#persist() expects parameter 1 to be an entity object,
array given.
**
below is my function:
public function jobSortAction()
{
$serviceLocator = $this->getServiceLocator();
$objectManager = $this->getEntityManager();
$form = new CreateJobSortForm($this->getEntityManager());
if ($this->request->isPost())
{
$form->setData($this->request->getPost());
if ($form->isValid()) {
$entity = $form->getData();
$model = new JobSort($objectManager, $serviceLocator);
$model->getEntityManager()->persist($entity);
$model->getEntityManager()->flush();
}
}
return array('form' => $form);
}
my form; i.e where the hydrator should be set
namespace Workers\Form;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Form\Form;
use Workers\Form\Fieldset\JobSortFieldset;
class CreateJobSortForm extends Form
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('JobSort');
// The form will hydrate an object of type "BlogPost"
$this->setHydrator(new DoctrineHydrator($objectManager, 'Workers\Entity\JobSort'));
// Add the user fieldset, and set it as the base fieldset
$JobSortFieldset = new JobSortFieldset($objectManager);
$JobSortFieldset->setUseAsBaseFieldset(true);
$this->add($JobSortFieldset);
If you check your code, you are creating a JobSort entity, setting only its id and binding it to the form:
$jobSort = new JobSort();
$jobSort->setId($id);
$form->bind($jobSort);
After that, you are dumping $jobSort and $this->request->getPost(). So, obviously, you are getting jobId in the POST data but not in the entity (you didn't set the entity's jobId before binding it to the form). There's nothing wrong with your entity's code.
The solution for this: don't bind anything to the form. You should only bind an entity to the form in the case of an edit action, that you fetch the entity from the database and want to populate the form with its values.
Example of add action:
public function addAction()
{
$serviceLocator = $this->getServiceLocator();
$objectManager = $this->getObjectManager();
$form = new Form\EmailCampaign\Add($serviceLocator, $objectManager);
if($this->request instanceof HttpRequest && $this->request->isPost())
{
$form->setData($this->request->getPost());
if($form->isValid())
{
$entity = $form->getData();
//If you want to modify a property of the entity (but remember that it's not recommended to do it here, do it in the model instead).
//$entity->setJobId(11);
$model = new Model\EmailCampaign($serviceLocator, $objectManager);
$model->save($entity);
if($entity->getId())
{
$this->flashMessenger()->addSuccessMessage('Email campaign successfully added to the database.');
return $this->redirect()->toRoute('admin/wildcard', ['controller' => 'email-campaign', 'action' => 'edit', 'id' => $entity->getId()]);
}
else
{
$this->flashMessenger()->addErrorMessage('There was an error adding the email campaign to the database. Contact the administrator.');
}
}
}
return new ViewModel
([
'form' => $form,
]);
}
Example of edit action:
public function editAction()
{
$serviceLocator = $this->getServiceLocator();
$objectManager = $this->getObjectManager();
$form = new Form\EmailCampaign\Edit($serviceLocator, $objectManager);
$id = $this->getEvent()->getRouteMatch()->getParam('id');
$entity = $objectManager
->getRepository('Application\Entity\EmailCampaign')
->findOneBy(['id' => $id]);
if($entity)
{
$form->bind($entity);
if($this->request instanceof HttpRequest && $this->request->isPost())
{
$form->setData($this->request->getPost());
if($form->isValid())
{
//If you want to modify a property of the entity (but remember that it's not recommended to do it here, do it in the model instead).
//$entity->setJobId(11);
$model = new Model\EmailCampaign($serviceLocator, $objectManager);
$model->save($entity);
$this->flashMessenger()->addSuccessMessage('Email campaign successfully saved to the database.');
}
}
}
else
{
$this->flashMessenger()->addErrorMessage('A email campaign with this ID was not found in the database.');
return $this->redirect()->toRoute('admin', ['controller' => 'email-campaign']);
}
return new ViewModel
([
'form' => $form,
'entity' => $entity,
]);
}
Hope this helps.
EDIT:
What I provided was an example of how to handle the form and the entities with Doctrine 2 + ZF2.
What you have to keep in mind is that Doctrine doesn't work with the concept of models, it just understands entities. The model I'm using in my application is a concept of the MVC (Model-View-Controller) design pattern (that ZF2 uses) and I have decided to wrap the entity manager calls (persist and flush) inside my model's method, that I named save() (in the case the entity needs some special treatment before being save to the database and also because it is not a good practice to use the entity manager directly in the controller - see this slide of Marcos Pivetta presentation http://ocramius.github.io/presentations/doctrine2-zf2-introduction/#/66).
Another thing that you may be misunderstanding is that when you do $form->getData() to a form that has the DoctrineObject hydrator, it will return you the entity object, and not an array with the data (this last happens if it has no hydrator). So you don't need to create the entity after doing $form->getData(), and if you do so, this created entity won't have any information provided by the form.
Your code should work now:
public function jobSortAction()
{
$serviceLocator = $this->getServiceLocator();
$entityManager = $this->getEntityManager();
$form = new CreateJobSortForm($entityManager);
if ($this->request->isPost())
{
$form->setData($this->request->getPost());
if ($form->isValid()) {
//I'm considering you are setting the DoctrineObject hydrator to your form,
//so here we will get the entity object already filled with the form data that came through POST.
$entity = $form->getData();
//Again, if you need special treatment to any data of your entity,
//you should do it here (well, I do it inside my model's save() method).
//$entity->setJobId(11);
$entityManager->persist($entity);
$entityManager->flush();
}
}
return array('form' => $form);
}

ZF2 Dependent Form Fields

How can i set a input filter which is dependent from another input field.
I want to set a form field as required only when the othe form field (checkbox) is selected.
How can i handle this in zf2 ?
I use the same idea as Crisp but I prefer to do it in the Form classes instead of the controller. I think it's better to have all validators defined all together in the same place. I do it this way:
1 - All Form classes inherits from a custom BaseForm:
class BaseForm extends ProvidesEventsForm
{
private $postData;
protected function getPostData() {
return $this->postData;
}
public function __construct( $name = null, $serviceManager ) {
parent::__construct( $name );
$this->serviceManager = $serviceManager;
$this->request = $serviceManager->get( 'Application' )->getMvcEvent()->getRequest();
$this->postData = get_object_vars( $this->request->getPost() );
}
}
This way you can easily pick any value from the post, like your checkbox (you can do the same approach with the route parameters, so you'll have all the view data in your Form).
2 - In the FormEdit class that inherits from BaseForm, you pass the getPostData() value to the SomeFilter this way:
class FormEdit extends BaseForm
{
public function __construct( $name = null, $serviceManager ) {
parent::__construct( $name, $serviceManager );
$filter = new SomeFilter( $this->getPostData() );
$this->setInputFilter( $filter );
}
3 - And now just use it in the SomeFilter:
class SomeFilter extends InputFilter
{
public function __construct( $postData ) {
if ( $postData[ 'checkbox' ] ) {
$this->add( array(
'name' => 'other_input',
'required' => true,
) );
}
}
}
This way you keep the Controller clean and all the validators in the same place.
You could test if the checkbox is populated and setValidationGroup accordingly on the form before validating it in your controller action...
public function someAction()
{
$form = new MyForm; // contains name, title, checkbox, required_if_checked fields
// usual form related setup
if ($request->isPost()) {
$form->setData($request->getPost());
// see if the checkbox is checked
$checked = $this->params()->fromPost('checkbox', false);
// not checked, set validation group, omitting the dependent field
if (!$checked) {
$form->setValidationGroup(array(
'name',
'title',
'checkbox', // could probably skip this too
));
}
if ($form->isValid()) {
// do stuff with valid data
}
}
}

Pass a form with post method to another controller

I have a simple Zend Form that contains a textbox with setRequired(TRUE) and other validators and a simple submit button in IndexController.
My question is, is it possible another controller will process and validate my post form?
Login.php
<?php
class Application_Form_Login extends Zend_Form
{
public function init()
{
$username = $this->createElement('text', 'username');
$username->setLabel('Username:');
$username->setRequired(TRUE);
$username->addValidator(new Zend_Validate_StringLength(array('min' => 3, 'max' => 10)));
$username->addFilters(array(
new Zend_Filter_StringTrim(),
new Zend_Filter_StringToLower()
)
);
$this->addElement($username);
// create submit button
$this->addElement('submit', 'login',
array('required' => false,
'ignore' => true,
'label' => 'Login'));
}}
IndexController.php
<?php
class AttendantController extends Zend_Controller_Action
{
public function indexAction()
{
$loginForm = new Application_Form_Login();
$loginForm->setAction('/Auth/process');
$loginForm->setMethod('post');
$this->view->loginForm = $loginForm;
}
}
AuthController.php
class AuthController extends Zend_Controller_Action
{
public function processAction()
{
// How to validate the form posted here in this action function?
// I have this simple code but I'm stacked here validating the form
// Get the request
$request = $this->getRequest();
// Create a login form
$loginForm = new Application_Form_Login();
// Checks the request if it is a POST action
if($request->isPost()) {
$loginForm->populate($request->getPost());
// This is where I don't know how validate the posted form
if($loginForm->isValid($_POST)) {
// codes here
}
}
}
}
You're pretty close. In the process action you create a new instance of the login form (which you are doing), and you pass the POST data to the isValid() method of that form in order to validate. So:
public function processAction()
{
$request = $this->getRequest();
$loginForm = new Application_Form_Login();
if($request->isPost()) {
if($loginForm->isValid($request->getPost)) {
// codes here
} else {
// assign the login form back to the view so errors can be displayed
$this->view->loginForm = $loginForm;
}
}
}
Generally it is easier to display and process the form within the same action, and redirect when the submission is successful. This is the Post/Redirect/Get pattern - see http://en.wikipedia.org/wiki/Post/Redirect/Get. This saves you having to create an instance of the same form in two different actions and makes it easier to redisplay the form in case of errors.
Are you using ' ?
change $loginForm->setAction(/Auth/process); to $loginForm->setAction('/auth/process');
from processAction you may remove $login->populate($request->getPost());