Reinvent wheel: Filters API

This commit is contained in:
Pig Fang 2019-09-03 18:41:19 +08:00
parent df3c1687ad
commit be86f161a2
8 changed files with 158 additions and 211 deletions

View File

@ -4,11 +4,11 @@ namespace App\Http\Controllers;
use View;
use Event;
use Eventy;
use Option;
use App\Models\User;
use App\Models\Player;
use App\Models\Texture;
use App\Services\Filter;
use App\Services\Rejection;
use Illuminate\Http\Request;
use App\Events\PlayerWasAdded;
@ -119,8 +119,12 @@ class PlayerController extends Controller
return json(trans('user.player.delete.success', ['name' => $playerName]), 0);
}
public function rename(Request $request, Dispatcher $dispatcher, $pid)
{
public function rename(
Request $request,
Dispatcher $dispatcher,
Filter $filter,
$pid
) {
$newName = $this->validate($request, [
'name' => 'required|player_name|min:'.option('player_name_length_min').'|max:'.option('player_name_length_max'),
])['name'];
@ -128,7 +132,7 @@ class PlayerController extends Controller
$dispatcher->dispatch('player.renaming', [$player, $newName]);
$can = Eventy::filter('can_rename_player', $player, $newName);
$can = $filter->apply('can_rename_player', [$player, $newName]);
if ($can instanceof Rejection) {
return json($can->getReason(), 1);
}

View File

@ -25,6 +25,7 @@ class AppServiceProvider extends ServiceProvider
$this->app->alias(\App\Services\Option::class, 'options');
$this->app->singleton('parsedown', \Parsedown::class);
$this->app->singleton('webpack', \App\Services\Webpack::class);
$this->app->singleton(\App\Services\Filter::class);
}
/**

52
app/Services/Filter.php Normal file
View File

@ -0,0 +1,52 @@
<?php
namespace App\Services;
use Closure;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
class Filter
{
protected $listeners = [];
public function add(string $hook, Closure $callback, $priority = 20)
{
if (! isset($this->listeners[$hook])) {
$this->listeners[$hook] = collect();
}
$this->listeners[$hook]->push([
'callback' => $callback,
'priority' => $priority,
]);
}
public function apply(string $hook, array $payload)
{
$listeners = $this->getListeners($hook);
if ($listeners->isNotEmpty()) {
$value = $payload[0];
unset($payload[0]);
$args = array_values($payload);
return $this->listeners[$hook]
->sortByDesc('priority')
->reduce(function ($carry, $item) use ($args) {
return call_user_func($item['callback'], $carry, ...$args);
}, $value);
} else {
return $payload[0];
}
}
public function remove(string $hook)
{
unset($this->listeners[$hook]);
}
public function getListeners(string $hook): Collection
{
return Arr::get($this->listeners, $hook, collect());
}
}

View File

@ -66,13 +66,6 @@ if (! function_exists('json')) {
}
}
if (! function_exists('add_filter')) {
function add_filter($hook, $callback, $priority = 20, $arguments = 1): void
{
app('eventy')->addFilter($hook, $callback, $priority, $arguments);
}
}
if (! function_exists('bs_footer_extra')) {
function bs_footer_extra(): string
{

View File

@ -25,8 +25,7 @@
"doctrine/dbal": "^2.9",
"tymon/jwt-auth": "dev-develop",
"laravel/passport": "^7.3",
"composer/ca-bundle": "^1.2",
"tormjens/eventy": "^0.5.7"
"composer/ca-bundle": "^1.2"
},
"require-dev": {
"fzaninotto/faker": "~1.8",

227
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "cc8c73538e2bc6907ba1778db5da12c4",
"content-hash": "c7430b05e825f77006591003ca2ccfd0",
"packages": [
{
"name": "composer/ca-bundle",
@ -1054,64 +1054,6 @@
],
"time": "2019-06-24T14:06:31+00:00"
},
{
"name": "jeremeamia/superclosure",
"version": "2.4.0",
"source": {
"type": "git",
"url": "https://github.com/jeremeamia/super_closure.git",
"reference": "5707d5821b30b9a07acfb4d76949784aaa0e9ce9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/5707d5821b30b9a07acfb4d76949784aaa0e9ce9",
"reference": "5707d5821b30b9a07acfb4d76949784aaa0e9ce9",
"shasum": ""
},
"require": {
"nikic/php-parser": "^1.2|^2.0|^3.0|^4.0",
"php": ">=5.4",
"symfony/polyfill-php56": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.4-dev"
}
},
"autoload": {
"psr-4": {
"SuperClosure\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jeremy Lindblom",
"role": "Developer",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
}
],
"description": "Serialize Closure objects, including their context and binding",
"homepage": "https://github.com/jeremeamia/super_closure",
"keywords": [
"closure",
"function",
"lambda",
"parser",
"serializable",
"serialize",
"tokenizer"
],
"time": "2018-03-21T22:21:57+00:00"
},
{
"name": "laravel/framework",
"version": "v5.8.33",
@ -1871,57 +1813,6 @@
],
"time": "2019-08-17T13:57:34+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.2.3",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "e612609022e935f3d0337c1295176505b41188c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/e612609022e935f3d0337c1295176505b41188c8",
"reference": "e612609022e935f3d0337c1295176505b41188c8",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0"
},
"bin": [
"bin/php-parse"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.2-dev"
}
},
"autoload": {
"psr-4": {
"PhpParser\\": "lib/PhpParser"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov"
}
],
"description": "A PHP parser written in PHP",
"keywords": [
"parser",
"php"
],
"time": "2019-08-12T20:17:41+00:00"
},
{
"name": "opis/closure",
"version": "3.3.1",
@ -4290,71 +4181,6 @@
"homepage": "https://github.com/tijsverkoyen/CssToInlineStyles",
"time": "2017-11-27T11:13:29+00:00"
},
{
"name": "tormjens/eventy",
"version": "0.5.7",
"source": {
"type": "git",
"url": "https://github.com/tormjens/eventy.git",
"reference": "4c4501aa085fbdc214af0e2b535d700a617dbc9e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tormjens/eventy/zipball/4c4501aa085fbdc214af0e2b535d700a617dbc9e",
"reference": "4c4501aa085fbdc214af0e2b535d700a617dbc9e",
"shasum": ""
},
"require": {
"illuminate/support": ">=5.3",
"jeremeamia/superclosure": "^2.4",
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"TorMorten\\Eventy\\EventServiceProvider",
"TorMorten\\Eventy\\EventBladeServiceProvider"
],
"aliases": {
"Eventy": "TorMorten\\Eventy\\Facades\\Events"
}
}
},
"autoload": {
"psr-4": {
"TorMorten\\Eventy\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tor Morten Jensen",
"homepage": "https://tormorten.no"
}
],
"description": "The WordPress filter/action system in Laravel",
"homepage": "https://github.com/tormjens/eventy",
"keywords": [
"HOOK",
"action",
"actions",
"event",
"events",
"filter",
"filters",
"hooks",
"laravel",
"wordpress"
],
"time": "2019-06-25T09:36:50+00:00"
},
{
"name": "tymon/jwt-auth",
"version": "dev-develop",
@ -5686,6 +5512,57 @@
],
"time": "2019-08-09T12:45:53+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.2.4",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "97e59c7a16464196a8b9c77c47df68e4a39a45c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/97e59c7a16464196a8b9c77c47df68e4a39a45c4",
"reference": "97e59c7a16464196a8b9c77c47df68e4a39a45c4",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0"
},
"bin": [
"bin/php-parse"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.2-dev"
}
},
"autoload": {
"psr-4": {
"PhpParser\\": "lib/PhpParser"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov"
}
],
"description": "A PHP parser written in PHP",
"keywords": [
"parser",
"php"
],
"time": "2019-09-01T07:51:21+00:00"
},
{
"name": "phar-io/manifest",
"version": "1.0.3",

View File

@ -3,11 +3,11 @@
namespace Tests;
use Event;
use Eventy;
use App\Events;
use App\Models\User;
use App\Models\Player;
use App\Models\Texture;
use App\Services\Filter;
use App\Services\Rejection;
use Illuminate\Foundation\Testing\DatabaseTransactions;
@ -190,17 +190,19 @@ class PlayerControllerTest extends TestCase
Event::assertDispatched('player.renaming');
// Rejected by filter
$filter = resolve(Filter::class);
$pid = $player->pid;
Eventy::addFilter('can_rename_player', function ($player) {
$filter->add('can_rename_player', function ($player, $newName) {
$this->assertEquals('new', $newName);
return new Rejection('rejected');
}, 20, 1);
});
$name = factory(Player::class)->create()->name;
$this->postJson('/user/player/rename/'.$player->pid, ['name' => 'new'])
->assertJson([
'code' => 1,
'message' => 'rejected',
]);
Eventy::removeAllFilters('can_rename_player');
$filter->remove('can_rename_player');
// Success
Event::fake();

View File

@ -2,32 +2,51 @@
namespace Tests;
use Eventy;
use App\Services\Filter;
class FilterTest extends TestCase
{
public function testAddFilter()
public function testAdd()
{
$this->mock('eventy', function ($mock) {
$mock->shouldReceive('addFilter')
->withArgs(function ($hook, $callback) {
$this->assertEquals('my.hook', $hook);
$this->assertEquals('Filtered text', $callback('text'));
return true;
})
->once();
});
add_filter('my.hook', function ($value) {
return "Filtered $value";
});
$filter = new Filter();
$filter->add('hook', function () {});
$filter->add('hook', function () {}, 10);
$this->assertCount(2, $filter->getListeners('hook'));
}
public function testIntegration()
public function testApply()
{
add_filter('hook.test', function ($value) {
return $value.'ed';
$filter = new Filter();
$this->assertEquals('value', $filter->apply('hook', ['value', 'add']));
$filter->add('hook', function ($value, $addition) {
$this->assertEquals('add', $addition);
return $value.'_medium';
});
$this->assertEquals('tested', Eventy::filter('hook.test', 'test'));
$filter->add('hook', function ($value) {
return $value.'_low';
}, 10);
$filter->add('hook', function ($value) {
return $value.'_high';
}, 30);
$this->assertEquals('value_high_medium_low', $filter->apply('hook', ['value', 'add']));
}
public function testRemove()
{
$filter = new Filter();
$filter->remove('hook');
$this->assertCount(0, $filter->getListeners('hook'));
$filter->add('hook', function () {});
$this->assertCount(1, $filter->getListeners('hook'));
$filter->remove('hook');
$this->assertCount(0, $filter->getListeners('hook'));
}
public function testGetListeners()
{
$filter = new Filter();
$this->assertCount(0, $filter->getListeners('hook'));
}
}