编程语言
首页 > 编程语言> > CakePHP:几个连接,belongsTo和hasMany关系在两个查询中完成

CakePHP:几个连接,belongsTo和hasMany关系在两个查询中完成

作者:互联网

我需要一些CakePHP 2.2.3的帮助.

是)我有的

我现在有以下设置:

邮寄hasMany附件

它工作正常,页面生成2个查询:

SELECT *, `Post`.`id` 
FROM `posts` AS `Post` 
WHERE 1 = 1 
ORDER BY `Post`.`created` DESC

SELECT 
    `Attachment`.`id`, 
    `Attachment`.`post_id`, 
    `Attachment`.`created` 
FROM 
    `attachments` AS `Attachment` 
WHERE 
    `Attachment`.`post_id` IN (1, 2, 3, ..., n) 

我想要的是

我想将关系扩展如下:

邮政有很多附件;每个附件属于所有类型

我不太热衷于让CakePHP遵循它.
基本上,我需要的是:

SELECT *, `Post`.`id` 
FROM `posts` AS `Post` 
WHERE 1 = 1 
ORDER BY `Post`.`created` DESC

SELECT 
    `Attachment`.`id`, 
    `Attachment`.`post_id`, 
    `Attachment`.`created`, 
    `Type`.`title`, `Type`.`icon` 
FROM 
    `attachments` AS `Attachment` 
LEFT JOIN 
    `types` AS `Type` 
    ON (`Attachment`.`type_id`=`Type`.`id`) 
WHERE 
    `Attachment`.`post_id` IN (1, 2, 3, ..., n) 

请注意添加了LEFT JOIN类型.

所以我在第二个查询中得到了相应的类型数据.我知道我可以循环获取数据或使用 – > query()调用,但我希望它尽可能有效和灵活.

问题

我尝试了Containable,Model Unbinding trick(and this one)但没有成功.我尝试了不同的选项组合,我相信我甚至删除了连接.这就是我的PostsController现在的样子.

class PostsController extends AppController {
    public function index() {

        $this->Post->unbindModel(array('hasMany' => array('Attachment')));
        $this->Post->Attachment->unbindModel(array('belongsTo' => array('Type')));

        $this->Post->bindModel(array(
            'hasMany' => array(
                'Attachment' => array(
                    'className'  => 'Attachment',
                // when uncommented, throws the "Unknown column Post.id" SQLSTATE error
                //  'conditions' => array('Post.id' => 'Attachment.post_id'),
                    'foreignKey' => false,
                ),
            ),
        ));
        $this->Post->Attachment->bindModel(array(
            'belongsTo' => array(
                'Filetype' => array(
                    'className'  => 'Filetype',
                //  'conditions' => array('Type.id' => 'Attachment.type_id'),
                    'foreignKey' => false,
                ),
            ),
        ));
        $all = $this->Post->find('all', array(
            'joins' => array(
                array(
                    'table' => 'users',
                    'prefix' => '',
                    'alias' => 'User',
                    'type' => 'INNER',
                    'conditions' => array(
                        'User.id = Post.user_id',
                    )
                ),
            ),
            'contain' => array('Attachment', 'Type'),
            'conditions' => array(),
            'fields' => array('*'),
            'order' => 'Post.created ASC'
        ));
        var_dump($all);exit;
    }
}

但它只是在循环中每次迭代运行一个额外的查询并获取所有附件:

SELECT `Attachment`.`id`, ... 
FROM `attachments` AS `Attachment` 
WHERE 1 = 1 

当我取消注释这个关联的条件时,它会抛出SQLSTATE“Column Post.id not found error” – 我想因为这里没有Post表加入.

我需要帮助设置它.

请帮忙!谢谢

UPDATE

我按如下方式更改了控制器.请注意,没有bindModel / unbindModel代码,关系是在models类中设置的(在这种情况下是正确的吗?).

class PostsController extends AppController {
    public function index() {
        $options = array(
            'contain' => array(
                'Post',
                'Type'
            ),
            'order' => 'Post.created DESC',
            'conditions' => array(
            //  'Post.title LIKE' => 'my post'
            )
        );

    //  The following throws "Fatal error: Call to a member function find() on a non-object"
    //  $posts = $this->Attachment->find('all', $options); 

    //  So I had to use $this->Post->Attachment instead of $this->Attachment
        $posts = $this->Post->Attachment->find('all', $options);
        $this->set(compact('posts'));
    }   
}

这是附件模型:

class Attachment extends AppModel {
    public $belongsTo = array(
        'Type' => array(
            'className' => 'Type',
            'foreignKey' => 'type_id',
        ),
        'Post' => array(
            'className' => 'Post',
            'foreignKey' => 'post_id',
        ),
    );
}

上面的代码运行此查询:

SELECT 
    `Attachment`.`id`, `Attachment`.`type_id`, `Attachment`.`post_id`, `Attachment`.`created`, 
    `Type`.`id`, `Type`.`title`, 
    `Post`.`id`, `Post`.`text`, `Post`.`created` 
FROM 
    `attachments` AS `Attachment` 
    LEFT JOIN `types` AS `Type` ON (`Attachment`.`type_id` = `Type`.`id`) 
    LEFT JOIN `posts` AS `Post` ON (`Attachment`.`post_id` = `Post`.`id`) 
WHERE 
    1 = 1 
ORDER BY 
    `Post`.`created` ASC

一切都是关于这里的附件.我的意思是帖子已加入附件,因此如果帖子没有附件,则不会返回.这可能是因为调用是Attachment-> find()所以它来自附件的观点.我猜它应该是:

// ...
FROM 
    `posts` AS `Post`
    LEFT JOIN `attachments` AS `Attachment`  ON (`Attachment`.`post_id` = `Post`.`id`) 
    LEFT JOIN `types` AS `Type` ON (`Attachment`.`type_id` = `Type`.`id`) 
// ...

但它不会起作用,是吗?您会看到有帖子,附件和类型,但它们确实具有不同的关系类型.最初,我发布了CakePHP运行的两个单独的查询 – 必须有这样的理由.

UPDATE2

我仍然相信在初始设置中将第二个查询更改为附件模型(请参阅“我想要的内容”部分).所以我将获得附件类型以及附件本身.我的意思是在那种情况下LEFT JOINING类型表到附件不会打破任何数据库关系逻辑,是吗?
我只想确保一个复杂但单一的find()调用无法做到这一点.

解决方法:

每当Cake看到hasMany关系时,它都会自动创建多个查询来提取数据.在构造这些查询时,它会查找可以LEFT连接到它的关系(hasOne和belongsTo).

由于Cake无法为您执行此操作,因此您需要自己合并它们.

public function index() {
  $posts = $this->Post->find('all');
  // get all attachments for all found posts
  $attachments = $this->Post->Attachment->find('all', array(
    'contain' => array('Type'),
    'conditions' => array('Post.id' => Set::extract('/Post/id', $posts)
  ));
  // now join them to the posts array
  foreach ($posts as $key => $data) {
    $postId = $data['Post']['id'];
    // append any data related to this post to the post's array
    $posts[$key] += Set::extract("/Attachment[post_id=$postId]/..", $attachments);
  }
  $this->set(compact('posts'));
}

这不是最有效的方法,因为你将多次遍历$attachments数组,但我相信你明白了.

标签:php,mysql,cakephp,has-many,belongs-to
来源: https://codeday.me/bug/20190629/1329961.html