feat: conditional extenders (#3759)

This commit is contained in:
Sami Mazouz 2023-03-14 21:53:16 +01:00 committed by GitHub
parent a6a067ad48
commit 8372363cc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 233 additions and 10 deletions

View File

@ -0,0 +1,61 @@
<?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\Extend;
use Flarum\Extension\Extension;
use Flarum\Extension\ExtensionManager;
use Illuminate\Contracts\Container\Container;
class Conditional implements ExtenderInterface
{
/**
* @var array<array{condition: bool|callable, extenders: ExtenderInterface[]}>
*/
protected $conditions = [];
/**
* @param ExtenderInterface[] $extenders
*/
public function whenExtensionEnabled(string $extensionId, array $extenders): self
{
return $this->when(function (ExtensionManager $extensions) use ($extensionId) {
return $extensions->isEnabled($extensionId);
}, $extenders);
}
/**
* @param bool|callable $condition
* @param ExtenderInterface[] $extenders
*/
public function when($condition, array $extenders): self
{
$this->conditions[] = [
'condition' => $condition,
'extenders' => $extenders,
];
return $this;
}
public function extend(Container $container, Extension $extension = null)
{
foreach ($this->conditions as $condition) {
if (is_callable($condition['condition'])) {
$condition['condition'] = $container->call($condition['condition']);
}
if ($condition['condition']) {
foreach ($condition['extenders'] as $extender) {
$extender->extend($container, $extension);
}
}
}
}
}

View File

@ -414,19 +414,19 @@ class Extension implements Arrayable
$links['source'] = $sourceUrl;
}
if (($discussUrl = $this->composerJsonAttribute('support.forum'))) {
if ($discussUrl = $this->composerJsonAttribute('support.forum')) {
$links['discuss'] = $discussUrl;
}
if (($documentationUrl = $this->composerJsonAttribute('support.docs'))) {
if ($documentationUrl = $this->composerJsonAttribute('support.docs')) {
$links['documentation'] = $documentationUrl;
}
if (($websiteUrl = $this->composerJsonAttribute('homepage'))) {
if ($websiteUrl = $this->composerJsonAttribute('homepage')) {
$links['website'] = $websiteUrl;
}
if (($supportEmail = $this->composerJsonAttribute('support.email'))) {
if ($supportEmail = $this->composerJsonAttribute('support.email')) {
$links['support'] = "mailto:$supportEmail";
}

View File

@ -65,7 +65,7 @@ class Gate
$appliedPolicies = [];
if ($model) {
$modelClasses = is_string($model) ? [$model] : array_merge(class_parents(($model)), [get_class($model)]);
$modelClasses = is_string($model) ? [$model] : array_merge(class_parents($model), [get_class($model)]);
foreach ($modelClasses as $class) {
$appliedPolicies = array_merge($appliedPolicies, $this->getPolicies($class));
@ -87,7 +87,7 @@ class Gate
// If no policy covered this permission query, we will only grant
// the permission if the actor's groups have it. Otherwise, we will
// not allow the user to perform this action.
if ($actor->isAdmin() || ($actor->hasPermission($ability))) {
if ($actor->isAdmin() || $actor->hasPermission($ability)) {
return true;
}

View File

@ -0,0 +1,162 @@
<?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\Tests\integration\extenders;
use Exception;
use Flarum\Api\Serializer\ForumSerializer;
use Flarum\Extend;
use Flarum\Extension\ExtensionManager;
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase;
class ConditionalTest extends TestCase
{
use RetrievesAuthorizedUsers;
/** @test */
public function conditional_works_if_condition_is_primitive_true()
{
$this->extend(
(new Extend\Conditional())
->when(true, [
(new Extend\ApiSerializer(ForumSerializer::class))
->attributes(function () {
return [
'customConditionalAttribute' => true
];
})
])
);
$this->app();
$response = $this->send(
$this->request('GET', '/api', [
'authenticatedAs' => 1,
])
);
$payload = json_decode($response->getBody()->getContents(), true);
$this->assertArrayHasKey('customConditionalAttribute', $payload['data']['attributes']);
}
/** @test */
public function conditional_does_not_work_if_condition_is_primitive_false()
{
$this->extend(
(new Extend\Conditional())
->when(false, [
(new Extend\ApiSerializer(ForumSerializer::class))
->attributes(function () {
return [
'customConditionalAttribute' => true
];
})
])
);
$this->app();
$response = $this->send(
$this->request('GET', '/api', [
'authenticatedAs' => 1,
])
);
$payload = json_decode($response->getBody()->getContents(), true);
$this->assertArrayNotHasKey('customConditionalAttribute', $payload['data']['attributes']);
}
/** @test */
public function conditional_works_if_condition_is_callable_true()
{
$this->extend(
(new Extend\Conditional())
->when(function () {
return true;
}, [
(new Extend\ApiSerializer(ForumSerializer::class))
->attributes(function () {
return [
'customConditionalAttribute' => true
];
})
])
);
$this->app();
$response = $this->send(
$this->request('GET', '/api', [
'authenticatedAs' => 1,
])
);
$payload = json_decode($response->getBody()->getContents(), true);
$this->assertArrayHasKey('customConditionalAttribute', $payload['data']['attributes']);
}
/** @test */
public function conditional_does_not_work_if_condition_is_callable_false()
{
$this->extend(
(new Extend\Conditional())
->when(function () {
return false;
}, [
(new Extend\ApiSerializer(ForumSerializer::class))
->attributes(function () {
return [
'customConditionalAttribute' => true
];
})
])
);
$this->app();
$response = $this->send(
$this->request('GET', '/api', [
'authenticatedAs' => 1,
])
);
$payload = json_decode($response->getBody()->getContents(), true);
$this->assertArrayNotHasKey('customConditionalAttribute', $payload['data']['attributes']);
}
/** @test */
public function conditional_injects_dependencies_to_condition_callable()
{
$this->expectNotToPerformAssertions();
$this->extend(
(new Extend\Conditional())
->when(function (?ExtensionManager $extensions) {
if (! $extensions) {
throw new Exception('ExtensionManager not injected');
}
}, [
(new Extend\ApiSerializer(ForumSerializer::class))
->attributes(function () {
return [
'customConditionalAttribute' => true
];
})
])
);
$this->app();
}
}

View File

@ -42,7 +42,7 @@ class LocalesTest extends TestCase
public function custom_translation_exists_if_added()
{
$this->extend(
(new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales'))
new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales')
);
$this->app()->getContainer()->make('flarum.locales');
@ -57,7 +57,7 @@ class LocalesTest extends TestCase
public function custom_translation_exists_if_added_with_intl_suffix()
{
$this->extend(
(new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales'))
new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales')
);
$this->app()->getContainer()->make('flarum.locales');
@ -72,7 +72,7 @@ class LocalesTest extends TestCase
public function messageformat_works_in_translations()
{
$this->extend(
(new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales'))
new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales')
);
$this->app()->getContainer()->make('flarum.locales');
@ -87,7 +87,7 @@ class LocalesTest extends TestCase
public function laravel_interface_methods_work()
{
$this->extend(
(new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales'))
new Extend\Locales(dirname(__FILE__, 3).'/fixtures/locales')
);
$this->app()->getContainer()->make('flarum.locales');