Reputation: 1481
I cannot understand how factories actually work. I prepared short files to test it for form elements.
Application/config/module.config.php
<?php
namespace Application;
use Zend\Router\Http\Literal;
use Zend\Router\Http\Segment;
use Zend\ServiceManager\Factory\InvokableFactory;
use Application\Route\StaticRoute;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Application\Form\Factory\AbcFormFactory;
use Application\Form\AbcForm;
return [
'form_elements' => [
'factories' => [
AbcForm::class => AbcFormFactory::class,
],
],
//(...)
];
Application/src/Form/Factory/AbcFormFactory.php
<?php
namespace Application\Form\Factory;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use Application\Form\AbcForm;
class AbcFormFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
return new AbcForm("It works");
}
}
Application/src/Form/AbcForm.php
<?php
namespace Application\Form;
use Zend\Form\Element;
use Zend\Form\Form;
use Zend\Hydrator\ClassMethods as ClassMethodsHydrator;
use Zend\InputFilter\InputFilter;
class AbcForm extends Form
{
public function __construct($letter='no factory')
{
die($letter);
}
}
The code above displays no factory
, so the factory is ignored. If it had not been ignored it would have displayed It works
.
How to create proper factory for form_elements?
UPDATE I call the form in controller:
<?php
namespace Application\Controller;
use Application\Form\AbcForm;
use Zend\Mvc\Controller\AbstractActionController;
class AbcController extends AbstractActionController
{
public function indexAction()
{
$form = new AbcForm();
}
}
What triggers form factory __invoke method? I think, when the form class is implemented via new the form factory __invoke method should run. Or not?
Upvotes: 0
Views: 295
Reputation: 5119
You instantiate your form directly by the new
operator. In zend framework 3 there is a service container, which contains all your classes you have noted in your module config. In this case it 's the AbcForm
class, which should be created over a factory. In this case your controller class should be also created with a factory. It 's a common practice to use dependency injection for telling your controller, which form to use.
Just have a look at the following example.
The controller factory
namespace Application\Controller\Service;
use Application\Form\AbcForm;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
class AbcControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$form = $container->get('FormElementManager')->get(AbcForm::class);
$controller = new AbcController($form);
return $controller;
}
}
The controller itself
namespace Application\Controller;
use Application\Form\AbcForm;
use Zend\Mvc\Controller\AbstractActionController;
class AbcController extends AbstractActionController
{
protected $form;
public function __construct(AbcForm $form)
{
$this->form = $form;
}
public function indexAction()
{
if ($this->form->isValid()) {
// ... and so on
}
}
}
Your module config
return [
'controllers' => [
'factories' => [
AbcController::class => AbcControllerFactory::class,
],
],
'form_elements' => [
'factories' => [
AbcForm::class => AbcFormFactory::class,
],
],
'router' => [
'routes' => [
'your-abcform-application' => [
'type' => Literal::class,
'options' => [
'route' => '/application/abcform/',
'defaults' => [
'controller' => AbcController::class,
],
],
],
],
],
];
You have to hand over your form via dependency injection to the constructor of your controller. Therefore we have created the controller factory, which instantiates your form class and gives it to the controller. In the controller itself you can access your form with the protected form property.
Upvotes: 2