Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/test' into test
Browse files Browse the repository at this point in the history
  • Loading branch information
thomas-sc committed Feb 26, 2025
2 parents c9b7d74 + f7daa1b commit 7ea57ae
Show file tree
Hide file tree
Showing 19 changed files with 337 additions and 77 deletions.
16 changes: 16 additions & 0 deletions Classes/Common/PageTitleProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);

namespace Slub\LisztCommon\Common;


use TYPO3\CMS\Core\PageTitle\AbstractPageTitleProvider;


final class PageTitleProvider extends AbstractPageTitleProvider
{
public function setTitle(string $title): void
{
$this->title = $title;
}
}
181 changes: 126 additions & 55 deletions Classes/Controller/SearchController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,90 +12,104 @@
use TYPO3\CMS\Core\Utility\GeneralUtility;
use Elastic\Elasticsearch\Exception\ClientResponseException;
use Elastic\Transport\Exception\RuntimeException;

// ToDo:
// Organize the transfer of the necessary parameters (index name, fields, etc.) from the other extensions (ExtensionConfiguration?) -> see in ElasticSearchServic
// Elastic Search Index return standardized fields? Standardized search fields or own params from the respective extension?
// process search parameters from the URL query parameters to search
use TYPO3\CMS\Core\MetaTag\MetaTagManagerRegistry;
use Slub\LisztCommon\Common\PageTitleProvider;
use TYPO3\CMS\Core\Page\AssetCollector;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;

final class SearchController extends ClientEnabledController
{
// set resultLimit as intern variable from $this->settings['resultLimit'];
protected int $resultLimit;
private FrontendInterface $runtimeCache;


// Dependency Injection of Repository
// https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/DependencyInjection/Index.html#Dependency-Injection

public function __construct(
private readonly ElasticSearchServiceInterface $elasticSearchService,
protected ExtensionConfiguration $extConf
)
{
protected ExtensionConfiguration $extConf,
private readonly PageTitleProvider $titleProvider,
private readonly AssetCollector $assetCollector,
CacheManager $cacheManager,
) {
$this->resultLimit = $this->settings['resultLimit'] ?? 25;
$this->runtimeCache = $cacheManager->getCache('runtime');
}

public function indexAction(array $searchParams = []): ResponseInterface
{
$language = $this->request->getAttribute('language');
$locale = $language->getLocale();
if (
isset($searchParams['page']) &&
(int) $searchParams['page'] > 0
) {
$currentPage = (int) $searchParams['page'];
} else {
$currentPage = 1;
}

// $totalItems = $this->elasticSearchService->count($searchParams, $this->settings);
//$totalItems = 100;
$locale = $this->request->getAttribute('language')->getLocale();
$currentPage = $this->getCurrentPage($searchParams);
$this->addViewTransitionStyle();

$elasticResponse = $this->elasticSearchService->search($searchParams, $this->settings);
$paginator = (new Paginator())->
setPage($currentPage)->
setTotalItems($elasticResponse['hits']['total']['value'])->
setExtensionConfiguration($this->extConf);
$pagination = $paginator->getPagination();
$showPagination = $paginator->getTotalPages() > 1 ? true : false;

$this->view->assign('locale', $locale);
$this->view->assign('totalItems', $elasticResponse['hits']['total']['value']);
$this->view->assign('searchParams', $searchParams);
$this->view->assign('searchResults', $elasticResponse);
$this->view->assign('pagination', $pagination);
$this->view->assign('showPagination', $showPagination);
// $this->view->assign('totalItems', $totalItems);
$this->view->assign('currentString', Paginator::CURRENT_PAGE);
$this->view->assign('dots', Paginator::DOTS);
$this->view->assign('detailPageId', $this->extConf->get('liszt_common','detailPageId'));
$totalItems = 0;
if (isset($elasticResponse['hits'], $elasticResponse['hits']['total'], $elasticResponse['hits']['total']['value'])) {
$totalItems = (int)$elasticResponse['hits']['total']['value'];
}

$paginator = (new Paginator())
->setPage($currentPage)
->setTotalItems($totalItems)
->setExtensionConfiguration($this->extConf);
$pagination = $paginator->getPagination();
$showPagination = $paginator->getTotalPages() > 1;

$this->view->assignMultiple([
'locale' => $locale,
'totalItems' => $totalItems,
'searchParams' => $searchParams,
'searchResults' => $elasticResponse,
'pagination' => $pagination,
'showPagination'=> $showPagination,
'currentString' => Paginator::CURRENT_PAGE,
'dots' => Paginator::DOTS,
'detailPageId' => $this->extConf->get('liszt_common', 'detailPageId'),
]);

return $this->htmlResponse();
}


public function searchBarAction(array $searchParams = []): ResponseInterface
{
$this->view->assign('searchParams', $searchParams);
return $this->htmlResponse();
}

public function detailsAction(array $searchParams = []): ResponseInterface

public function detailsHeaderAction(array $searchParams = []): ResponseInterface
{
$documentId = $this->getDocumentIdFromRouting();
if (!$documentId) {
return $this->redirectToNotFoundPage();
}

try {
$elasticResponse = $this->loadDetailPageFromElastic($documentId);
} catch (ClientResponseException $e) {
if ($e->getCode() === 404) {
return $this->redirectToNotFoundPage();
}
throw $e;
}

$this->view->assign('searchResult', $elasticResponse);
return $this->htmlResponse();
}

$routing = $this->request->getAttribute('routing');
$routingArgs = $routing->getArguments();

// Check if 'tx_lisztcommon_searchdetails' exists and if 'detailId' has a valid value.
$documentId = null;
if (!empty($routingArgs['tx_lisztcommon_searchdetails']['documentId'])) {
$documentId = $routingArgs['tx_lisztcommon_searchdetails']['documentId'];
} else {
public function detailsAction(array $searchParams = []): ResponseInterface
{
$documentId = $this->getDocumentIdFromRouting();
if (!$documentId) {
return $this->redirectToNotFoundPage();
}

try {
$elasticResponse = $this->elasticSearchService->getDocumentById($documentId, []);
$elasticResponse = $this->loadDetailPageFromElastic($documentId);
} catch (ClientResponseException $e) {
// Handle 404 errors
if ($e->getCode() === 404) {
Expand All @@ -105,25 +119,82 @@ public function detailsAction(array $searchParams = []): ResponseInterface

}

$this->view->assign('searchParams', $searchParams);
$this->view->assign('routingArgs', $routingArgs);
$this->view->assign('detailId', $documentId);
$this->view->assign('searchResult', $elasticResponse);
$this->view->assign('detailPageId', $this->extConf->get('liszt_common','detailPageId'));
// set page title
$pageTitle = $this->formatPageTitle($elasticResponse['_source']['title'] ?? 'Details');
$this->titleProvider->setTitle($pageTitle);

// set meta description
$metaDescription = '';
if (isset($elasticResponse['_source'], $elasticResponse['_source']['tx_lisztcommon_searchable'])) {
$metaDescription = (string)$elasticResponse['_source']['tx_lisztcommon_searchable'];
}
$metaTagManager = GeneralUtility::makeInstance(MetaTagManagerRegistry::class)
->getManagerForProperty('description');
$metaTagManager->addProperty('description', $metaDescription);

$this->addViewTransitionStyle();

$this->view->assignMultiple([
'searchParams' => $searchParams,
'routingArgs' => $this->request->getAttribute('routing')->getArguments(),
'detailId' => $documentId,
'searchResult' => $elasticResponse,
'detailPageId' => $this->extConf->get('liszt_common', 'detailPageId'),
]);

return $this->htmlResponse();
}

private function getCurrentPage(array $params): int
{
return (isset($params['page']) && (int)$params['page'] > 0) ? (int)$params['page'] : 1;
}


// add view transition styles as inline style for animation
private function addViewTransitionStyle(): void
{
$this->assetCollector->addInlineStyleSheet(
'view-transitions-root',
'@media screen and (prefers-reduced-motion: no-preference) { @view-transition { navigation: auto; } }'
);
}

private function getDocumentIdFromRouting(): ?string
{
$routingArgs = $this->request->getAttribute('routing')->getArguments();
return $routingArgs['tx_lisztcommon_searchdetails']['documentId'] ?? null;
}

private function formatPageTitle(string $title): string
{
$maxTitleLength = 50;
return (mb_strlen($title) > $maxTitleLength)
? mb_substr($title, 0, $maxTitleLength - 3) . '...'
: $title;
}

private function loadDetailPageFromElastic(string $documentId): Collection
{
$cachedResult = $this->runtimeCache->get($documentId);
if (!$cachedResult instanceof Collection) {
$result = $this->elasticSearchService->getDocumentById($documentId, []);
if (!$result instanceof Collection) {
throw new \UnexpectedValueException("The return value of getDocumentById does not correspond to the expected collection type."); }
$this->runtimeCache->set($documentId, $result);
return $result;
}
return $cachedResult;
}



public function redirectToNotFoundPage(): ResponseInterface
{
// see: https://docs.typo3.org/m/typo3/reference-coreapi/12.4/en-us/ExtensionArchitecture/Extbase/Reference/Controller/ActionController.html
// see: https://docs.typo3.org/m/typo3/reference-coreapi/12.4/en-us/ExtensionArchitecture/Extbase/Reference/Controller/ActionController.html
// $uri could also be https://example.com/any/uri
// $this->resourceFactory is injected as part of the `ActionController` inheritance
return $this->responseFactory->createResponse(301)
->withHeader('Location', '/404/'); // the uri of the 404 page from typo installation
}

}
25 changes: 25 additions & 0 deletions Classes/Event/Listener/SiteConfigurationLoadedEventListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Slub\LisztCommon\Event\Listener;

use TYPO3\CMS\Core\Configuration\Event\SiteConfigurationLoadedEvent;
use TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader;
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
* Event to modify the site configuration array before loading the configuration
*/
final class SiteConfigurationLoadedEventListener
{

public function modify(SiteConfigurationLoadedEvent $event): void
{
$configuration = $event->getConfiguration();
$fileLoader = GeneralUtility::makeInstance(YamlFileLoader::class);
$routeEnhancersConfiguration = $fileLoader->load('EXT:liszt_common/Configuration/Routing/routeEnhancers.yaml');
ArrayUtility::mergeRecursiveWithOverrule($configuration, $routeEnhancersConfiguration);
$event->setConfiguration($configuration);
}

}
23 changes: 23 additions & 0 deletions Classes/ViewHelpers/GetDetailBreadCrumbArrayViewHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);

namespace Slub\LisztCommon\ViewHelpers;

use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;

class GetDetailBreadCrumbArrayViewHelper extends AbstractViewHelper
{

public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext)
: ?array
{

$request = $renderingContext->getRequest();$frontendController = $request->getAttribute('frontend.controller');
$rootline = $frontendController->rootLine;
return array_reverse($rootline);
}
}
File renamed without changes.
9 changes: 9 additions & 0 deletions Configuration/Services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,14 @@ services:
Slub\LisztCommon\:
resource: '../Classes/*'
exclude: '../Classes/Domain/Model/*'
Slub\LisztCommon\Event\Listener\SiteConfigurationLoadedEventListener:
tags:
- name: event.listener
method: modify
identifier: 'ext-lisztcommon/site-configuration-loaded'
event: TYPO3\CMS\Core\Configuration\Event\SiteConfigurationLoadedEvent



# if more than one! class implement the same interface (i.e.Search Interface) read: https://usetypo3.com/dependency-injection/
# and https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/DependencyInjection/Index.html
7 changes: 7 additions & 0 deletions Configuration/TCA/Overrides/tt_content.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@
'Liszt Search Details'
);


ExtensionUtility::registerPlugin(
'liszt_common',
'SearchDetailsHeader',
'Liszt Search Details Header'
);

// Adds the content element to the "Type" dropdown
ExtensionManagementUtility::addTcaSelectItem(
'tt_content',
Expand Down
8 changes: 0 additions & 8 deletions Configuration/TypoScript/constants.typoscript
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,4 @@
}*/


/*
plugin.tx_liszt_common {
view {
templateRootPath = EXT:liszt_common/Resources/Private/Templates/
partialRootPath = EXT:liszt_common/Resources/Private/Partials/
layoutRootPath = EXT:liszt_common/Resources/Private/Layouts/

}
}*/
Loading

0 comments on commit 7ea57ae

Please sign in to comment.