2010-07-29 54 views
1

当我开始尝试实现这一点时,我得到了相当的困扰。我如何管理M:N Post-Tag关系(例如编辑/删除)

一些业务规则

1后可以有很多的标签。 1标签可以有很多文章

数据库看起来像。

  • 帖子(ID,标题,正文,...)
  • Posts_Tags(邮局,标签)
  • 标签(标识,标签,...)

当我插入 - 直截了当

  • 标签将来自用户输入作为逗号分隔值
  • explode($tags)获得个人标签
  • 的foreach $标签
    • 如果检查标签存在
    • 如果是,获得ID
    • 如果没有,插入标签&获得ID
  • 插入柱与标签

我在想这是不是最好的方法?如果标签存在,我是否可以取消循环chk?或将其简化为1个查询?

更新后,升技更难

  • 如何检查用户是否更新任何标记。另一个循环?但这个时候会有一些变化(斜体)

  • explode($tags)获得个人标签

  • 的foreach $标签
    • 如果检查这个帖子已被标记与此标记
    • 如果没有,
      • 是否存在标签?
        • 是,获得ID
        • 没有,插入并获得ID
    • 如果是,获得ID与标签

  • 更新后, ...更新更混乱,你将如何实现这一点?

    我使用PHP 5.3,Zend Framework的1.10,学说2

  • 回答

    2

    我认为后标签关系应该是多对多的;即:帖子有和属于许多标签。这可以通过一个联结表来实现。这里有关于这个主题的一些literature。然后......

    插入:你现在正在做同样的事情,但你可以在一个查询获取所有标签:

    SELECT name FROM tags WHERE name IN ($tags) 
    

    更新:最简单的办法:删除所有当前标签,插入标签,就好像它们都是新的。或...

    $tags = explode(',' $_POST['tags']); // remove whitespaces 
    
    # delete all current tags that were not included in the edit 
    DELETE FROM post_tags WHERE post_id=$post_id AND tag_id NOT IN ($tags) 
    
    # find out what the current tags are, use a JOIN to find out their labels 
    SELECT tag_id FROM post_tags WHERE post_id=$post_id 
    fetch results, remove found tags from $tags, then 
    foreach new $tag, insert as if they were new 
    
    +0

    你说得对,更新了我的帖子。删除和插入所有标签不会降低性能太多我猜? – 2010-07-29 13:32:39

    +0

    我从来不喜欢多对多的标签模式。看起来效率不高,为了获取标签列表,必须将3个表加在一起而不是2个,特别是因为tag和post_tag表可以变得相当大,这取决于网站的活跃程度。 – KallDrexx 2010-07-29 13:36:41

    +0

    @ KallDrexx不幸的是似乎是[最好的方法](http://stackoverflow.com/questions/3152850/best-way-to-store-a-many-to-many-relationship-in-mysql)到做到这一点 – NullUserException 2010-07-29 13:40:59

    2

    用于更新的理念:

    • 存放在隐藏的价值
    • 领带启用/禁用用户JS值一个onchange事件标签输入然后设置一个隐藏的变量设置为true,所以你知道的标签已经改变
    • 如果启用JS和标签已经改变删除所有标签属于这个帖子然后将实际的标签(比如第一)
      • 预置:如果JS禁用,您需要检查针对得救的提交标签。
    +0

    假设用户启用了js,这将是一种更高效的方法。 – 2010-07-29 13:34:37

    +0

    虽然你仍然需要在PHP端进行处理,因为你不能保证JS被启用。 – 2010-07-29 13:51:25

    2

    我做的标记非常相似更新后的伪代码是怎么了,除了一个增加的步骤。您需要检查以确保没有不在用户输入中的帖子存在。例如,如果一个帖子被标记为“php,sql,doctrine”,并且用户将标签更改为“c#,sql,doctrine”,您必须知道删除php标签。

    所以我的代码循环通过现有的标签,看看哪些标记需要删除,然后我遍历用户提供的标签,看看哪些需要添加。

    0

    对于你的第一个问题,你可以简化为单个查询。 (非参数)SQL会是这个样子:

    SELECT * FROM Tags WHERE name='foo' OR name='bar' OR name='etc' 
    /* and so on and so forth */ 
    

    您可以再通过在你的PHP代码来检查其归还标签周期;我会使用key_exists(“keyname”,$ associativeArrayContainingQueryResults)。

    我愿意做您​​的查询的第二部分类似的东西了。不过,我不知道性能优势是什么。SQL可能会更好地缓存来自几个较小的查询的结果,但我不知道整体上它会更快。

    +0

    嗯,我想我会做一个'IN()':'选择*从标签的名称在('foo','bar','baz')' – 2010-07-29 13:48:04

    +0

    这将更容易生成。 :-) – James 2010-07-29 15:23:14

    +0

    你为什么这么说?它似乎对我而言,而不是产生'name ='foo''我只生成''foo'' ltr使用'',''作为胶水并将其附加到'WHERE'子句中使它们内爆? – 2010-07-30 02:27:21

    0

    我认为在Doctrine中有一个Taggable行为。看看这个,这可以帮助。

    +0

    嗯,如果我没有错教义2不支持行为? – 2010-07-29 13:49:18

    +0

    哦,这是可能的。我知道在教条1.2中有这样的东西,但你是对的:http://www.doctrine-project.org/blog/doctrine2-behaviours-nutshell – GiDo 2010-07-29 14:06:57

    相关问题