Silex, монтируйте несколько поставщиков контроллеров с замыканиями

Я пробую Silex, и у меня есть небольшая проблема, или, я бы сказал, скорее неудобство...

Я пытаюсь загрузить 2 маршрута из 2 отдельных файлов yaml, но почему-то монтирование ($app->mount(...)) не работает с замыканиями.

Вот код:

// 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));

Это работает.

Что не работает, так это то, что я делаю то же самое с замыканиями, например:

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

Выдает следующую ошибку:

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

Но

var_dump($app['controllers_factory']);

выдает объект типа Silex\ControllerCollection.

Я явно что-то упускаю.

Спасибо за помощь.


person Trevor Donahue    schedule 26.02.2014    source источник


Ответы (1)


Эта проблема

В вашем первом примере вы монтируете результат функции. Во втором примере вы монтируете саму функцию.

Функция bla() возвращает коллекцию контроллеров при вызове. Когда вы делаете

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

сначала выполняется функция, а затем монтируется возвращенный ControllerCollection.

Но когда вы делаете

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

функция не выполняется. Он рассматривается как объект и монтируется. Поскольку сама функция не является ControllerCollection или ControllerProviderInterface, вы получаете ошибку.

Две альтернативы

Использовать PHP-маршрутизацию

Вот как я люблю это делать. Я не знаю, является ли это «способом Сайлекса», но мне он хорошо помогает.

Вы монтируете каждую коллекцию контроллеров следующим образом:

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

Каждая коллекция контроллеров находится в отдельном файле в папке controllers. Итак, api.php может выглядеть так:

$controllers = $app['controllers_factory'];

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

return $controllers;

Возможно, даже есть способ сделать это с помощью загрузчика YML и сохранения ваших маршрутов в файлах yml, но я вообще не люблю смешивать yml и php. Зачем использовать две технологии, если можно использовать только одну.

Более причудливый способ

Взгляните на эту статью. . Его техника намного элегантнее моей, но и сложнее. Это, вероятно, лучше для более крупных проектов. Может быть, это будет работать лучше для вас.

person Alex Grin    schedule 26.02.2014
comment
хорошо, так вы говорите, что нет возможности выполнить закрытие непосредственно в параметре? Даже если нет, то как это сделать в Silex/Symfony2? - person Trevor Donahue; 27.02.2014
comment
Отредактировал мой ответ, чтобы включить несколько предложений о том, как это сделать. Silex не предписывает какой-то один способ ведения дел, вот что я придумал. - person Alex Grin; 27.02.2014
comment
Полный способ Symfony2, вероятно, будет заключаться в использовании всего фреймворка и в том, чтобы каждый маршрут соответствовал действию в контроллере. - person Alex Grin; 27.02.2014