From d55d3455b7e0714f228238fac11b732fe32e5acd Mon Sep 17 00:00:00 2001 From: Georgi Mateev <georgi.mateev@sgalinski.de> Date: Wed, 16 Oct 2024 18:19:55 +0300 Subject: [PATCH] [BUGFIX] Fix frontend filters --- Classes/Controller/VimeoController.php | 55 ++++++++++------ Classes/Filter/DurationFilter.php | 86 +++++--------------------- Classes/Filter/FilterInterface.php | 7 +++ Classes/Service/VimeoService.php | 54 ++++++++-------- README.md | 6 +- 5 files changed, 92 insertions(+), 116 deletions(-) diff --git a/Classes/Controller/VimeoController.php b/Classes/Controller/VimeoController.php index 8f565d2..d531076 100644 --- a/Classes/Controller/VimeoController.php +++ b/Classes/Controller/VimeoController.php @@ -80,15 +80,10 @@ class VimeoController extends ActionController { $vimeoParameters = [ 'id' => $id, - 'clientId' => $clientId, - 'clientSecret' => $clientSecret, - 'personalAccessToken' => $personalAccessToken, 'queryString' => $queryString, ]; - $filterIds = GeneralUtility::trimExplode(',', $filterIds); - $maxResultsWithFilters = (string) ($maxResults + count($filterIds)); // Get input values $elementId = $this->request->getAttribute('currentContentObject')->data['uid']; @@ -112,10 +107,13 @@ class VimeoController extends ActionController { // add Filter Values $vimeoParameters['filterValues'] = $filterValues; - $filterParameterBag =new FilterParameterBag($vimeoParameters,$filterInstances); + $filterParameterBag = new FilterParameterBag($vimeoParameters, $filterInstances); $vimeoService = GeneralUtility::makeInstance( VimeoService::class, + $clientId, + $clientSecret, + $personalAccessToken, $filterParameterBag, $this->cache ); @@ -126,6 +124,12 @@ class VimeoController extends ActionController { // Use the possibly modified parameters $response = $vimeoService->getVimeoData($filterParameterBag); + if (count($response['items']) < 1) { + $this->view->assignMultiple([ + 'notFound' => TRUE, + 'pluginContentData' => $this->request->getAttribute('currentContentObject')->data + ]); + } if ($response === NULL) { return $this->htmlResponse(); @@ -136,11 +140,11 @@ class VimeoController extends ActionController { } // Dispatch the AfterVimeoCallEvent - $afterYoutubeCallEvent = new AfterVimeoCallEvent($response); - $this->eventDispatcher->dispatch($afterYoutubeCallEvent); + $afterVimeoCallEvent = new AfterVimeoCallEvent($response); + $this->eventDispatcher->dispatch($afterVimeoCallEvent); // Use the possibly modified response - $response = $afterYoutubeCallEvent->getResponse(); + $response = $afterVimeoCallEvent->getResponse(); if (is_array($response['items'])) { $response['items'] = array_filter($response['items'], function ($item) use ($filterIds) { @@ -176,16 +180,8 @@ class VimeoController extends ActionController { * Just checks if the end of `link` is the same as `videoId`, and if not, it replaces `link`. * This is needed as a workaround so that glightbox can detect the video as a vimeo video correctly in the frontend. */ - $endOfLink = substr($item['link'], -strlen($item['videoId'])); - if (!((int) $endOfLink === $item['videoId'])) { - $item['link'] = strstr($item['link'], '.com/', TRUE) . '.com/' . $item['videoId']; - } + $this->fixVideoLink($item); - if (isset($item['embed']['html'])) { - $embedLink = []; - preg_match('/src="([^"]+)"/i', $item['embed']['html'], $embedLink); - $item['embedLink'] = html_entity_decode($embedLink[1]); - } } unset($item); @@ -275,6 +271,25 @@ class VimeoController extends ActionController { return $response; } + /** + * Fixes the embed Link format + * + * @param mixed $item + * @return array + */ + private function fixVideoLink(array &$item): void { + $endOfLink = substr($item['link'], -strlen($item['videoId'])); + if (!((int) $endOfLink === $item['videoId'])) { + $item['link'] = strstr($item['link'], '.com/', TRUE) . '.com/' . $item['videoId']; + } + + if (isset($item['embed']['html'])) { + $embedLink = []; + preg_match('/src="([^"]+)"/i', $item['embed']['html'], $embedLink); + $item['embedLink'] = html_entity_decode($embedLink[1]); + } + } + /** * Applies the filterIds setting from the plugin configuration * @@ -351,7 +366,9 @@ class VimeoController extends ActionController { if (class_exists($filterConfig['filterClass'])) { $specificFilterValues = $filterValues[$filterName] ?? []; - $filterInstance = GeneralUtility::makeInstance($filterConfig['filterClass'], $specificFilterValues, $filterConfig); + $filterInstance = GeneralUtility::makeInstance( + $filterConfig['filterClass'], $specificFilterValues, $filterConfig + ); // Register filter to modify the request before API call $filterInstance->setFilterValues($specificFilterValues); diff --git a/Classes/Filter/DurationFilter.php b/Classes/Filter/DurationFilter.php index ec90e4f..99f7abf 100644 --- a/Classes/Filter/DurationFilter.php +++ b/Classes/Filter/DurationFilter.php @@ -50,16 +50,8 @@ class DurationFilter implements FilterInterface { */ public function modifyRequest(array &$parameters): void { $this->originalParameters = $parameters; - if (isset($this->filterValues['duration']) && !empty($this->filterValues['duration'])) { - if ($this->filterValues['duration'] === "1") { - $parameters['min_duration'] = 0; - $parameters['max_duration'] = 5*60; - } - - if ($this->filterValues['duration'] === "2") { - $parameters['min_duration'] = 5*60; - } - } + $parameters['fields'] .= ',duration'; + $parameters['per_page'] = 100; } /** @@ -67,76 +59,28 @@ class DurationFilter implements FilterInterface { * In this case, we won't filter the results, as we're modifying the query. */ public function modifyResponse(array &$data): void { - if (!(isset($this->filterValues['duration']) && !empty($this->filterValues['duration']))) { - return; - } - - $youTubeService = GeneralUtility::makeInstance(YoutubeService::class); - - $count = 0; - $filteredItems = []; - foreach ($data['items'] as $key => $videoData) { - if ($count === (int) $this->originalParameters['maxResults']) { - break; - } - - $videoId = ''; - if (isset($videoData['snippet']['resourceId']['videoId'])) { - $videoId = trim($videoData['snippet']['resourceId']['videoId']); - } + $counter = 0; + if (isset($this->filterValues['duration']) && !empty($this->filterValues['duration'])) { + foreach ($data['items'] as $key => $item) { + $counter++; - if (!$videoId && isset($videoData['id'])) { - $videoId = $videoData['id']['videoId'] ?? $videoData['id']; - // This is a check, because the $videoData['id'] can be a whole sub-channel-id. - if (is_array($videoId)) { - continue; + if ($counter >= $this->originalParameters['per_page']) { + break; } - $videoId = trim($videoId); - } - - if (!$videoId) { - continue; - } - - $params = $this->originalParameters; - $params['id'] = $videoId; - $url = $youTubeService->getApiUrl($params, []); - $url = str_replace('snippet', 'contentDetails', $url); - - $shouldInclude = FALSE; - try { - $result = $youTubeService->getJsonAsArray(new FilterParameterBag([ - 'id' => '', - 'maxResults' => '10', - 'key' => $this->originalParameters['key'], - 'url' => $url - ])); - - - if (isset($result['items'][0]['contentDetails']['duration'])) { - $durationSeconds = $this->youtubeDurationToSeconds( - $result['items'][0]['contentDetails']['duration'] - ); - if ($this->filterValues['duration'] === "1" && $durationSeconds <= 5 * 60) { - $shouldInclude = TRUE; + if ($this->filterValues['duration'] === "1") { + if ($item['duration'] > 1*60) { + unset($data['items'][$key]); } + } - if ($this->filterValues['duration'] === "2" && $durationSeconds > 5 * 60) { - $shouldInclude = TRUE; + if ($this->filterValues['duration'] === "2") { + if ($item['duration'] <= 1*60) { + unset($data['items'][$key]); } } - } catch (Exception $exception) { - // No duration data found - } - - if ($shouldInclude) { - $filteredItems[] = $videoData; - $count++; } } - - $data['items'] = $filteredItems; } public function getFilterValues(): array { diff --git a/Classes/Filter/FilterInterface.php b/Classes/Filter/FilterInterface.php index a00aa0a..33fc370 100644 --- a/Classes/Filter/FilterInterface.php +++ b/Classes/Filter/FilterInterface.php @@ -44,4 +44,11 @@ interface FilterInterface { * @return void */ public function modifyRequest(array &$parameters): void; + + /** + * Returns the filter values + * + * @return array + */ + public function getFilterValues(): array; } diff --git a/Classes/Service/VimeoService.php b/Classes/Service/VimeoService.php index ad8865e..8fa0fd0 100644 --- a/Classes/Service/VimeoService.php +++ b/Classes/Service/VimeoService.php @@ -100,14 +100,16 @@ class VimeoService implements LoggerAwareInterface { * @param string $clientId * @param string $clientSecret * @param string $personalAccessToken + * @param FilterParameterBag $filterParameterBag + * @param FrontendInterface $cache */ public function __construct( + string $clientId, + string $clientSecret, + string $personalAccessToken, FilterParameterBag $filterParameterBag, FrontendInterface $cache ) { - $clientId = $filterParameterBag->get('clientId'); - $clientSecret = $filterParameterBag->get('clientSecret'); - $personalAccessToken = $filterParameterBag->get('personalAccessToken'); $this->vimeoApiClient = new Vimeo($clientId, $clientSecret, $personalAccessToken); // We only need to request an unauthenticated token, if there is no personal access token provided already. // An authenticated access token with the public scope is identical to an unauthenticated access token, @@ -134,9 +136,15 @@ class VimeoService implements LoggerAwareInterface { $parameterBag->set('query', $queryString); } + $filterValues = []; + foreach ($filters as $filter) { + $filterValues[] = $filter->getFilterValues(); + } + $filtersHash = md5(json_encode($filterValues)); + $response = []; $this->maxResultsPerPage = $maxResults; - $cacheKey = 'sg_vimeo' . sha1($vimeoId . $maxResults . $queryString); + $cacheKey = 'sg_vimeo' . sha1($vimeoId . $maxResults . $queryString . $filtersHash); $disableVimeoCache = (bool) GeneralUtility::_GP('disableVimeoCache'); if (!$disableVimeoCache) { $cachedResult = $this->cache->get($cacheKey); @@ -145,8 +153,6 @@ class VimeoService implements LoggerAwareInterface { } } - - if (str_starts_with($vimeoId, 'showcase')) { $showcaseId = explode('/', $vimeoId)[1]; $response['items'] = $this->addVideoIdsToResponse($this->getShowcaseVideos((int) $showcaseId, $parameterBag)); @@ -164,7 +170,6 @@ class VimeoService implements LoggerAwareInterface { $filter->modifyResponse($response); } - if (!$disableVimeoCache) { $this->cache->set($cacheKey, $response, [], self::CACHE_LIFETIME_IN_SECONDS); } @@ -233,7 +238,7 @@ class VimeoService implements LoggerAwareInterface { $this->amountOfVideosFetched += $amountOfVideosInResponse; $this->paginatedResponseData[] = $response['body']['data']; $nextUrl = $response['body']['paging']['next']; - if ($this->amountOfVideosFetched === $this->maxResultsPerPage || $nextUrl === NULL) { + if ($this->amountOfVideosFetched >= $this->maxResultsPerPage || $nextUrl === NULL) { // return flattened array here, so that we don't end up with one sub array per pagination page return array_merge(...$this->paginatedResponseData); } @@ -270,14 +275,13 @@ class VimeoService implements LoggerAwareInterface { // use field filtering, to save on quota, see: https://developer.vimeo.com/guidelines/rate-limiting $fieldsToSelect = 'uri,name,description,link,embed,pictures,release_time,width,height'; - $filterParameterBag->set('fieldsToSelect', $fieldsToSelect); + $parameters = []; + $parameters['fields'] = $fieldsToSelect; foreach ($filterParameterBag->getFilterInstances() as $filter) { - $filter->modifyRequest($filterParameterBag->all()); + $filter->modifyRequest($parameters); } - $parameters = $filterParameterBag->all(); - $query = http_build_query($parameters); try { @@ -301,16 +305,16 @@ class VimeoService implements LoggerAwareInterface { // use field filtering, to save on quota, see: https://developer.vimeo.com/guidelines/rate-limiting $fieldsToSelect = 'uri,name,description,link,embed,pictures,release_time,width,height'; - $filterParameterBag->set('fieldsToSelect', $fieldsToSelect); - $filterParameterBag->set('sort', 'default'); - $filterParameterBag->set('per_page', $this->maxResultsPerPage); + $parameters = [ + 'fields' => $fieldsToSelect, + 'sort' => 'default', + 'per_page' => $this->maxResultsPerPage + ]; foreach ($filterParameterBag->getFilterInstances() as $filter) { - $filter->modifyRequest($filterParameterBag->all()); + $filter->modifyRequest($parameters); } - $parameters = $filterParameterBag->all(); - $query = http_build_query($parameters); try { @@ -337,17 +341,17 @@ class VimeoService implements LoggerAwareInterface { public function getShowcaseVideos(string $showcaseId, FilterParameterBag $filterParameterBag): ?array { // use field filtering, to save on quota, see: https://developer.vimeo.com/guidelines/rate-limiting $fieldsToSelect = 'uri,name,description,link,embed,pictures,release_time,width,height'; - $filterParameterBag->set('fieldsToSelect', $fieldsToSelect); - // sort videos by the user-selected default: ?sort=default - $filterParameterBag->set('sort', 'default'); - $filterParameterBag->set('per_page', $this->maxResultsPerPage); + + $parameters = [ + 'fields' => $fieldsToSelect, + 'sort' => 'default', + 'per_page' => $this->maxResultsPerPage + ]; foreach ($filterParameterBag->getFilterInstances() as $filter) { - $filter->modifyRequest($filterParameterBag->all()); + $filter->modifyRequest($parameters); } - $parameters = $filterParameterBag->all(); - $query = http_build_query($parameters); try { diff --git a/README.md b/README.md index 3a06f7f..1e18240 100644 --- a/README.md +++ b/README.md @@ -316,7 +316,11 @@ Once it runs it will create the file and we can commit the new version and use i 2. Add a new content element and select the Vimeo plugin from the list. 3. Provide the necessary Vimeo details in the plugin settings (like Vimeo API key, video/channel/playlist ID, max results, etc.). -### **Step 2: Configuring Filters via FlexForm** +### **Step 2: Disable caching for the extension** +1. In the TYPO3 backend, go to Settings -> Extensions and open the sg_vimeo settings. Tick the box that says 'uncached' and save. +2. This way the the extension will not cache the results and the the data will be loaded dynamically based on the filter settings + +### **Step 3: Configuring Filters via FlexForm** 1. In the plugin's FlexForm settings, you will see a section for "Filters." 2. Depending on your site configuration, filters will be available in a select field. You can select the filters you want to display (like search term, video duration, etc.). 3. Save your settings and publish the page. -- GitLab