Php Silex控制器中的动作方法代码重用

Php Silex控制器中的动作方法代码重用,php,silex,Php,Silex,今天,在为Silex应用程序创建简单控制器时,我注意到许多操作方法的代码几乎相同: public function someAction() { $id = $this->request->attributes->get('id') if($id) { $data = getMyDataFromDatabaseWithThisID($id); //do something with data $this

今天,在为Silex应用程序创建简单控制器时,我注意到许多操作方法的代码几乎相同:

public function someAction()
{
    $id = $this->request->attributes->get('id')
    if($id)
    {
        $data = getMyDataFromDatabaseWithThisID($id);

        //do something with data

        $this->app->json($data, 200);
    }
    else
    {
        //do error stuff
    }
}

public function someOtherAction()
{
    $id = $this->request->attributes->get('id')
    if($id)
    {
        $data = getMyDataFromDatabaseWithThisID($id);

        //do something else with data

        $this->app->json($data, 200);
    }
    else
    {
        //do error stuff
    }
}
每种方法的要点几乎完全相同。我想如果我有3或4个方法遵循相同的模式,我可能应该抽象出一些代码

我的第一反应是使用一个大的executeAction($action)方法,但我不知道如何从Silex路由将变量传递给被调用的控制器操作。第二,我认为用一个大的方法代替很多小的方法是自找麻烦

我的下一个想法是创建一个executeAction(Closure$action)方法,该方法由传递所需任务的闭包的现有操作方法调用

因此,像updateAction()这样的操作方法可以将闭包传递给executeAction(),告诉它更新所需的资源:

public function updateAction
{
    $this->executeAction(function($resource, $request) {
        $resource->doSomethingToUpdateItFromInfoInRequest($request->get('data'));
    });
}

public function executeAction(Closure $action)
{
    $id = $this->request->attributes->get('id')
    if($id)
    {
        $data = getMyDataFromDatabaseWithThisID($id);

        //execute closure action
        $action($data, $this->request);

        $this->app->json($data, 200);
    }
    else
    {
        //do error stuff
    }
}
从表面上看,这看起来很干净。它也很灵活,因为它取决于每个单独的方法是否使用executeAction。这个想法的问题是,我需要确保在闭包中所做的任何事情都在闭包之外得到正确反映(即变量/对象是否正确更新等)。这也感觉不是正确的方法。虽然这可能是因为PHP中的闭包对我来说是相当新的(在使用Silex之前,我从未在PHP代码中使用过它们)

第三种选择是将一些公共部分简化为它们自己的方法,例如

public function getResourceById($id)
{
    //do stuff
    return $resource;
}

public function errorStuff($code, $message)
{
    //do stuff
}

//then in action method
public function updateAction()
{
    $data = $this->getResourceById($this->request->get('id');
    if($data)
    {
        //do stuff
    }
    else
    {
        $this->errorStuff(1001, 'uh oh!');
    }
}
该方法看起来更小,但存在相同的问题-我将有几个看起来几乎相同的方法,如果有什么变化(方法名称等),则需要更新这些方法


因此,考虑到我正在使用Silex和Silex控制器类,这些方法中哪一种(如果有的话)是避免代码重复的更好选择?有人能提出完全不同的解决方案吗?

您上面的代码在我看来不像silex代码库,更像symfony控制器。
所以我不会对这一点发表评论

不过,我建议您熟悉闭包,因为您已经重新连接了闭包,因为它们在Silex中大量使用

出于您的目的,您可能希望了解的Silex实现。
他们可以使用ThisID函数从数据库获取GetMyDataFromDatabase的一部分。此外,它们还可以处理错误

您可以在应用程序中注册findOr404方法:

$app['findOr404'] = $app->protect(function($id, $message = null) use ($app) {
  //get the data or abort with 404
}
并将其用作Silex控制器中的参数转换器:

$app->get("/get/{id}", function (Data $data) {
    // ...
})->convert("id", $app['findOr404']($id);
这个例子的灵感来源于此,你可以在这里找到更多的技巧


如果您在闭包中迷路了,还可以看看如何包装您的代码。这可能感觉有点熟悉。

我在Silex项目中使用控制器类。我喜欢Silex使用简单闭包作为动作的能力(我用它来做更简单的事情),但我确实喜欢将相关动作组合到一个控制器中。我从来没有想过要看param转换器,所以谢谢你让我注意到它们。我认为建议的
findOr404
方法是一个很好的主意,可以帮助我避免很多重复。它可以在所有操作和控制器中重用也是一个很大的优点!