Php Silex中的自定义BaseController

Php Silex中的自定义BaseController,php,symfony,silex,Php,Symfony,Silex,我在Silex 1.3.4中创建了一个简单的应用程序,我希望有一个基本控制器,它将有一个_构造方法,接受$app和$request。然后,所有继承控制器都应该有各自的构造函数并调用父控制器构造方法 //Use statements here.... class AppController { public function __construct(Application $app, Request $request){ $this->app = $app; $this

我在Silex 1.3.4中创建了一个简单的应用程序,我希望有一个基本控制器,它将有一个_构造方法,接受$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');
$app['dispatcher']->addSubscriber(new BeforeControllerExecuteListener($app));
我曾考虑使用dispatcher并覆盖其中的一些进程,并以自己的方式创建控制器实例,但我不知道如何以及这是否是一个好主意

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

您可以使用将控制器定义为应用程序中的服务。但是您不能以这种方式注入
请求。顺便说一句,您可以有多个请求,如果您执行子请求,则请求实例可以更改。您可以插入
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应用程序和来自事件的请求

public function onKernelController(FilterControllerEvent $event)
{
    $collection = $event->getController();
    $controller = $collection[0];

    if($controller instanceof BaseControllerAwareInterface){
        $controller->initialize($this->app, $event->getRequest());
      }
 }
我在我的引导文件中简单地分派它,如下所示:

   $app->post(
     '/items/list', 'MySilexTestDrive\Controller\ItemsController::listAction'
   )->bind('list');
$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);
  }
如果正在调用的当前运行的控制器按照我定义的BaseControllerAwareInterface接口,那么这意味着我应该向该控制器注入应用程序和请求实例。我让控制器处理如何管理每个动作的响应,就像我上面的例子一样,我可能需要JsonResponse的响应对象本身,甚至任何其他类型的响应,所以这完全取决于控制器来处理

然后,路由保持简单,如下所示:

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

谢谢@Leggendario。基本上,你的意思是,如果没有应用程序和请求参数注入,即使有你的建议,我也不能让我的控制器动作?这个想法对我来说不那么简单,我还想利用在BaseController中编写一些可重用函数的优势,但是在控制器上创建继承并让它与Silex一起开箱即用似乎并不容易。谢谢,我会尝试一下并反馈给你。谢谢@rabbts,但我想听听你对我提出的解决方案的看法。尽管它让我有机会至少了解Symfony事件组件的内部结构,但您认为它是否像我认为的那样详尽?我喜欢的另一件事是,它使我能够充分利用面向对象编程的概念。很高兴听到你的意见。