Zend Framework 2 Внедрение зависимостей в фильтр

Я сейчас пытаюсь реализовать свой собственный фильтр в 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 должен получать serviceLocator через setServiceLocator, но это не так.

Что мне не хватает?

Любая помощь приветствуется.

0

Решение

Введение сервисного локатора — плохая стратегия проектирования; лучшим подходом было бы ввести то, что нужно классу, 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 и вернуть отформатированное значение.

1

Другие решения

Фильтр ввода в вашем случае не создается менеджером службы, поэтому у вас нет экземпляра локатора службы там. Чтобы решить эту проблему, вы можете создать свой объект фильтра вручную, чтобы получить доступ к диспетчеру сервисов. Затем вы можете прикрепить его к цепочке фильтров входного фильтра в вашей форме.

обновленный

Я нашел решение для вашей проблемы. Вы можете сохранить свой код как есть. Если вы создаете свою форму из контроллера, то следующий фрагмент кода будет хорошо работать для вас (проверено)

    $form = new AuthForm();
$filterChain = $form->getInputFilter()->get('portrait_file')->getFilterChain();
$filterChain->getPluginManager()->setServiceLocator($this->getServiceLocator());

Оказывается, цепочка фильтров управляет своими фильтрами с помощью менеджера плагинов. По умолчанию, менеджер плагинов не сохраняет локатор сервисов, поэтому вы можете установить его, как я делал в моем примере выше. В коде фильтра вы можете получить доступ к основному локатору службы следующим образом:

$mainServiceLocator = $this->getServiceLocator()->getServiceLocator();
0

По вопросам рекламы [email protected]