ahmadvoid/simple-aop

SimpleAOP 是一个简单的 AOP (面向切面编程) 实现,它利用 PHP 8 的 #[Attributes] 语法提供在控制器方法上应用切面的能力

dev-main 2023-11-16 18:28 UTC

This package is auto-updated.

Last update: 2024-09-16 20:29:29 UTC


README

SimpleAOP 是一个 Laravel 扩展包,为您的 Laravel 应用程序提供面向切面编程 (AOP) 功能。AOP 是一种编程范式,允许您将跨切面关注点(如日志记录、缓存、事务管理等)模块化。通过定义可以应用于不同控制器类方法的切面。使用 SimpleAOP,您可以使用 PHP 8 的特性(属性类)轻松创建和使用切面。

目录

安装

您可以通过运行以下命令使用 Composer 安装 SimpleAOP:

composer require ahmadvoid/simple-aop

安装包后,您需要在您的 config/app.php 文件中注册 AspectServiceProvider

'providers' => [
    // ...
    AhmadVoid\SimpleAOP\AspectServiceProvider::class,
];

您还需要在您的 app/provider/RouteServiceProvider.php 文件中通过 aspect 别名中间件传递您的路由

public function boot()
{
    $this->configureRateLimiting();

    $this->routes(function () {
        Route::prefix('api')
            ->middleware('api')
            ->middleware('aspect') // passing requests in aspect
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));

        Route::middleware('web')
            ->namespace($this->namespace)
            ->group(base_path('routes/web.php'));
        });
}

最后,您需要通过运行以下命令发布包配置文件:

php artisan vendor:publish --provider="AhmadVoid\SimpleAOP\AspectServiceProvider"

这将在配置目录中创建一个 config/aop.php 文件,您可以在此处自定义包的设置。

使用方法

要使用 SimpleAOP,您需要创建定义您想要应用于方法或类的逻辑的切面。您可以使用属性类创建切面,这是 PHP 8 的特性,它允许您使用命令为代码添加元数据

php artisan make:aspect AspectName

这将创建一个具有以下原型(例如,路径为 app/Aspects)的切面属性类:

php artisan make:aspect Logger
<?php

namespace App\Aspects;

use AhmadVoid\SimpleAOP\Aspect;

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
class Logger implements Aspect
{

    // The constructor can accept parameters for the attribute
    public function __construct()
    {

    }

    public function executeBefore($request, $controller, $method)
    {
        // TODO: Implement executeBefore() method.
    }

    public function executeAfter($request, $controller, $method, $response)
    {
        // TODO: Implement executeAfter() method.
    }

    public function executeException($request, $controller, $method, $exception)
    {
        // TODO: Implement executeException() method.
    }
}

切面实现

AhmadVoid\SimpleAOP\Aspect 抽象类提供了 3 个抽象方法,您需要在您的切面类中实现这些方法

  • executeBefore:此方法在调用控制器方法之前执行。它接收请求、控制器实例和方法名称作为参数。

  • executeAfter:此方法在调用控制器方法之后执行。它接收请求、控制器实例、方法名称和响应作为参数。

  • executeException:如果在控制器方法执行期间抛出异常,则执行此方法。它接收请求、控制器实例、方法名称和异常作为参数。

让我们编写一些实现来记录请求、响应和异常

<?php

namespace App\Aspects;

use AhmadVoid\SimpleAOP\Aspect;
use Illuminate\Support\Facades\Log;

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
class Logger implements Aspect
{
    // The constructor can accept parameters for the attribute
    public function __construct(public string $message = 'Logging...')
    {
        //
    }

    public function executeBefore($request, $controller, $method)
    {
        Log::info($this->message);
        Log::info('Request: ' . $request->fullUrl());
        Log::info('Controller: ' . get_class($controller));
        Log::info('Method: ' . $method);
    }

    public function executeAfter($request, $controller, $method, $response)
    {
        Log::info('Response: ' . $response->getContent());
    }

    public function executeException($request, $controller, $method, $exception)
    {
        Log::error($exception->getMessage());
    }
}

然后,您可以将属性应用于您想要记录的任何控制器方法

<?php

namespace App\Http\Controllers;

use App\Aspects\Logger;
use Illuminate\Http\Request;

class TestController extends Controller
{
    #[Logger]
    public function index(Request $request)
    {
        var_dump('hello from index method');
    }
}

例如,index 方法的路由

Route::get('test', [TestController::class, 'index']);

现在,每次访问 /test 路由时,都会在 index 方法之前和之后执行 Logger 切面,并将请求和响应详细信息记录下来。

我们还可以通过在控制器类本身上应用切面属性来将切面应用于所有控制器方法。例如

<?php

namespace App\Http\Controllers;

use App\Aspects\Logger;
use Illuminate\Http\Request;

#[Logger]
class TestController extends Controller
{
    public function index(Request $request)
    {
        var_dump('hello from index method');
    }

    public function create(Request $request)
    {
        var_dump('hello from create method');
    }
}

这将导致将切面 'Logger' 应用于 TestController 的每个方法。

您可以根据需要创建和使用任意数量的切面,并将它们应用于不同的方法或类。您还可以在同一个方法或类上使用多个切面属性,并且它们将按照定义的顺序执行。

功能

SimpleAOP 为您的 Laravel 应用程序提供了以下功能

  • 使用属性类轻松创建和使用切面
  • 支持 3 种类型的切面方法:before、after 和 exception。
  • 切面的灵活配置和定制。
  • 缓存属性实例以提高性能
  • 兼容 PHP 8 和 Laravel 8

要求

SimpleAOP需要以下版本的PHP和Laravel

  • PHP >= 8.0
  • Laravel >= 8.0

贡献者和许可证

SimpleAOP由[Ahmad Alhalabi]创建和维护。

SimpleAOP遵循[MIT许可证],这意味着您可以自由地使用、修改和分发它,只要您给予原作者信用并在您的项目中包含许可证文件。