skybluesofa / laravel-wrapped-facade
Laravel 门面带 before/after 方法功能
Requires
- php: ^8.1
- laravel/framework: ^10 || ^9.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- barryvdh/laravel-ide-helper: ^2.13
- orchestra/testbench: ^7.11 || ^8.21
README
为 Facades 添加 before- 和 after- 方法调用。
目的
这个库创建了一种在调用 Facade 方法时添加前/后方法的能力。你可以在 tests
文件夹中找到一个示例。
我发现最有用的用途是缓存信息而不是执行请求。
Laravel 版本兼容性
此包支持 Laravel v9
和 v10
安装
composer require skybluesofa/laravel-wrapped-facade
设置
安装配置文件
发布配置文件
运行 artisan 命令以发布包的配置文件
php artisan vendor:publish --tag=wrapped-facade-config
或
复制配置文件
将 wrapped-facade.php
文件从 vendor/skybluesofa/laravel-wrapped-facade/config
文件夹复制到您的应用程序的 config
文件夹。
使用 Wrapped Facades
Wrapped Facades 默认与标准 (Laravel Facades)[https://laravel.net.cn/docs/10.x/facades] 的工作方式完全相同。
基本 Facade 功能
让我们从基本的 Fruits
类开始
<?php
namespace App\Classes;
class Fruits
{
protected $data = [
1 => 'Apple',
2 => 'Banana',
3 => 'Carrot',
4 => 'Durifruit',
5 => 'Eggplant',
];
public function getAll(): array
{
return $this->data;
}
}
现在我们将创建一个 SuperFruits
门面,尽管如果你愿意,也可以将其命名为 Fruits
<?php
namespace App\Facades;
use App\Fruits;
use SkyBlueSofa\WrappedFacade\Facades\WrappedFacade;
class SuperFruits extends WrappedFacade
{
public static function getFacadeAccessor()
{
return Fruits::class;
}
}
当你运行门面代码时,你会得到一个包含水果和蔬菜的返回数组。
\App\Classes\SuperFruitsSuperFruits::getAll();
// Returns an array of fruits, just as we'd expect
将侧载功能添加到门面中
区别在于当你希望在方法运行之前和/或之后添加一些新功能时。
示例:缓存结果
我们将添加一个新属性和几个方法
<?php
namespace App\Facades;
use App\Fruits;
use SkyBlueSofa\WrappedFacade\Facades\WrappedFacade;
class SuperFruits extends WrappedFacade
{
public static function getFacadeAccessor()
{
return Fruits::class;
}
protected static $cachedFruits = null;
protected static function preIndex(array $args): ?callable
{
$cachedFruits = Cache::get('cachedFruits');
if (is_null($cachedFruits)) {
Log::info('Cache has expired');
return null;
}
// If we found the results, then we'll store it here until we're all done
Log::info('Returning cached results');
static::$cachedFruits = $cachedFruits;
return function () use ($cachedFruits) {
return $cachedFruits;
};
}
protected static function postIndex(array $args, mixed $results): mixed
{
if (! static::$cachedFruits) {
Log::info('Caching fruit data');
Cache::set('cachedFruits', $results);
static::$cachedFruits = null;
} else {
Log::info('Fruits were already in the cache');
}
return $results;
}
}
现在当你运行门面代码时,你仍然会得到一个包含水果和蔬菜的返回数组,但下一次访问时,它将从缓存中返回。
\App\Classes\SuperFruitsSuperFruits::getAll();
// Returns an array of fruits, just as we'd expect
示例:修改结果
在这个例子中,我们不会缓存结果。相反,我们将根据登录用户的偏好来过滤结果。
我们将把类更改为只有一个 'postIndex' 方法
<?php
namespace App\Facades;
use App\Fruits;
use SkyBlueSofa\WrappedFacade\Facades\WrappedFacade;
class SuperFruits extends WrappedFacade
{
public static function getFacadeAccessor()
{
return Fruits::class;
}
protected static function postIndex(array $args, mixed $results): mixed
{
// In this example , the user hates 'Banana'
$hatedFruit = Auth::user()->mostHatedFruit;
return array_diff(
$results,
[$hatedFruit]
);
}
}
现在当你运行门面代码时,你仍然会得到一个包含水果和蔬菜的返回数组,但 'Banana' 已经从数组中移除。
\App\Classes\SuperFruitsSuperFruits::getAll();
// Returns an array of fruits, sans Banana
[
1 => 'Apple',
2 => 'Carrot',
3 => 'Durifruit',
4 => 'Eggplant',
]
示例:使用多个侧载功能
在这个例子中,我们将在缓存结果之前验证结果。
我们将更新类以包括一个新的 'postIndexValidate' 方法和 'sideloadedMethodOrder' 属性
<?php
namespace App\Facades;
use App\Fruits;
use App\FruitValidator;
use SkyBlueSofa\WrappedFacade\Facades\WrappedFacade;
class SuperFruits extends WrappedFacade
{
public static function getFacadeAccessor()
{
return Fruits::class;
}
protected static $sideloadedMethodOrder = [
'postIndexValidate',
'postIndex',
];
protected static function postIndexValidate(array $args, mixed $results): mixed
{
// This is an example validator. How it works really doesn't matter.
$fruitValidator = new FruitValidator($results);
if (! $fruitValidator->validates()) {
throw new \RuntimeException('Fruit does not validate!');
}
return $results;
}
protected static function postIndex(array $args, mixed $results): mixed
{
// In this example , the user hates 'Banana'
$hatedFruit = Auth::user()->mostHatedFruit;
return array_diff(
$results,
[$hatedFruit]
);
}
}
我们假设 FruitValidator::validates()
将返回 false
。所以现在当你运行门面代码时,将抛出一个 \RuntimeException
。
\App\Classes\SuperFruitsSuperFruits::getAll();
// RuntimeException('Fruit does not validate!');
请注意,$sideloadedMethodOrder
数组可以有多种格式。所有这些都是有效的
// If you don't care what order things are run in:
// Don't add the $sideloadedMethodOrder property at all, or:
protected static $sideloadedMethodOrder = [];
// If you have only a few sideloaded methods, a simple array might be easiest.
// The array lists the specific sideloaded method names:
protected static $sideloadedMethodOrder = [
'postIndexValidate',
'postIndex',
];
// If you have quite a few sideloaded methods, a nested array might be clearer.
// The first level of the array is the sideloaded key (<pre|post> + <methodName>).
// The second level of the array lists the specific sideloaded method names:
protected static $sideloadedMethodOrder = [
'postIndex' => [
'postIndexValidate',
'postIndex',
],
];