jonaskahn/laravel-aspect

该软件包已被废弃且不再维护。未建议替代软件包。

为 Laravel 框架和 Lumen 设计的面向切面编程库

dev-main 2024-08-30 08:41 UTC

This package is auto-updated.

Last update: 2024-09-30 08:48:48 UTC


README

  • 修复了一些错误
  • 扩展了函数的能力
  • 事务逻辑现在应该像 Spring 框架那样自然工作

为什么不创建一个 pull request

  • 我的代码将破坏当前实现。例如,当我遇到源代码时,我发现事务相当“奇怪”(与 Spring 框架相比),然后我决定进行分支并更改源代码以满足我的目的。

注意

  • 如果您正在使用原始实现,请勿使用我的工作。
  • 我的工作自 2021 年开始实施,现在我将此源代码开源。

Laravel-Aspect

为 Laravel 框架提供的面向切面编程软件包

Build Status StyleCI

License Latest Version Total Downloads

此库在很大程度上受到 jcabi/jcabi-aspects 的启发。

用法

Laravel 版本兼容性

安装

$ composer require ytake/laravel-aspect

支持的自动发现(^Laravel5.5)

针对 Laravel9

Laravel-Aspect 支持 Laravel5.6

  "require": {
   "php": ">=7.1.3",
   "laravel/framework": "^5.7",
   "ytake/laravel-aspect": "^8.0.0"
 },

添加 serviceProvider

'providers' => [
    // added AspectServiceProvider 
    \Ytake\LaravelAspect\AspectServiceProvider::class,
    // added Artisan Command
    \Ytake\LaravelAspect\ConsoleServiceProvider::class,
]

针对 Lumen

将 App\Providers\LumenAspectServiceProvider 添加到您的 bootstrap/app.php 文件中。

$app->register(\App\Providers\LumenAspectServiceProvider::class);
$app->register(\Ytake\LaravelAspect\ConsoleServiceProvider::class);

发布 aspect 模块类

$ php artisan ytake:aspect-module-publish

更多命令选项 [--help]

发布配置

  • 基本
$ php artisan vendor:publish
  • 使用 tag 选项
$ php artisan vendor:publish --tag=aspect
  • 使用提供者
$ php artisan vendor:publish --provider="Ytake\LaravelAspect\AspectServiceProvider"

注册 aspect 模块

config/ytake-laravel-aop.php

        'modules' => [
            // append modules
            // \App\Modules\CacheableModule::class,
        ],

使用 classes 属性

namespace App\Modules;

use Ytake\LaravelAspect\Modules\CacheableModule as PackageCacheableModule;

/**
 * Class CacheableModule
 */
class CacheableModule extends PackageCacheableModule
{
    /** @var array */
    protected $classes = [
        \YourApplication\Services\SampleService::class
    ];
}

示例

namespace YourApplication\Services;

use Ytake\LaravelAspect\Annotation\Cacheable;

class SampleService
{
    /**
     * @Cacheable(cacheName="testing1",key={"#id"})
     */
    public function action($id) 
    {
        return $this;
    }
}

注意

  • 必须使用服务容器
  • 类必须非最终
  • 方法必须是公共的

针对 Lumen

覆盖 Ytake\LaravelAspect\AspectServiceProvider

use Ytake\LaravelAspect\AspectManager;
use Ytake\LaravelAspect\AnnotationManager;
use Ytake\LaravelAspect\AspectServiceProvider as AspectProvider;

/**
 * Class AspectServiceProvider
 */
final class AspectServiceProvider extends AspectProvider
{
    /**
     * {@inheritdoc}
     */
    public function register()
    {
        $this->app->configure('ytake-laravel-aop');
        $this->app->singleton('aspect.manager', function ($app) {
            $annotationConfiguration = new AnnotationConfiguration(
                $app['config']->get('ytake-laravel-aop.annotation')
            );
            $annotationConfiguration->ignoredAnnotations();
            // register annotation
            return new AspectManager($app);
        });
    }
}

bootstrap/app.php

$app->register(App\Providers\AspectServiceProvider::class);

if ($app->runningInConsole()) {
    $app->register(Ytake\LaravelAspect\ConsoleServiceProvider::class);
}

缓存清除命令

$ php artisan ytake:aspect-clear-cache

预编译命令

$ php artisan ytake:aspect-compile

注解

@Transactional

用于数据库事务(illuminate/database)

您必须使用 TransactionalModule 选项

  • 选项
use Bssd\LaravelAspect\Annotation\Transactional;

/**
 * @Transactional("master")
 */
public function save(array $params)
{
    return $this->eloquent->save($params);
}

多重事务

use Bssd\LaravelAspect\Annotation\Transactional;

/**
 * @Transactional({"master", "second_master"})
 */
public function save(array $params)
{
    $this->eloquent->save($params);
    $this->query->save($params);
}

异常回滚

use Bssd\LaravelAspect\Annotation\Transactional;

/**
 * @Transactional(expect="\QueryException")
 */
public function save(array $params)
{
    $this->eloquent->save($params);
    $this->query->save($params);
}

多重异常回滚

use Bssd\LaravelAspect\Annotation\Transactional;

/**
 * @Transactional(expect={"\QueryException", "\RuntimeException"})
 */
public function save(array $params)
{
    $this->eloquent->save($params);
    $this->query->save($params);
}

@Cacheable

用于缓存(illuminate/cache)

您必须使用 CacheableModule

  • 选项
use Bssd\LaravelAspect\Annotation\Cacheable;

/**
 * @Cacheable(cacheName="testing1",key={"#id","#value"})
 * @param $id
 * @param $value
 * @return mixed
 */
public function namedMultipleKey($id, $value)
{
    return $id;
}

@CacheEvict

用于缓存(illuminate/cache) / 删除缓存

您必须使用 CacheEvictModule

  • 选项
use Bssd\LaravelAspect\Annotation\CacheEvict;

/**
 * @CacheEvict(cacheName="testing",tags={"testing1"},allEntries=true)
 * @return null
 */
public function removeCache()
{
    return null;
}

@CachePut

用于缓存(illuminate/cache) / 缓存放置

您必须使用 CachePutModule

  • 选项
use Bssd\LaravelAspect\Annotation\CachePut;

/**
 * @CachePut(cacheName={"testing1"},tags="testing1")
 */
public function throwExceptionCache()
{
    return 'testing';
}

@Loggable / @LogExceptions

用于日志(illuminate/log, monolog)

您必须使用 LoggableModule / LogExceptionsModule

  • 选项
use Bssd\LaravelAspect\Annotation\Loggable;

class AspectLoggable
{
    /**
     * @Loggable
     * @param null $id
     * @return null
     */
    public function normalLog($id = null)
    {
        return $id;
    }
}

示例)

[2015-12-23 08:15:30] testing.INFO: Loggable:__Test\AspectLoggable.normalLog {"args":{"id":1},"result":1,"time":0.000259876251221}

关于 @LogExceptions

此外,还可以查看 @Loggable。此注解执行相同的操作,但还可以记录非异常情况。

use Bssd\LaravelAspect\Annotation\LogExceptions;

class AspectLoggable
{
    /**
     * @LogExceptions
     * @param null $id
     * @return null
     */
    public function dispatchLogExceptions()
    {
        return $this->__toString();
    }
}

关于 @QueryLog

用于数据库查询日志(illuminate/log, monolog, illuminate/database)

use Bssd\LaravelAspect\Annotation\QueryLog;
use Illuminate\Database\ConnectionResolverInterface;

/**
 * Class AspectQueryLog
 */
class AspectQueryLog
{
    /** @var ConnectionResolverInterface */
    protected $db;

    /**
     * @param ConnectionResolverInterface $db
     */
    public function __construct(ConnectionResolverInterface $db)
    {
        $this->db = $db;
    }

    /**
     * @QueryLog
     */
    public function multipleDatabaseAppendRecord()
    {
        $this->db->connection()->statement('CREATE TABLE tests (test varchar(255) NOT NULL)');
        $this->db->connection('testing_second')->statement('CREATE TABLE tests (test varchar(255) NOT NULL)');
        $this->db->connection()->table("tests")->insert(['test' => 'testing']);
        $this->db->connection('testing_second')->table("tests")->insert(['test' => 'testing second']);
    }
}
testing.INFO: QueryLog:AspectQueryLog.multipleDatabaseAppendRecord {"queries":[{"query":"CREATE TABLE tests (test varchar(255) NOT NULL)","bindings":[],"time":0.58,"connectionName":"testing"},{"query":"CREATE TABLE tests (test varchar(255) NOT NULL)","bindings":[],"time":0.31,"connectionName":"testing_second"} ...

@PostConstruct

PostConstruct 注解用于需要在依赖注入完成后执行初始化的方法。

您必须使用 PostConstructModule

use Bssd\LaravelAspect\Annotation\PostConstruct;

class Something
{
    protected $abstract;
    
    protected $counter = 0;
    
    public function __construct(ExampleInterface $abstract)
    {
        $this->abstract = $abstract;
    }
    
    /**
     * @PostConstruct
     */
    public function init()
    {
        $this->counter += 1;
    }
    
    /**
     * @return int
     */
    public function returning()
    {
        return $this->counter;
    }
}

该方法不得有任何参数

@RetryOnFailure

在发生异常的情况下重试方法。

您必须使用 RetryOnFailureModule。

  • 选项
use Bssd\LaravelAspect\Annotation\RetryOnFailure;

class ExampleRetryOnFailure
{
    /** @var int */
    public $counter = 0;

    /**
     * @RetryOnFailure(
     *     types={
     *         LogicException::class,
     *     },
     *     attempts=3,
     *     ignore=Exception::class
     * )
     */
    public function ignoreException()
    {
        $this->counter += 1;
        throw new \Exception;
    }
}

@MessageDriven

用于消息队列(illuminate/queue, illuminate/bus)的注解。

您必须使用 MessageDrivenModule。

  • 选项
use Bssd\LaravelAspect\Annotation\EagerQueue;
use Bssd\LaravelAspect\Annotation\LazyQueue;
use Bssd\LaravelAspect\Annotation\Loggable;
use Bssd\LaravelAspect\Annotation\MessageDriven;

/**
 * Class AspectMessageDriven
 */
class AspectMessageDriven
{
    /**
     * @Loggable
     * @MessageDriven(
     *     @LazyQueue(3),
     *     onQueue="message"
     * )
     * @return void
     */
    public function exec($param)
    {
        echo $param;
    }

    /**
     * @MessageDriven(
     *     @EagerQueue
     * )
     * @param string $message
     */
    public function eagerExec($message)
    {
        $this->logWith($message);
    }

    /**
     * @Loggable(name="Queued")
     * @param string $message
     *
     * @return string
     */
    public function logWith($message)
    {
        return "Hello $message";
    }
}

懒队列

处理类 Bssd\LaravelAspect\Queue\LazyMessage

急切队列

处理类 Bssd\LaravelAspect\Queue\EagerMessage

忽略注解

使用 config/ytake-laravel-aspect.php 文件

默认: LaravelCollective/annotations

    'annotation' => [
        'ignores' => [
            // global Ignored Annotations
            'Hears',
            'Get',
            'Post',
            'Put',
            'Patch',
            'Options',
            'Delete',
            'Any',
            'Middleware',
            'Resource',
            'Controller'
        ],
    ],

添加自定义注解

    'annotation' => [
        'ignores' => [
            // global Ignored Annotations
            'Hears',
            'Get',
            'Post',
            'Put',
            'Patch',
            'Options',
            'Delete',
            'Any',
            'Middleware',
            'Resource',
            'Controller'
        ],
        'custom' => [
            \Acme\Annotations\Transactional::class
            // etc...
        ]
    ],

用于测试

使用 none 驱动

<env name="ASPECT_DRIVER" value="none"/>