如何更改cakephp传递关联模型数据的方式?

时间:2013-04-22 23:16:03

标签: php cakephp cakephp-appmodel

我已经尝试过寻找答案,因为我确定之前已经解决了这个问题,但是我找不到讨论cakephp如何格式化模型返回的数据。通常我只是看看数据是如何来的,并根据需要为每个Controller / View处理数据。但是,在这种情况下,我想重用我的观点,不幸的是,cakephp向我提供来自不同控制器的数据的方式正在给我带来问题。

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

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',
    )
)
)

在GroupsController中使用     $这 - >集团 - >包含(阵列( '用户'));     $ 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',

    )
)

无论如何,我可以改变我对模型数据的调用方式,让它以一致的方式传递给不同的控制器,无论是主模型还是相关模型?或者我是否只需每次循环访问数据并以正确的格式重建数据?这似乎一旦我的数据集增长,它将成为效率问题。

2 个答案:

答案 0 :(得分:0)

确实,不建议手动修改阵列。 试图影响模型返回关联数据的方式也是不明智的。

我能想到的最好的是以下内容。

假设您的用户索引具有以下内容:

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

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

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

看起来并不昂贵。

答案 1 :(得分:0)

您以奇数格式获取数据的原因是因为您正在使用包含而不是获取相关数据(而不是直接数据)的数据。

我建议您修改find​​()调用,而不是为此实现规范化:

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

注意:在不需要时使用contains()会在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获取相关数据而不是直接获取数据。

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

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

在适用型号上的每次查找后,都会触发此回调。在AppModel :: afterFind()中实现它将影响应用程序中的每个查找调用。

附注:规范化数据的一种简单方法是使用Set :: extract(),但是,根据我的经验,由于实现的强大程度,它可能会导致比自行循环数据更多的开销。可能是一个好主意,看看它是否符合您的需求。就个人而言,我不会在afterFind()中自己使用它,因为它可以添加,但是,我将它包含在这里,因为它可能符合您的需要。

1.3设置提取文档:

2.0设置提取文档:

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