Search code examples
routestypo3tx-newstypo3-9.x

TYPO3 9: add date to URL routing enhancers for news extension


For the detail pages of tx_news records as well as a calendar extension I wrote myself I want the record date in the URL as I had it until TYPO3 8LTS with the realURL extension: /path-to/my-page/yyyy/mm/dd/extension-record-path-segment/. I managed to have the link created but with the cHash attached.

My routeEnhancers settings for the tx_news_pi1 in /typo3conf/sites/my-site/config.yaml are as follows:

routeEnhancers:
  NewsPlugin:
    type: Extbase
    limitToPages: [7]
    extension: News
    plugin: Pi1
    routes:
      - { routePath: '/{year}/{month}/{day}/{news}', _controller: 'News::detail' }
    defaultController: 'News::detail'
    requirements:
      year: '^20[0-9]{2}$'
      month: '^[01][0-9]$'
      day: '^[0-3][0-9]$'
    aspects:
      news:
        type: PersistedAliasMapper
        tableName: 'tx_news_domain_model_news'
        routeFieldName: 'path_segment'

I added the requirements section with quite strict regular expressions because the description in the T3 changelog mentions this as needed in order to avoid the cHash.

I also tried using StaticRangeMappers in the aspects section for year, month, and day (as described in this answer) but that results in the PersistedAliasMapper being ignored and showing the UID of the news record instead. Or sometimes even in a TYPO3 exception (1/1) #1537696772 OverflowException: Possible range of all mappers is larger than 10000 items (it even did so when I removed them for month and day and set the range for year to only 2016–2019).

      year:
        type: StaticRangeMapper
        start: '2016'
        end: '2100'
      month:
        type: StaticRangeMapper
        start: '01'
        end: '12'
      day:
        type: StaticRangeMapper
        start: '01'
        end: '31'
      event:
        type: PersistedAliasMapper
        tableName: 'tx_thesimplecal_domain_model_events'
        routeFieldName: 'path_segment'

EDIT: I have updated this post to be shorter as magically some of the originally mentioned errors disappeared.


Solution

  • The reason for this problem is that the month comes as string with a leading zero but the StaticRangeMapper buildes the range without leading 0s and does not map a month like 01. The mapping stops as soon one value cannot be mapped and now the uid of the news record is not mapped since this would happen after the mapping of the month.

    A simple solution is to write a StaticMonthMapper

    class StaticMonthMapper implements StaticMappableAspectInterface, \Countable
    {
    /**
     * @var array
     */
    protected $settings;
    
    
    /**
     * @param array $settings
     * @throws \InvalidArgumentException
     */
    public function __construct(array $settings)
    {
        $this->settings = $settings;
    }
    
    /**
     * {@inheritdoc}
     */
    public function count(): int
    {
        return 12;
    }
    
    /**
     * {@inheritdoc}
     */
    public function generate(string $value): ?string
    {
        return $this->respondWhenInRange($value);
    }
    
    /**
     * {@inheritdoc}
     */
    public function resolve(string $value): ?string
    {
        return $this->respondWhenInRange($value);
    }
    
    /**
     * @param string $value
     * @return string|null
     */
    protected function respondWhenInRange(string $value): ?string
    {
        switch ($value) {
            case '01':
            case '02':
            case '03':
            case '04':
            case '05':
            case '06':
            case '07':
            case '08':
            case '09':
            case '10':
            case '11':
            case '12':
                return $value;
            default:
                return null;
        }
    }
    }
    

    and register it with

    $GLOBALS['TYPO3_CONF_VARS']['SYS']['routing']['aspects']['StaticMonthMapper'] = \Package\Namespace\StaticMonthMapper::class;
    

    This can be used in the site config. For the days parameter a similar mapper can be created.

    year:
        type: StaticRangeMapper
        start: '2016'
        end: '2100'
    month:
        type: StaticMonthMapper