javascript/laravel-macroable-models

一个动态为Laravel模型添加方法的包

1.0.6 2023-05-23 15:04 UTC

This package is auto-updated.

Last update: 2024-09-23 17:52:39 UTC


README

一个动态为Laravel模型添加方法的包 🕊

该包为开发者提供了一种简单的方式,可以以编程方式向Laravel Eloquent 模型 添加方法。幕后,它使用了Laravel自带的可宏特例。更多详情,请查看我在博客上的解释。

安装

只需使用composer安装此包

composer require javoscript/laravel-macroable-models

(仅适用于Laravel <5.5,或如果您想明确指定) - 将服务提供者添加到config/app.php文件中的providers数组

// config/app.php

$providers = [
    // ...
    \Javoscript\MacroableModels\MacroableModelsServiceProvider::class,
    // ...
];

使用示例

该包提供了一个门面,以方便访问其功能。或者,您也可以通过app('macroable-models')辅助函数访问。

出于明显的原因,宏应该在其他系统部分使用它之前添加到模型中。因此,服务提供者boot方法是开始添加宏的好地方。

例如,在AppServiceProvider中向\App\User模型添加方法

// app/Providers/AppServiceProvider.php

// ...

use \Javoscript\MacroableModels\Facades\MacroableModels;
use \App\User;

// ...

public function boot()
{

    MacroableModels::addMacro(User::class, 'sayHi', function() {
        return 'Hi!';
    });

}

在向User模型添加宏之后,现在每个Eloquent模型的实例都将具有可用的sayHi()方法。我们可以在artisan tinker中快速验证这一点。

php artisan tinker

>>> \App\User::first()->sayHi()
=> "Hi!"

在专门的MacrosServiceProvider文件中

如果您想将多个宏定义放在一起,那么添加一个服务提供者可能是好主意。

您可以使用artisan生成一个新的服务提供者

php artisan make:provider MacrosServiceProvider

然后,您应该将其添加到config/app.php文件中的providers数组。

// config/app.php

$providers = [
    // ...
    App\Providers\MacrosServiceProvider::class,
    // ...
];

然后,在新服务提供者的boot方法中,您可以集中定义宏

// app/Providers/MacrosServiceProvider.php

// ...

use \Javoscript\MacroableModels\Facades\MacroableModels;
use \App\User;

// ...

public function boot()
{
    
    MacroableModels::addMacro(User::class, 'sayHi', function() {
        return 'Hi!';
    });
    
    MacroableModels::addMacro(User::class, 'sayBye', function() {
        return 'Bye bye';
    });
    
}

可用方法

以下示例将使用\App\User模型,以便您可以在新的Laravel应用程序中尝试这些示例。任何扩展了Illuminate\Database\Eloquent\Model类的类都可以使用这些宏进行扩展。

addMacro(Model::class, 'macroName', function() {}) : void

此包最重要的方法,也是您最有可能大量使用的方法。向Model::class模型添加名为macroName的宏。

在添加宏之后,您可以像通常那样在模型上调用该方法。

MacroableModels::addMacro(\App\User::class, 'sayHi', function() { return "Hi!"; });

\App\User::first()->sayHi();

带参数

定义的宏函数可以接收任何数量和类型的参数。

MacroableModels::addMacro(\App\User::class, 'say', function(string $something) { return $something; });

$user = \App\User::first();
$user->say("Hello world!");

上下文绑定...正确的$this

在宏函数中,您有权访问$this对象,该对象引用执行函数的模型实例。

MacroableModels::addMacro(\App\User::class, 'getId', function() { return $this->id; });

\App\User::first()->getId();
// 1

添加关系

您也可以定义关系函数!

MacroableModels::addMacro(\App\User::class, 'posts', function() {
    return $this->hasMany(App\Post::class);
});

注意!您将无法使用Laravel的魔法关系属性。

$user = App\User::first();

$user->posts;
// null
// This will always return null, as the posts attribute wasn't defined

$user->posts()->get()
// This will correctly return the posts Eloquent collection

覆盖现有宏

如果您添加了一个与现有宏具有相同名称的宏,则它将替换它。

MacroableModels::addMacro(\App\User::class, 'greet', function() { return "Hi!"; });
\App\User::first()->greet();
// "Hi!"

MacroableModels::addMacro(\App\User::class, 'greet', function() { return "Hello human"; });
\App\User::first()->greet();
// "Hello human"

模型的优先级

如果您添加了一个与模型中现有方法同名的大宏,后者将具有优先权。您无法使用此包覆盖它。

class Dog extends Illuminate\Database\Eloquent\Model
{
    public function bark()
    {
        return "Woof!";
    }
}

MacroableModels::addMacro(Dog::class, 'bark', function() { return "Miauuu!"; });

$dog = new Dog;
$dog->bark();
// "Woof!"

removeMacro(Model::class, 'macroName') : boolean

这是addMacro的反操作,此方法从指定的模型中删除之前添加的大宏。如果模型上已注册该名称的大宏并且已正确删除,则返回true - 否则返回false

MacroableModels::removeMacro(\App\User::class, 'salute');
// false

MacroableModels::addMacro(\App\User::class, 'salute', function() { return "Hello!"; });

MacroableModels::removeMacro(\App\User::class, 'salute');
// true

附加功能

因为为什么不呢?🤷‍♂

getAllMacros() : Array

返回所有已注册的大宏,按名称分组。

MacroableModels::addMacro(\App\User::class, 'hi', function() { return "Hi!"; })

MacroableModels::addMacro(\App\Dog::class, 'hi', function() { return "Woof!"; })

MacroableModels::addMacro(\App\User::class, 'bye', function() { return "Bye bye"; })

MacroableModels::getAllMacros()

/*
   [
     "hi" => [
       "App\User" => Closure() {#3362 …2},
       "App\Dog" => Closure() {#3376 …2},
     ],
     "bye" => [
       "App\User" => Closure() {#3366 …2},
     ],
   ]
*/

modelHasMacro(Model::class, 'macroName') : boolean

很简单:如果模型具有该宏,则返回true - 否则返回false

MacroableModels::modelHasMacro(\App\User::class, 'salute');
// false

MacroableModels::addMacro(\App\User::class, 'salute', function() { return "Hi!"; });
MacroableModels::modelHasMacro(\App\User::class, 'salute');
// true

modelsThatImplement('macroName') : Array

给定一个宏名称,它返回一个数组,包含已向其添加的模型类。

MacroableModels::addMacro(\App\User::class, 'hi', function() { return "Hi!"; });
MacroableModels::addMacro(\App\Dog::class, 'hi', function() { return "Woof!"; });

MacroableModels::modelsThatImplement('hi');
/*
   [
      "App\User",
      "App\Dog",
   ]
*/

macrosForModel(Model::class) : Array

给定模型类,它返回一个数组,包含添加到该模型的所有宏,详细说明每个宏定义的参数。

MacroableModels::addMacro(\App\User::class, 'say', function(String $something) { return $something; });
MacroableModels::addMacro(\App\User::class, 'sum', function(Integer $a, Integer $b) { return $a + $b; });

MacroableModels::macrosForModel(\App\User::class);
/*
   [
     "say" => [
       "name" => "say",
       "parameters" => [
         ReflectionParameter {#3385
           +name: "something",
           position: 0,
           typeHint: "string",
         },
       ],
     ],
     "sum" => [
       "name" => "sum",
       "parameters" => [
         ReflectionParameter {#3357
           +name: "a",
           position: 0,
           typeHint: "Integer",
         },
         ReflectionParameter {#3360
           +name: "b",
           position: 1,
           typeHint: "Integer",
         },
       ],
     ],
   ]
*/

相关包

有一些相关的包,从中汲取了一些灵感。

  • imanghafoori1/eloquent-relativity: github
  • spatie/laravel-collection-macros: github
  • spatie/macroable: github