a middleware cannot run in front of a controller.
it worked before controller action in ZF2. i debugged it 2 minutes ago (in ZF2 and ZF3).
Config:
'zfcuser' => array(
'child_routes' => array(
'resetpassword' => array(
'type' => 'Segment',
'options' => array(
'route' => '/reset-password/:userId/:token',
'defaults' => array(
'middleware' => \User\Goalio\ForgotPassword\Middleware\ResetPassword::class,
'controller' => 'goalioforgotpassword_forgot',
'action' => 'reset',
),
'constraints' => array(
'userId' => '[A-Fa-f0-9]+',
'token' => '[A-F0-9]+',
),
),
),
),
),
Middleware:
namespace User\Goalio\ForgotPassword\Middleware;
use User\Goalio\ForgotPassword\Listener\ResetPasswordListener;
class ResetPassword {
public function __construct( $eventManager ) {
$eventManager->attach( new ResetPasswordListener() );
}
}
ResetPasswordListener:
<?php
namespace User\Goalio\ForgotPassword\Listener;
use Album\H\Token;
use Album\Model\Transaction;
use User\H\Curl;
use User\Model\UsrTb;
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;
class ResetPasswordListener implements ListenerAggregateInterface
{
/**
* @var \Zend\Stdlib\CallbackHandler[]
*/
protected $listeners = [];
protected $serviceManager;
/**
* {@inheritDoc}
*/
public function __construct(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator = null)
{
$this->serviceManager = $serviceLocator;
}
public function attach(EventManagerInterface $events)
{
$sharedEvents = $events->getSharedManager();
$this->listeners[] = $sharedEvents->attach(
'User\Goalio\ForgotPassword\Service\Password',
['resetPassword'],
[$this, 'action'],
100);
$this->listeners[] = $sharedEvents->attach(
'User\Goalio\ForgotPassword\Service\Password',
['resetPassword.post'],
[$this, 'actionPost'],
100);
}
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
public function action($e)
{
$user = $e->getParam( 'user');
$password = $e->getParam('password');
$user->syncFTPUsrPwd($password);
Transaction::begin();
return $this;
}
public function actionPost($e)
{
Transaction::commit();
return $this;
}
}
@xerkus
so this above worked way was temporary solution and now it was replaced with different approach, when middleware can return response WITHOUT further run action of controller?
as fast solution i changed my middleware to code in Module.php:
public function onBootstrap( Event $e )
{
$this->attachListeners( $e );
}
public function attachListeners( Event $e )
{
$eventManager = $e->getApplication()->getEventManager();
$sm = $e->getApplication()
->getServiceManager();
$eventManager->attach( MvcEvent::EVENT_ROUTE, function ( $e ) use ( $eventManager ) {
$routeMatch = $e->getRouteMatch();
# this part was done as middleware ResetPassword::class, BUT ZF3 killed they way, how it worked in ZF2, so moved here
if ( in_array( $routeMatch->getMatchedRouteName(), [
Route::ZFCUSER_RESET_PASSWORD,
] ) ) {
( new ResetPasswordListener() )->attach( $eventManager );
}
} );
}
but this code will run for every request, what will have additional uneeded overhead for other routes.
abstractly saying in real world not every controller action can’t be migrated to separate RequestHandler
, because it can be vendor
-code (in my case it is).
maybe i am missing something.
@froschdesign
@xerkus
how to resolve this task including each required target:
- code runs only for concrete related 1 (1…N) routes
- controller action is fixed (
vendor
-code), but we need to run it after
it seems ideal solution (which resolves both targets) is absent?
thanks!