gawsoft / laravel-macroable-models

从用于动态为Laravel模型添加方法的包派生而来

v1.0.0 2023-03-25 12:15 UTC

This package is auto-updated.

Last update: 2024-09-25 16:04:07 UTC


README

这是从原始仓库 javoscript/laravel-macroable-models 分支出来的。原始仓库未更新,且所有者不接受pull请求。

Laravel 动态宏模型

一个用于动态为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