我有一个简单的应用程序,其中包含帖子和标签。
帖子可以有多个标签,标签可以属于多个帖子。基本的DB模式是这样的:
帖子表:
id
title
slug
content
标签表:
id
title
slug
tag_posts表:
id
tag_id
post_id
因此,当用户保存帖子时,它会在字段中获取标签列表,然后首先检查标签是否存在。如果标记不存在,则创建它们,或者如果不存在则存在。 (所有标记都是低级的,因此您无法拥有Tag
和tag
)。然后通过将id添加到tag_posts
表中来将标签链接到帖子。
到目前为止这是有效的,但执行它的代码真的很糟糕。我在Tag模型中有以下方法,它采用标签列表并执行上述操作:
公共函数savePostTags($ postId,$ tags) {
// Explode the topics by comma, so we have an array to run through
$tags = explode(',', $tags);
// Array for collecting all the data
$collection = array();
//debug($tags);
function is_array_empty( $mixed ) {
if ( is_array($mixed) ) {
foreach ($mixed as $value) {
if ( ! is_array_empty($value) ) {
return false;
}
}
} elseif ( ! empty($mixed) ) {
return false;
}
return true;
}
if(is_array_empty($tags) ) {
return false;
}
// First of all we bin off existing associations to make sure we don't duplicate
// NOTE: The false means don't delete the topics or posts related!!! VERY IMPORTANT!
$this->TagPost->deleteAll(array('TagPost.post_id' => $postId), false);
$tags = array_unique($tags);
// Make sure all tags are unique
foreach($tags as $tag)
{
// Trim it so remove unwanted white spaces in the beginning and the end.
$tag = trim($tag);
// If tag is empty exit here
if(empty($tag) ) {
return false;
}
// Make it all lowercase for consistency of tag names
$tag = strtolower($tag);
// Check if we already have a topic like this
$controlFind = $this->find(
'first',
array(
'conditions' => array(
'title' => $tag
)
)
);
//debug($controlFind);
// No record found (create new tag and link it up)
if(!$controlFind)
{
$this->create();
if(
!$this->save(
array(
'title' => $tag,
'slug' => Inflector::slug($tag)
)
)
)
{
// If only one saving fails we stop the whole loop and method.
return false;
}
else
{
$temp = array(
'TagPost' => array(
'tag_id' => $this->id,
'post_id' => $postId
)
);
}
}
else // Or if found link it with the post
{
$temp = array(
'TagPost' => array(
'tag_id' => $controlFind['Tag']['id'],
'post_id' => $postId
)
);
}
$collection[] = $temp;
}
return $this->TagPost->saveAll($collection, array('validate' => false));
}
关于如何重构这个的任何想法?
因为感觉真的很啰嗦,似乎打破了CakePHP的惯例。
答案 0 :(得分:0)
试试这个
public function savePostTags($postId, $tags)
{
$tags = explode(',', $tags);
foreach($tags as $key=>$value){
$listTags[$key] = trim(strtolower($value));
}
# find the list of existing tags
$listOfExistingTags = $this->find('list',
array('conditions' => array('title' => $tags),
'recursive' => -1));
$newTags = array_diff($tags, $listOfExistingTags);
#save new tags
foreach($newTags as $key=>$value){
$saveData[$key]['Tag']['title'] = $value;
$saveData[$key]['Tag']['slug'] = Inflector::slug($value);
}
if(!empty($saveData))$this->saveAll($saveData);
# this save all the tags
# now save data in tag_posts
$listOfExistingTags = $this->find('list',
array('conditions' =>array('title' => $tags),
'fields'=>array('id','title'),
'recursive' => -1));
$i = 0;
foreach($listOfExistingTags as $key=>$value){
$tagPostData[$i]['TagPost']['tag_id'] = $key;
$tagPostData[$i]['TagPost']['post_id'] = $postId; $i++;
}
if(!empty($tagPostData)){
App::import('model','TagPost');
$TagPost = new TagPost();
$TagPost->saveAll($tagPostData);
}
}
答案 1 :(得分:0)
关于如何重构这个的任何想法?
使用the CakeDC Tags plugin。它经过单元测试,易于投入,耗时约15分钟。看到它的readme.md。它基本上只是添加行为并在表单中添加字段“tags”。