To solve the issue you should use a Listener class and Factory. It would also help you with more separation of concerns :)
You seem quite capable of figuring stuff out, judging by your code. As such, I'm just going to give you an example of my own, so you should fill yours in with your own code (I'm also a bit lazy and do not wish to rewrite everything when I can copy/paste my code in ;) )
In your module.config.php
:
'listeners' => [
// Listing class here will automatically have them "activated" as listeners
ActiveSessionListener::class,
],
'service_manager' => [
'factories' => [
// The class (might need a) Factory
ActiveSessionListener::class => ActiveSessionListenerFactory::class,
],
],
The Factory
<?php
namespace UserFactoryListener;
use DoctrineCommonPersistenceObjectManager;
use DoctrineORMEntityManager;
use InteropContainerContainerInterface;
use UserListenerActiveSessionListener;
use ZendAuthenticationAuthenticationService;
use ZendServiceManagerFactoryFactoryInterface;
class ActiveSessionListenerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
/** @var ObjectManager $entityManager */
$entityManager = $container->get(EntityManager::class);
/** @var AuthenticationService $authenticationService */
$authenticationService = $container->get(AuthenticationService::class);
return new ActiveSessionListener($authenticationService, $entityManager);
}
}
The Listener
<?php
namespace UserListener;
use DoctrineCommonPersistenceObjectManager;
use DoctrineORMEntityManager;
use UserEntityUser;
use ZendAuthenticationAuthenticationService;
use ZendEventManagerEvent;
use ZendEventManagerEventManagerInterface;
use ZendEventManagerListenerAggregateInterface;
use ZendMvcMvcEvent;
/**
* Class ActiveSessionListener
*
* @package UserListener
*
* Purpose of this class is to make sure that the identity of an active session becomes managed by the EntityManager.
* A User Entity must be in a managed state in the event of any changes to the Entity itself or in relations to/from it.
*/
class ActiveSessionListener implements ListenerAggregateInterface
{
/**
* @var AuthenticationService
*/
protected $authenticationService;
/**
* @var ObjectManager|EntityManager
*/
protected $objectManager;
/**
* @var array
*/
protected $listeners = [];
/**
* CreatedByUserListener constructor.
*
* @param AuthenticationService $authenticationService
* @param ObjectManager $objectManager
*/
public function __construct(AuthenticationService $authenticationService, ObjectManager $objectManager)
{
$this->setAuthenticationService($authenticationService);
$this->setObjectManager($objectManager);
}
/**
* @param EventManagerInterface $events
*/
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
/**
* @param EventManagerInterface $events
*/
public function attach(EventManagerInterface $events, $priority = 1)
{
$events->attach(MvcEvent::EVENT_ROUTE, [$this, 'haveDoctrineManagerUser'], 1000);
}
/**
* @param Event $event
*
* @throws DoctrineCommonPersistenceMappingMappingException
* @throws DoctrineORMORMException
*/
public function haveDoctrineManagerUser(Event $event)
{
if ($this->getAuthenticationService()->hasIdentity()) {
// Get current unmanaged (by Doctrine) session User
$identity = $this->getAuthenticationService()->getIdentity();
// Merge back into a managed state
$this->getObjectManager()->merge($identity);
$this->getObjectManager()->clear();
// Get the now managed Entity & replace the unmanaged session User by the managed User
$this->getAuthenticationService()->getStorage()->write(
$this->getObjectManager()->find(User::class, $identity->getId())
);
}
}
/**
* @return AuthenticationService
*/
public function getAuthenticationService() : AuthenticationService
{
return $this->authenticationService;
}
/**
* @param AuthenticationService $authenticationService
*
* @return ActiveSessionListener
*/
public function setAuthenticationService(AuthenticationService $authenticationService) : ActiveSessionListener
{
$this->authenticationService = $authenticationService;
return $this;
}
/**
* @return ObjectManager|EntityManager
*/
public function getObjectManager()
{
return $this->objectManager;
}
/**
* @param ObjectManager|EntityManager $objectManager
*
* @return ActiveSessionListener
*/
public function setObjectManager($objectManager)
{
$this->objectManager = $objectManager;
return $this;
}
}
The important bits:
- The
Listener
class must implement ListenerAggregateInterface
- Must be activated in the
listeners
key of the module configuration
That's it really. You then have the basic building blocks for a Listener.
Apart from the attach
function you could take the rest and make that into an abstract class if you'd like. Would save a few lines (read: duplicate code) with multiple Listeners.
NOTE: Above example uses the normal EventManager
. With a simple change to the above code you could create "generic" listeners, by attaching them to the SharedEventManager
, like so:
/**
* @param EventManagerInterface $events
*/
public function attach(EventManagerInterface $events, $priority = 1)
{
$sharedManager = $events->getSharedManager();
$sharedManager->attach(SomeClass::class, EventConstantClass::SOME_STRING_CONSTANT, [$this, 'callbackFunction']);
}
public function callbackFunction (MvcEvent $event) {...}