router icon indicating copy to clipboard operation
router copied to clipboard

Handle DI in controller/action calls

Open mhipo1364 opened this issue 6 years ago • 5 comments

Hi guys

I need to know about DI in instantiating controller object, how could we handle it via this package?

mhipo1364 avatar Jul 06 '18 12:07 mhipo1364

@mhipo1364 , are you wanting to pass params to your controller via DI? For example:

<?php

use Some\Request;

class HomeController {
  public function index(Request $request) {
    // $request
  }
}

levidurfee avatar Jul 28 '18 20:07 levidurfee

Closing this issue due to inactivity. I'll gladly reopen when it becomes active again.

bramus avatar Jan 25 '19 22:01 bramus

Noticed that the PR in #76 is related to this, so reopening.

What's missing from that PR is updated documentation (~ an example) + tests

bramus avatar Jan 30 '19 13:01 bramus

I was struggling with this as well. I use Auryn DI as well as keep a "map" of my routes that I load and wanted to add via a loop. Here is what I did.

$router = new \Bramus\Router\Router();
$routes = include('Routes.php');

foreach ($routes as $route) {
    // GET/POST/PUT : my/route/pattern : [ controller, method]
    list($method, $location, $callback) = $route;

    match(strtolower($method)) {
        'get', 'post' => $router->get($location, function(...$params) use ($callback, $injector, $response) {
            $class = $injector->make($callback[0]);
            if (method_exists($class, $callback[1])) {
                $response->setContent(call_user_func_array(array($class, $callback[1]), $params));
            }
        }),
        default => throw new \Exception('Invalid router parameters')
    };
}

$router->run();

I don't keep get and post together as this shows, I just had it together figuring everything out. My routes are mapped as such:

return array(
    array('GET',    '/',                            ['App\Controllers\Frontpage', 'index']),
    array('GET',    '/login',                    ['App\Controllers\Login',   'index']),
    array('POST',   '/login/process',     ['App\Controllers\Login',   'processLogin']),
    array('GET',    '/logout',                  ['App\Controllers\Logout',  'logout'])

);

Essentially, I am looping through my routes and adding them with get(), post(), etc. I don't want the router to instantiate the class, I want my DI to do so. In this case, rather than passing my controller/method callback, I used an anonymous function and a splat operator (?) to retrieve the params. From here, I could use my DI to make my class, set the response content from calling it and that's it. Note, this example is using the match operator which works only with PHP 8. You can easily change this to a switch statement to work on previous versions.

I realize this is an old issue, but I had found absolutely nothing on this when searching. This covers applying routes from an external route map, di and using a typical response object (in my case, Symfonys http foundation response).

WeaponsTheyFear avatar Dec 11 '20 03:12 WeaponsTheyFear

I'm also figuring out, how I could use my DI container in a less verbose way. here is how i did it:

class dispatcher{
  
  // app is your DI container
  public static $app;

  public static function __callStatic($m, $args){
    list($class, $meth) = explode('__', $m);
    $api = self::$app->get("api\\{$class}");
    if(preg_match("/^post_/", $meth)){
      $args[] = get_json_req();
    }
    $res = $api->$meth(...$args);
    resp($res);
  }
}

dispatcher::$app = $app;

$router->mount('/admin', function() use ($router) {
 
  $router->get('/orgs', "dispatcher::orgs__get_orgs");
  $router->get('/org/(\w+)', "dispatcher::orgs__get_org");
  $router->post('/org/(\w+)', "dispatcher::orgs__post_create");
  $router->delete('/org/(\w+)', "dispatcher::orgs__delete");
 
});

cwmoss avatar Mar 09 '21 16:03 cwmoss