Skip to content

Commit

Permalink
Get tag list creation and saving fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
markstory committed Apr 16, 2024
1 parent 3610494 commit 302cfb6
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 8 deletions.
10 changes: 2 additions & 8 deletions src/Controller/ArticlesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,12 @@ public function delete($slug)
}
}

public function tags()
public function tags(array $tags = [])
{
$this->Authorization->skipAuthorization();

// The 'pass' key is provided by CakePHP and contains all
// the passed URL path segments in the request.
$tags = $this->request->getParam('pass');

// Use the ArticlesTable to find tagged articles.
$articles = $this->Articles->find('tagged', [
'tags' => $tags
]);
$articles = $this->Articles->find('tagged', tags: $tags);

// Pass variables into the view template context.
$this->set([
Expand Down
18 changes: 18 additions & 0 deletions src/Model/Entity/Article.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace App\Model\Entity;

use Cake\Collection\Collection;
use Cake\ORM\Entity;
use Cake\Utility\Text;

Expand Down Expand Up @@ -42,6 +43,7 @@ class Article extends Entity
'modified' => true,
'user' => true,
'tags' => true,
'tag_string' => true,
];

protected function _setTitle(string $title): string
Expand All @@ -50,4 +52,20 @@ protected function _setTitle(string $title): string

return $title;
}

protected function _getTagString(): string
{
if (isset($this->_fields['tag_string'])) {
return $this->_fields['tag_string'];
}
if (empty($this->tags)) {
return '';
}
$tags = new Collection($this->tags);
$str = $tags->reduce(function ($string, $tag) {
return $string . $tag->title . ', ';
}, '');

return trim($str, ', ');
}
}
71 changes: 71 additions & 0 deletions src/Model/Table/ArticlesTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

namespace App\Model\Table;

use ArrayObject;
use Cake\Event\EventInterface;
use Cake\ORM\Query\SelectQuery;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
Expand Down Expand Up @@ -106,4 +109,72 @@ public function buildRules(RulesChecker $rules): RulesChecker

return $rules;
}

public function beforeSave(EventInterface $event, $entity, ArrayObject $options)
{
if ($entity->tag_string) {
$entity->tags = $this->_buildTags($entity->tag_string);
}

// Other code
}

protected function _buildTags($tagString)
{
// Trim tags
$newTags = array_map('trim', explode(',', $tagString));
// Remove all empty tags
$newTags = array_filter($newTags);
// Reduce duplicated tags
$newTags = array_unique($newTags);

$out = [];
$tags = $this->Tags->find()
->where(['Tags.title IN' => $newTags])
->all();

// Remove existing tags from the list of new tags.
foreach ($tags->extract('title') as $existing) {
$index = array_search($existing, $newTags);
if ($index !== false) {
unset($newTags[$index]);
}
}
// Add existing tags.
foreach ($tags as $tag) {
$out[] = $tag;
}
// Add new tags.
foreach ($newTags as $tag) {
$out[] = $this->Tags->newEntity(['title' => $tag]);
}
return $out;
}

// The $query argument is a query builder instance.
// The $options array will contain the 'tags' option we passed
// to find('tagged') in our controller action.
public function findTagged(SelectQuery $query, array $tags = []): SelectQuery
{
$columns = [
'Articles.id', 'Articles.user_id', 'Articles.title',
'Articles.body', 'Articles.published', 'Articles.created',
'Articles.slug',
];
$query = $query
->select($columns)
->distinct($columns);

if (empty($tags)) {
// If there are no tags provided, find articles that have no tags.
$query->leftJoinWith('Tags')
->where(['Tags.title IS' => null]);
} else {
// Find articles that have one or more of the provided tags.
$query->innerJoinWith('Tags')
->where(['Tags.title IN' => $tags]);
}

return $query->groupBy(['Articles.id']);
}
}

0 comments on commit 302cfb6

Please sign in to comment.