更好的解决方案,在php应用程序的路由中烦人的嵌套if语句

时间:2014-06-20 18:58:30

标签: php rest if-statement optimization

我使用的是瘦弱的php,但这并不是特别简单,这在不同的php框架的路由中很常见,特别是在使用其他应用时。

好的,这是可以在博客或存档应用程序中找到的最常见的路线

 $app->get('docs(/:year(/:month(/:day)))', function($y=0;$m=0;$d=0) use ($app){
    if ($year !== 0 && $month !==0 && $day !== 0) {
        // query database with conditions of year, month, day
    } else if ($year !== 0 && $month !== 0) {
        // query database with conditions of year, month
    } else if ($year !== 0) {
        // query database with conditions of year
    } else {
        // query database, return all
    }
 })

此外,您希望添加get参数以缩小搜索范围,例如limitoffset

 $app->get('docs(/:year(/:month(/:day)))', function($y=0;$m=0;$d=0) use ($app){
    // additionally you optionally allowed filters like: limit, offset, all     
    $tmpLimit = $app->request()->get('limit');
    $tmpOffSet = $app->request()->get('offset');

    $limit = isset($tmpLimit) ? $tmpLimit : 10;
    $offset = isset($tmpOffSet) ? $tmpOffSet : 0;

    ... below add the code previously, and query would change according to if filters(limit,offset) has been set.
 })

还有更多解决方案吗?有太多的代码告诉我,我做得不对。

3 个答案:

答案 0 :(得分:2)

您可以使用中间件(Route-Middleware / Middleware)和/或挂钩(Hooks-Overview)来保持您的路线简单。

的Route-中间件:

$mw = function($app) {
  return function() use($app) {
     $tmpLimit = $app->request()->get('limit');
     $tmpOffSet = $app->request()->get('offset');
     $app->docsLimit = isset($tmpLimit) ? $tmpLimit : 10;
     $app->docsOffSet = isset($tmpOffSet) ? $tmpOffSet : 0; 
  };
};

路线:

$app->get('/docs(/:year(/:month(/:day)))', $mw($app),function($y=0,$m=0,$d=0) use ($app) {

    echo $app->docsLimit."<br/>";
    echo $app->docsOffSet."<br/>";

    ... your previously code
});

钩:

$app->hook('slim.before.router', function() use($app){
    if (strpos($app->request()->getPath(), '/docs') === 0) {
        $tmpLimit = $app->request()->get('limit');
        $tmpOffSet = $app->request()->get('offset');
        $app->docsLimit = isset($tmpLimit) ? $tmpLimit : 10;
        $app->docsOffSet = isset($tmpOffSet) ? $tmpOffSet : 0;
    }
});

路线:

$app->get('/docs(/:year(/:month(/:day)))', function($y=0,$m=0,$d=0) use ($app) {

    echo $app->docsLimit."<br/>";
    echo $app->docsOffSet."<br/>";

    ... your previously code
});

答案 1 :(得分:1)

我说你应该稍微研究一下查询构建器对象。例如Doctrine DBAL中的那个。这允许您有条件地构建查询,而无需将字符串连接在一起(这会打开各种可能的错误和安全问题的潘多拉盒子):

$queryBuilder
    ->select('b.id', 'b.title')
    ->from('blog', 'b');

if ($year) {
    $queryBuilder->where('b.year = :year')
                 ->setParameter('year', $year);
}
if ($month) {
    queryBuilder->where('b.month = :month')
                ->setParameter('month', $month);
}
if ($day) {
    $queryBuilder->where('b.day = :day')
                 ->setParameter('year', $day)
}

除此之外,看起来您将所有功能都放在路线中,但您应该考虑将一些任务分成服务。快速扫描slimphp文档我无法找到&#34; services&#34;的任何概念,但所有这意味着你为$ app添加了一个单独的函数,以便你可以重用该功能。按理说你会想要获取博客&#34;来自多条路线。它应该像(docs here)一样简单:

$app->findBlogPosts = function($y = null, $m = null, $d = null) use ($app) {
  // do the DB stuff here, return results
}

我将默认参数更改为null,因为0的$ year值无意义。如果你打算说'#34;这个东西可能没有价值&#34;,请使用&#34; null&#34;的语言概念。 - 每种编程语言都有这样的概念。

答案 2 :(得分:0)

感谢@deceze@ramon指导我完成重构代码的整个过程,

首先,我被赋予了有条件地构建 SQL语句的想法,这引出了我:

if ($year !== 0) {
   $where[] = 'YEAR(date_created) = :year';
   $bind['where'] = $year; 
}
... // if month, if year..
...
$query = sprintf('SELECT * FROM table WHERE %s', join(' AND ', $where));
Document::raw_query($query, $bind)->find_array();

根据@ ramon,他建议使用查询构建器,这将会或可能会导致问题, 这样:

我可以做类似的事情:

$queryBuilder
->select('b.id', 'b.title')
->from('blog', 'b');

查看paris提供的基本方法,如文档中所示,我无法在活动记录库的where方法中传递本机sql函数,但是挖掘更多,我意识到它是建立在idiorm之上,我只需要查看文档,如果可以通过where子句传递函数,并且通过玩我的IDE一点,我发现where_raw存在。

我想出了这个......

$where = array();
$bind = array();

if (!is_null($day)) {
    $where[] = 'DAY(`date_created`) = ?';
    $bind[] = $day;
}

if (!is_null($month)) {
    $where[] = 'MONTH(`date_created`) = ?';
    $bind[] = $month;
}

if (!is_null($year)) {
    $where[] = 'YEAR(`date_created`) = ?';
    $bind[] = $year;

    $query = sprintf('%s', join(' AND ', $where));
    $foo = Foo::where_raw($query, $bind)
            ->order_by_desc('date_created')
            ->offset($offset)
            ->limit($limit)
            ->find_array();
} else {
    $documents = Foo::order_by_desc('date_created')
            ->offset($offset)
            ->limit($limit)
            ->find_array();
}

我对接受用户的输入有点自信,orm在执行之前准备了查询,我认为会做一些安全检查。