I am having trouble with my Extbase-Plugin, redirects and route enhancers:
I have a plugin that gets job offers via an API and displays as a list on a Typo3-page. I have written a route enhancer to make the URLs for the single job offers pretty.
If a user clicks on a link, the method "showJob" from the controller is called. This method redirects the user to a different page (I do need two distinct pages for this) and calls the method "showSingleJob".
I have written this redirect like this:
{
$currentPid = $GLOBALS['TSFE']->id;
$jobID = $this->request->getArgument('jobID');
$jobTitle = $this->request->getArgument('jobTitle');
$pageID = $this->request->getArgument('pageID');
$args = [
'jobID' => $jobID,
'jobTitle' => $jobTitle,
"pageID" => $pageID
];
$response = json_decode($this->curl_get_contents('https://api.jobsAPI.com/job/' . $jobID));
if ($pageID != $currentPid) {
$uriBuilder = $this->uriBuilder;
$uri = $uriBuilder
->reset()
->setTargetPageUid(intval($pageID))
->setAddQueryString(TRUE)
->uriFor('showSingleJob', $args, 'UmJobs', 'UmJobs', 'jobliste');
$this->redirectToUri($uri, 0, 404);
}
$this->view->assign('apiJob', $response);
}
The method "showSingleJob" simply gets the data for the desired job and displays it. This works just fine.
But I need pretty urls for the redirected page. At the moment I get my typo3-Url plus all the parameters I am passing. So I tried my hand at a route enhancer:
routeEnhancers:
UmJobs:
type: Extbase
limitToPages:
- 1
- 3
extension: UmJobs
plugin: jobliste
routes:
- routePath: '/karriere/'
_controller: 'UmJobs::list'
- routePath: '/karriere/{jobTitle}/{jobID}/{pageID}'
_controller: 'UmJobs::showJob'
_arguments:
jobTitle: jobTitle
jobID: jobID
pageID: pageID
defaultController: 'UmJobs::showJob'
- routePath: '/karriere/job/{jobTitle}/{jobID}/{pageID}'
_controller: 'UmJobs::showSingleJob'
_arguments:
jobTitle: jobTitle
jobID: jobID
pageID: pageID
defaultController: 'UmJobs::showSingleJob'
requirements:
jobID: '^[0-9].*$'
pageID: '^[0-9].*$'
jobTitle: '^[a-zA-Z0-9].*$'
Again this works fine for "showJobs" but It doens't work at all for "showSingleJobs". It seems as if the enhancer is completely ingored by $uribuilder.
Anyone have an idea what I am doing wrong?
Thanks a lot in advance!
Seems to me as if your URIs are not unique...
'UmJobs::showJob
routePath: '/karriere/{jobTitle}/{jobID}/{pageID}'
Now lets the values be:
jobTitle = job // Matching the requirement '^[a-zA-Z0-9].*$'
jobID = 123 // Matching the requirement '^[0-9].*$'
pageID = 987 // Matching the requirement '^[0-9].*$'
The path would be: /karriere/job/123/987
'UmJobs::showSingleJob
routePath: '/karriere/job/{jobTitle}/{jobID}/{pageID}'
Now lets the values be:
jobTitle = 123 // Matching the requirement '^[a-zA-Z0-9].*$'
jobID = 987 // Matching the requirement '^[0-9].*$'
pageID = '' // Matching the requirement '^[0-9].*$'
The path would be: /karriere/job/123/987
Conclusion
You can have the same URI for different actions - which can not be served.
Related
I'm using the ArrayPaginator for my Extbase list view, since Fluid widget functionality will no longer be available in TYPO3 v11.
And I'm currently trying to use the RouteEnhancer with this.
My list action just receives the argument for the current page as integer.
And the code for the RouteEnhancer looks like this:
RefList:
type: Extbase
limitToPages:
- 142
extension: Ref
plugin: Pi2
routes:
-
routePath: /seite-{page}
_controller: 'Ref::list'
_arguments:
page: currentPage
defaultController: 'Ref::list'
requirements:
page: \d+
aspects:
page:
type: StaticRangeMapper
start: '1'
end: '1000'
I've seen a lot examples for the Fluid pagination widget that contained the value #widget_0/currentPage for the argument page.
The URL is generated correctly if I switch to another page but the content displayed from the list view is still the same as on page 1.
What am I missing here?
You can us a QueryResultPaginator instead of a ArrayPaginator.
Route
routeEnhancers:
RefList:
type: Extbase
extension: Ref
plugin: Pi2
routes:
- routePath: '/'
_controller: 'Ref::list'
- routePath: '/{page}'
_controller: 'Ref::list'
_arguments:
page: current-page
defaultController: 'Ref::list'
aspects:
current-page:
type: StaticRangeMapper
start: '1'
end: '100'
RefController.php Get current-page from request
public function listAction()
{
$refs = $this->refRepository->findAll();
$currentPage = $this->request->hasArgument('current-page') ? $this->request->getArgument('current-page') : 1;
$paginatedRefs = new QueryResultPaginator($refs, $currentPage, $this->itemsPerPage);
$simplePagination = new SimplePagination($paginatedRefs);
$pagination = $this->buildSimplePagination($simplePagination, $paginatedRefs);
$this->view->assignMultiple([
'refs' => $paginatedRefs,
'pagination' => $pagination,
]);
}
/**
* Build simple pagination
*
* #param SimplePagination $simplePagination
* #param QueryResultPaginator $paginator
* #return array
*/
protected function buildSimplePagination(SimplePagination $simplePagination, QueryResultPaginator $paginator): array
{
$firstPage = $simplePagination->getFirstPageNumber();
$lastPage = $simplePagination->getLastPageNumber();
return [
'lastPageNumber' => $lastPage,
'firstPageNumber' => $firstPage,
'nextPageNumber' => $simplePagination->getNextPageNumber(),
'previousPageNumber' => $simplePagination->getPreviousPageNumber(),
'startRecordNumber' => $simplePagination->getStartRecordNumber(),
'endRecordNumber' => $simplePagination->getEndRecordNumber(),
'currentPageNumber' => $paginator->getCurrentPageNumber(),
'pages' => range($firstPage, $lastPage)
];
}
List.html add pagination template
<f:for each="{refs.paginatedItems}" as="ref">
<f:render partial="List/ListItem" arguments="{ref: ref}" />
</f:for>
<f:render partial="List/Pagination" arguments="{pagination:pagination, action:'list'}" />
Partial List/Pagination.html
add links for pagination: previous
<f:link.action action="{action}" arguments="{current-page:pagination.previousPageNumber}">previous</f:link.action>
add links for pagination: pages
<f:link.action action="{action}" arguments="{current-page:page}">{page}</f:link.action>
add links for pagination: next
<f:link.action action="{action}" arguments="{current-page: pagination.nextPageNumber}">next</f:link.action>
I've found a workaround.
Inside the controller list action: $currentPage = (int) ($_GET['tx_ref_pi2']['currentPage'] ?? 1);
I was searching all night on how to generate sitemap for tt_address records and coudn't find anything…… anyone knows how to generate it?
I also use route enhancers, is there a way to beautify my sitemap by using the slugs instead of the those long controllers, IDs, etc URLs?
so after reading and tweaking I came up with a working solution:
tx_seo.config.xmlSitemap.sitemaps {
addresses {
provider = TYPO3\CMS\Seo\XmlSitemap\RecordsXmlSitemapDataProvider
config {
table = tt_address
sortField = sorting
lastModifiedField = tstamp
### ID of address storage records ###
pid = 13
recursive = 2
url {
### ID of detail view page ###
pageId = 18
fieldToParameterMap {
uid = tx_ttaddress_listview[address]
}
additionalGetParameters {
tx_ttaddress_listview.controller = Address
tx_ttaddress_listview.action = show
}
useCacheHash = 1
}
}
}
}
and the routeenhancer is:
routeEnhancers:
AddressPlugin:
type: Extbase
extension: TtAddress
plugin: ListView
routes:
-
routePath: /
_controller: 'Address::list'
-
routePath: '/{address_slug}'
_controller: 'Address::show'
_arguments:
address_slug: address
aspects:
address_slug:
type: PersistedAliasMapper
tableName: tt_address
routeFieldName: slug
I have the following route enhancer configuration which is working so far:
routeEnhancers:
Plugin:
type: Extbase
extension: Plugin
plugin: Plugin
routes:
- { routePath: '/test/{var1}', _controller: 'ContactPerson::list', _arguments: { 'var1': '#widget_0/var1' } }
defaultController: 'Plugin::list'
defaults:
var1: 'a'
requirements:
var1: '[a-z]'
The problem I am facing is that my widget has two arguments (get variables), the second one is optional. So I changed the route enhancer to this:
routeEnhancers:
Plugin:
type: Extbase
extension: Plugin
plugin: Plugin
routes:
- { routePath: '/test/{var1}/{var2}', _controller: 'ContactPerson::list', _arguments: { 'var1': '#widget_0/var1' , 'var2': '#widget_0/var2' } }
defaultController: 'Plugin::list'
defaults:
var1: 'a'
var2: ''
requirements:
var1: '[a-z]'
var2: '[a-z]'
Unfortunately this does not work and my route is not recognized at all anymore.
Your var2 default does not match the requirements. Thus when resolving an URL there is no match with your routeEnhancer.
It should be
defaults:
var1: 'a'
var2: ''
requirements:
var1: '[a-z]'
var2: '[a-z]*'
I used the example verbatim from the Changelog:
The only thing I changed was the limitToPages.
routeEnhancers:
NewsPlugin:
type: Extbase
limitToPages: [82]
extension: News
plugin: Pi1
routes:
- { routePath: '/{news_title}', _controller: 'News::detail', _arguments: {'news_title': 'news'} }
defaultController: 'News::detail'
aspects:
news_title:
type: PersistedAliasMapper
tableName: 'tx_news_domain_model_news'
routeFieldName: 'path_segment'
routeValuePrefix: '/'
This throws an exception in 9.5.4:
Symfony\Component\Routing\Exception\InvalidParameterException
Parameter "tx_news_pi1__news" for route "tx_news_pi1_0" must match "[^/]++" ("" given) to generate a corresponding URL.
in /var/www/example/htdocs/typo3_src-9.5.4/vendor/symfony/routing/Generator/UrlGenerator.php line 155
at Symfony\Component\Routing\Generator\UrlGenerator->doGenerate(array('tx_news_pi1__news' => 0), array('_controller' => 'News::detail'), array(), array(array('variable', '/', '[^/]++', 'tx_news_pi1__news', true), array('text', '/aktuelles/artikel')), array('tx_news_pi1__news' => ''), 'tx_news_pi1_0', 1, array(), array())
in /var/www/example/htdocs/typo3_src-9.5.4/vendor/symfony/routing/Generator/UrlGenerator.php line 128
Currently, no other route enhancers exist. But I successfully used a simpler configuration on that exact same page and that worked:
NewsDetail:
type: Extbase
limitToPages: [82]
extension: News
plugin: Pi1
routes:
- { routePath: '/{news_id}', _controller: 'News::detail', _arguments: {'news_id': 'news'} }
Not sure where to look and how best to troubleshoot. I was hoping someone had similar problem or could point me in the right direction.
Check if empty path_segment is the problem here:
select count(*) from tx_news_domain_model_news where path_segment='';
Fix
If there are news entry with empty titles, you may want to remove these or update the title first.
Run update wizard: "Updates slug field "path_segment" of EXT:news records" (you may have to mark it as "undone" in Upgrade Wizard first (BE: Upgrade > Upgrade Wizard > Run Upgrade Wizard)
Or manually set tx_news_domain_model_news.path_segment
Same problem for me, the problem was because 'path_segment' generated with Install Tool Wizard had a slash, like : "the-path/another-segment"
The solution is to check for slash in 'path_segment' and replace them with another symbol, request like this :
SELECT uid, pid, path_segment, title FROM tx_news_domain_model_news WHERE path_segment LIKE "%/%";
and change path_segment like that : "the-path_another-segment"
I am struggling with the URL generation of TYPO3 in my own extension.
Site Config:
routeEnhancers:
JobsPlugin:
type: Extbase
limitToPages: [11]
extension: Company
plugin: Jobs
routes:
- { routePath: '/{job_title}', _controller: 'Jobs::job', _arguments: {'job_title': 'id'} }
defaultController: 'Jobs::job'
requirements:
job_title: '[0-9]{1..6}'
aspects:
job_title:
type: PersistedAliasMapper
tableName: 'tx_company_domain_model_job'
routeFieldName: 'path_segment'
routeValuePrefix: '/'
Controller:
/**
* #param int $id
*/
public function jobAction(int $id) { }
Problem
The generated URL looks fine: /de/karriere/technischen-verkaufsberaterin-aussendienst
But when you want to access the page a PageNotFoundException is thrown.
Do I need to make any additional configurations or did I configure anything wrong?
Thanks in advance!
The problem was routeValuePrefix.
After I removed it, the URL could be resolved.
I assume, that this leads to a double slash when resolving: /de/karriere//technischen-verkaufsberaterin-aussendienst