我现在正试图在ZF2中实现我自己的过滤器。
然而,我遇到了一个问题,我找不到足够清晰的文档。
我的过滤器需要同时获得选项数组(在我的例子中,它包含width
和height
字段)和服务定位器实例。
但是,我无法使它接收WebinoImageThumb
类实例。
以下是筛选代码(这里,$this->serviceLocator
总是保持NULL,这就是问题所在):
<?php
namespace Application'Form'Filter;
use Zend'Filter'Exception;
use Zend'ServiceManager'ServiceLocatorAwareInterface;
use Zend'ServiceManager'ServiceLocatorInterface;
class FitImage extends 'Zend'Filter'AbstractFilter implements ServiceLocatorAwareInterface
{
protected $serviceLocator;
private $width;
private $height;
private $thumbnailer;
public function __construct($generalServiceLocator/*$options*/)
{
var_dump($generalServiceLocator);
$width = $options['width'];
$height = $options['height'];
$this->width = $width;
$this->height = $height;
// We encourage to use Dependency Injection instead of Service Locator
$this->thumbnailer = $this->getServiceLocator()->get('WebinoImageThumb');
}
public function filter($value)
{
$thumb = $thumbnailer->create($value, $options = array(), $plugins = array());
$thumb->resize($this->width, $this->height);
$thumb->save($value);
return $value;
}
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
}
我以这样的形式使用它:
<?php
namespace Backend'Form;
use Zend'InputFilter'InputFilter;
use Zend'InputFilter'InputFilterProviderInterface;
use Zend'InputFilter'InputFilterInterface;
use Zend'Form'Form;
class AuthorForm extends Form implements InputFilterProviderInterface
{
public function __construct($name = null)
{
// we want to ignore the name passed
parent::__construct('author');
$this->add(array(
'name' => 'portrait_file',
'type' => 'file',
'options' => array(
'label' => 'Портрет',
)
));
$this->add(array(
'name' => 'submit',
'type' => 'Submit',
'attributes' => array(
'value' => 'Go',
'id' => 'submitbutton',
),
));
}
public function getInputFilterSpecification()
{
return array(
array(
'name' => 'portrait_file',
'required' => false,
'filters' => array(
array(
'name' => 'Application'Form'Filter'FitImage',
'options' => array(
'width' => 300,
'height' => 250
)
)
),
// validators go here
)
);
}
}
似乎通过实现ServiceLocatorAwareInterface
,FitImage过滤器应该通过setServiceLocator
接收serviceLocator,但它没有。
我错过了什么?
感谢您的帮助。
注入服务定位器是一种糟糕的设计策略;更好的方法是注入类所需的WebinoImageThumb
"服务"。
首先删除ServiceLocator
引用,并添加新服务作为构造函数参数。
namespace MyModule'Filter;
class FitImage extends AbstractFilter
{
protected $thumbnailService;
protected $height;
protected $width;
// Type hinting on 'ThumbnailServiceInterface' would mean you can swap
// out the 'service' with another at a later date
public function __construct(ThumbnailServiceInterface $thumbnailService, $height = 100, $width = 100)
{
$this->thumbnailService = $thumbnailService;
$this->height = $height;
$this->width = $width;
}
public function filter($value)
{
$thumb = $this->thumbnailService->create($value);
$thumb->resize($this->height, $this->width);
$thumb->save($value);
return $value;
}
public function setHeight($height) {
$this->height = intval($height);
}
public function setWidth($width) {
$this->width = intval($width);
}
}
然后创建一个服务工厂来创建过滤器。
namespace MyModule'Filter;
use Zend'ServiceManager'FactoryInterface;
use Zend'ServiceManager'ServiceLocatorInterface;
class FitImageFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
// $serviceLocator here is the 'filter plugin manager'
$serviceManager = $serviceLocator->getServiceLocator();
$options = $this->getOptions($serviceLocator);
return new FitImage(
$serviceManager->get('WebinoImageThumb'),
$options['height'],
$options['width']
);
}
protected function getOptions(ServiceLocatorInterface $serviceLocator)
{
// This could be loaded from config
return array('height' => 100, 'width' => 100);
}
}
最后,添加对模块配置或Module.php
的引用,如下所示
public function getFilterConfig()
{
return array(
'factories' => array(
'MyModule'Filter'FitImage' => 'MyModule'Filter'FitImageFactory',
),
);
}
在不了解您的具体项目的情况下,您可能需要考虑将缩略图创建从"过滤器"转移到单独的服务中。过滤器用于过滤/修改给定的输入$value
并返回格式化的值。
您的案例中的输入过滤器不是由服务管理器实例化的,这就是为什么您没有服务定位器的实例。要解决此问题,可以手动创建过滤器对象,以便访问服务管理器。然后,您可以将其附加到表单中输入过滤器的过滤器链上
已更新
我找到了解决你问题的办法。你可以保持你的代码原样。如果你从控制器创建你的表单,那么下面的代码片段将很适合你(测试)
$form = new AuthForm();
$filterChain = $form->getInputFilter()->get('portrait_file')->getFilterChain();
$filterChain->getPluginManager()->setServiceLocator($this->getServiceLocator());
事实证明,过滤器链使用插件管理器来管理过滤器。通过defalt,插件管理器不保留任何服务定位器,所以你可以像我在上面的例子中那样随意设置一个。在您的过滤代码中,您可以访问以下主要服务定位器:
$mainServiceLocator = $this->getServiceLocator()->getServiceLocator();