tobento/app-slugging

应用别名支持。

1.0.1 2024-09-11 09:28 UTC

This package is auto-updated.

Last update: 2024-09-11 09:29:26 UTC


README

使用 Slugifier 服务 为应用提供别名支持。

目录

入门

运行此命令安装应用别名项目的最新版本。

composer require tobento/app-slugging

要求

  • PHP 8.0 或更高版本

文档

应用

如果您正在使用骨架,请查看 应用骨架

您还可以查看 应用 了解有关应用的一般信息。

别名启动

别名启动执行以下操作:

  • 安装和加载别名配置文件
  • 实现别名接口
use Tobento\App\AppFactory;
use Tobento\App\Slugging\SlugRepositoryInterface;
use Tobento\Service\Slugifier\SlugifierFactoryInterface;
use Tobento\Service\Slugifier\SlugifierInterface;
use Tobento\Service\Slugifier\SlugifiersInterface;
use Tobento\Service\Slugifier\SlugsInterface;

// Create the app
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots
$app->boot(\Tobento\App\Slugging\Boot\Slugging::class);
$app->booting();

// Implemented interfaces:
$slugifierFactory = $app->get(SlugifierFactoryInterface::class);
$slugifier = $app->get(SlugifierInterface::class);
$slugifiers = $app->get(SlugifiersInterface::class);
$slugs = $app->get(SlugsInterface::class);
$slugRepository = $app->get(SlugRepositoryInterface::class);

// Run the app
$app->run();

别名配置

别名配置位于默认应用骨架配置位置(在 app/config/slugging.php 文件中),您可以在其中指定应用的别名以及其他配置。

生成别名

要生成别名,请使用别名接口

use Tobento\Service\Slugifier\SlugifierInterface;
use Tobento\Service\Slugifier\SlugifiersInterface;

class SomeService
{
    public function __construct(
        protected SlugifierInterface $slugifier,
        protected SlugifiersInterface $slugifiers,
    ) {}
    
    private function slugify()
    {
        // using the default slugifier:
        $slug = $this->slugifier->slugify(string: 'Lorem Ipsum!', locale: 'de');
        
        // using a custom slugifier:
        $slug = $this->slugifiers->get('custom')->slugify('Lorem Ipsum!');
    }
}

您可以通过查看 别名服务 了解更多信息。

添加别名

您可以将别名添加到防止重复别名或用于路由目的,例如在路由中使用 别名匹配

从配置中

您可以直接在 别名配置 中使用资源添加别名。

使用应用

有时,在应用内部使用资源添加别名可能会有用

use Tobento\Service\Slugifier\Resource\ArrayResource;
use Tobento\Service\Slugifier\SlugsInterface;

// Adding slugs resources only if requested:
$app->on(SlugsInterface::class, static function(SlugsInterface $slugs): void {
    $slugs->addResource(new ArrayResource(
        slugs: ['login'],
    ));
});

仓库资源

使用 RepositoryResource 类,您可以将任何实现 RepositoryInterface 的仓库添加为资源。

use Tobento\App\Slugging\Resource\RepositoryResource;
use Tobento\Service\Repository\RepositoryInterface;
use Tobento\Service\Slugifier\SlugsInterface;

// Adding slugs resources only if requested:
$app->on(SlugsInterface::class, static function(SlugsInterface $slugs, BlogRepositoryInterface $blogRepo): void {
    $slugs->addResource(new RepositoryResource(
        repository: $blogRepo,
        priority: 100, // higher priority will be first.
        
        resourceKey: 'blog', // or null
        // or using a closure:
        resourceKey: static function (null|object $blog): null|string {
            return $blog->resourceKey();
        },
        
        resourceId: static function (object $blog): null|string|int {
            return $blog->id();
        },
        // or null if none:
        resourceId: null,
        
        // you may customize the where query parameters:
        whereParameters: static function (string $slug, string $locale): array {
            return $locale === ''
                ? ['slug' => $slug] // locale independent (default)
                : ['slug' => $slug, 'locale' => $locale]; // locale dependent
            
            // JSON SYNTAX:
            return ['slug->'.$locale => $slug]; // locale dependent
        },
    ));
});

别名仓库

默认情况下,别名仓库会添加到 别名配置 中的别名中,从而防止重复别名。

使用别名仓库的优势在于,在生成别名或使用 别名匹配 时,如果它是唯一的 添加别名资源,则只会进行一次查询。

保存别名

使用 saveSlug 方法保存别名

use Tobento\App\Slugging\SlugRepositoryInterface;
use Tobento\Service\Slugifier\Slug;

$slugRepository = $app->get(SlugRepositoryInterface::class);

$savedSlug = $slugRepository->saveSlug(new Slug(
    slug: 'lorem-ipsum',
    locale: 'en',
    resourceKey: 'blog', // null|string
    resourceId: 125, // null|int|string
));

删除别名

使用 deleteSlug 方法删除别名

use Tobento\App\Slugging\SlugRepositoryInterface;
use Tobento\Service\Slugifier\Slug;

$slugRepository = $app->get(SlugRepositoryInterface::class);

$deletedSlug = $slugRepository->deleteSlug(new Slug(
    slug: 'lorem-ipsum',
    locale: 'en',
));

路由

首先,您需要安装 App Http

别名匹配

您可以使用 SlugMatches 类来使用仅带有别名的不同控制器进行多个路由的匹配,基于 resouceKey 参数。

use Tobento\App\Slugging\Routing\SlugMatches;

$app->route(
    method: 'GET',
    uri: '{slug}',
    //handler: [BlogController::class, 'show'],
    handler: function (string $slug) {
        return $createdResponse;
    },
)->matches(new SlugMatches(resourceKey: 'blog'));

$app->route(
    method: 'GET',
    uri: '{slug}',
    //handler: [ProductController::class, 'show'],
    handler: function (string $slug) {
        return $createdResponse;
    },
)->matches(new SlugMatches(resourceKey: 'product'));

使用地区

您可以使用 withLocale 参数来定义 URI 地区参数的名称。一旦定义,别名将根据地区进行匹配。

use Tobento\App\Slugging\Routing\SlugMatches;

$app->route(
    method: 'GET',
    uri: '{?locale}/{slug}',
    handler: function (string $slug) {
        return $createdResponse;
    },
)
->locales(['de', 'en'])
->localeOmit('en')
->matches(new SlugMatches(
    resourceKey: 'blog',
    withLocale: 'locale',
));

使用资源 ID

您可以使用withUriId参数来定义传递给处理器的参数名称,其中将传递来自slug实体的资源ID$slug->resourceId()

use Tobento\App\Slugging\Routing\SlugMatches;

$app->route(
    method: 'GET',
    uri: '{slug}',
    handler: function (int|string $id) {
        return $createdResponse;
    },
)->matches(new SlugMatches(
    resourceKey: 'blog',
    withUriId: 'id',
));

自定义Slug URI

您可以使用uriSlugName参数来更改slug的URI名称。

use Tobento\App\Slugging\Routing\SlugMatches;

$app->route(
    method: 'GET',
    uri: '{alias}',
    handler: function (string $alias) {
        return $createdResponse;
    },
)->matches(new SlugMatches(
    resourceKey: 'blog',
    uriSlugName: 'alias',
));

唯一别名验证规则

要求

需要App Validation

composer require tobento/app-validation

别忘了启动验证器

use Tobento\App\AppFactory;

// Create the app
$app = (new AppFactory())->createApp();

// Adding boots
$app->boot(\Tobento\App\Validation\Boot\Validator::class);
$app->boot(\Tobento\App\Slugging\Boot\Slugging::class);

// Run the app
$app->run();

唯一Slug规则

use Tobento\App\Slugging\Validation\UniqueSlugRule;

$validation = $validator->validate(
    data: [
        'slug' => 'login',
        'slug.de' => 'anmelden',
        'slug.en' => 'login',
    ],
    rules: [
        'slug' => [
            new UniqueSlugRule(
                locale: 'en',
                // you may specify a custom error message:
                errorMessage: 'Custom error message',
            ),
        ],
        'slug.de' => [
            new UniqueSlugRule(), // locale is automatically determined as 'de'.
        ],
        'slug.en' => [
            new UniqueSlugRule(), // locale is automatically determined as 'en'.
        ],
    ]
);

跳过验证

您可以使用skipValidation参数在某些条件下跳过验证

use Tobento\App\Slugging\Validation\UniqueSlugRule;

$validation = $validator->validate(
    data: [
        'slug.en' => 'login',
    ],
    rules: [
        'slug.en' => [
            // skips validation:
            new UniqueSlugRule(skipValidation: true),

            // does not skip validation:
            new UniqueSlugRule(skipValidation: false),

            // skips validation:
            new UniqueSlugRule(skipValidation: fn (mixed $value): bool => $value === 'foo'),
        ],
    ]
);

致谢