如何更改cakepp为关联模型传递数据的方式


How can I change the way cakephp passes the data for an associated model?

我已经尝试搜索这个问题的答案,因为我确信这是以前已经解决过的问题,但我找不到任何讨论cakephp如何格式化从模型返回的数据的内容。通常情况下,我只看到数据是如何来的,并根据每个控制器/视图的需要进行处理。然而,在这种情况下,我想重用我的视图,不幸的是,cakepp将来自不同控制器的数据交给我的方式给我带来了问题。

我有两个模型,关联如下:

class Group extends AppModel {
public $hasMany = array(  'User' ); 
}
class User extends AppModel {
public $belongsTo = array(
'Group'  ); 
}

我想让View/Groups/view/id显示各个组的详细信息,以及属于该组的用户列表。理想情况下,我不想重新创建代码来显示用户列表,因为它已经存在于View/Users/index

我发现我可以使用$this->extend('/Users/index'(,但我不能像我想要的那样只使用`$this-->set('Users',$group['User'](,因为数组的构建方式不同。

在UsersController::index((中,我会调用$users = $this->find('all');,它给出了一个用户列表,如下所示:debug($users);

array(
(int) 0 => array(
    'User' => array(
        'id' => '100',
        'group_id' => '101', 
    )
),
(int) 1 => array(
    'User' => array(
        'id' => '101',
        'group_id' => '101',
    )
)
)

在组中使用控制器$this->Group->contain(数组('User'((;$group=$this->GroupsController->group->find(‘first’,‘conditions’=>array(‘id’=>$id(;

它返回一个组列表,但以这种格式代替debug($group['User']);

 'User' => array(
    (int) 0 => array(
        'id' => '101',
        'group_id' => '101', 
    ),
    (int) 1 => array(
        'id' => '100',
        'group_id' => '101',
    )
)

无论是主模型还是关联模型,我是否可以更改调用模型数据的方式,使其以一致的方式在不同的控制器上传递?还是我每次都必须循环浏览数据,并以正确的格式重建数据?这似乎意味着,一旦我的数据集增长,它将成为一个效率问题。

获取奇数格式数据的原因是,您使用的包含意味着不获取相关数据(而不是直接数据(。

与其为此实现规范化,我建议修改find((调用:

$group = $this->GroupsController->Group->User->find('list', array(
    'conditions' => array('User.group_id' => $id)
));

注意:在不需要的时候使用contain((会为SQL查询添加额外的JOIN,这会影响性能。

我不喜欢规范化/重新格式化我的CakePHP查找数据,因为这会使它成为非标准的。CakePHP总是以可预测的方式返回数据,这只是一个习惯它并使用适当的方法检索数据的问题。

检索直接数据将以以下格式返回:

  array(
    (int) 0 => array(
        'MODEL' => array(
            'field1' => 'value1',
            'field2' => 'value2', 
        )
    ),
    (int) 1 => array(
        'MODEL' => array(
            'field1' => 'value1',
            'field2' => 'value2',
        )
    )
  )

检索直接数据和相关数据(通过使用Contain(将以以下格式返回:

  array(
    (int) 0 => array(
        'MODEL' => array(
            'field1' => 'value1',
            'field2' => 'value2', 
            'RELATEDMODEL' => array(
                (int) 0 => array(
                    'field1' => 'value1'
                    'field2' => 'value2'
                ),
                (int) 1 => array(
                    'field1' => 'value1'
                    'field2' => 'value2'
                )
            )
        )
    ),
    (int) 1 => array(
        'MODEL' => array(
            'field1' => 'value1',
            'field2' => 'value2',
            'RELATEDMODEL' => array(
                (int) 0 => array(
                    'field1' => 'value1'
                    'field2' => 'value2'
                ),
                (int) 1 => array(
                    'field1' => 'value1'
                    'field2' => 'value2'
                )
            )
        )
    )
  )

您的数据之所以不同,是因为您告诉MySQL获取相关数据,而不是直接获取。

如果你真的想规范化你的数据(我不建议这样做(,请继续阅读:

有几种方法可以做到这一点,但最合适的方法是在Find((回调之后在模型(或AppModel(中实现数据规范化。

  • 1.3文件:http://book.cakephp.org/1.3/en/The-Manual/Developing-with-CakePHP/Models.html#afterfind

  • 2.x文件:http://book.cakephp.org/2.0/en/models/callback-methods.html#afterfind

在对适用模型的每次查找之后都会调用此回调。在AppModel::afterFind((中实现它将影响应用程序中的每个find调用。

旁注:规范化数据的一个简单方法是使用Set::extract((,然而,根据我的经验,由于实现的健壮性,它可能会比自己循环数据带来更多的开销。看看它是否符合您的需求可能是个好主意。就我个人而言,我自己不会在afterFind((中使用它,因为它可能会添加一些过头的内容,但是,我将它包含在这里,因为它可以满足您的需求。

1.3集合提取文档:

  • classicExtract:http://book.cakephp.org/1.3/en/The-Manual/Core-Utility-Libraries/Set.html#classicextract
  • 摘录:http://book.cakephp.org/1.3/en/The-Manual/Core-Utility-Libraries/Set.html#extract

2.0设置摘录文档:

  • classicExtract:http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::classicExtract
  • 摘录:http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::extract

关于效率问题:做一个常规循环根本不会增加太多开销。尽管如此,正常化当然会增加一点开销。

实际上,手动修改数组是不可取的。试图影响模型返回相关数据的方式也是不明智的。

我能想出的最好的办法如下。

假设你的用户索引有类似的东西:

foreach($users as $user) {
    debug($user['User']); // made up for brevity
}

foreach块的开头添加以下内容:

if (!isset($user['User']) {
    $user = array('User' => $user);
}

它似乎没有那么昂贵。