简体   繁体   English

确保与Phalcon相关的nn模型的唯一性

[英]Ensuring uniqueness in Phalcon related n-n models

I have a model contents that has a many to many relationship with tags through the intermediary table contents_tags . 我有一个模型contents ,该contents_tags通过中介表contents_tagstags有很多关系。 When I insert a new row in contents I want to also add multiple tags. 当我在contents插入新行时,我还想添加多个标签。 While this works fine, I want the tags entries to be unique, so they will be inserted if they are new, or updated (although nothing changes) if they already exist. 尽管这可以正常工作,但我希望tags条目是唯一的,因此如果tags条目是新tags ,则将其插入;如果tags已存在,则将对其进行更新(尽管没有任何更改)。

This unit test seems to imply that this can be done automatically, but I can't manage to replicate the same behaviour. 这个单元测试似乎暗示可以自动完成,但是我无法复制相同的行为。 If I don't have a unique index on my tag table, then I get multiple of the same entries. 如果我的标签表上没有唯一索引,那么我会得到多个相同的条目。 If I do then the tag model throws an error. 如果我这样做,则标记模型将引发错误。

This is my test code: 这是我的测试代码:

$content                = new Content();
$content->title         = 'xkcd';
$content->description   = 'description goes here';
$content->url           = 'http://xkcd.com/';
$content->created_on    = new Phalcon\Db\RawValue('NOW()');
$content->tags          = array();

$tagsText = 'xkcd,comics,testing';

$tags = array();
foreach(explode(',', $tagsText) as $tagText) {
    $tag = new Tag();
    $tag->tag = trim($tagText);
    $tags[] = $tag;
}
$content->tags = $tags;

if($content->save()) {
    $app->response->setStatusCode(201, "Created");
    $app->response->setJsonContent($content->overview());
} else {
    $app->response->setStatusCode(400, "Bad Request");
    $app->response->setJsonContent(array('errors'=>$content->getMessagesAsArray()));
}

Contents model: 内容模型:

class Content {
    public function initialize() {
        $this->hasManyToMany(
            'id',
            'ContentsTags',
            'content_id',
            'tag_id',
            'Tag',
            'id',
            array('alias' => 'tags')
        );
    }

    public function getSource() {
        return 'contents';
    }
}

ContentsTag model: ContentsTag模型:

class ContentsTags {

    public function initialize() {
        $this->belongsTo('content_id', 'Content', 'id', array('alias' => 'content'));
        $this->belongsTo('tag_id', 'Tag', 'id', array('alias' => 'tag'));
    }

    public function getSource() {
        return 'contents_tags';
    }
}

Tag model: 标签型号:

class Tag {

    public function getSource() {
        return 'tags';
    }

    public function initialize() {
        $this->hasManyToMany(
            'id',
            'ContentsTags',
            'tag_id',
            'content_id',
            'Content',
            'id',
            array('alias' => 'contents')
        );
    }
}

Example data from the tables: 表中的示例数据:

contents: 内容:

+----+-------+-----------------------+------------------+
| id | title | description           | url              |
+----+-------+-----------------------+------------------+
| 11 | xkcd  | description goes here | http://xkcd.com/ |
+----+-------+-----------------------+------------------+

contents_tags: contents_tags:

+----+------------+--------+
| id | content_id | tag_id |
+----+------------+--------+
|  1 |         11 |      1 |
|  2 |         11 |      2 |
+----+------------+--------+

tags: 标签:

+----+--------+
| id | tag    |
+----+--------+
|  1 | comics |
|  2 | maths  |
+----+--------+

The models for the unit test mentioned above seem to have no special parameters set, and I can't find the actual table declarations for them so I am at a bit of a loss. 上面提到的用于单元测试的模型似乎没有设置特殊的参数,并且我找不到它们的实际表声明,所以我有点茫然。 The models for the unit test can be seen here: 可以在此处看到用于单元测试的模型:

This was a misunderstanding by me of what the Unit test was doing. 这是我对单元测试所做的误解。 I thought it was noticing that "Part 1" and "Part 2" already existed as parts, what it was actually doing was noticing that they had an ID, and hence did not need inserting. 我以为是在注意到“第1部分”和“第2部分”已经作为部分存在了,它实际上所做的是注意到它们具有ID,因此不需要插入。

I added this to the Tag class: 我将此添加到Tag类:

/**
 * Look to see if a tag exists, if it does then
 * return it. If it doesn't then create it and
 * return it.
 *
 * @param  string $tagName
 * @return Tag    $tag
 */
public static function getOrCreate($tagName) {
    $tag = static::findFirst(
        array(
            'conditions' => "tag=?0", 
            "bind" => array($tagName)
        )
    );
    if($tag) return $tag;

    try {
        $tag = new Tag();
        $tag->tag = $tagName;
        $tag->save();
        return $tag;
    } catch(Exception $e) {
        $this->appendMessage(new Message($e->getMessage(), 'tags'));
        return false;
    }
}

and altered the test code to this: 并将测试代码更改为此:

$tags = array();
foreach(explode(',', $tagsText) as $tagText) {
    $tags[] = Tag::getOrCreate(trim($tagText));
}
$content->tags = $tags;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM