1
0
mirror of https://github.com/flarum/core.git synced 2025-07-19 07:41:22 +02:00

feat: discussion UTF-8 slug driver (#3606)

* feat: add utf-8 slug driver
* test: add tests for slugging expectations
* fix: non-word characters aren't removed

Signed-off-by: Sami Mazouz <ilyasmazouz@gmail.com>
Co-authored-by: Alexander Skvortsov <sasha.skvortsov109@gmail.com>
This commit is contained in:
Sami Mazouz
2022-08-21 15:27:41 +01:00
committed by GitHub
parent ec97ee41f9
commit f7dd609b26
4 changed files with 143 additions and 1 deletions

View File

@@ -441,6 +441,7 @@ class Discussion extends AbstractModel
*
* This automatically creates a matching slug for the discussion.
*
* @todo slug should be set by the slugger, drop slug column entirely?
* @param string $title
*/
protected function setTitleAttribute($title)

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion;
use Flarum\Database\AbstractModel;
use Flarum\Http\SlugDriverInterface;
use Flarum\User\User;
class Utf8SlugDriver implements SlugDriverInterface
{
/**
* @var DiscussionRepository
*/
protected $discussions;
public function __construct(DiscussionRepository $discussions)
{
$this->discussions = $discussions;
}
public function toSlug(AbstractModel $instance): string
{
$slug = preg_replace('/[-\s]+/u', '-', $instance->title);
$slug = preg_replace('/[^\p{L}\p{N}\p{M}_-]+/u', '', $slug);
$slug = strtolower($slug);
return $instance->id.(trim($slug) ? '-'.$slug : '');
}
public function fromSlug(string $slug, User $actor): AbstractModel
{
if (strpos($slug, '-')) {
$slug_array = explode('-', $slug);
$slug = $slug_array[0];
}
return $this->discussions->findOrFail($slug, $actor);
}
}

View File

@@ -11,6 +11,7 @@ namespace Flarum\Http;
use Flarum\Discussion\Discussion;
use Flarum\Discussion\IdWithTransliteratedSlugDriver;
use Flarum\Discussion\Utf8SlugDriver;
use Flarum\Foundation\AbstractServiceProvider;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\IdSlugDriver;
@@ -37,7 +38,8 @@ class HttpServiceProvider extends AbstractServiceProvider
$this->container->singleton('flarum.http.slugDrivers', function () {
return [
Discussion::class => [
'default' => IdWithTransliteratedSlugDriver::class
'default' => IdWithTransliteratedSlugDriver::class,
'utf8' => Utf8SlugDriver::class,
],
User::class => [
'default' => UsernameSlugDriver::class,

View File

@@ -0,0 +1,93 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace integration\slugger;
use Carbon\Carbon;
use Flarum\Discussion\Discussion;
use Flarum\Http\SlugManager;
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase;
use Flarum\User\User;
class SlugDriverTest extends TestCase
{
use RetrievesAuthorizedUsers;
protected function setUp(): void
{
parent::setUp();
$this->prepareDatabase([
'users' => [
$this->normalUser(),
],
'discussions' => [
['id' => 20, 'title' => 'Empty discussion', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'first_post_id' => null, 'comment_count' => 0, 'is_private' => 0],
['id' => 21, 'title' => 'తెలుగు', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'first_post_id' => null, 'comment_count' => 0, 'is_private' => 0],
['id' => 22, 'title' => '支持中文吗', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'first_post_id' => null, 'comment_count' => 0, 'is_private' => 0],
['id' => 23, 'title' => 'తెలుగు%$', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'first_post_id' => null, 'comment_count' => 0, 'is_private' => 0],
['id' => 24, 'title' => '支持中文吗%*', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'first_post_id' => null, 'comment_count' => 0, 'is_private' => 0],
],
]);
}
/**
* @dataProvider slugInstancePairDataProvider
* @test
*/
public function slugger_formats_the_correct_slug_from_instance(string $driver, string $modelClassName, int $id, string $slug)
{
$this->setting("slug_driver_$modelClassName", $driver);
/** @var SlugManager $slugger */
$slugger = $this->app()->getContainer()->make(SlugManager::class)->forResource($modelClassName);
$instance = $modelClassName::query()->find($id);
/** @see Discussion::setTitleAttribute() */
if ($modelClassName === Discussion::class) {
$instance->title = $instance->title;
}
$this->assertEquals($slug, $slugger->toSlug($instance));
}
/**
* @dataProvider slugInstancePairDataProvider
* @test
*/
public function slugger_returns_the_correct_instance_from_slug(string $driver, string $modelClassName, int $id, string $slug)
{
$this->setting("slug_driver_$modelClassName", $driver);
/** @var SlugManager $slugger */
$slugger = $this->app()->getContainer()->make(SlugManager::class)->forResource($modelClassName);
$this->assertEquals($modelClassName::query()->find($id), $slugger->fromSlug($slug, User::query()->find(1)));
}
public function slugInstancePairDataProvider(): array
{
return [
['default', Discussion::class, 20, '20-empty-discussion'],
['default', Discussion::class, 21, '21'],
['default', Discussion::class, 22, '22'],
['utf8', Discussion::class, 20, '20-empty-discussion'],
['utf8', Discussion::class, 21, '21-తెలుగు'],
['utf8', Discussion::class, 22, '22-支持中文吗'],
['utf8', Discussion::class, 23, '23-తెలుగు'],
['utf8', Discussion::class, 24, '24-支持中文吗'],
['default', User::class, 2, 'normal'],
['id', User::class, 2, '2'],
];
}
}