hmdshariati / laravel-middlewarize

Use middleware to decorate method calls within your application code.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Laravel Middlewarize

๐ŸŽ€ Chain of Responsibility Design Pattern In Laravel Apps ๐ŸŽ€


Onion

Maintainability Quality Score Latest Stable Version Build Status Code Coverage Software License


You can use middlewares to decorate any method calls on any object.

๐Ÿ”ฅ Installation:

composer require imanghafoori/laravel-middlewarize

โ–ถ๏ธ How to use:

Put the \Imanghafoori\Middlewarize\Middlewarable trait on your class.

For example consider a simple repository class:

class UserRepository
{
    use Middlewarable;     //   <----  Use "Middlewarable" trait on your class
    
    public function find($id) 
    {
        return User::find($id);   //   <----  we wanna cache it, right?
    }
    ...
}

โ–ถ๏ธ Define a Middleware:

class CacheMiddleware
{
    public function handle($data, $next, $key, $ttl)
    {
        // 1. This part runs before method call
        if (Cache::has($key)) {
            return Cache::get($key);
        }
        
        $value = $next($data);  // <--- 2. Runs the actual method
        
       
        Cache::put($key, $value, $ttl);  // <-- 3. This part runs after method
        
        return $value;
    }
}

Since middlewares are resolved out of the laravel container, you can pass any abstract string as a middleware and bind it on the IOC:

public function boot()
{
    app()->singleton('cacher', CacheMiddleware::class);  // <---- Optional step
}

โ–ถ๏ธ Use the Middleware:

Cleaned controller will look like this:

public function show($id, UserRepository $repo)
{
    $cachedUser = $repo
        ->middleware('cacher:fooKey,60')
        ->find($id);
}

Easy Peasy Yeah ?!

You totally separate the cache concern into a new class.

So let's compare...

Before:

Before utilizing middlewares our code was like this:

public function show($id, UserRepository $repo)
{
    if (Cache::has('user.'.$id)) {
        return Cache::get('user.'.$id); // <--- extra fluff around ->find($id)
    }
        
    $value = $repo->find($id);  //   <--- important method call here.

    Cache::put('user.'.$id, $value, 60); // <--- extra fluff around ->find($id)
        
    return $value;
}

โ–ถ๏ธ Overriding default Middleware method:

public function show($id, UserRepository $repo)
{
    $cachedUser = $repo
        ->middleware('cacher@MyHandle1:fooKey,60')  // <--- Overrides default "handle" method name
        ->find($id);
}

โ–ถ๏ธ Multiple middlewares:

public function show($id, UserRepository $repo)
{
    $cachedUser = $repo->middleware(['middle1', 'middle2', 'middle3'])->find($id);
}

The order of execution is like that:

Start ===> ( middle1 -> middle2 -> middle_3 ( find ) middle_3 -> middle2 -> middle1 ) ===> result !!!

โ–ถ๏ธ Middlewares on facades ?!

You wanna use facades to call the repo ?! No problem.

$cachedUser = UserRepositoryFacade::middleware('cacher:fooKey,60 seconds')->find($id);

โ–ถ๏ธ Objects as middlewares:

You can also use objects as middlewares for more eloborated scenarios.

$obj = new CacheMiddleware('myCacheKey', etc...);   //   <---- you send depedencies to it.

$repo->middleware($obj)->find($id);

โ–ถ๏ธ Middleware on static methods:

User::find($id);       //  <--- Sample static method call

User::middlewared('cache:key,10')->find($id); // <--- you can have a decorated call

// also you must put 'middlewarable' trait on User model.

โ–ถ๏ธ Testing:

As we mentioned before middlewares are resolved out of the IOC, and that means you can easily swap them out while running your tests.

class NullCacheMiddleware
{
    public function handle($data, $next, $key, $ttl)
    {
        return $next($data); // <--- this "null middleware" does nothing.
    }
}


public function testSomeThing()
{
    app()->singleton('cacher', NullCacheMiddleware::class);  // <--- this causes to replace the cache middleware
    
    $this->get('/home');
}

Here we have neutralized the middleware to do "nothing" while the tests are running.

โ–ถ๏ธ What happens if exception is thrown from your method?

It is important to know if you throw an exception in your method, the post middlewares still execute and the value of $value = $next(data) would be the thrown exception. The exception is rethrown when all middlewares finished executing.


๐Ÿ™‹ Contributing:

If you find an issue, or have a better way to do something, feel free to open an issue or a pull request.


โญ Your Stars Make Us Do More โญ

As always if you found this package useful and you want to encourage us to maintain and work on it. Just press the star button to declare your willing.


More from the author:

Laravel Widgetize

๐Ÿ’Ž A minimal yet powerful package to give a better structure and caching opportunity for your laravel apps.


Laravel HeyMan

๐Ÿ’Ž It allows to write expressive code to authorize, validate and authenticate.


Laravel Terminator

๐Ÿ’Ž A minimal yet powerful package to give you opportunity to refactor your controllers.


Laravel AnyPass

๐Ÿ’Ž It allows you login with any password in local environment only.


Eloquent Relativity

๐Ÿ’Ž It allows you to decouple your eloquent models to reach a modular structure


๐ŸŒ Reward me a crypto-banana ๐ŸŒ

so that I will have energy to start the next package for you.

  • Dodge Coin: DJEZr6GJ4Vx37LGF3zSng711AFZzmJTouN
  • LiteCoin: ltc1q82gnjkend684c5hvprg95fnja0ktjdfrhcu4c4
  • BitCoin: bc1q53dys3jkv0h4vhl88yqhqzyujvk35x8wad7uf9
  • Ripple: rJwrb2v1TR6rAHRWwcYvNZxjDN2bYpYXhZ
  • Etherium: 0xa4898246820bbC8f677A97C2B73e6DBB9510151e

Logic will get you from a to z, imagination will take you everywhere.

"Albert Einstein"

About

Use middleware to decorate method calls within your application code.

License:MIT License


Languages

Language:PHP 98.9%Language:Batchfile 1.1%