Added tag relations database interface
This commit is contained in:
parent
850e496215
commit
0bd0589e32
6 changed files with 184 additions and 11 deletions
21
TODO
21
TODO
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
22
src/Upgrades/Upgrade24.php
Normal file
22
src/Upgrades/Upgrade24.php
Normal 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)
|
||||
)');
|
||||
}
|
||||
}
|
|
@ -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),
|
||||
];
|
||||
}),
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue