Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Silex, mount multiple controller providers with closures

Tags:

closures

silex

I'm trying out Silex and I'm having a bit of a problem, or I might say, more of an inconvenience...

I'm trying to load 2 routes from 2 separate yaml files, but for some reason the mounting ($app->mount(...)) doesn't work with closures.

Here's some code:

// load configuration
$loader->load('core.yml');
$loader->load('api.yml');


function bla($app, $container, $key) {
    $myApp = $app['controllers_factory'];

    foreach ($container->getExtensionConfig('routes')[$key] as $name => $route) {
        $controller = $myApp->match($route['pattern'], $route['controller']);
        $controller->method($route['requirements']['_method']);
        $controller->bind($name);
    }
    return $myApp;
}

$app->mount('/core', bla($app, $container, 0));
$app->mount('/api', bla($app, $container, 1));

This works.

What doesn't work is if I do the exact same thing with closures, like this:

$app->mount('/core', function ($app, $container, $key) {
    return $app['controllers_factory'];
});

Gives the following error:

LogicException: The "mount" method takes either a ControllerCollection or a ControllerProviderInterface instance.

But

var_dump($app['controllers_factory']);

spits out an object of type Silex\ControllerCollection.

I'm obviously missing something.

Thank you for your help.

like image 542
Trevor Donahue Avatar asked Oct 11 '25 14:10

Trevor Donahue


1 Answers

The problem

In your first example, you're mounting the result of a function. In your second example, you're mounting the function itself.

Function bla() returns the controller collection when it's called. When you do

$app->mount('/core', bla($app, $container, 0));

the function is executed first and then the returned ControllerCollection is mounted.

But when you do

$app->mount('/core', function ($app, $container, $key) {...});

the function is not executed. It is treated as an object and mounted. Since the function itstelf is not a ControllerCollection or a ControllerProviderInterface, you get the error.

Two alternatives

Use PHP routing

This is how I like to do it. I don't know if this is "the Silex way", but it works well for me.

You mount each controller collection like so:

$app->mount('/core', include 'controllers/core.php');
$app->mount('/api', include 'controllers/api.php');

Each controller collection goes in a separate file in the controllers folder. So api.php might look like this:

$controllers = $app['controllers_factory'];

$controllers->get('/version', function() use ($app) {
  // do whatever you want
  return 'version 1.2';
});

return $controllers;

There may even be a way of doing this using the YML loader and keeping your routes in yml files, but I don't like mixing yml and php in general. Why use two technologies when you can just use one.

A fancier way

Take a look at this article. His technique is way more elegant than mine, but also more complicated. It's probably better for larger projects. Maybe it will work better for you.

like image 105
Alex Grin Avatar answered Oct 14 '25 03:10

Alex Grin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!