0

I have a form that is repeated over several different modules.

I would like to avoid repeating the same process over and over again and want to render the form once (in my application module) and then simply use a partial view script to call it wherever I wish like this;

<?php echo $this->partial('partialLayout/advertForm'); ?>

Following the advice here it would be pretty straightforward to do this if I simply created a HTML form in the partial script and then called it.

However, I want to use Zend Forms. Bearing in mind that zend form are loaded onto the page via the controller- how do I get around this.

i guess that the crux of the question is - how do you call a Zend Form in another module using a partial view script.

Community
  • 1
  • 1
theSeeker
  • 297
  • 4
  • 12
  • You can achieve this using the `forward` plugin; I have [another answer that shows an example](http://stackoverflow.com/questions/25533751/zf2-widgets-views-in-layout/25535518#25535518). Essentially you would have one controller action that just renders the form as normal and any controller that needs to include the form can call that. – AlexP Jan 07 '16 at 18:35
  • thanks AlexPs, novel solution. i will however opt for Alain P solution – theSeeker Jan 11 '16 at 14:31

2 Answers2

0

I did something like that with a ViewHelper. My solution is posted here, in Zend Forums.

There it is.

The code ViewHelper :

<?php
/**
* View helper to return the HTML code of the login form. 
*
* @filesource LoginForm.php
* @encodage UTF-8
* @author DAFAP Informatique - Alain Pomirol
* @date 10 nov. 2015
* @version 2015-1
*/
namespace Login\View\Helper;

use Zend\View\Helper\AbstractHelper;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\View\Model\ViewModel;
use Login\Form\LoginForm as Formulaire;

class LoginForm extends AbstractHelper implements ServiceLocatorAwareInterface
{

  protected $sm;

  public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
  {
    $this->sm = $serviceLocator;
    return $this;
  }

  public function getServiceLocator()
  {
    return $this->sm;
  }

  public function __invoke()
  {
    $form = new Formulaire();
    $layout = new ViewModel(array(
        'form' => $form
    ));
    $viewRender = $this->getServiceLocator()->getServiceLocator()->get('ViewRenderer');
    $layout->setTemplate('login/index/index.phtml');
    return $viewRender->render($layout);
  }
}

The statement in module.config.php in Login module :

'view_helpers' => array(
    'invokables' => array(
        'loginForm' => 'Login\View\Helper\LoginForm'
    )
),

Use in view of the application module :

'view_helpers' => array(
    'invokables' => array(
        'loginForm' => 'Login\View\Helper\LoginForm'
    )
),
Alain Pomirol
  • 828
  • 7
  • 14
  • hello Alain. thank for the advice. i will try it out – theSeeker Jan 08 '16 at 08:44
  • hI Alain- your solution is perfect. do you think you could post the actual code here so that i can mark it as the acceptable answer.it would really help other searchers if they could see the actual code rather than following a link to another site – theSeeker Jan 11 '16 at 14:30
  • I just publish it. Delighted to have been helpful – Alain Pomirol Jan 11 '16 at 15:00
0

It's a common problem! Forms can really be a slow-down with ZF2.

I use Twig (recommended) but you can port this approach to plain old ZF2 templates too.

Here's one such template I use nearly everywhere:

horizontal_form.twig

{# render rows only, not the form tag #}
{% do form.prepare() %}
{% for f in form %}
    {% do f.setOption( 'twb-layout', 'horizontal' ) %}
    {{  formRow( f ) }}
{% endfor %}

I've got a second with a slightly different approach to support a specific IdentifiableForm in my code:

identifiable_form.twig

<form id="{{ form.getAttribute('name') }}" name="{{ form.getAttribute('name') }}" action="{{ form.getAttribute('action') }}" class="form-horizontal" role="form">
    <input type="hidden" name="class" value="{{ form.getAttribute('class') }}">
    {% for f in form %}
        {% do f.setOption( 'twb-layout', 'horizontal' ) %}
        {% do f.setOption( 'twb-form-group-size', 'form-group-sm' ) %}
        {{ formRow( f ) }}
    {% endfor %}
    <div class="hr-line-dashed"></div>
    <button type="submit" class="btn btn-primary ladda-button" data-style="expand-right">Save</button>
</form>

With those two in the pocket, my usage looks like this:

In a twig template that should use a form

...include the template from the other:

<div class="panel-body">

    {% set form = general_config_form %}
    {% do form.prepare() %}
    {% include 'application/generic/identifiable_form' %}

</div>

The controller action that operates that template looks like:

$vm = new ViewModel();
$vm->setTerminal( true );
$vm->setTemplate( 'application/admin/config/index' );

$sm = $this->getServiceLocator();
$fm = $sm->get( 'FormElementManager' );

$country = $config_mapper->get('general.country', true );
$general_config_form = $fm->get( GeneralConfigForm::class, [ 'country' => $country ] );
$general_config_form->setAttribute('action', '/admin-config/form-save' );
$vm->setVariable( 'general_config_form', $general_config_form );

In the end it's just a game of:

  • instantiating/loading the form in the action
  • setting the form as a variable in the ViewModel
  • including the "generic form template" from that action's actual template

On topic, if you hate rigging forms as much as I do, I made a little tool to save time here: https://github.com/Saeven/zf2-circlical-formtool

Second, if you use Bootstrap in your app, this form helper replacement really makes things look nice: https://github.com/neilime/zf2-twb-bundle

Good luck!

Saeven
  • 2,280
  • 1
  • 20
  • 33