Added sorting by tag usage dates to tag list

This commit is contained in:
Marcin Kurczewski 2014-07-31 11:53:19 +02:00
parent c1f8a5e632
commit 9e29441c68
7 changed files with 124 additions and 36 deletions

View file

@ -4,6 +4,8 @@ use \Chibi\Sql as Sql;
final class TagEntity extends AbstractEntity implements IValidatable, ISerializable
{
private $name;
private $creationDate;
private $updateDate;
public function fillNew()
{
@ -13,6 +15,8 @@ final class TagEntity extends AbstractEntity implements IValidatable, ISerializa
{
$this->id = (int) $row['id'];
$this->name = $row['name'];
$this->creationDate = TextHelper::toIntegerOrNull($row['creation_date']);
$this->updateDate = TextHelper::toIntegerOrNull($row['update_date']);
if (isset($row['post_count']))
$this->setCache('post_count', (int) $row['post_count']);
@ -57,6 +61,16 @@ final class TagEntity extends AbstractEntity implements IValidatable, ISerializa
return $this->name;
}
public function getCreationDate()
{
return $this->creationDate;
}
public function getUpdateDate()
{
return $this->updateDate;
}
public function getPostCount()
{
if ($this->hasCache('post_count'))

View file

@ -43,47 +43,69 @@ final class PostModel extends AbstractCrudModel
$stmt->setCriterion(Sql\Functors::equals('id', new Sql\Binding($post->getId())));
Core::getDatabase()->execute($stmt);
//tags
$tags = $post->getTags();
$stmt = Sql\Statements::delete();
$stmt->setTable('post_tag');
$stmt->setCriterion(Sql\Functors::equals('post_id', new Sql\Binding($post->getId())));
Core::getDatabase()->execute($stmt);
foreach ($tags as $postTag)
{
$stmt = Sql\Statements::insert();
$stmt->setTable('post_tag');
$stmt->setColumn('post_id', new Sql\Binding($post->getId()));
$stmt->setColumn('tag_id', new Sql\Binding($postTag->getId()));
Core::getDatabase()->execute($stmt);
}
//relations
$relations = $post->getRelations();
$stmt = Sql\Statements::delete();
$stmt->setTable('crossref');
$binding = new Sql\Binding($post->getId());
$stmt->setCriterion(Sql\Functors::disjunction()
->add(Sql\Functors::equals('post_id', $binding))
->add(Sql\Functors::equals('post2_id', $binding)));
Core::getDatabase()->execute($stmt);
foreach ($relations as $relatedPost)
{
$stmt = Sql\Statements::insert();
$stmt->setTable('crossref');
$stmt->setColumn('post_id', new Sql\Binding($post->getId()));
$stmt->setColumn('post2_id', new Sql\Binding($relatedPost->getId()));
Core::getDatabase()->execute($stmt);
}
self::saveTags($post);
self::saveRelations($post);
});
return $post;
}
private static function saveTags($post)
{
$newTagIds = array_map(function($tag) { return $tag->getId(); }, $post->getTags());
$stmt = Sql\Statements::select();
$stmt->setTable('post_tag');
$stmt->setColumn('tag_id');
$stmt->setCriterion(Sql\Functors::equals('post_id', new Sql\Binding($post->getId())));
$rows = Core::getDatabase()->fetchAll($stmt);
$oldTagIds = array_map(function($row) { return $row['tag_id']; }, $rows);
$tagIdsToInsert = array_diff($newTagIds, $oldTagIds);
$tagIdsToDelete = array_diff($oldTagIds, $newTagIds);
if (count($tagIdsToDelete))
{
$stmt = Sql\Statements::delete();
$stmt->setTable('post_tag');
$stmt->setCriterion(Sql\Functors::conjunction()
->add(Sql\Functors::in('tag_id', Sql\Binding::fromArray($tagIdsToDelete)))
->add(Sql\Functors::equals('post_id', new Sql\Binding($post->getId()))));
Core::getDatabase()->execute($stmt);
}
foreach ($tagIdsToInsert as $tagIdToInsert)
{
$stmt = Sql\Statements::insert();
$stmt->setTable('post_tag');
$stmt->setColumn('post_id', new Sql\Binding($post->getId()));
$stmt->setColumn('tag_id', new Sql\Binding($tagIdToInsert));
Core::getDatabase()->execute($stmt);
}
}
private static function saveRelations($post)
{
$relations = $post->getRelations();
$stmt = Sql\Statements::delete();
$stmt->setTable('crossref');
$binding = new Sql\Binding($post->getId());
$stmt->setCriterion(Sql\Functors::disjunction()
->add(Sql\Functors::equals('post_id', $binding))
->add(Sql\Functors::equals('post2_id', $binding)));
Core::getDatabase()->execute($stmt);
foreach ($relations as $relatedPost)
{
$stmt = Sql\Statements::insert();
$stmt->setTable('crossref');
$stmt->setColumn('post_id', new Sql\Binding($post->getId()));
$stmt->setColumn('post2_id', new Sql\Binding($relatedPost->getId()));
Core::getDatabase()->execute($stmt);
}
}
protected static function removeSingle($post)
{
Core::getDatabase()->transaction(function() use ($post)

View file

@ -38,6 +38,10 @@ class TagSearchParser extends AbstractSearchParser
{
if ($orderByString == 'popularity')
$this->statement->setOrderBy('post_count', $orderDir);
elseif ($orderByString == 'creation_date')
$this->statement->setOrderBy('tag.creation_date', $orderDir);
elseif ($orderByString == 'update_date')
$this->statement->setOrderBy('tag.update_date', $orderDir);
elseif ($orderByString == 'alpha')
$this->statement->setOrderBy(Sql\Functors::{'case'}('tag.name'), $orderDir);
else

View file

@ -0,0 +1,15 @@
ALTER TABLE tag ADD COLUMN creation_date INTEGER DEFAULT NULL;
ALTER TABLE tag ADD COLUMN update_date INTEGER DEFAULT NULL;
DROP TRIGGER post_tag_insert;
CREATE TRIGGER post_tag_insert AFTER INSERT ON post_tag FOR EACH ROW
BEGIN
UPDATE post SET tag_count = tag_count + 1 WHERE post.id = NEW.post_id;
UPDATE tag SET update_date = UNIX_TIMESTAMP() WHERE tag.id = NEW.tag_id;
END;
CREATE TRIGGER tag_insert BEFORE INSERT ON tag FOR EACH ROW
BEGIN
SET NEW.creation_date = UNIX_TIMESTAMP();
SET NEW.update_date = UNIX_TIMESTAMP();
END;

View file

@ -0,0 +1,15 @@
ALTER TABLE tag ADD COLUMN creation_date INTEGER DEFAULT NULL;
ALTER TABLE tag ADD COLUMN update_date INTEGER DEFAULT NULL;
DROP TRIGGER post_tag_insert;
CREATE TRIGGER post_tag_insert AFTER INSERT ON post_tag FOR EACH ROW
BEGIN
UPDATE post SET tag_count = tag_count + 1 WHERE post.id = NEW.post_id;
UPDATE tag SET update_date = STRFTIME('%s', 'NOW') WHERE tag.id = NEW.tag_id;
END;
CREATE TRIGGER tag_insert AFTER INSERT ON tag FOR EACH ROW
BEGIN
UPDATE tag SET creation_date = STRFTIME('%s', 'NOW') WHERE tag.id = NEW.id;
UPDATE tag SET update_date = STRFTIME('%s', 'NOW') WHERE tag.id = NEW.id;
END;

View file

@ -7,6 +7,8 @@
'order:alpha,desc' => 'Sort Z→A',
'order:popularity,desc' => 'Often used first',
'order:popularity,asc' => 'Rarely used first',
'order:update_date,desc' => 'Recently used',
'order:creation_date,desc' => 'Recently created',
];
?>

View file

@ -0,0 +1,16 @@
<?php
class TagModelTest extends AbstractTest
{
public function testSavingAndRetrieving()
{
$tag = TagModel::spawn();
$tag->setName('test');
TagModel::save($tag);
$otherTag = TagModel::getById($tag->getId());
$this->assert->areEqual($tag->getName(), $otherTag->getName());
$this->assert->areEqual(time(), $otherTag->getCreationDate());
$this->assert->areEqual(time(), $otherTag->getUpdateDate());
}
}