【问题标题】:does CakePHPs Containable-behavior support custom expressions as conditions?CakePHPs Containable-behavior 是否支持自定义表达式作为条件?
【发布时间】:2015-06-27 13:14:54
【问题描述】:

社区,

我目前面临基于数据源表达式构建器的可包含行为设置条件的问题。我正在使用带有 PostgreSQL 数据库的 CakePHP 2.6.2。

目前有效:

我编写了一个行为,它可以动态地将条件添加到 find-操作中,以根据 privileges 表来限制结果。我使用 cake 提供的 buildstatement()expression() 函数的子查询。我从 CakeBook 上关注了这篇文章:

http://book.cakephp.org/2.0/en/models/retrieving-your-data.html

这是一个简单的代码-sn-p,实际上是它的两个 OR 语句:

$conditionsSubQueryRecord = array(
  'Privilege.objecttable' => $model->table,
  'Privilege.objectid = '.$model->alias.'.'.$model->primaryKey,
  'Privilege.read' => true,
  'Privilege.id' => $this->recordPermissions
);
$dsPrivilege = $this->privilegeModel->getDataSource();
$subQueryRecordPrivs = $dsPrivilege->buildStatement(
array(
  'fields'     => array('"'.$this->privilegeModel->alias.'"."id"'),
  'table'      => $dsPrivilege->fullTableName($this->privilegeModel),
  'alias'      => $this->privilegeModel->alias,
  'limit'      => null,
  'offset'     => null,
  'joins'      => array(),
  'conditions' => $conditionsSubQueryRecord,
  'order'      => null,
  'group'      => null
),
$this->privilegeModel
);
$subQueryRecordPrivs = ' EXISTS (' . $subQueryRecordPrivs . ') ';
$subQueryRecordPrivsExpression = $dsPrivilege->expression($subQueryRecordPrivs);

我将该语句添加到我的条件数组中,然后在我的行为 beforeFind()-hook 中。到目前为止,这一切都很好。添加条件,过滤结果。

忽略我包含的模型的条件:

我现在的问题是在包含的模型上使用此条件。我编写了一个递归算法,它遍历所有包含的模型,如果模型作为我的行为,我将相同的条件附加到它的条件数组。但是当我执行我的搜索时,包含的模型上的条件会被忽略,并且只附加到主模型上。

这是我正在执行的完整条件字符串:

array(
    'conditions' => array(
        'Requestinstance.id' => (int) 4,
        (int) 0 => object(stdClass) {
            type => 'expression'
            value => ' EXISTS (SELECT "Privilege"."id" FROM "core"."privileges" AS "Privilege"   WHERE "Privilege"."objecttable" = 'requestinstances' AND "Privilege"."objectid" = "Requestinstance"."id" AND "Privilege"."read" = 'TRUE' AND "Privilege"."id" = (8))  OR  EXISTS (SELECT "Privilege"."id" FROM "core"."privileges" AS "Privilege"   WHERE "Privilege"."objecttable" = 'requestinstances' AND "Privilege"."read" = 'TRUE' AND "Privilege"."id" IN (7, 13, 6, 9, 10, 12) AND "Privilege"."objectid" IS NULL) '
        }
    ),
    'fields' => null,
    'joins' => array(),
    'limit' => (int) 1,
    'offset' => null,
    'order' => array(
        (int) 0 => null
    ),
    'page' => (int) 1,
    'group' => null,
    'callbacks' => true,
    'contain' => array(
        'Requesttype' => array(
            'Steptype' => array(
                'order' => array(
                    (int) 0 => 'RequesttypesSteptype.phase ASC'
                ),
                'conditions' => object(stdClass) {
                    type => 'expression'
                    value => ' EXISTS (SELECT "Privilege"."id" FROM "core"."privileges" AS "Privilege"   WHERE "Privilege"."objecttable" = 'steptypes' AND "Privilege"."objectid" = "Steptype"."id" AND "Privilege"."read" = 'TRUE' AND "Privilege"."id" = (8))  OR  EXISTS (SELECT "Privilege"."id" FROM "core"."privileges" AS "Privilege"   WHERE "Privilege"."objecttable" = 'steptypes' AND "Privilege"."read" = 'TRUE' AND "Privilege"."id" IN (7, 13, 6, 9, 10, 12) AND "Privilege"."objectid" IS NULL) '
                }
            ),
            (int) 0 => 'RequesttypesSteptype',
            'conditions' => object(stdClass) {
                type => 'expression'
                value => ' EXISTS (SELECT "Privilege"."id" FROM "core"."privileges" AS "Privilege"   WHERE "Privilege"."objecttable" = 'requesttypes' AND "Privilege"."objectid" = "Requesttype"."id" AND "Privilege"."read" = 'TRUE' AND "Privilege"."id" = (8))  OR  EXISTS (SELECT "Privilege"."id" FROM "core"."privileges" AS "Privilege"   WHERE "Privilege"."objecttable" = 'requesttypes' AND "Privilege"."read" = 'TRUE' AND "Privilege"."id" IN (7, 13, 6, 9, 10, 12) AND "Privilege"."objectid" IS NULL) '
            }
        ),
        'Stepinstance' => array(
            (int) 0 => 'Steptype',
            (int) 1 => 'Stepdatainstance',
            (int) 2 => 'Sectioninstance'
        ),
        'Requestdatainstance' => array(),
        'Taskinstance' => array()
    ),
    'recursive' => (int) 2
)

如您所见,条件已正确添加到某些包含的模型中。但是,执行的 SQL 查询,即“Steptype”模型,生成时没有条件:

SELECT "Steptype"."id" AS "Steptype__id", "Steptype"."name" AS "Steptype__name", "Steptype"."description" AS "Steptype__description", "Steptype"."subscribe" AS "Steptype__subscribe", "RequesttypesSteptype"."id" AS "RequesttypesSteptype__id", "RequesttypesSteptype"."phase" AS "RequesttypesSteptype__phase", "RequesttypesSteptype"."endsphase" AS "RequesttypesSteptype__endsphase", "RequesttypesSteptype"."endsrequest" AS "RequesttypesSteptype__endsrequest", "RequesttypesSteptype"."usertype_id" AS "RequesttypesSteptype__usertype_id", "RequesttypesSteptype"."requesttype_id" AS "RequesttypesSteptype__requesttype_id", "RequesttypesSteptype"."steptype_id" AS "RequesttypesSteptype__steptype_id" FROM "core"."steptypes" AS "Steptype" JOIN "core"."requesttypes_steptypes" AS "RequesttypesSteptype" ON ("RequesttypesSteptype"."requesttype_id" = 6 AND "RequesttypesSteptype"."steptype_id" = "Steptype"."id") ORDER BY "RequesttypesSteptype"."phase" ASC

直接使用 buildStatement 也不起作用

我还尝试直接使用语句本身,而不是从中构建表达式。这实际上创建了我想要的 SQL 查询,但没有在 FROM 子句中正确添加表别名的引号,因此导致 postgreSQL 抛出错误:

SELECT "Requestinstance"."id" AS "Requestinstance__id", "Requestinstance"."user_id" AS "Requestinstance__user_id", "Requestinstance"."created" AS "Requestinstance__created", "Requestinstance"."requesttype_id" AS "Requestinstance__requesttype_id", "Requestinstance"."currentphase" AS "Requestinstance__currentphase", "Requestinstance"."selfsolving" AS "Requestinstance__selfsolving", "User"."username" AS "User__username", "User"."id" AS "User__id", "User"."company_id" AS "User__company_id", "User"."usertype_id" AS "User__usertype_id", "Requesttype"."id" AS "Requesttype__id", "Requesttype"."name" AS "Requesttype__name", "Requesttype"."subtitle" AS "Requesttype__subtitle", "Requesttype"."description" AS "Requesttype__description", "Requesttype"."order" AS "Requesttype__order", "Requesttype"."selfsolving" AS "Requesttype__selfsolving" FROM "core"."requestinstances" AS "Requestinstance" LEFT JOIN "core"."users" AS "User" ON ("Requestinstance"."user_id" = "User"."id") LEFT JOIN "core"."requesttypes" AS "Requesttype" ON ("Requestinstance"."requesttype_id" = "Requesttype"."id") WHERE EXISTS (SELECT "Privilege"."id" FROM "core"."privileges" AS Privilege WHERE "Privilege"."objecttable" = 'requestinstances' AND "Privilege"."objectid" = "Requestinstance"."id" AND "Privilege"."read" = 'TRUE' AND "Privilege"."id" = (8)) OR EXISTS (SELECT "Privilege"."id" FROM "core"."privileges" AS Privilege WHERE "Privilege"."objecttable" = 'requestinstances' AND "Privilege"."read" = 'TRUE' AND "Privilege"."id" IN (7, 13, 6, 9, 10, 12) AND "Privilege"."objectid" IS NULL) LIMIT 1 

在构建语句时手动将引号添加到别名字符串也无济于事,因为框架会去除引号。

最后是我的问题:

有谁知道,containable-behavior 是否支持表达式?我已经深入研究了 DboSource、PdoSource 和 Postgresql 数据源,但在这里找不到任何问题。 Containable 行为看起来也很简单。我在这里做错了吗?

或者还有其他方法可以实现我想要的吗?

我很高兴在这件事上得到任何帮助! 提前致谢!

【问题讨论】:

    标签: postgresql cakephp pdo expression containable


    【解决方案1】:

    我终于明白了!

    正式回答问题:

    是的,可包含行为确实支持表达式语法!

    我的问题在于处理顺序:框架处理配置顺序的行为,我在自定义行为之前意外加载了可包含项,这就是为什么它从未收到我修改的条件...

    使用正确的顺序,可包含的行为可以很好地处理被操纵的条件字符串。

    为了完全确定行为顺序,我将行为加载移至 AppModels 的 __construct() 方法:

    // unload any configured Containable behavior
    if($this->Behaviors->loaded('Containable')) {
        $this->Behaviors->unload('Containable');    
    }
    // load the PrivilegeItem behavior
    if($this->alias !== 'Privilege') {
        $this->Behaviors->load('PrivilegeItem');
    }
    // and finally (re-)attach the Containable behavior     
    $this->Behaviors->load('Containable');
    

    也许它可以帮助其他人避免两天的调试头痛......

    【讨论】:

      猜你喜欢
      • 2011-01-13
      • 2016-02-17
      • 1970-01-01
      • 2011-06-23
      • 1970-01-01
      • 2019-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多