SQL JOINs with CakePHP


SQL JOINs with CakePHP

我有一个images表和servers表。images具有server_id字段,该字段是servers表中的id字段的外键。servers表还有一个名为name的字段,这就是我想要检索的内容。

这是我的控制器动作代码:

$images = $this->Image->find('all', array(
    'conditions' => array('Image.user_id' => $this->Auth->user('id')),
    'order' => array('Image.uploaded DESC')
));
$this->set('images', $images);

它得到的数据是这样的:

Array
(
    [0] => Array
        (
            [Image] => Array
                (
                    [id] => 103
                    [orig_name] => Untitled-5.jpg
                    [hash] => MnfWKk
                    [filename] => MnfWKk.jpg
                    [uploaded] => 2012-07-12 00:09:08
                    [views] => 0
                    [album_id] => 
                    [user_id] => 15
                    [server_id] => 1
                )
        )
)

我想从servers表中获取name字段,而不是server_id。我如何调整我的find()方法来获得它?我知道这是一个SQL连接,但我不知道如何告诉Cake做一个连接来获得服务器名称。

谢谢。

TLDR:

设置正确的CakePHP关联,并使用CakePHP的Containable。(带有递归-1)。

详细描述:

最好的做法是将find代码保留在模型中,所以这就是我要展示的内容,但请随意(如果必须的话)将其移回控制器中。

通过这种方式,您可以从任何控制器调用相同的getImages()函数,并根据您想要返回的内容传递不同的参数。这样编码的好处是,如果您在寻找与查询/数据库相关的代码,您总是知道应该在模型中查找。当下一个查看您代码的人不必去搜索时,这是非常有益的。

由于图像和服务器之间建立了关联,因此在查询图像时可以"包含"服务器信息。但是,在指定要将模型设为$actAs = array('Containable');之前,不能使用"包含"。〔CakePHP书:可控制〕

最后,在您的AppModel中,最好设置$recursive = -1;。这使得所有型号都默认为-1。如果出于某种原因您反对这样做,请确保在任何时候使用containable时都将递归设置为-1。而且——一旦你学会了使用containable,你就再也不会回头了——这太棒了。你可以的东西还有很多

代码:

//AppModel *******
//...
$recursive = -1;
//...
//Images controller *******
//...
public function whatever() {
    $opts = array();
    $opts['user'] = $this->Auth->user('id');
    $images = $this->Image->getImages($opts);
    $this->set(compact('images'));
}
//...

//Image model *******
//...
public $actsAs = array('Containable');
public belongsTo = array('Server');
public function getImages($opts = array()) {
    $params = array('condtions'=>array());
    //specific user
    if(!empty($opts['user'])) {
        array_push($params['conditions'], array('Image.user_id'=>$opts['user']);
    }
    //order
    $params['order'] = 'Image.uploaded DESC';
    if(!empty($opts['order'])) {
        $params['opts'] = $opts['order'];
    }
    //contain
    $params['contain'] = array('Server');
    //returns the data to the controller
    return $this->find('all', $params);
}

其他一些注意事项

  • 您还应该在服务器模型中设置关联
  • 我给出的代码示例写得相当冗长(这是一个单词吗?)。随意压缩
  • 您还可以扩展模型的getImages()方法,以接受更多的参数,如find、limit。。。等等。你想怎么定制就怎么定制——这不是办法——就像我通常使用的一样
  • 根据您的问题,如果您只需要一个字段,您可以在"包含"中指定您想要的字段-有关详细信息,请参阅本书
  • 现在这可能看起来很困惑,但值得学习如何正确地做这件事——这会让你的生活更轻松

Cake有很多模型关系来实现这一点。看看这个页面,我想你会使用下面的To关系

生成的简单替代方法

$images = $this->Image->find('all', array(
    'conditions' => array('Image.user_id' => $this->Auth->user('id')),
    'joins' => array(
                    array(
                        'table' => 'servers',
                        'alias' => 'Server',
                        'type' => 'inner',  //join of your choice left, right, or inner
                        'foreignKey' => true,
                        'conditions' => array('Image.server_id=Server.id')
                    ),
                ),
    'order' => array('Image.uploaded DESC')
));

这在性能上非常好