Aspect Oriented Programming library for laravel framework, and lumen
ytake/laravel-aspect is a Laravel package for aspect oriented programming library for laravel framework, and lumen.
It currently has 138 GitHub stars and 142.806 downloads on Packagist (latest version 11.0.1).
Install it with composer require ytake/laravel-aspect.
Discover more Laravel packages by ytake
or browse all Laravel packages to compare alternatives.
Last updated
aspect-oriented programming Package for laravel framework
This library is heavily inspired by the jcabi/jcabi-aspects.
Laravel | Package :---------|:---------- 5.0.x | 1.x 5.1.x | 1.x 5.2.x | 1.x 5.3.x | 1.x 5.4.x | 1.x 5.5.x | 2.0.* 5.6.x | 2.1.* 5.7.x | 3.0.* 6.0.x | 4.0 7.x | 6.0 8.x | 7.0 9.x | 8.0 10.x | 9.0
$ composer require ytake/laravel-aspect
Supported Auto-Discovery(^Laravel5.5)
Laravel-Aspect Supported Laravel5.6
"require": {
"php": ">=7.1.3",
"laravel/framework": "^5.7",
"ytake/laravel-aspect": "^8.0.0"
},
'providers' => [
// added AspectServiceProvider
\Ytake\LaravelAspect\AspectServiceProvider::class,
// added Artisan Command
\Ytake\LaravelAspect\ConsoleServiceProvider::class,
]
Add App\Providers\LumenAspectServiceProvider to your bootstrap/app.php file.
$app->register(\App\Providers\LumenAspectServiceProvider::class);
$app->register(\Ytake\LaravelAspect\ConsoleServiceProvider::class);
$ php artisan ytake:aspect-module-publish
more command options [--help]
$ php artisan vendor:publish
$ php artisan vendor:publish --tag=aspect
$ php artisan vendor:publish --provider="Ytake\LaravelAspect\AspectServiceProvider"
config/ytake-laravel-aop.php
'modules' => [
// append modules
// \App\Modules\CacheableModule::class,
],
use classes property
namespace App\Modules;
use Ytake\LaravelAspect\Modules\CacheableModule as PackageCacheableModule;
/**
* Class CacheableModule
*/
class CacheableModule extends PackageCacheableModule
{
/** @var array */
protected $classes = [
\YourApplication\Services\SampleService::class
];
}
example
namespace YourApplication\Services;
use Ytake\LaravelAspect\Annotation\Cacheable;
class SampleService
{
/**
* @Cacheable(cacheName="testing1",key={"#id"})
*/
public function action($id)
{
return $this;
}
}
notice
override 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
for database transaction(illuminate/database)
you must use the TransactionalModule
| params | description | |-----|-------| | value (or array) | database connection | | expect | expect exception |
use Ytake\LaravelAspect\Annotation\Transactional;
/**
* @Transactional("master")
*/
public function save(array $params)
{
return $this->eloquent->save($params);
}
use Ytake\LaravelAspect\Annotation\Transactional;
/**
* @Transactional({"master", "second_master"})
*/
public function save(array $params)
{
$this->eloquent->save($params);
$this->query->save($params);
}
for cache(illuminate/cache)
you must use the CacheableModule
| params | description | |-----|-------| | key | cache key | | cacheName | cache name(merge cache key) | | driver | Accessing Cache Driver(store) | | lifetime | cache lifetime (default: 120min) | | tags | Storing Tagged Cache Items | | negative(bool) | for null value (default: false) |
use Ytake\LaravelAspect\Annotation\Cacheable;
/**
* @Cacheable(cacheName="testing1",key={"#id","#value"})
* @param $id
* @param $value
* @return mixed
*/
public function namedMultipleKey($id, $value)
{
return $id;
}
for cache(illuminate/cache) / remove cache
you must use the CacheEvictModule
| params | description | |-----|-------| | key | cache key | | cacheName | cache name(merge cache key) | | driver | Accessing Cache Driver(store) | | tags | Storing Tagged Cache Items | | allEntries | flush(default:false) |
use Ytake\LaravelAspect\Annotation\CacheEvict;
/**
* @CacheEvict(cacheName="testing",tags={"testing1"},allEntries=true)
* @return null
*/
public function removeCache()
{
return null;
}
for cache(illuminate/cache) / cache put
you must use the CachePutModule
| params | description | |-----|-------| | key | cache key | | cacheName | cache name(merge cache key) | | driver | Accessing Cache Driver(store) | | lifetime | cache lifetime (default: 120min) | | tags | Storing Tagged Cache Items |
use Ytake\LaravelAspect\Annotation\CachePut;
/**
* @CachePut(cacheName={"testing1"},tags="testing1")
*/
public function throwExceptionCache()
{
return 'testing';
}
for logger(illuminate/log, monolog)
you must use the LoggableModule / LogExceptionsModule
| params | description | |-----|-------| | value | log level (default: Level::Info->value). Supports integer constants, Monolog Level enum values, or string level names ("debug", "info", etc.) | | skipResult | method result output to log | | name |log name prefix(default: Loggable) | | driver | logger driver or channel name docs |
use Ytake\LaravelAspect\Annotation\Loggable;
class AspectLoggable
{
/**
* @Loggable(driver="stack")
* @param null $id
* @return null
*/
public function normalLog($id = null)
{
return $id;
}
}
sample)
[2015-12-23 08:15:30] testing.INFO: Loggable:__Test\AspectLoggable.normalLog {"args":{"id":1},"result":1,"time":0.000259876251221}
Also, take a look at @Loggable. This annotation does the same, but also logs non-exceptional situations.
use Ytake\LaravelAspect\Annotation\LogExceptions;
class AspectLoggable
{
/**
* @LogExceptions(driver="custom")
* @param null $id
* @return null
*/
public function dispatchLogExceptions()
{
return $this->__toString();
}
}
for database query logger(illuminate/log, monolog, illuminate/database)
use Ytake\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(driver="custom")
*/
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"} ...
Retry the method in case of exception.
you must use the RetryOnFailureModule.
| params | description | |-----|-------| | attempts (int) | How many times to retry. (default: 0) | | delay (int) | Delay between attempts. (default: 0 / sleep(0) ) | | types (array) | When to retry (in case of what exception types). (default: <\Exception::class> ) | | ignore (string) | Exception types to ignore. (default: \Exception ) |
use Ytake\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;
}
}
Annotation for a Message Queue(illuminate/queue. illuminate/bus).
you must use the MessageDrivenModule.
| params | description | |-----|-------| | value (Delayed) | \Ytake\LaravelAspect\Annotation\LazyQueue or \Ytake\LaravelAspect\Annotation\EagerQueue (default: EagerQueue)| | onQueue (string) | To specify the queue. (default: null) ) | | mappedName (string) | queue connection. (default: null/ default queue driver) |
use Ytake\LaravelAspect\Annotation\EagerQueue;
use Ytake\LaravelAspect\Annotation\LazyQueue;
use Ytake\LaravelAspect\Annotation\Loggable;
use Ytake\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";
}
}
Handle Class Ytake\LaravelAspect\Queue\LazyMessage
Handle Class Ytake\LaravelAspect\Queue\EagerMessage
use config/ytake-laravel-aspect.php file
default: 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...
]
],
use none driver
<env name="ASPECT_DRIVER" value="none"/>