【问题标题】:cakephp dynamic virtualfield or apply beforeFind callback with containablecakephp 动态虚拟字段或可包含的应用 beforeFind 回调
【发布时间】:2013-10-18 16:22:46
【问题描述】:

我目前在beforeFind() 中附加一个虚拟字段,因为我需要将当前用户的ID 插入到查询中。在相关模型上调用 find 并包含此模型包括静态定义的虚拟字段,但不包括 beforeFind().. 中的虚拟字段。直接在模型上调用 find 包括动态附加的虚拟字段。

这是我的 beforeFind 回调:

public function beforeFind($query = array()) {
    $user_id = $this->getCurrentUser()['id'];
    $this->virtualFields = array_merge($this->virtualFields, array( 
        'cost_for_user' => sprintf('CASE WHEN Inventory.user_id = %s THEN Inventory.cost ELSE Inventory.cost_for_team END', $user_id),
    ));
    return $query;
}

由于cost_for_user 动态附加在 beforeFind 中,我无法在运行时复制虚拟字段,就像cookbook 中建议的那样。是否有更好的回调来动态附加虚拟字段以便包含在包含结果中?

【问题讨论】:

    标签: php cakephp containable cakephp-2.4


    【解决方案1】:

    如果只是在查找结果中包含虚拟字段,那么您可以例如使用单独的方法来初始化它们,并从当前查询的模型beforeFind() 回调中调用此方法,例如:

    public function beforeFind($query = array())
    {
        if(!parent::beforeFind($query))
        {
            return false;
        }
    
        $this->RelatedModel->setupVirtualFields();
        return true;
    }
    
    public function setupVirtualFields()
    {
        $user_id = $this->getCurrentUser()['id'];
        $this->virtualFields = array_merge($this->virtualFields, array
        ( 
            'cost_for_user' => sprintf('CASE WHEN Inventory.user_id = %s THEN Inventory.cost ELSE Inventory.cost_for_team END', $user_id),
        ));
    }
    

    您还可以通过将其应用于所有模型和关联来使其更通用一点,例如在AppModel::beforeFind() 回调中或使用行为:

    public function beforeFind($query)
    {
        if(!parent::beforeFind($query))
        {
            return false;
        }
    
        $this->_setupVirtualFields($this);
        foreach(array_keys($this->getAssociated()) as $modelName)
        {
            $this->_setupVirtualFields($this->{$modelName});
        }
    
        return true;
    }
    
    protected function _setupVirtualFields(Model $model)
    {
        $method = 'setupVirtualFields';
        if(method_exists($model, $method) && is_callable(array($model, $method)))
        {
            $model->setupVirtualFields();
        }
    }
    

    【讨论】:

    • 这非常有效,谢谢.. 不过有几个问题。 beforeFind() 不应该返回 $query 以及从 AppModel 检查 parent::beforeFind($query) 的意义何在?
    • @DevinCrossman 不客气。 Model::beforeFind() 需要返回$query 只有在$query 被修改并且这些修改应该实际使用的情况下,返回true 意味着继续原始查询数据。在大多数情况下,在 AppModel 上调用 parent::beforeFind() 应该是不必要的,假设它直接Model 继承。然而,就我个人而言,我总是调用父级以确保即使父级实现发生变化(无论是直接在父方法中还是通过扩展不同的类间接地),一切都可以继续工作。
    猜你喜欢
    • 1970-01-01
    • 2020-05-18
    • 1970-01-01
    • 2012-08-30
    • 2021-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    相关资源
    最近更新 更多