在Silex中自定义BaseController


Custom BaseController in Silex

我在Silex 1.3.4中创建了一个简单的应用程序,我想有一个基本控制器,它将有一个__construct方法接受$app和$request。所有继承的控制器都应该有各自的构造函数,并调用父控制器的构造方法。

//Use statements here....
class AppController
{
  public function __construct(Application $app, Request $request){
    $this->app = $app;
    $this->request = $request;
   }
 }
继承控制器的

将写成如下:

//Use statements here....
class ItemsController extends AppController
{
  public function __construct(Application $app, Request $request){
    parent::__construct($app, $request);
   }
  public function listAction()
  {
    //code here without having to pass the application and request objects
   }
 }

我决定的路由方法如下所示:

   $app->post(
     '/items/list', 'MySilexTestDrive'Controller'ItemsController::listAction'
   )->bind('list');

我正在考虑使用调度程序并覆盖那里的一些进程,并以我自己的方式创建我的控制器实例,但我不知道如何以及这是否是个好主意。

有人做过类似的事情吗?请帮助。

你可以使用servicecontrollererserviceprovider将你的控制器定义为应用程序中的服务。但是你不能这样注射Request。顺便说一句,你可以有多个请求,如果你做子请求,请求实例可以改变。您可以注入RequestStack,然后在需要获取当前请求时调用$requestStack->getCurrentRequest()

$app = new Silex'Application();
abstract class AppController
{
    protected $app;
    protected $requestStack;
    public function __construct(Silex'Application $app, Symfony'Component'HttpFoundation'RequestStack $requestStack)
    {
        $this->app = $app;
        $this->requestStack = $requestStack;
    }
    public function getRequest()
    {
        return $this->requestStack->getCurrentRequest();
    }
}
class ItemsController extends AppController
{
    public function listAction()
    {
        $request = $this->getRequest();
        // ...
    }
}
$app->register(new Silex'Provider'ServiceControllerServiceProvider());
$app['items.controller'] = $app->share(function() use ($app) {
    return new ItemsController($app, $app['request_stack']);
});
$app->get('/items/list', "items.controller:listAction");

这样做有意义吗?我不这么认为。特别是当框架通过类型提示为您提供请求实例时。只做

public function listAction(Application $app, Request $request)
{
    // ...
}

你也可以试试这个:

class BaseController
{
    protected $app;
    protected $request;
    public function __call($name, $arguments)
    {
        $this->app = $arguments[0];
        $this->request = $arguments[1];
        return call_user_func_array(array($this,$name), [$arguments[0], $arguments[1]]);
    }
    protected function getSystemStatus(Application $app, Request $request)
    {
        [...]
    }
[...]
}

@Rabbis和@Federico我已经提出了一个更优雅的解决方案,我已经创建了一个BeforeControllerExecuteListener,我与我的应用程序实例调度。这个监听器接受FilterControllerEvent对象,然后从基本控制器调用一个方法,在该方法中注入Silex Application和来自事件的请求。

public function onKernelController(FilterControllerEvent $event)
{
    $collection = $event->getController();
    $controller = $collection[0];
    if($controller instanceof BaseControllerAwareInterface){
        $controller->initialize($this->app, $event->getRequest());
      }
 }

在我的引导文件中简单地分派它,如下所示:

$app['dispatcher']->addSubscriber(new BeforeControllerExecuteListener($app));

这允许我访问这个对象,而不必将它们作为参数添加到我的操作中。下面是我在制作中的一个动作的样子:

public function listAction($customer)
 {
     $connection = $this->getApplication()['dbs']['db_orders'];
     $orders= $connection->fetchAll($sqlQuery);
     $results = array();
     foreach($orders as  $order){
         $results[$order['id']] = $order['number'] . ' (' . $order['customer'] . ')';
      }

     return new JsonResponse($results);
  }

如果当前正在运行的被调用的控制器遵循我所定义的basecontrollererawareinterface接口,那么这意味着我应该用Application和Request实例注入该控制器。我让控制器来处理它们如何管理每个动作的响应,就像我上面的例子一样,我可能需要JsonResponse的响应对象本身,甚至任何其他类型的响应,所以它完全取决于控制器来处理它。

则路由保持如下:

$app->match('/orders/list/{cusstomer}', 'Luyanda'Controller'OrdersController::listAction')
->bind('list-orders');