Chinaunix首页 | 论坛 | 博客
  • 博客访问: 964573
  • 博文数量: 335
  • 博客积分: 10287
  • 博客等级: 上将
  • 技术积分: 3300
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-08 15:29
文章分类

全部博文(335)

文章存档

2015年(4)

2014年(15)

2013年(17)

2012年(11)

2011年(12)

2010年(96)

2009年(27)

2008年(34)

2007年(43)

2006年(39)

2005年(37)

我的朋友

分类:

2007-09-14 16:11:08

现在你已经掌握了比较简单的关联,让我们转移到最后一个关联:hasAndBelongsToMany ( HABTM).最后一个是最难的,它会让你团团转,但是它也是其中最有用的一个。如果你有2model,而这2model又一个join表联系在一起,HABTM关联这个时候是有用的。Join表抓住了互相关联的各自的行。

hasMany hasAndBelongsToMany的区别是:对于hasMany,关联的model是不共享的。这对我们接下来的工作是非常有用:关联PostTag model。当一个Tag属于一个Post时,我们不会让他使用完,我们会继续将他和其他Post关联。

为了实现它,我们需要为这个关系建立正确的表。当然你需要为你的Tag model转被一个“tags“表,Post准备一个”posts“表,但是你也需要为此关联创建一个join表。HABTM join表的命名规则是[复数的model1]_[复数的model2],这里,model名按字母排序。

HABTM Join : model样例以及他们的Join

1.    Posts Tags: posts_tags

2.    MonkeysIceCubes: ice_cubes_monkeys

3.    CategoriesArticles: articles_categories

HABTM Join表至少需要包含2个他们连接的model的外键。在我们的例子中,"post_id" "tag_id"就是我们所需要的。

下面导出的SQL看起来是为我们的Posts HABTM Tags实例准备的哟:

--

-- Table structure for table `posts`

--

 

CREATE TABLE `posts` (

  `id` int(10) unsigned NOT NULL auto_increment,

  `user_id` int(10) default NULL,

  `title` varchar(50) default NULL,

  `body` text,

  `created` datetime default NULL,

  `modified` datetime default NULL,

  `status` tinyint(1) NOT NULL default '0',

  PRIMARY KEY  (`id`)

) TYPE=MyISAM;

 

-- --------------------------------------------------------

 

--

-- Table structure for table `posts_tags`

--

 

CREATE TABLE `posts_tags` (

  `post_id` int(10) unsigned NOT NULL default '0',

  `tag_id` int(10) unsigned NOT NULL default '0',

  PRIMARY KEY  (`post_id`,`tag_id`)

) TYPE=MyISAM;

 

-- --------------------------------------------------------

 

--

-- Table structure for table `tags`

--

 

CREATE TABLE `tags` (

  `id` int(10) unsigned NOT NULL auto_increment,

  `tag` varchar(100) default NULL,

  PRIMARY KEY  (`id`)

) TYPE=MyISAM;

随着我们的表已创建,让我们在Post model里定义关联:

/app/models/post.php hasAndBelongsToMany

class Post extends AppModel

{

    var $name = 'Post';

    var $hasAndBelongsToMany = array('Tag' =>

                               array('className'    => 'Tag',

                                     'joinTable'    => 'posts_tags',

                                     'foreignKey'   => 'post_id',

                                     'associationForeignKey'=> 'tag_id',

                                     'conditions'   => '',

                                     'order'        => '',

                                     'limit'        => '',

                                     'uniq'         => true,

                                     'finderQuery'  => '',

                                     'deleteQuery'  => '',

                               )

                               );

}

?>

$hasAndBelongsToMany数组是Cake用来创建PostTag model之间的关联的。数组中的每个键允许你更进一步配置关联:

1.    className (必须): 你想要关联的model的类名。例如:

在我们的例子中,我们想指定‘Tagmodel 类名。

2.    joinTable:它是为没有遵循Cake命名规则的数据库而准备的。如果你的表不是【复数的model1_【复数的model2】的词语顺序,你可以在这里指定你的表名。

3.    foreignKey: 指向当前modelJOIN表的外键名。

在这里,你正在操作一个没有遵循Cake命名规则的数据库。

4.    associationForeignKey:指向关联model的外键名。

5.    conditions:定义关系的SQL条件语句

我们可以使用它告诉Cake仅关联一个通过验证的Tag。为了实现它,将键值设置为" Tag.approved = 1"或者其他类似的。

6.    order:关联model的顺序。

例如,如果你想让你的关联model以某顺序排列,为此键设置一个SQL排序谓语:" Tag.tag DESC "

7.    limit:  你想让Cake获取关联model的最大数

用来限制获取关联的Tag数。

8.    uniq:如果设置为true,重复的关联对象会被访问者和查询方法忽略。

一般来说,如果关联不同,将他设置为true"Awesomeness"Tag仅可以分配到Post "Cake Model Associations"一次,并且在结果数组中仅出现一次。

9.    finderQuery:指定一个完整的SQL语句获取关联。

对于复杂的依赖多个表的关联,这是一种优秀的方法。如果Cake的自动关联不工作,在这里,你可以定义它。

10.deleteQuery:一完整的SQL语句,用来删除HABTM model之间的关联。

如果你不愿意按Cake的方法完成删除操作或者你的创建是以某种方法自己定义的,你可以在这里提供你自己的查询来改变本方法完成操作任务。

现在,当执行Post modelfind()findAll()调用时,在这里我们也应该可以看到我们关联的Tag model

$post = $this->Post->read(null, '2');

print_r($post);

 

//输出:

Array

(

    [Post] => Array

        (

            [id] => 2

            [user_id] => 25

            [title] => Cake Model Associations

            [body] => Time saving, easy, and powerful.

            [created] => 2006-04-15 09:33:24

            [modified] => 2006-04-15 09:33:24

            [status] => 1

        )

 

    [Tag] => Array

        (

            [0] => Array

                (

                    [id] => 247

                    [tag] => CakePHP

                )

 

            [1] => Array

                (

                    [id] => 256

                    [tag] => Powerful Software

                )

        )

)

保存相关的Model数据

当你操作关联的model时,需要记住的一件重要事情是,保存model数据应该一直由相应的Cake model来完成。如果正在保存一个新的Post以及它的Comment(留言)的话,那么在保存的过程中,你需要使用PostComment model

如果在系统中不存在一个关联的model(例如,你想同时保存一个新的Post和一个相关的Comment),你需要首先保存主要的,或者说是父model。为了知道它如何进行,让我们想象一下,在我们的PostsController中有一个动作(action),它保存新的Post和相关Comment。下面的动作实例假设你已经发布一个PostComment

/app/controllers/posts_controller.php (部分)

function add()

{

    if (!empty($this->data))

    {

        //We can save the Post data:

        //it should be in $this->data['Post']

       

        $this->Post->save($this->data);

 

        //Now, we'll need to save the Comment data

        //But first, we need to know the ID for the

        //Post we just saved...

 

        $post_id = $this->Post->getLastInsertId();

 

        //Now we add this information to the save data

        //and save the comment.

 

        $this->data['Comment']['post_id'] = $post_id;

 

        //Because our Post hasMany Comments, we can access

        //the Comment model through the Post model:

 

        $this->Post->Comment->save($this->data);

 

    }

}

尽管如此,如果父Model在系统中已经存在(例如,加一个Comment到一个已存在的Post),在保存之前你需要知道父ModelID。你可以将此ID作为URL参数,或者作为表单中的一个隐藏元素。

/app/controllers/posts_controller.php (部分)

//Here's how it would look if the URL param is used...

function addComment($post_id)

{

    if (!empty($this->data))

    {

        //You might want to make the $post_id data more safe,

        //but this will suffice for a working example..

 

        $this->data['Comment']['post_id'] = $post_id;

 

        //Because our Post hasMany Comments, we can access

        //the Comment model through the Post model:

 

        $this->Post->Comment->save($this->data);

    }

}

如果ID作为一个表单的隐藏元素传递的话,你可能想命名这个字段(如果你正在使用HtmlHelper),以至在发出的数据里它会中止,在这里,它应该为:

如果PostID是在 $post['Post']['id']...

echo $html->hidden('Comment/post_id', array('value' => $post['Post']['id'])); ?>

按这种方式,父Post modelID可以在$this->data['Comment']['post_id']中访问,并且都为$this->Post->Comment->save($this->data)所准备。

如果你正保存多个子model,这些相同的基本技术都会工作,仅需要将那些save()调用放在一个循环(记住使用Model::Create()清除model信息哟)中。

总之,如果你正保存关联的数据(belongsTo, hasOne, hasMany relations关系),重要的一点是得到父modelID,并将他保存到子model

阅读(1259) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~