Skip to content

Commit

Permalink
[FEATURE] Add a filter plugin that combines category and tag
Browse files Browse the repository at this point in the history
More filters are possible via filter interface.
  • Loading branch information
sat-hub committed Sep 17, 2024
1 parent ce2dc48 commit d3d7e33
Show file tree
Hide file tree
Showing 27 changed files with 912 additions and 2 deletions.
1 change: 1 addition & 0 deletions Classes/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,6 @@ class Constants
'blog_commentswidget' => -1600000017,
'blog_archivewidget' => -1600000018,
'blog_feedwidget' => -1600000019,
'blog_filter' => -1600000020,
];
}
25 changes: 25 additions & 0 deletions Classes/Controller/PostController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use T3G\AgencyPack\Blog\Domain\Factory\PostFilterFactory;
use T3G\AgencyPack\Blog\Domain\Model\Author;
use T3G\AgencyPack\Blog\Domain\Model\Category;
use T3G\AgencyPack\Blog\Domain\Model\Post;
Expand All @@ -27,6 +28,7 @@
use T3G\AgencyPack\Blog\Utility\ArchiveUtility;
use TYPO3\CMS\Core\Http\NormalizedParams;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Pagination\QueryResultPaginator;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
Expand Down Expand Up @@ -251,6 +253,29 @@ public function listPostsByTagAction(?Tag $tag = null, int $currentPage = 1): Re
return $this->htmlResponse();
}

/**
* Show a list of posts by given filter.
*/
public function listPostsByFilterAction(int $currentPage = 1): ResponseInterface
{
$factory = GeneralUtility::makeInstance(PostFilterFactory::class, $this->categoryRepository, $this->tagRepository);
$filter = $factory->getFilterFromRequest($this->request);
$posts = $this->postRepository->findAllByFilter($filter);
$pagination = $this->getPagination($posts, $currentPage);

$this->view->assign('type', 'byfilter');
$this->view->assign('posts', $posts);
$this->view->assign('pagination', $pagination);
$this->view->assign('filter', $filter);
$this->view->assign('categories', $this->categoryRepository->findAll());
$this->view->assign('tags', $this->tagRepository->findAll());

MetaTagService::set(MetaTagService::META_TITLE, $filter->getTitle());
MetaTagService::set(MetaTagService::META_DESCRIPTION, $filter->getDescription());

return $this->htmlResponse();
}

/**
* Sidebar action.
*/
Expand Down
47 changes: 47 additions & 0 deletions Classes/Domain/Factory/PostFilterFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php
declare(strict_types = 1);

/*
* This file is part of the package t3g/blog.
*
* For the full copyright and license information, please read the
* LICENSE file that was distributed with this source code.
*/

namespace T3G\AgencyPack\Blog\Domain\Factory;

use T3G\AgencyPack\Blog\Domain\Filter\Post\CategoryTag;
use T3G\AgencyPack\Blog\Domain\Filter\PostFilter;
use T3G\AgencyPack\Blog\Domain\Repository\CategoryRepository;
use T3G\AgencyPack\Blog\Domain\Repository\TagRepository;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Extbase\Mvc\RequestInterface;

/**
* The post filter factory sets filter values from the request.
*/
class PostFilterFactory implements SingletonInterface
{
protected CategoryRepository $categoryRepository;

protected TagRepository $tagRepository;

public function __construct(CategoryRepository $categoryRepository, TagRepository $tagRepository)
{
$this->categoryRepository = $categoryRepository;
$this->tagRepository = $tagRepository;
}

public function getFilterFromRequest(RequestInterface $request): PostFilter
{
// Currently there is only one filter implementation.
$filter = new CategoryTag();
if ($request->hasArgument('category')) {
$filter->setCategory($this->categoryRepository->findByUid((int)$request->getArgument('category')));
}
if ($request->hasArgument('tag')) {
$filter->setTag($this->tagRepository->findByUid((int)$request->getArgument('tag')));
}
return $filter;
}
}
29 changes: 29 additions & 0 deletions Classes/Domain/Filter/Post/AbstractBase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
declare(strict_types = 1);

/*
* This file is part of the package t3g/blog.
*
* For the full copyright and license information, please read the
* LICENSE file that was distributed with this source code.
*/

namespace T3G\AgencyPack\Blog\Domain\Filter\Post;

use T3G\AgencyPack\Blog\Domain\Filter\PostFilter;

/**
* Base class for all post filters.
*/
abstract class AbstractBase implements PostFilter
{
/**
* The class name (without namespace) is used as the filter's name.
*/
public function getName(): string
{
$classWithNamespace = get_class($this);
$rightBackslash = strrpos($classWithNamespace, '\\') ?? 0;
return substr($classWithNamespace, $rightBackslash > 0 ? ++$rightBackslash : $rightBackslash);
}
}
99 changes: 99 additions & 0 deletions Classes/Domain/Filter/Post/CategoryTag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php
declare(strict_types = 1);

/*
* This file is part of the package t3g/blog.
*
* For the full copyright and license information, please read the
* LICENSE file that was distributed with this source code.
*/

namespace T3G\AgencyPack\Blog\Domain\Filter\Post;

use T3G\AgencyPack\Blog\Domain\Model\Category;
use T3G\AgencyPack\Blog\Domain\Model\Tag;
use TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException;
use TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;

/**
* This filter combines one selected Category and one selected Tag (both optional).
*/
class CategoryTag extends AbstractBase
{
protected ?Category $category = null;

protected ?Tag $tag = null;

/**
* Title is simply the concatenated Category and Tag titles (separated by a SPACE character).
*/
public function getTitle(): string
{
if ($this->category) {
if ($this->tag) {
return trim($this->category->getTitle() . ' ' . $this->tag->getTitle());
} else {
return $this->category->getTitle();
}
}
if ($this->tag) {
return $this->tag->getTitle();
}
return '';
}

/**
* Description is simply the concatenated Category and Tag titles (separated by a SPACE character).
*/
public function getDescription(): string
{
if ($this->category) {
if ($this->tag) {
return trim($this->category->getDescription() . ' ' . $this->tag->getDescription());
} else {
return $this->category->getDescription();
}
}
if ($this->tag) {
return $this->tag->getDescription();
}
return '';
}

/**
* @return array<ComparisonInterface>
* @throws InvalidQueryException
*/
public function getConstraints(QueryInterface $query): array
{
$constraints = [];
if ($this->category) {
$constraints[] = $query->contains('categories', $this->category);
}
if ($this->tag) {
$constraints[] = $query->contains('tags', $this->tag);
}
return $constraints;
}

public function getCategory(): ?Category
{
return $this->category;
}

public function setCategory(?Category $category): void
{
$this->category = $category;
}

public function getTag(): ?Tag
{
return $this->tag;
}

public function setTag(?Tag $tag): void
{
$this->tag = $tag;
}
}
42 changes: 42 additions & 0 deletions Classes/Domain/Filter/PostFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
declare(strict_types = 1);

/*
* This file is part of the package t3g/blog.
*
* For the full copyright and license information, please read the
* LICENSE file that was distributed with this source code.
*/

namespace T3G\AgencyPack\Blog\Domain\Filter;

use TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;

/**
* Interface for post filters used in the listPostsByFilterAction.
*/
interface PostFilter
{
/**
* The name of this filter, used for rendering the corresponding Fluid partial.
*/
public function getName(): string;

/**
* The title of the filter result, used in MetaTagService.
*/
public function getTitle(): string;

/**
* A description of the filter result, used in MetaTagService.
*/
public function getDescription(): string;

/**
* Apply current filter values in given Posts query.
*
* @return array<ComparisonInterface>
*/
public function getConstraints(QueryInterface $query): array;
}
13 changes: 13 additions & 0 deletions Classes/Domain/Repository/PostRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Psr\Http\Message\ServerRequestInterface;
use T3G\AgencyPack\Blog\Constants;
use T3G\AgencyPack\Blog\DataTransferObject\PostRepositoryDemand;
use T3G\AgencyPack\Blog\Domain\Filter\PostFilter;
use T3G\AgencyPack\Blog\Domain\Model\Author;
use T3G\AgencyPack\Blog\Domain\Model\Category;
use T3G\AgencyPack\Blog\Domain\Model\Post;
Expand Down Expand Up @@ -226,6 +227,18 @@ public function findAllByTag(Tag $tag): QueryResultInterface
return $query->matching($query->logicalAnd(...$constraints))->execute();
}

public function findAllByFilter(PostFilter $filter): QueryResultInterface
{
$query = $this->createQuery();
$constraints = array_merge($this->defaultConstraints, $filter->getConstraints($query));
$storagePidConstraint = $this->getStoragePidConstraint();
if ($storagePidConstraint instanceof ComparisonInterface) {
$constraints[] = $storagePidConstraint;
}

return $query->matching($query->logicalAnd(...$constraints))->execute();
}

public function findByMonthAndYear(int $year, int $month = null): QueryResultInterface
{
$query = $this->createQuery();
Expand Down
8 changes: 8 additions & 0 deletions Configuration/TCA/Overrides/tt_content.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@
);
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_excludelist']['blog_archive'] = 'select_key';

\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
'Blog',
'Filter',
'LLL:EXT:blog/Resources/Private/Language/locallang_db.xlf:plugin.blog_filter.title',
'plugin-blog-filter'
);
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_excludelist']['blog_filter'] = 'select_key';

\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
'Blog',
'Sidebar',
Expand Down
9 changes: 9 additions & 0 deletions Configuration/TsConfig/Page/Wizards.tsconfig
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ mod.wizards.newContentElement.wizardItems.blog {
list_type = blog_archive
}
}
blog_filter {
iconIdentifier = plugin-blog-filter
title = LLL:EXT:blog/Resources/Private/Language/locallang_db.xlf:plugin.blog_filter.title
description = LLL:EXT:blog/Resources/Private/Language/locallang_db.xlf:plugin.blog_filter.description
tt_content_defValues {
CType = list
list_type = blog_filter
}
}
blog_demandedposts {
iconIdentifier = plugin-blog-demandedposts
title = LLL:EXT:blog/Resources/Private/Language/locallang_db.xlf:plugin.blog_demandedposts.title
Expand Down
5 changes: 5 additions & 0 deletions Configuration/TypoScript/Static/setup.typoscript
Original file line number Diff line number Diff line change
Expand Up @@ -440,3 +440,8 @@ blog_rss_author < blog_rss_posts
blog_rss_author.typeNum = 250
blog_rss_author.10 < tt_content.list.20.blog_authorposts
blog_rss_author.10.format = rss

blog_rss_filter < blog_rss_posts
blog_rss_filter.typeNum = 260
blog_rss_filter.10 < tt_content.list.20.blog_filter
blog_rss_filter.10.format = rss
11 changes: 11 additions & 0 deletions Resources/Private/Language/locallang.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
<trans-unit id="headline.rssfeed" xml:space="preserve">
<source>RSS-Feeds</source>
</trans-unit>
<trans-unit id="headline.filter" xml:space="preserve">
<source>Filter</source>
</trans-unit>

<!-- Form -->
<trans-unit id="form.comment.name" xml:space="preserve">
Expand Down Expand Up @@ -210,6 +213,14 @@
<source>Show Archive</source>
</trans-unit>

<!-- Filter -->
<trans-unit id="filter.category.all" xml:space="preserve">
<source>All categories</source>
</trans-unit>
<trans-unit id="filter.tag.all" xml:space="preserve">
<source>All tags</source>
</trans-unit>

<!-- Backend -->
<trans-unit id="backend.headline.setup_wizard" xml:space="preserve">
<source>SetupWizard</source>
Expand Down
6 changes: 6 additions & 0 deletions Resources/Private/Language/locallang_db.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
<trans-unit id="plugin.blog_tag.description" xml:space="preserve">
<source>Allows the users to show all posts tagged with a specific keyword.</source>
</trans-unit>
<trans-unit id="plugin.blog_filter.title" xml:space="preserve">
<source>Blog: List by filter</source>
</trans-unit>
<trans-unit id="plugin.blog_filter.description" xml:space="preserve">
<source>Allows the users to show a list of filtered posts.</source>
</trans-unit>
<trans-unit id="plugin.blog_archive.title" xml:space="preserve">
<source>Blog: Archive</source>
</trans-unit>
Expand Down
Loading

0 comments on commit d3d7e33

Please sign in to comment.