Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slim 3 framework - Passing data from middleware to controller - action args

I'm using a controller/middleware build with slim 3 and i want from the middleware attached to a group, to pass some data to the $args parameter in my controller - action.

Here's some code:

class MyController
{
    protected $container;

    public function __construct(ContainerInterface $container) {
        $this->container = $container;
    }

    public function index(Request $request, Response $response, $args) {
        return $this->container->get('renderer')->render($response, "index.html.twig", $args);
    }
}
class MyMiddleware
{
    public function __invoke(Request $request, Response $response, $next)
    {
// do some stuff to inject further down to $args some data
        return $next($request, $response);
    }
}
$app->group('/group', function () use ($app){
//routes
    })->add(new MyMiddleware());

My use case is to send stuff to all the views rendered by the actions of these controllers, so i'm also fine with other ways to do this :)

Thanks.

like image 532
C Apetrei Avatar asked Nov 29 '25 18:11

C Apetrei


2 Answers

so you need just pass data from Middleware to Controller

what about

class MyMiddleware
{
    public function __invoke(Request $request, Response $response, $next)
    {
        $request = $request->withAttribute('myMagicArgument', 42);
        return $next($request, $response);
    }
}

and then in controller

class MyController
{
    //...
    public function index(Request $request, Response $response) {
        $yourAttributeFromMiddleware = $request->getAttribute('myMagicArgument');
        //...
    }
}
like image 92
jDolba Avatar answered Dec 01 '25 08:12

jDolba


For completeness, I'm going to extend the excellent answer given @jDolba

Unfortunately, though it got me going in the right direction, it still took a little experimentation to get everything working.

Basically, as explained in the slim router docs

The route callback signature is determined by a route strategy. By default, Slim expects route callbacks to accept the request, response, and an array of route placeholder arguments. This is called the RequestResponse strategy. However, you can change the expected route callback signature by simply using a different strategy. As an example, Slim provides an alternative strategy called RequestResponseArgs that accepts request and response, plus each route placeholder as a separate argument. Here is an example of using this alternative strategy; simply replace the foundHandler dependency provided by the default \Slim\Container:

$c = new \Slim\Container();
$c['foundHandler'] = function() {
    return new \Slim\Handlers\Strategies\RequestResponseArgs();
};

$app = new \Slim\App($c);
$app->get('/hello/{name}', function ($request, $response, $name) {
    return $response->write($name);
});

You can provide your own route strategy by implementing the \Slim\Interfaces\InvocationStrategyInterface.

however, for the task of injecting some standardised data into the $args[] array, the default \Slim\Handlers\Strategies\RequestResponse class does everything it needs to minus injecting the data.

As such, I simply extended that class:

<?php

namespace MyProject\Handlers\Strategies;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

use \Slim\Handlers\Strategies\RequestResponse;

class SomeNewInvocationStrategy extends RequestResponse
{
    /**
     * Invoke a route callable.
     *
     * @param callable               $callable The callable to invoke using the strategy.
     * @param ServerRequestInterface $request The request object.
     * @param ResponseInterface      $response The response object.
     * @param array                  $routeArguments The route's placholder arguments
     *
     * @return ResponseInterface|string The response from the callable.
     */
    public function __invoke( callable $callable, ServerRequestInterface $request, ResponseInterface $response, array $routeArguments)
    {
        $routeArguments['test'] = 'testing testing 123';
        return parent::__invoke( $callable, $request, $response, $routeArguments );
    }
} 

My container declaration looks like this:

<?php

use Slim\App;

return function (App $app) {
    $container = $app->getContainer();

    $container['foundHandler'] = function() {
        return new MyProject\Handlers\Strategies\SomeNewInvocationStrategy();
    };
}

Then in all of my controller actions I have access to $args['test']. Further, this can be passed straight through to any Twig views.

This is useful for tasks like access control where by I always want to load the roles of users before processing the request but I'm sure there'll be many other use-cases for it.

I Hope this helps somebody.

like image 29
DazBaldwin Avatar answered Dec 01 '25 08:12

DazBaldwin