From a8fa57ad30e195af5b0dfc600dfe12b04e3270e3 Mon Sep 17 00:00:00 2001 From: Matthew Kilgore Date: Mon, 23 Nov 2020 19:55:00 -0500 Subject: [PATCH] WIP Extender --- src/Extend/ModelUrl.php | 75 ++++++++++ src/Http/HttpServiceProvider.php | 9 +- src/Http/UrlGenerator.php | 4 +- tests/integration/extenders/ModelUrlTest.php | 137 +++++++++++++++++++ 4 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 src/Extend/ModelUrl.php create mode 100644 tests/integration/extenders/ModelUrlTest.php diff --git a/src/Extend/ModelUrl.php b/src/Extend/ModelUrl.php new file mode 100644 index 000000000..6de14188b --- /dev/null +++ b/src/Extend/ModelUrl.php @@ -0,0 +1,75 @@ +modelClass = $modelClass; + } + + /** + * Add a slug driver. + * + * @param string $identifier Identifier for slug driver. + * @param string $driver ::class attribute of driver class, which must implement Flarum\Http\SlugDriverInterface + * @return self + */ + public function addSlugDriver(string $identifier, string $driver) { + $this->slugDrivers[$identifier] = $driver; + + return $this; + } + + /** + * Overrides the url generator for this resource. + * + * @param callable|string $callback + * @return self + * + * The callable can be a closure or invokable class, and should accept: + * - \Flarum\Http\UrlGenerator $urlGenerator: an instance of the URL generator. + * - \Flarum\Database\AbstractModel $instance: The model instance for which the url is being generated + * - ...$args: Any additional optional arguments + * + * The callable should return: + * - string $url: A valid URL pointing to the resource instance + */ + public function setUrlGenerator($callback) + { + $this->urlGenerator = $callback; + + return $this; + } + + public function extend(Container $container, Extension $extension = null) + { + if ($this->urlGenerator) { + $container->extend('flarum.http.resourceUrlGenerators', function($existingUrlGenerators) use ($container) { + $existingUrlGenerators[$this->modelClass] = ContainerUtil::wrapCallback($this->urlGenerator, $container); + return $existingUrlGenerators; + }); + } + if ($this->slugDrivers) { + $container->extend('flarum.http.slugDrivers', function ($existingDrivers) { + $existingDrivers[$this->modelClass] = array_merge(Arr::get($existingDrivers, $this->modelClass, []), $this->slugDrivers); + return $existingDrivers; + }); + } + } +} diff --git a/src/Http/HttpServiceProvider.php b/src/Http/HttpServiceProvider.php index fc2c0bc39..6d1d6eaf8 100644 --- a/src/Http/HttpServiceProvider.php +++ b/src/Http/HttpServiceProvider.php @@ -51,6 +51,9 @@ class HttpServiceProvider extends AbstractServiceProvider foreach ($this->app->make('flarum.http.slugDrivers') as $resourceClass => $resourceDrivers) { $driverClass = $resourceDrivers[$settings->get("slug_driver_$resourceClass", 'default')]; + echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + echo "slug_driver_$resourceClass"; + //echo $settings->get("slug_driver_$resourceClass", 'default'); $compiledDrivers[$resourceClass] = $this->app->make($driverClass); } @@ -63,18 +66,18 @@ class HttpServiceProvider extends AbstractServiceProvider return [ Discussion::class => function (UrlGenerator $urlGenerator, Discussion $discussion) use ($slugManager) { return $urlGenerator->to('forum')->route('discussion', [ - 'id' => $slugManager->toResource(Discussion::class)->toSlug($discussion) + 'id' => $slugManager->forResource(Discussion::class)->toSlug($discussion) ]); }, Post::class => function (UrlGenerator $urlGenerator, Post $post) use ($slugManager) { return $urlGenerator->to('forum')->route('user', [ - 'id' => $slugManager->toResource(Discussion::class)->toSlug($post->discussion), + 'id' => $slugManager->forResource(Discussion::class)->toSlug($post->discussion), 'near' => $post->id, ]); }, User::class => function (UrlGenerator $urlGenerator, User $user) use ($slugManager) { return $urlGenerator->to('forum')->route('user', [ - 'id' => $slugManager->toResource(User::class)->toSlug($user) + 'id' => $slugManager->forResource(User::class)->toSlug($user) ]); }, ]; diff --git a/src/Http/UrlGenerator.php b/src/Http/UrlGenerator.php index e17f1bb33..4d0a3152e 100644 --- a/src/Http/UrlGenerator.php +++ b/src/Http/UrlGenerator.php @@ -79,6 +79,8 @@ class UrlGenerator { $callback = $this->resourceUrlGenerators[$resourceClass]; - return $callback($this, $instance, ...$args); + $result = $callback($this, $instance, ...$args); + + return $result; } } diff --git a/tests/integration/extenders/ModelUrlTest.php b/tests/integration/extenders/ModelUrlTest.php new file mode 100644 index 000000000..94df2018c --- /dev/null +++ b/tests/integration/extenders/ModelUrlTest.php @@ -0,0 +1,137 @@ +prepareDatabase([ + 'users' => [ + $this->adminUser(), + $this->normalUser(), + ], + ]); + } + + protected function activateCustomDriver() { + $userClass = User::class; + $this->prepareDatabase([ + 'settings' => [ + ['key' => "slug_driver_$userClass", 'value' => 'testDriver'], + ], + ]); + } + +// public function tearDown() +// { +// $userClass = User::class; +// $this->prepareDatabase([ +// 'settings' => [ +// ['key' => "slug_driver_$userClass", 'value' => 'default'], +// ], +// ]); +// parent::tearDown(); +// } + + /** + * @test + */ + public function default_url_generator_used_by_default() { + $this->prepDb(); + + $urlGenerator = $this->app()->getContainer()->make(UrlGenerator::class); + + $testUser = User::find(1); + + $this->assertEquals($urlGenerator->to('forum')->route('user', ['username' => 'admin']), $urlGenerator->toResource(User::class, $testUser)); + } + + /** + * @test + */ + public function custom_url_generator_can_be_used() { + $this->extend( + (new Extend\ModelUrl(User::class))->setUrlGenerator(function(UrlGenerator $urlGenerator, User $instance) { + return "hello there!"; + }) + ); + + $this->prepDb(); + + $urlGenerator = $this->app()->getContainer()->make(UrlGenerator::class); + + $testUser = User::find(1); + + $this->assertEquals("hello there!", $urlGenerator->toResource(User::class, $testUser)); + } + + public function uses_default_driver_by_default() { + $this->prepDb(); + + $slugManager = $this->app()->getContainer()->make(SlugManager::class); + + $testUser = User::find(1); + + $this->assertEquals('admin', $slugManager->forResource(User::class)->toSlug($testUser)); + $this->assertEquals('1', $slugManager->forResource(User::class)->fromSlug('admin', $testUser)->id); + } + + /** + * @test + */ + public function custom_slug_driver_doesnt_have_effect_unless_enabled() { + $this->extend((new Extend\ModelUrl(User::class))->addSlugDriver('testDriver', TestSlugDriver::class)); + + $this->prepDb(); + + $slugManager = $this->app()->getContainer()->make(SlugManager::class); + + $testUser = User::find(1); + + $this->assertEquals('admin', $slugManager->forResource(User::class)->toSlug($testUser)); + $this->assertEquals('1', $slugManager->forResource(User::class)->fromSlug('admin', $testUser)->id); + } + + /** + * @test + */ + public function custom_slug_driver_has_effect_if_enabled() { + $this->extend((new Extend\ModelUrl(User::class))->addSlugDriver('testDriver', TestSlugDriver::class)); + + $this->prepDb(); + $this->activateCustomDriver(); + + $slugManager = $this->app()->getContainer()->make(SlugManager::class); + + $testUser = User::find(1); + + $this->assertEquals('test-slug', $slugManager->forResource(User::class)->toSlug($testUser)); + $this->assertEquals('1', $slugManager->forResource(User::class)->fromSlug('random-gibberish', $testUser)->id); + } +} + +class TestSlugDriver implements SlugDriverInterface { + + public function toSlug(AbstractModel $instance): string + { + return 'test-slug'; + } + + public function fromSlug(string $slug, User $actor): AbstractModel + { + return User::find(1); + } +}