Added tag relations database interface

This commit is contained in:
Marcin Kurczewski 2014-10-15 16:00:03 +02:00
parent 850e496215
commit 0bd0589e32
6 changed files with 184 additions and 11 deletions

21
TODO
View file

@ -28,16 +28,17 @@ everything related to tags:
- tag editing
- category (from config.ini)
- description
- implications - when entering child tag, add parent tag
- take care of recursion
- listing
- sort alphabetically
- sort by time of addition
- adding
- removing
- editing
- source tag
- target tags (allow multiple)
- relations
- handle tag relations editing in frontend
- privileges
- template
- ajax
- handle tag relations editing in backend
- tagservice::update
- tageditformdata
- tagcontroller
- privileges
- handle relations in autocomplete
refactors:
- add enum validation in IValidatables (needs refactors of enums and

View file

@ -3,9 +3,14 @@ namespace Szurubooru\Dao;
use Szurubooru\Dao\EntityConverters\PostEntityConverter;
use Szurubooru\Dao\EntityConverters\TagEntityConverter;
use Szurubooru\DatabaseConnection;
use Szurubooru\Entities\Entity;
use Szurubooru\Entities\Tag;
class TagDao extends AbstractDao implements ICrudDao
{
const TAG_RELATION_IMPLICATION = 1;
const TAG_RELATION_SUGGESTION = 2;
public function __construct(DatabaseConnection $databaseConnection)
{
parent::__construct(
@ -49,7 +54,7 @@ class TagDao extends AbstractDao implements ICrudDao
->disableSmartJoin()
->innerJoin('postTags pt1 ON pt1.tagId = tags.id')
->innerJoin('postTags pt2 ON pt2.postId = pt1.postId')
->where('pt2.tagId = ?', $tagId)
->where('pt2.tagId', $tagId)
->groupBy('tags.id')
->orderBy('tags.usages DESC, name ASC');
$arrayEntities = iterator_to_array($query);
@ -60,4 +65,87 @@ class TagDao extends AbstractDao implements ICrudDao
{
$this->deleteBy('usages', 0);
}
protected function afterLoad(Entity $tag)
{
$tag->setLazyLoader(
Tag::LAZY_LOADER_IMPLIED_TAGS,
function (Tag $tag)
{
return $this->findImpliedTags($tag);
});
$tag->setLazyLoader(
Tag::LAZY_LOADER_SUGGESTED_TAGS,
function (Tag $tag)
{
return $this->findSuggested($tag);
});
}
protected function afterSave(Entity $tag)
{
$this->syncImpliedTags($tag);
$this->syncSuggestedTags($tag);
}
private function findImpliedTags(Tag $tag)
{
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_IMPLICATION);
}
private function findSuggested(Tag $tag)
{
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_SUGGESTION);
}
private function syncImpliedTags($tag)
{
$this->syncRelatedTagsByType($tag, $tag->getImpliedTags(), self::TAG_RELATION_IMPLICATION);
}
private function syncSuggestedTags($tag)
{
$this->syncRelatedTagsByType($tag, $tag->getSuggestedTags(), self::TAG_RELATION_SUGGESTION);
}
private function syncRelatedTagsByType(Tag $tag, array $relatedTags, $type)
{
$this->fpdo->deleteFrom('tagRelations')
->where('tag1id', $tag->getId())
->where('type', $type)
->execute();
$relatedTagIds = array_filter(array_unique(array_map(
function ($tag)
{
if (!$tag->getId())
throw new \RuntimeException('Unsaved entities found');
return $tag->getId();
},
$relatedTags)));
foreach ($relatedTagIds as $tagId)
{
$this->fpdo
->insertInto('tagRelations')
->values([
'tag1id' => $tag->getId(),
'tag2id' => $tagId,
'type' => $type])
->execute();
}
}
private function findRelatedTagsByType(Tag $tag, $type)
{
$tagId = $tag->getId();
$query = $this->fpdo->from($this->tableName)
->disableSmartJoin()
->innerJoin('tagRelations tr ON tags.id = tr.tag2id')
->where('tr.type', $type)
->where('tr.tag1id', $tagId);
$arrayEntities = iterator_to_array($query);
return $this->arrayToEntities($arrayEntities);
}
}

View file

@ -7,6 +7,9 @@ final class Tag extends Entity
private $creationTime;
private $banned = false;
const LAZY_LOADER_IMPLIED_TAGS = 'implications';
const LAZY_LOADER_SUGGESTED_TAGS = 'suggestions';
const META_USAGES = 'usages';
public function getName()
@ -44,4 +47,23 @@ final class Tag extends Entity
return $this->getMeta(self::META_USAGES);
}
public function getImpliedTags()
{
return $this->lazyLoad(self::LAZY_LOADER_IMPLIED_TAGS, []);
}
public function setImpliedTags(array $impliedTags)
{
$this->lazySave(self::LAZY_LOADER_IMPLIED_TAGS, $impliedTags);
}
public function getSuggestedTags()
{
return $this->lazyLoad(self::LAZY_LOADER_SUGGESTED_TAGS, []);
}
public function setSuggestedTags(array $suggestedTags)
{
$this->lazySave(self::LAZY_LOADER_SUGGESTED_TAGS, $suggestedTags);
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace Szurubooru\Upgrades;
use Szurubooru\DatabaseConnection;
use Szurubooru\Services\TagService;
class Upgrade24 implements IUpgrade
{
public function run(DatabaseConnection $databaseConnection)
{
$pdo = $databaseConnection->getPDO();
$driver = $databaseConnection->getDriver();
$pdo->exec(
'CREATE TABLE tagRelations (
id INTEGER PRIMARY KEY ' . ($driver === 'mysql' ? 'AUTO_INCREMENT' : 'AUTOINCREMENT') . ',
tag1id INTEGER NOT NULL,
tag2id INTEGER NOT NULL,
type INTEGER(2) NOT NULL,
UNIQUE (tag1id, tag2id, type)
)');
}
}

View file

@ -39,6 +39,7 @@ return [
$container->get(\Szurubooru\Upgrades\Upgrade21::class),
$container->get(\Szurubooru\Upgrades\Upgrade22::class),
$container->get(\Szurubooru\Upgrades\Upgrade23::class),
$container->get(\Szurubooru\Upgrades\Upgrade24::class),
];
}),

View file

@ -25,6 +25,45 @@ final class TagDaoTest extends AbstractDatabaseTestCase
$this->assertEntitiesEqual($tag, $actualTag);
}
public function testSavingRelations()
{
$tag1 = new Tag();
$tag1->setName('test 1');
$tag1->setCreationTime(date('c'));
$tag2 = new Tag();
$tag2->setName('test 2');
$tag2->setCreationTime(date('c'));
$tag3 = new Tag();
$tag3->setName('test 3');
$tag3->setCreationTime(date('c'));
$tag4 = new Tag();
$tag4->setName('test 4');
$tag4->setCreationTime(date('c'));
$tagDao = $this->getTagDao();
$tagDao->save($tag1);
$tagDao->save($tag2);
$tagDao->save($tag3);
$tagDao->save($tag4);
$tag = new Tag();
$tag->setName('test1');
$tag->setCreationTime(date('c'));
$tag->setImpliedTags([$tag1, $tag3]);
$tag->setSuggestedTags([$tag2, $tag4]);
$this->assertGreaterThan(0, count($tag->getImpliedTags()));
$this->assertGreaterThan(0, count($tag->getSuggestedTags()));
$tagDao->save($tag);
$actualTag = $tagDao->findById($tag->getId());
$this->assertEntitiesEqual($tag, $actualTag);
$this->assertEntitiesEqual(array_values($tag->getImpliedTags()), array_values($actualTag->getImpliedTags()));
$this->assertEntitiesEqual(array_values($tag->getSuggestedTags()), array_values($actualTag->getSuggestedTags()));
$this->assertGreaterThan(0, count($actualTag->getImpliedTags()));
$this->assertGreaterThan(0, count($actualTag->getSuggestedTags()));
}
public function testFindByPostIds()
{
$pdo = $this->databaseConnection->getPDO();