cpsit/cps-shortnr 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

cpsit/cps-shortnr

最新稳定版本:4.0.2

Composer 安装命令:

composer require cpsit/cps-shortnr

包简介

routing alias enhancer over middleware

README 文档

README

Routing alias enhancer via middleware for TYPO3 CMS. Generates and resolves short URLs for pages and plugin records using configurable patterns.

Requirements

  • PHP ^8.2
  • TYPO3 ^13.4

Dependencies

Installation

composer require cpsit/shortnr

The extension auto-registers its middleware and cache configuration.

Configuration

Default Configuration

The extension ships with a minimal default configuration in Configuration/config.yaml:

shortNr:
  _default:
    notFound: "/"
    languageParentField: "l10n_parent"
    languageField: "sys_language_uid"
    identifierField: "uid"

  pages:
    type: page
    table: pages
    pattern: "p{uid:int(min=1)}(-{sys_language_uid:int(min=0,default=0)})"

Pattern Syntax

Patterns use the typed-pattern-engine syntax:

Syntax Description
{field:int(min=1)} Integer with minimum value
{field:int(min=0,default=0)} Integer with default
(-{field}) Optional segment (parentheses)
PREFIX{field} Static prefix

Example: NEWS{uid:int(min=1)}(-{sys_language_uid:int(min=0,default=0)}) generates NEWS123 or NEWS123-1

Adding Custom Configuration

Create an event listener to register your configuration file:

<?php
namespace Vendor\SitePackage\EventListener\ShortNr;

use CPSIT\ShortNr\Event\ShortNrConfigPathEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;

#[AsEventListener(
    identifier: 'site-package/shortNrConfigListener',
    event: ShortNrConfigPathEvent::class,
    method: 'loadConfig'
)]
class ConfigLoadingEventListener
{
    public function loadConfig(ShortNrConfigPathEvent $event): void
    {
        $event->addConfigPath('EXT:site_package/Configuration/cps_shortnr.yaml');
    }
}

Config Merging Behavior

Configs are merged via array_replace_recursive - higher priority configs (default: 10) override lower ones (extension default: -1000).

  • Every field can be overwritten by later configs
  • Arrays merge recursively (add new keys, override existing)
  • Set a field to null to remove it
  • the priority can be altered at the ShortNrConfigPathEvent::addConfigPath call

Configuration Examples

Page type:

shortNr:
  pages:
    type: page
    table: pages
    pattern: "PAGE{uid:int(min=1)}(-{sys_language_uid:int(min=0,default=0)})"

Plugin type (e.g., News):

shortNr:
  news:
    type: plugin
    table: tx_news_domain_model_news
    pattern: "NEWS{uid:int(min=1)}(-{sys_language_uid:int(min=0,default=0)})"
    plugin:
      extension: News
      plugin: Pi1
      pid: 43           # Page UID containing the plugin
      action: detail
      controller: News
      objectName: news  # Request parameter name

With conditions:

shortNr:
  event:
    type: plugin
    table: tx_news_domain_model_news
    pattern: "EVENT{uid:int(min=1)}(-{sys_language_uid:int(min=0,default=0)})"
    plugin:
      extension: News
      plugin: Pi1
      pid: 474
      action: detail
      controller: News
      objectName: news
    condition:
      is_event: 1

Available Condition Operators

See Configuration/config.example.full.yaml for detailed examples.

Operator Example Description
implicit field: value Equals
eq field: {eq: value} Equals (explicit)
in field: [a, b, c] Value in array
contains field: {contains: "text"} Substring match
starts field: {starts: "prefix"} Starts with
ends field: {ends: "suffix"} Ends with
gt, gte field: {gte: 50} Greater than (or equal)
lt, lte field: {lt: 100} Less than (or equal)
between field: {between: [10, 50]} Range
isset field: {isset: true} Field exists
not field: {not: {eq: value}} Negation

Usage

ViewHelper

Generate short URLs in Fluid templates:

<html xmlns:sn="http://typo3.org/ns/CPSIT/ShortNr/ViewHelpers"
      data-namespace-typo3-fluid="true">

<!-- By config name and UID -->
<sn:shortUrl name="news" uid="123" output="result" absolute="1">
    <f:if condition="{result.uri}">
        <a href="{result.uri}">{result.uri}</a>
    </f:if>
</sn:shortUrl>

<!-- From current page context (no name/uid = environment demand) -->
<sn:shortUrl output="shortNr" absolute="1">
    {shortNr.uri}
</sn:shortUrl>

<!-- From domain object -->
<sn:shortUrl object="{newsItem}" output="result" absolute="1">
    {result.uri}
</sn:shortUrl>

ViewHelper Arguments:

Argument Type Description
output string Variable name for result (required)
languageUid int Target language
absolute bool Generate absolute URL

The ViewHelper supports three demand modes (mutually exclusive):

Mode Arguments Description
Config + UID name + uid Explicit config name and record UID
Object object Domain object (extracts config + UID automatically)
Environment (none) Uses current page/plugin context

Service (PHP)

Encoding (generate short URL):

use CPSIT\ShortNr\Service\EncoderService;
use CPSIT\ShortNr\Service\Url\Demand\Encode\ConfigNameEncoderDemand;
use CPSIT\ShortNr\Service\Url\Demand\Encode\ObjectEncoderDemand;
use CPSIT\ShortNr\Service\Url\Demand\Encode\EnvironmentEncoderDemand;

// Inject EncoderService via constructor
public function __construct(private readonly EncoderService $encoderService) {}

// 1. Config + UID: Explicit config name and record UID
$demand = (new ConfigNameEncoderDemand('news', 123))
    ->setRequest($request)      // Required for site context
    ->setLanguageId(0)          // Target language (null = from request)
    ->setAbsolute(true);        // Full URL vs relative path
$uri = $this->encoderService->encode($demand);

// 2. Object: From domain object (AbstractEntity)
$demand = (new ObjectEncoderDemand($newsEntity))
    ->setRequest($request)
    ->setAbsolute(true);
$uri = $this->encoderService->encode($demand);

// 3. Environment: From current request context
$demand = (new EnvironmentEncoderDemand(
    $request->getQueryParams(),
    $request->getAttribute('frontend.page.information')?->getPageRecord() ?? [],
    $request->getAttribute('routing'),
    $request->getAttribute('extbase')
))
    ->setRequest($request)
    ->setAbsolute(true);
$uri = $this->encoderService->encode($demand);

Decoding (resolve short URL):

use CPSIT\ShortNr\Service\DecoderService;
use CPSIT\ShortNr\Service\Url\Demand\Decode\DecoderDemand;

// Inject DecoderService via constructor
public function __construct(private readonly DecoderService $decoderService) {}

// Direct: From short URL string
$demand = new DecoderDemand('NEWS123');
$fullUri = $this->decoderService->decode($demand);

// From request: Extracts short URL from request path
$demand = $this->decoderService->getDecoderDemandFromRequest($request);
$fullUri = $demand ? $this->decoderService->decode($demand) : null;

How It Works

  1. Middleware intercepts GET requests and checks for short URL patterns
  2. DecoderService matches request path against configured patterns
  3. On match: 301 redirect to resolved full URL
  4. On no match: request continues to TYPO3 routing

Encoding compiles record data into short URL using configured pattern. Decoding extracts UID from short URL, queries database with conditions, generates full URL.

Caching

  • Compiled patterns cached to filesystem
  • Encoded/decoded URLs cached with 1 week TTL
  • Cache cleared on cache:all or cache:pages flush
  • Cache tags: all, uri, encode, decode

NotFound Handling

Configure fallback behavior when a short URL cannot be resolved:

shortNr:
  _default:
    notFound: 2           # Page UID
    # or
    notFound: "/404"      # URI string
    # or
    notFound: ""          # Disable (continue to TYPO3 routing)

Extension Setup

The extension registers:

  • PSR-15 middleware (early in stack, before site resolution)
  • TYPO3 cache configuration (cps_shortnr)
  • DataHandler hook for cache invalidation

统计信息

  • 总下载量: 1.13k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 3
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 3
  • Watchers: 2
  • Forks: 4
  • 开发语言: PHP

其他信息

  • 授权协议: GPL-2.0-or-later
  • 更新时间: 2017-03-30

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固