Zend Framework 2:从配置创建表单 - 如何修复 ServiceNotCreatedException
Zend Framework 2: Creating forms from configuration - how to fix ServiceNotCreatedException
我想通过配置在 Zend Framework 2 中创建一个表单,类似于 docs 中所述。因此,不要以 class 的形式对每个元素执行此操作:
// [...]
$this->add(array(
'name' => 'fname',
'type' => 'text',
));
// [...]v
我想这样做:
// [...]
$form = $factory->createForm(array(
'elements' => array(
array(
'spec' => array(
'name' => 'fname',
'type' => 'text',
),
),
),
));
// [...]
由于我是这个框架的新手,我仍然有点不确定事情的进展以及正确的做事方式,但我认为我的轨道很好——我只需要让事情正常进行更了解他们。
目前我的代码导致了一个异常,这让我有点困惑,虽然我以某种方式理解它:
An exception was raised while creating "MyForm"; no instance returned
除了我的困惑,我已经知道我的代码可能哪里出错了。
表单 class 看起来很简单,因为这里不会注入实际元素:
namespace My\Form;
use Zend\Form\Form;
class MyForm extends Form
{
public function __construct()
{
parent::__construct();
$this->setAttribute('method', 'post');
$this->setAttribute('action', '/some-action');
}
}
表单元素的配置如下所示:
namespace My\Form;
use Zend\Form\Factory;
class MyFormFactory extends Factory
{
public function __construct()
{
$factory = new Factory();
$form = $factory->createForm(array(
'elements' => array(
array(
'spec' => array(
'name' => 'fname',
'type' => 'text',
),
),
),
));
return $form;
}
}
为了将两者连接起来,我在模块的 module.config.php
:
中有这个服务管理器配置
'service_manager' => array(
'factories' => array(
'MyForm' => function ($servicemanager) {
$form = new \My\Form\MyForm();
$factory = $servicemanager->get('MyFormFactory');
$form->add($factory);
return $form;
},
'MyFormFactory' => function ($servicemanager) {
$factory = new \My\Form\MyFormFactory();
return $factory;
},
),
),
最后但同样重要的是,控制器:
namespace My\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class MyController extends AbstractActionController
{
public function indexAction()
{
$form = $this->getServiceLocator()->get('MyForm');
return new ViewModel(array(
'form' => $form,
));
}
}
如前所述,唯一发生的事情是非常清楚的异常:MyForm class 没有 return 实例。为了解决这个问题,我已经尝试 return 一些东西,但是那没有做任何事情。
需要更改什么才能创建表单?我的方法好还是我走错了路?
这里的一些事情可能会让你将来的生活更轻松。
ZF2 附带一个 AbstractPluginManager
专门用于表单和表单元素,称为 FormElementManager
。可以使用 form_elements
配置键从此管理器配置表单。
在此处找到有关此内容的文档:http://framework.zend.com/manual/current/en/modules/zend.form.advanced-use-of-forms.html
用这个代替一般的ServiceManager
。
在您的 MyForm
工厂回调中,$form->add()
需要 ElementInterface
或 Traversable
的实例,您正在将其传递给工厂.我假设这是抛出 InvalidArgumentException
。为此检查您的日志。我认为这是您问题的根源。
此外,在您的 MyFormFactory
中,您正试图 return 来自工厂构造函数的表单。这将产生一些有趣的结果(加上打破 SRP),我会重新考虑 class 完全。
为获得最佳实践,请尽可能避免在控制器中使用 ServiceManager
。我知道它在那里,而且我知道如果您需要服务,抓住它是一件容易的事,但该表格实际上应该在控制器自己的工厂中注入到您的控制器中(在 controllers
-> factories
配置键)
为了通过配置创建表单,您将需要使用 Zend\Form\Factory
,这将return 表单元素基于您的配置提供它。让我们称之为 "FormFactory".
但是,要在 FormElementManager
中将此表单注册为名为 'MyForm' 的服务,您需要 还 创建一个服务管理器工厂。 "factory" 是 class 实现 Zend\ServiceManager\FactoryInterface
。让我们称之为 "ServiceFactory".
如果我要更正您的代码,我会按以下方式进行。
删除classMyForm
。没有真正需要实际扩展基本形式 Zend\Form\Form
;这是因为您只设置了表单的属性,可以通过 FormFactory
来完成(您给它配置这些属性,它将 return 一个已经设置好的新表单)。
删除MyFormFactory
。为了创建我们的新表单,我们不需要扩展表单工厂或创建它的新实例,而是我们 使用 它是客户端代码中的 API。
删除service_manager
下的配置。我们应该使用 'FormElementManager' 注册我们的表单(使用 `form_elements' 配置键)。 'plugin manager' 配置为 return 表单元素。
通过这些更改,您只需一个 "ServiceFactory" 即可创建表单。例如。
namespace My\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class MyFormFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $formElementManager)
{
// Get the config of the new form
$config = $this->getElementConfig($formElementManager);
// Get the service manager
$serviceManager = $formElementManager->getServiceLocator();
// Get the form factory (service that creates the form)
// from the service manager, FormFactory is the default
$formFactory = new \Zend\Form\Factory($formElementManager);
// Create the form using the factory and config and then return it
return $formFactory->create($config);
}
/** Return the config for the factory **/
protected function getElementConfig(ServiceLocatorInterface $formElementManager)
{
// you could use the form element manager / service manager
// here to load the config from elsewhere...
return [
'name' => 'myform',
'type' => 'Zend\Form\Form',
'attributes' => [
'method' => 'post',
'action' => '/foo/bar',
],
'fieldsets' => [
/....
],
'elements' => [
//...
]
];
}
}
然后在您的 module.config.php 中您可以将工厂注册为新服务
'form_elements' => [
'factories' => [
'MyForm' => 'My\Factory\MyFormFactory',
],
],
注意上面的配置在 'form_elements' 键下。当我们使用表单元素管理器注册服务时,您的控制器代码也应该更新。
$serviceManager = $this->getServiceLocator();
$form = $serviceManager->get('FormElementManager')->get('MyForm');
我想通过配置在 Zend Framework 2 中创建一个表单,类似于 docs 中所述。因此,不要以 class 的形式对每个元素执行此操作:
// [...]
$this->add(array(
'name' => 'fname',
'type' => 'text',
));
// [...]v
我想这样做:
// [...]
$form = $factory->createForm(array(
'elements' => array(
array(
'spec' => array(
'name' => 'fname',
'type' => 'text',
),
),
),
));
// [...]
由于我是这个框架的新手,我仍然有点不确定事情的进展以及正确的做事方式,但我认为我的轨道很好——我只需要让事情正常进行更了解他们。
目前我的代码导致了一个异常,这让我有点困惑,虽然我以某种方式理解它:
An exception was raised while creating "MyForm"; no instance returned
除了我的困惑,我已经知道我的代码可能哪里出错了。
表单 class 看起来很简单,因为这里不会注入实际元素:
namespace My\Form;
use Zend\Form\Form;
class MyForm extends Form
{
public function __construct()
{
parent::__construct();
$this->setAttribute('method', 'post');
$this->setAttribute('action', '/some-action');
}
}
表单元素的配置如下所示:
namespace My\Form;
use Zend\Form\Factory;
class MyFormFactory extends Factory
{
public function __construct()
{
$factory = new Factory();
$form = $factory->createForm(array(
'elements' => array(
array(
'spec' => array(
'name' => 'fname',
'type' => 'text',
),
),
),
));
return $form;
}
}
为了将两者连接起来,我在模块的 module.config.php
:
'service_manager' => array(
'factories' => array(
'MyForm' => function ($servicemanager) {
$form = new \My\Form\MyForm();
$factory = $servicemanager->get('MyFormFactory');
$form->add($factory);
return $form;
},
'MyFormFactory' => function ($servicemanager) {
$factory = new \My\Form\MyFormFactory();
return $factory;
},
),
),
最后但同样重要的是,控制器:
namespace My\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class MyController extends AbstractActionController
{
public function indexAction()
{
$form = $this->getServiceLocator()->get('MyForm');
return new ViewModel(array(
'form' => $form,
));
}
}
如前所述,唯一发生的事情是非常清楚的异常:MyForm class 没有 return 实例。为了解决这个问题,我已经尝试 return 一些东西,但是那没有做任何事情。
需要更改什么才能创建表单?我的方法好还是我走错了路?
这里的一些事情可能会让你将来的生活更轻松。
ZF2 附带一个
AbstractPluginManager
专门用于表单和表单元素,称为FormElementManager
。可以使用form_elements
配置键从此管理器配置表单。在此处找到有关此内容的文档:http://framework.zend.com/manual/current/en/modules/zend.form.advanced-use-of-forms.html
用这个代替一般的
ServiceManager
。在您的
MyForm
工厂回调中,$form->add()
需要ElementInterface
或Traversable
的实例,您正在将其传递给工厂.我假设这是抛出InvalidArgumentException
。为此检查您的日志。我认为这是您问题的根源。此外,在您的
MyFormFactory
中,您正试图 return 来自工厂构造函数的表单。这将产生一些有趣的结果(加上打破 SRP),我会重新考虑 class 完全。为获得最佳实践,请尽可能避免在控制器中使用
ServiceManager
。我知道它在那里,而且我知道如果您需要服务,抓住它是一件容易的事,但该表格实际上应该在控制器自己的工厂中注入到您的控制器中(在controllers
->factories
配置键)
为了通过配置创建表单,您将需要使用 Zend\Form\Factory
,这将return 表单元素基于您的配置提供它。让我们称之为 "FormFactory".
但是,要在 FormElementManager
中将此表单注册为名为 'MyForm' 的服务,您需要 还 创建一个服务管理器工厂。 "factory" 是 class 实现 Zend\ServiceManager\FactoryInterface
。让我们称之为 "ServiceFactory".
如果我要更正您的代码,我会按以下方式进行。
删除class
MyForm
。没有真正需要实际扩展基本形式Zend\Form\Form
;这是因为您只设置了表单的属性,可以通过FormFactory
来完成(您给它配置这些属性,它将 return 一个已经设置好的新表单)。删除
MyFormFactory
。为了创建我们的新表单,我们不需要扩展表单工厂或创建它的新实例,而是我们 使用 它是客户端代码中的 API。删除
service_manager
下的配置。我们应该使用 'FormElementManager' 注册我们的表单(使用 `form_elements' 配置键)。 'plugin manager' 配置为 return 表单元素。
通过这些更改,您只需一个 "ServiceFactory" 即可创建表单。例如。
namespace My\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class MyFormFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $formElementManager)
{
// Get the config of the new form
$config = $this->getElementConfig($formElementManager);
// Get the service manager
$serviceManager = $formElementManager->getServiceLocator();
// Get the form factory (service that creates the form)
// from the service manager, FormFactory is the default
$formFactory = new \Zend\Form\Factory($formElementManager);
// Create the form using the factory and config and then return it
return $formFactory->create($config);
}
/** Return the config for the factory **/
protected function getElementConfig(ServiceLocatorInterface $formElementManager)
{
// you could use the form element manager / service manager
// here to load the config from elsewhere...
return [
'name' => 'myform',
'type' => 'Zend\Form\Form',
'attributes' => [
'method' => 'post',
'action' => '/foo/bar',
],
'fieldsets' => [
/....
],
'elements' => [
//...
]
];
}
}
然后在您的 module.config.php 中您可以将工厂注册为新服务
'form_elements' => [
'factories' => [
'MyForm' => 'My\Factory\MyFormFactory',
],
],
注意上面的配置在 'form_elements' 键下。当我们使用表单元素管理器注册服务时,您的控制器代码也应该更新。
$serviceManager = $this->getServiceLocator();
$form = $serviceManager->get('FormElementManager')->get('MyForm');