一直在努力学习如何实现服务,因为他们得到一个监听器触发。 Havebeendoingaseriouslotofreadingthelast几天来得到它的工作,但都被发现很难。因此,我认为我对事物顺序的理解可能有缺陷。ZF2 - 如何监听事件并因此触发服务?
使用情况下,我试图去工作如下:
仅仅是一个地址实体之前(与学说,但这不是 重要)获取保存(刷新),服务必须被触发,以检查 如果地址坐标设置,如果没有,创建和 填补了新坐标实体,并将其链接到地址。该 坐标是从谷歌地图API地理编码得到。
下面会显示什么以及我如何理解事情,希望我自己清楚。据我所知,它会逐步完成显示附加代码,并告诉你什么工作,哪些工作不工作。
现在,我所有的我已经得到了最近几天的信息的理解是这样的:
器监听器必须与ZF2的的ServiceManager注册。监听器将某些条件“附加”到(共享)EventManager。 EventManager对象是唯一的,但SharedEventManager在应用程序中是“全局”的。
在地址模块的Module.php
类我已经添加了以下功能:
/**
* @param EventInterface $e
*/
public function onBootstrap(EventInterface $e)
{
$eventManager = $e->getTarget()->getEventManager();
$eventManager->attach(new AddressListener());
}
这得到工程,AddressListener被触发。
的AddressListener如下:
use Address\Entity\Address;
use Address\Service\GoogleCoordinatesService;
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;
use Zend\Stdlib\CallbackHandler;
class AddressListener implements ListenerAggregateInterface
{
/**
* @var CallbackHandler
*/
protected $listeners;
/**
* @param EventManagerInterface $events
*/
public function attach(EventManagerInterface $events)
{
$sharedEvents = $events->getSharedManager();
// Not sure how and what order params should be. The ListenerAggregateInterface docblocks didn't help me a lot with that either, as did the official ZF2 docs. So, been trying a few things...
$this->listeners[] = $sharedEvents->attach(GoogleCoordinatesService::class, 'getCoordinates', [$this, 'addressCreated'], 100);
$this->listeners[] = $sharedEvents->attach(Address::class, 'entity.preFlush', [GoogleCoordinatesService::class, 'getCoordinates'], 100);
}
/**
* @param EventManagerInterface $events
*/
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
public function addressCreated()
{
$foo = 'bar'; // This line is here to as debug break. Line is never used...
}
}
我期待一个监听器作为工作跳板点,事情被触发,基于function attach(...){}
的->attach()
功能排序的。然而,这似乎并不奏效,因为没有任何东西被触发。不是addressCreated()
功能,而不是getCoordinates
功能在GoogleCoordinatesService
。
上面的代码应该触发GoogleCoordinatesService
功能getCoordinates
。尽管该服务有一些要求,例如存在Doctrine的EntityManager,它涉及的地址实体和配置。
为此,我创建了以下配置。
文件google.config.php
(被加载时,经检查发现)
return [
'google' => [
'services' => [
'maps' => [
'services' => [
'geocoding' => [
'api_url' => 'https://maps.googleapis.com/maps/api/geocode/json?',
'api_key' => '',
'url_params' => [
'required' => [
'address',
],
'optional' => [
'key'
],
],
],
],
],
],
],
];
而在module.config.php
我所注册的服务与厂
'service_manager' => [
'factories' => [
GoogleCoordinatesService::class => GoogleCoordinatesServiceFactory::class,
],
],
工厂是非常标准的ZF2的东西,但画一个完整的图片,这里是GoogleCoordinatesServiceFactory.php
类。 (删除评论/提示/等)
class GoogleCoordinatesServiceFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator, $options = [])
{
$serviceManager = $serviceLocator->getServiceLocator();
$entityManager = $serviceManager->get(EntityManager::class);
$config = $serviceManager->get('Config');
if (isset($options) && isset($options['address'])) {
$address = $options['address'];
} else {
throw new InvalidArgumentException('Must provide an Address Entity.');
}
return new GoogleCoordinatesService(
$entityManager,
$config,
$address
);
}
}
以下是GoogleCoordinatesService
类。然而,在那里没有任何东西被触发执行。由于它甚至没有被调用,我敢肯定问题在于上面的代码,但无法找出原因。从我读过的和尝试过的,我期望班级本身应该被调用,通过工厂,并且应该触发功能getCoordinates
。
所以,这个班级。我已经删除了一大堆标准的getter/setter,注释,docblocks和typehints以缩短它。
class GoogleCoordinatesService implements EventManagerAwareInterface
{
protected $eventManager;
protected $entityManager;
protected $config;
protected $address;
/**
* GoogleCoordinatesServices constructor.
* @param EntityManager $entityManager
* @param Config|array $config
* @param Address $address
* @throws InvalidParamNameException
*/
public function __construct(EntityManager $entityManager, $config, Address $address)
{
$this->config = $config;
$this->address = $address;
$this->entityManager = $entityManager;
}
public function getCoordinates()
{
$url = $this->getConfig()['api_url'] . 'address=' . $this->urlFormatAddress($this->getAddress());
$response = json_decode(file_get_contents($url), true);
if ($response['status'] == 'OK') {
$coordinates = new Coordinates();
$coordinates
->setLatitude($response['results'][0]['geometry']['location']['lat'])
->setLongitude($response['results'][0]['geometry']['location']['lng']);
$this->getEntityManager()->persist($coordinates);
$this->getAddress()->setCoordinates($coordinates);
$this->getEntityManager()->persist($this->getAddress());
$this->getEntityManager()->flush();
$this->getEventManager()->trigger(
'addressReceivedCoordinates',
null,
['address' => $this->getAddress()]
);
} else {
// TODO throw/set error/status
}
}
public function urlFormatAddress(Address $address)
{
$string = // format the address into a string
return urlencode($string);
}
public function getEventManager()
{
if ($this->eventManager === null) {
$this->setEventManager(new EventManager());
}
return $this->eventManager;
}
public function setEventManager(EventManagerInterface $eventManager)
{
$eventManager->addIdentifiers([
__CLASS__,
get_called_class()
]);
$this->eventManager = $eventManager;
return $this;
}
// Getters/Setters for EntityManager, Config and Address
}
所以,这是当某个事件被触发时处理它的设置。现在它应该被触发。对于这个用例,我在我自己的AbstractActionController
中设置了一个触发器(扩展了ZF2的AbstractActionController
)。这样做:
if ($form->isValid()) {
$entity = $form->getObject();
$this->getEntityManager()->persist($entity);
try {
// Trigger preFlush event, pass along Entity. Other Listeners can subscribe to this name.
$this->getEventManager()->trigger(
'entity.preFlush',
null,
[get_class($entity) => $entity] // key = "Address\Entity\Address" for use case
);
$this->getEntityManager()->flush();
} catch (\Exception $e) {
// Error thrown
}
// Success stuff, like a trigger "entity.postFlush"
}
所以是的。目前在如何实现它的工作方面有点不知所措。
任何帮助将非常感激,并会喜欢解释为什么它是一个解决方案的原因。这真的会帮助我做出更多的这些服务:)