Php 如何在find()中包含与fieldlist的关联

Php 如何在find()中包含与fieldlist的关联,php,cakephp,cakephp-1.3,Php,Cakephp,Cakephp 1.3,我希望通过find(all)接收模型数据,但是用户应该只获得一组受限的表字段。这很简单: $ret = $this->find('all',array('fields'=>array( 'Employee.id','Employee.address_id' ))); 但这种模式(员工模式)也有一个belongsTo关联: var $belongsTo = array( 'Address' => array( 'className' =>

我希望通过find(all)接收模型数据,但是用户应该只获得一组受限的表字段。这很简单:

$ret = $this->find('all',array('fields'=>array(
    'Employee.id','Employee.address_id'
)));
但这种模式(员工模式)也有一个belongsTo关联:

var $belongsTo = array(
    'Address' => array(
        'className' => 'Address',
        'foreignKey' => 'address_id',
        'fields' => array('Address.full_name')
    )
);

我希望
Address.full_name
字段也出现在我获取的数据中。但它不适用于上面的find()调用,在尝试以下操作时会抛出一个错误(SQL错误:1054:“字段列表”中的未知列“Address.full_name”):

'fields'=>array('Employee.id','Employee.address_id','Address.full_name')
有人知道怎么解决这个问题吗

编辑:我完全忘记了那个地址。全名是一个虚拟字段。看看Cakephp生成的SQL,很明显它为什么不工作:

SELECT
    `Employee`.`id`, `Employee`.`address_id`, `Address`.`full_name`
FROM
    `employees` AS `Employee`
    LEFT JOIN `addresses` AS `Address`
        ON (`Employee`.`address_id` = `Address`.`id`)
WHERE 1 = 1
在地址模型中,全名的定义如下:

var $virtualFields = array(
    'full_name' => 'CONCAT_WS(" ", Address.firstname, Address.surname)'
);
$params = array('fields' => array('Employee.id', 'Employee.address_id'), 
    'contain' => array('Address' => array('fields' => array('Address.full_name')));
$ret = $this->find('all', $params);

因此,问题是:它不能在为find()提供的字段列表中包含(外部模型的)虚拟字段,这是CakePHP错误吗?

在这种情况下,我将使用可包含的行为

首先确保在员工模型中加载了可包含的行为:

var $actsAs = array('Containable');
然后,当您试图获取数据时,请按如下方式操作:

var $virtualFields = array(
    'full_name' => 'CONCAT_WS(" ", Address.firstname, Address.surname)'
);
$params = array('fields' => array('Employee.id', 'Employee.address_id'), 
    'contain' => array('Address' => array('fields' => array('Address.full_name')));
$ret = $this->find('all', $params);
有关可包含行为的更多信息,请参见此处:

SQL错误:1054:未知列 “字段列表”中的“地址.全名”)


此错误提示您的列名调用有问题(可能是
fullname
而不是
full\u name
),或者更可能是模型定义有问题。员工属于某个地址,但该地址是否有一个或多个员工?

不幸的是,您无法按希望的方式使用虚拟字段。来自Cake文档中的:

1.3中virtualFields的实现有一些限制。首先,不能在条件、顺序或字段数组的关联模型上使用virtualFields。这样做通常会导致SQL错误,因为ORM不会替换字段。这是因为很难估计可能找到关联模型的深度


看起来您必须使用Containable行为。

我以前使用过Containable行为,直到我意识到它是不必要的,因为我需要每个控制器操作中包含的数据。现在,我不再每次在find()或paginate()调用之前都调用containable行为,而是通过静态设置模型中的关系并设置model->recursive=0来实现“经典”方式。因此,总之,它也应该在没有containable行为的情况下工作。此外,我以前在可包含行为方面也遇到过同样的问题,因此将containable和find('all',array('fields'=>…)组合起来也不起作用。您以前是否将recursive设置为-1?这可以解释您的问题,因为Cake的ORM在该模式下不执行任何连接,因此在构建数据源查询时不会解析belongsTo关联已在我的模型中设置。您可能希望逐步查看您的代码,查找
员工。recursive
设置为
-1
,因为我尝试复制您的问题,唯一可以重新设置错误的方法是设置
员工。recursive=-1
。任何其他设置都会使事情按预期进行。我会将所有“字段”放在find()调用中。我更愿意认为我的地址属于我,而不是相反。;-)@班瑟·斯利,我不明白你的意思@Daniel是的,可能在RL中,但不在我的应用程序中:P@joni:
$ret=$this->find('all',array('fields'=>array('Employee.id','Employee.address\u id','address.id','address.full\u name'))@bancer是的,这正是我在代码中所做的。在代码块中,我只是将其“缩短”为“'fields'=>array('Employee.id'、'Employee.address\u id'、'address.full\u name')”,而不是“$ret=$this->find('all',array('fields'=>array('Employee.id'、'Employee.address\u id'、'address.id'、'address.full\u name'))”);”<代码>地址。全名
是正确的字段名。当我在字段列表中省略它时,不会出现SQL错误,但是不会获取相关的地址数据。您确定引用的模型中必须有haveMany/One(本例中的地址)吗?因为,如果没有
字段
参数,find('all)将毫无问题地获取相关数据。冒着编辑的风险,我发现这种事情在Cake中非常常见。他们将实现一个看起来相当整洁的功能,但随后对其使用进行了严格的限制,以至于任何给定复杂性的应用程序都无法使用它们。我在这里分享您的观点。。。看起来,除了“静态地”使用可包含行为之外,我别无选择。你知道怎么做吗?如果可能的话,我不想每次都手动调用contain(),但在我尝试的过程中,beforeFInd()回调函数中的contain()不起作用。我将尝试使用烹饪书中描述的解决方法,当我在belongsTo fields声明中省略Address.full_name,并通过在查找回调函数之前将其添加到员工模型中,在运行时添加虚拟字段时,它会起作用:`$this->virtualFields['full_name']=$this->Address->virtualFields['full_name'`