一直在努力學習如何實現服務,因爲他們得到一個監聽器觸發。 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"
}
所以是的。目前在如何實現它的工作方面有點不知所措。
任何幫助將非常感激,並會喜歡解釋爲什麼它是一個解決方案的原因。這真的會幫助我做出更多的這些服務:)