Обеспечение уникальности в n-n моделях, связанных с Phalcon

У меня есть модель contents который имеет много-много отношений с tags через промежуточную таблицу contents_tags, Когда я вставляю новую строку в contents Я хочу также добавить несколько тегов. Хотя это работает нормально, я хочу tags Записи должны быть уникальными, поэтому они будут вставлены, если они новые, или обновлены (хотя ничего не меняется), если они уже существуют.

Это юнит тест кажется, подразумевает, что это может быть сделано автоматически, но мне не удается воспроизвести такое же поведение. Если у меня нет уникального индекса в таблице тегов, я получаю несколько одинаковых записей. Если я это сделаю, то модель тега выдаст ошибку.

Это мой тестовый код:

$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()));
}

Содержание модели:

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

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

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';
}
}

Модель тега:

class Tag {

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

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

Пример данных из таблиц:

содержание:

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

contents_tags:

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

теги:

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

Модели для упомянутого выше модульного теста, кажется, не имеют специальных установленных параметров, и я не могу найти фактические объявления таблиц для них, поэтому я немного растерялся. Модели для модульного тестирования можно увидеть здесь:

0

Решение

Это было недопонимание мной того, что делал модульный тест. Я подумал, что заметил, что «Часть 1» и «Часть 2» уже существуют как части, на самом деле он заметил, что у них есть удостоверение личности, и, следовательно, вставлять его не нужно.

Я добавил это в класс 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;
}
}

и изменил код теста на это:

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

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]