imanghafoori/laravel-heyman

一个帮助您用函数式方法编写表达性防御性代码的包

v2.2.58 2024-03-02 15:42 UTC

README

可读性计数。事实上,可读性是您代码的主要价值!!!

Quality Score Coverage Status Maintainability Imports Test StyleCI Latest Stable Version Daily Downloads Total Downloads Awesome Laravel Software License

🎀 Heyman 从其他角色权限包留下的地方继续...

我们结合了 CDD(创意驱动开发)和 TDD

为每个智能的 Laravel 开发者用心构建

非常经过测试,优化,并已准备好生产使用!

我们在幕后处理了很多 复杂性,为您提供了很多 简单性

安装


composer require imanghafoori/laravel-heyman

要求

  • PHP v7.0 或以上
  • Laravel v5.1 或以上

示例

您可以在以下位置看到一个很好的示例

https://github.com/imanghafoori1/council

特别是这个文件

https://github.com/imanghafoori1/council/blob/master/app/Providers/AuthServiceProvider.php

这是从 laracasts.com 教程系列的结果进行重构,以使用 Heyman 包。

Heyman,让我们打击僵尸

僵尸 HTTP 请求 =>


<= Laravel Heyman





一个故事

想象一下,您的老板来找您说

 Hey man !!!
 
 When you visit the login form,
 
 You should be guest,
 
 Otherwise you get redirected to '/panel',

现在给我写代码,但请注意,您不允许触摸当前的代码。它非常敏感,我们不希望您篡改它。您可能会破坏它。

然后您在 Service Provider 的 boot 方法中编写这样的代码来实现您老板的要求。

image

这就是这个包为您做的事情+更多...

可定制的语法

如果您不喜欢默认提供的过多冗长的语法,您可以像这样给方法起别名。

  • 别名情况(例如,将 whenYouMakeView 别名为 view
  • 别名条件(例如,将 youShouldBeGuest 别名为 beGuest

您应该在 boot 方法中执行此操作。

alias methods

结构优势

1- 这样,您可以完全 解耦 授权和很多防御性代码与您应用程序的其他代码,并将其放在另一个地方。因此,您的控制器和路由变得不那么拥挤,您将有一个中央位置来限制用户对您的应用程序的访问或执行请求验证。

2- 实际上,当您以这种方式编写代码时,您正在遵循著名的 "告诉而不是询问原则。"

您正在告诉框架在特定情况下要做什么,而不是获取信息然后决定要做什么。

过程性代码获取信息然后做出决定。面向对象代码告诉对象做事情。 —— Alec Sharp

3- 这种方法特别适用于您编写需要 ACL 但希望允许您的包用户覆盖并应用他们自己的 ACL(或验证)规则到您的包路由的包...

当您使用 laravel-HeyMan 进行 ACL 时,这成为可能。用户可以轻松取消默认规则,并在常规 Service Providers 中重写他们喜欢的 acl 或验证内容。

Hey Man,这是惊人的东西!

// This is written in package and lives in vendor folder, So we can not touch it.
HeyMan::whenYouHitRouteName('myPackageRoute')->youShouldHaveRole(....; 

要覆盖它,我们使用 forget 方法,在 app/Providers/...

public function boot() {
  
  // Cancels out the current rules
   HeyMan::forget()->aboutRoute('myPackageRoute');
  
  
   // Add new rules by package user.
   HeyMan::whenYouHitRouteName('myPackageRoute')-> ... 
   
}

Hey Man,我应该记住所有方法吗?!

您不需要任何备忘单。

IDE 的 自动完成 完全支持。

refactor5

嘿,兄弟,我该在哪里放置这些 Heyman:: 调用?

你可以将它们放在 AuthServiceProvider.php(或任何其他服务提供者)的 boot 方法中。

image

用法

你应该调用 HeyMan Facade 类的以下方法。

use Imanghafoori\HeyMan\Facades\HeyMan;
// or
use HeyMan;  // <--- alias

再次推荐您访问此文件

工作 heyman 样例规则

情况

HeyMan::  (situation) ->   (condition)   -> otherwise() -> (reaction) ;

1- URL 匹配

HeyMan::whenYouVisitUrl(['/welcome', '/home'])->...   // you can pass an Array
HeyMan::whenYouVisitUrl('/admin/*')->...     // or match by wildcard
HeyMan::whenYouSendPost('/article/store')->   ...   
HeyMan::whenYouSendPatch('/article/edit')->  ...  
HeyMan::whenYouSendPut('/article/edit')->    ...     
HeyMan::whenYouSendDelete('/article/delete')-> ...

2- 路由名称匹配

HeyMan::whenYouHitRouteName('welcome.name')->...              // For route names
HeyMan::whenYouHitRouteName('welcome.*')->...                 // or match by wildcard

3- 控制器操作即将调用

HeyMan::whenYouCallAction('HomeController@index')->...
HeyMan::whenYouCallAction('HomeController@*')->...          // or match by wildcard

4- 即将渲染视图文件

 HeyMan::whenYouMakeView('article.editForm')->...     // also accepts an array
 HeyMan::whenYouMakeView('article.*')->...            // You can watch a group of views

实际上,它指的是执行 view('article.editForm') 的时刻。

5- 触发自定义事件

HeyMan::whenEventHappens('myEvent')->...

实际上,它指的是执行 event('myEvent') 的时刻。

6- 即将保存 Eloquent 模型

HeyMan::whenYouSave(\App\User::class)->...
HeyMan::whenYouFetch(\App\User::class)->...
HeyMan::whenYouCreate(\App\User::class)->...
HeyMan::whenYouUpdate(\App\User::class)->...
HeyMan::whenYouDelete(\App\User::class)->...

实际上,它指的是 eloquent 触发其内部事件(如:保存、删除、创建等)的时刻。

注意,即将保存的模型被传递到下一个链式调用中的回调门。所以,例如,你可以检查正在保存的模型的 ID。

条件

HeyMan::  (situation) ->   (condition)   -> otherwise() -> (reaction) ;

在提到情况之后,是时候提到条件了。

1- 门

// define Gate
Gate::define('hasRole', function(){...});

然后你可以使用门

HeyMan::whenYouVisitUrl('/home')->thisGateShouldAllow('hasRole', 'editor')->otherwise()->...;

将闭包作为门传递

$gate = function($user, $role) {
    /// some logic
    return true;
}
HeyMan::whenYouVisitUrl('/home')->thisGateShouldAllow($gate, 'editor')->otherwise()->...;

2- 身份验证相关

HeyMan::whenYouVisitUrl('/home')->  youShouldBeGuest()    ->otherwise()->...;
HeyMan::whenYouVisitUrl('/home')->  youShouldBeLoggedIn() ->otherwise()->...;

3- 检查 ClosureMethodValue

HeyMan::whenYouVisitUrl('home')->thisMethodShouldAllow('someClass@someMethod', ['param1' => 'value1'])->otherwise()->...;
HeyMan::whenYouVisitUrl('home')->thisClosureShouldAllow( function($a) { ... }, ['param1'] )  ->otherwise()->...;
HeyMan::whenYouVisitUrl('home')->thisValueShouldAllow( $someValue )->otherwise()->...;

4- 验证请求

HeyMan::whenYouHitRouteName('articles.store')->yourRequestShouldBeValid([
    'title' => 'required', 'body' => 'required',
]);

你也可以通过调用 beforeValidationModifyData() 在验证之前修改数据。

$modifier = function ($data) {
  // removes "@" character from the "name" before validation.
  $data['name'] = str_replace('@', '', $data['name']);
  return $data;
}

HeyMan::whenYouHitRouteName('welcome.name')
        ->yourRequestShouldBeValid(['name' => 'required'])
        ->beforeValidationModifyData($modifier);

5- 检查点

你还可以在应用程序代码中某个地方声明一些检查点,并为其设置一些规则

HeyMan::checkPoint('MyLane');

并放置一些规则

HeyMan::whenYouReachCheckPoint('MyLane')->youShouldHaveRole('Zombie')-> ...
HeyMan::whenYouVisitUrl('home')->always()-> ...
HeyMan::whenYouVisitUrl('home')->sessionShouldHave('key1')->...

其他事情

你也可以使用 "always" 和 "sessionShouldHave" 方法

HeyMan::whenYouVisitUrl('home')->always()-> ...
HeyMan::whenYouVisitUrl('home')->sessionShouldHave('key1')->...

定义自己的条件

你可以扩展条件,并向 Heyman API 中引入新方法,如下所示

// Place this code:
// In the `boot` method of your service providers

HeyMan::condition('youShouldBeMan', function () {
   return function () {
       return auth()->user() && auth()->user()->gender === 'Man';
   };
});

// or 

HeyMan::condition('youShouldBeMan', '\App\SomeWhere\SomeClass@someMethod');

然后你可以这样使用它

HeyMan::whenYouVisitUrl('home')->youShouldBeMan()-> ...

不错,不是吗 ?!

反应

HeyMan::  (situation) ->   (condition)   -> otherwise() -> (reaction) ;

1- 拒绝访问

HeyMan::whenSaving(\App\User::class)->thisGateShouldAllow('hasRole', 'editor')->otherwise()->weDenyAccess();

如果需要,将抛出 AuthorizationException

2- 重定向

HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->redirect()->to(...)     ->with([...]);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->redirect()->route(...)  ->withErrors(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->redirect()->action(...) ->withInput(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->redirect()->intended(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->redirect()->guest(...);

实际上,这里的重定向方法与 Laravel 的 redirect() 辅助函数非常相似。

3- 抛出异常

$msg = 'My Message';

HeyMan::whenYouVisitUrl('/login')
    ->youShouldBeGuest()
    ->otherwise()
    ->weThrowNew(AuthorizationException::class, $msg);

4- 中断

HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->abort(...);

5- 发送响应

调用这些函数将生成与在 response() 辅助函数上调用它们完全相同的效果:return response()->json(...);

HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->response()->json(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->response()->view(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->response()->jsonp(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->response()->make(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->response()->download(...);

6- 发送自定义响应

HeyMan::whenYouVisitUrl('/login')-> 
       ...
      ->otherwise()
      ->weRespondFrom('\App\Http\Responses\Authentication@guestsOnly');
namespace App\Http\Responses;

class Authentication
{
    public function guestsOnly()
    {
        if (request()->expectsJson()) {
            return response()->json(['error' => 'Unauthenticated.'], 401);
        }

        return redirect()->guest(route('login'));
    }
}

嘿,兄弟,你看?我们这里只有一个 HTTP 响应。所以我们的控制器可以自由处理正确的情况,不必担心异常情况。

更高级的反应

嘿,兄弟,你可能想在发送响应之前调用某些方法或触发事件。你可以通过 afterCalling()afterFiringEvent() 方法来实现。

HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->afterFiringEvent('explode')->response()->json(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->afterCalling('someclass@method1')->response()->json(...);

禁用 Heyman

你可以这样禁用 HeyMan 检查(在测试时很有用)

untitled

HeyMan::turnOff()->eloquentChecks();

...
/// You may save some eloquent models here...
/// without limitations from HeyMan rules.
...

HeyMan::turnOn()->eloquentChecks();

🙋 贡献

如果你发现了一个问题,或者有更好的方法来做某事,请随意打开一个 issue 或 pull request。

⭐ 你的 Star 让我们做得更多 ⭐

一如既往,如果你觉得这个包很有用,并且你想鼓励我们维护和改进它,只需按 star 按钮,声明你的意愿。

Star 历史

Star History Chart

作者的其他作品

Laravel Widgetize

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

Laravel Terminator

💎 一个简单但强大的包,给你机会重构你的控制器。

Laravel AnyPass

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

Laravel Microscope

💎 它自动检查你的 Laravel 应用程序(

Great spirits have always encountered violent opposition from mediocre minds.

"Albert Einstein"