imanghafoori/laravel-decorator

一个易于装饰函数调用的包。

v1.1.0 2024-05-06 16:47 UTC

This package is auto-updated.

Last update: 2024-09-06 17:36:22 UTC


README

Laravel应用中的装饰器模式

Quality Score StyleCI Software License Check Imports Latest Stable Version Code Coverage Total Downloads

为聪明的整洁程序员而设计,爱心满满

尝试将Python语言中的"装饰器"功能移植到Laravel框架中。

python-and-prey

🚚 安装

composer require imanghafoori/laravel-decorator

什么是 "装饰器"

装饰器是一个可调用的函数,它围绕原始装饰的可调用函数包装,以形成一个新的可调用函数,该函数由前两个组成。

就像一条蛇把一只鹿整个吞下去,然后围绕它的身体盘旋!

之后,这条蛇就具有了吃草和消化草的能力了,因为它的体内有只鹿。

技术上,一个 "装饰器"

1- 是一个 "可调用对象"

2- 它接受另一个 "可调用对象"(就像蛇吞食另一条蛇一样,作为它的唯一参数)

3- 并返回一个新的 "可调用对象"(它在内部调用原始的可调用对象,在它之前和之后放置一些代码)

什么?!?!?! (0_o)

在Laravel中,什么可以被认为是 "可调用对象"?!?

简单来说,任何可以被调用(调用)的东西,例如:使用 App::call();call_user_func() 调用,如:'MyClass@myMethod' 或闭包,[UserRepo::class, 'find']

像专业人士一样缓存

缓存数据库查询总是需要的,但总是很麻烦要在现有代码中添加更多代码。它会使代码更加混乱,我们可能会破坏当前的代码,毕竟它增加了一层雾。

想象一下,你有一个 UserController,它调用 UserRepo@find 来获取 $user

然后过了一段时间,你决定出于明显的原因在这两个类之间添加一个缓存层。

根据SOLID原则,你不应该在控制器或UserRepo中放置缓存代码逻辑,而应该在两者之间。

换句话说,你希望在不修改现有代码的情况下添加新功能(在这个例子中是缓存)。

这听起来像是 开闭原则 对吧?!👃

你希望保持职责分离。在这种情况下,缓存不应该在存储库或控制器中,而应该在其自己的类中。

这听起来像是 单一职责原则 对吧?!👃

class UserRepository
{
    function find($uid)
    {
        return User::find($uid);
    }
}

class MadUsersController extends Controller
{
    function show ($madUserId)
    {
        $madUser = app()->call('UserRepository@find', ['id' => $madUserId]);
    }
}

现在没有缓存,直接调用。

借助laravel-decorator内置的缓存装饰器,你可以去 AppServiceProvider.php(或任何其他服务提供者)

<?php

use Imanghafoori\Decorator\Decorators\DecoratorFactory;

class AppServiceProvider extends ServiceProvider
{

    public function boot()
    {
        $keyMaker = function ($madId) {
            return 'mad_user_key_' . $madId;
        };
        $time = 10;
        $decorator = DecoratorFactory::cache($keyMaker, $time);
        
        \Decorator::decorate('UserRepository@find', $decorator);
    }
}

你将在你的 UserController 中从调用中获取缓存的输出,而不需要触摸它!但请记住更改

 app()->call('UserRepository@find', ...
 // to :
  app('decorator')->call('UserRepository@find', ...

定义你自己的装饰器

public function boot ()
{
    \Decorator::define('myDecoratorName1', 'SomeClass@someMethod');
    
    // or

    \Decorator::define('myDecoratorName2', function ($callable) {
        return function (...) use ($callable){ ... } 
    });
}

然后你可以使用这个名称(myDecoratorName)来装饰方法。

如何装饰一个方法?

// You may set multiple decorators on a single method... 
\Decorator::decorate('class@method, 'someClass@someOtherDecorator'); // (first)

// or reference the decorator by its name :
\Decorator::decorate('class@method, 'myDecoratorName'); // (second)

如何调用带其装饰器的方法?

image

装饰门面

装饰门面方法

首先,你应该扩展 Imanghafoori\Decorator\DecoratableFacade 类(而不是laravel基门面)。

image

现在你可以在你的服务提供者的boot方法中应用装饰器

image

然后,当你像平常一样调用你的门面时,你会得到装饰的结果。

image

⚠️ 注意

能力越大,责任越大。

记住,当你装饰某物时,不要违反 Liskoves替代原则

例如,一个返回 int|null 的方法调用在装饰后不应该意外地返回 string

$result = app('decorate')->call(...

因为方法的用户应该准备好接受他们得到的值的类型。

但是如果你只返回 int 类型,并且你的装饰器导致 null 值被过滤掉,那就没问题。

⭐ 你的点赞让我们做得更多 ⭐

一如既往,如果你觉得这个包很有用,并希望鼓励我们维护和改进它,请 点击星号按钮 表达你的意愿。

作者的其他包

💎 一个简洁而强大的包,为你提供重构控制器的机会。

💎 一个简洁而强大的包,为你的Laravel应用提供更好的结构和缓存机会。

💎 它仅允许你在本地环境中使用任何密码登录。

💎 与 hey-man 包一起,授权和ACL现在变得非常简单!