kodeine/laravel-meta

为Eloquent模型提供流畅的元数据,就像它是模型上的一个属性。

2.2.3 2024-03-13 15:19 UTC

This package is auto-updated.

Last update: 2024-09-13 16:19:35 UTC


README

Laravel Source Build Status License

Metable Trait添加了将元数据访问为模型属性的能力。Metable是流畅的,就像使用eloquent模型属性,您可以设置或取消设置元数据。按照文档了解详细信息。

变更日志

访问CHANGELOG.md

安装

Composer

Laravel可以安装到laravel 8.x或更高版本。

运行

composer require kodeine/laravel-meta

对于laravel 7.x或更低版本,请访问此链接

升级指南

composer.json中更改此行

"kodeine/laravel-meta": "master"

"kodeine/laravel-meta": "^2.0"

然后,运行composer update以升级包。

升级通知

Laravel meta 2有一些不兼容的更改,如下所示

  1. Laravel 7或更低版本不支持。

  2. 移除了以下方法:__get__set__isset。如果您已经定义了这些方法中的任何一个,那么您的模型中可能类似这样:

    class User extends Model{
        use Metable{
            __get as __metaGet
        }

    您需要移除方法中的as运算符。

  3. 移除了遗留的getter。在旧版本中,如果您有一个名为getSomething()的方法,那么您可以通过$model->something访问此方法的返回值。现在不再是这样,您必须调用$model->getSomething()

  4. 添加了新的方法setAttribute,它覆盖了父方法。

  5. getMetaDefaultValue方法重命名为getDefaultMetaValue

  6. getMeta方法的第二个参数现在是元数据为null时的默认值。

  7. 移除了whereMeta方法,改为使用scopeWhereMeta。例如:User::whereMeta($key,$value)->get();

  8. 移除了getModelKey方法。

迁移表模式

每个模型都需要自己的元数据表。

这是一个示例迁移。您需要更改其中的一部分。

在这个例子中,我们假设您有一个名为Post的模型。

元数据表名应该是您的模型表名加上_meta,在这个例子中,模型的表名是模型名称的复数形式。所以表名变成了posts_meta

如果您不想遵循这个命名约定并使用其他名称作为表名,请确保将其添加到您的模型体中

protected $metaTable = 'custom_meta_table';

外键名称应该是您的模型名称加上_id = post_id

如果您使用了其他的外键名称,请确保将其添加到您的模型体中

protected $metaKeyName = 'custom_foreign_key';
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
    Schema::create('posts_meta', function (Blueprint $table) {
        $table->bigIncrements('id');

        $table->bigInteger('post_id')->unsigned();
        $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');

        $table->string('type')->default('null');

        $table->string('key')->index();
        $table->text('value')->nullable();

        $table->timestamps();
    });
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
    Schema::drop('posts_meta');
}

配置

模型设置

接下来,将Metable trait添加到您的每个可元数据模型定义中

use Kodeine\Metable\Metable;

class Post extends Eloquent
{
    use Metable;
}

Metable Trait会自动根据您的模型名称设置元数据表。默认元数据表名会是,models_meta,其中models是模型名称的复数形式。如果您需要在模型中定义自己的元数据表名,您可以在模型中指定

class Post extends Eloquent
{
    protected $metaTable = 'posts_meta'; //optional.
}

默认模型属性值

此外,您可以通过在模型上设置一个名为$defaultMetaValues的数组来设置默认值。设置默认值有两个副作用

  1. 如果元数据属性不存在,将返回默认值而不是null
  2. 如果您尝试将元属性设置为默认值,则元表中的行将被删除,按照规则1,将返回默认值。

这对于大多数项目来说是一个期望和预期的功能,但请注意,如果这个功能不符合您的需求,您可能需要重新实现默认功能,使用您自己的自定义访问器和修改器。

此功能最适合标记规则异常的元条目。例如:员工因病缺勤(默认值:在办公室),节点因维护而下线(默认值:节点在线)等。这意味着表格不需要存储处于预期状态的每个条目的数据,只需存储处于异常状态的行,并且允许在创建行时具有默认状态,而无需添加写入代码。

   public $defaultMetaValues = [
      'is_user_home_sick' => false,
   ];

注意!

当您扩展模型并希望继续使用相同的元表时,必须覆盖getMetaKeyName函数。

class Post extends Eloquent
{

}

class Slideshow extends Post
{
    protected function getMetaKeyName()
    {
        return 'post_id' // The parent foreign key
    }   
}

与元数据一起工作

设置内容元

要设置现有内容或创建新数据的元值

流畅方式,您可以在常规eloquent模型上像设置元值一样流畅地设置元值。Metable会检查属性是否属于模型,如果不是,它将访问元模型以追加或设置新的元值。

$post = Post::find(1);
$post->name = 'hello world'; // model attribute
$post->content = 'some content goes here'; // meta data attribute
$post->save(); // save attributes to respective tables

或者

$post = Post::find(1);
$post->name = 'hello world'; // model attribute
$post->setMeta('content', 'Some content here');
$post->save();

一次性设置多个元

...
$post->setMeta([
    'content' => 'Some content here',
    'views' => 1,
]);
$post->save();

或者一次性设置多个元和列

...
$post->setAttributes([
    'name' => 'hello world'; // model attribute
    'content' => 'Some content here',
    'views' => 1,
]);
$post->save();

注意:如果内容已经存在元,现有值将被更新。

您也可以使用saveMeta保存元,而不保存模型本身

$post->content = 'some content goes here'; // meta data attribute
$post->saveMeta(); // will save metas to database but won't save the model itself

取消设置内容元

同样,您可以从现有内容中取消设置元

流畅方式取消设置。

$post = Post::find(1);
$post->name // model attribute
unset($post->content) // delete meta on save
$post->save();

或者

$post->unsetMeta('content');
$post->save();

一次性取消多个元

$post->unsetMeta('content,views');
// or
$post->unsetMeta('content|views');
// or
$post->unsetMeta('content', 'views');
// or array
$post->unsetMeta(['content', 'views']);

$post->save();

注意:如果内容没有请求的元,系统不会抛出错误。

检查元

要查看内容是否具有元

流畅方式,Metable足够聪明,可以理解$post->content是元的一个属性。

if (isset($post->content)) {

}
// or
if ($post->hasMeta('content')){

}

您还可以检查模型是否具有多个元

$post->hasMeta(['content','views']); // returns true only if all the metas exist
// or
$post->hasMeta('content|views');
// or
$post->hasMeta('content,views');

检索元

要检索内容的元值,请使用getMeta方法

流畅方式,您可以像访问模型上的属性一样访问元数据。就像您在常规eloquent模型上做的那样。

$post = Post::find(1);
dump($post->name);
dump($post->content); // will access meta.

或者

$post = $post->getMeta('content');

或指定默认值(如果没有设置)

$post = $post->getMeta('content', 'Something');

注意:在defaultMetaValues属性中设置的默认值将优先于传递给此方法的默认值。

您还可以一次性检索多个元,并获取一个Illuminate集合

// using comma or pipe
$post = $post->getMeta('content|views');
// or an array
$post = $post->getMeta(['content', 'views']);
// specify default values
$post->getMeta(['content', 'views'],['content'=>'something','views'=>0]);
// or specify one default value for all missing metas
$post->getMeta(['content', 'views'],'none');// result if the metas are missing: ['content'=>'none','views'=>'none']
// without specifying default value result will be null
$post->getMeta(['content', 'views']);// result if the metas are missing: ['content'=>null,'views'=>null]

禁用流畅访问

如果您不想以流畅的方式访问元,您可以通过向模型添加以下属性来禁用它

protected $disableFluentMeta = true;

通过设置该属性,此包将不再以下列方式处理元

$post->content='something';// will not set meta. original laravel action will be taken
$post->content;// will not retrieve meta
unset($post->content);// will not unset meta
isset($post->content);// will not check if meta exists

检索所有元

要检索与内容关联的所有元,请使用不带任何参数的getMeta

$metas = $post->getMeta();

检索所有元的数组

要检索与内容关联的所有元并将它们作为数组返回,请使用toArray方法

$metas = $post->getMeta()->toArray();

元表连接

当您需要根据元数据过滤模型时,您可以使用Eloquent查询构建器的meta作用域。

$post = Post::meta()
    ->where(function($query){
          $query->where('posts_meta.key', '=', 'revision')
                ->where('posts_meta.value', '=', 'draft');
    })

预加载

当您需要从模型检索多个结果时,您可以预加载metas

$post = Post::with(['metas'])->get();

防止元属性被填充

当您将模型转换为数组(或json)并且不需要所有元字段时,您可以在模型属性中创建一个属性来防止元被添加到结果数组中。您还可以在eloquent关系上使用它。

/* Post model */
public $hideMeta = true; // Do not add metas to array

事件

Laravel 元数据触发多个事件,允许您钩入以下事件:metaCreatingmetaCreatedmetaSavingmetaSavedmetaUpdatingmetaUpdatedmetaDeletingmetaDeleted。监听器应该期望两个参数,首先是模型实例,其次是事件发生的元数据名称。要启用事件,您需要将 HasMetaEvents 特性添加到您的模型中。

use Kodeine\Metable\Metable;
use Kodeine\Metable\HasMetaEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use Metable,HasMetaEvents;
}

之后,您可以像处理模型事件一样监听事件。

如果在任何以 ing 结尾的事件监听器中返回 return false;,则该操作将被中止。

其他事件

还有一些扩展现有 Laravel 事件的其他事件。这些事件不需要 HasMetaEvents 特性,并且像默认的 Laravel 事件一样,事件监听器应该期望一个参数。事件名称:createdWithMetasupdatedWithMetassavedWithMetas。这些事件的行为与默认的 Laravel 事件完全相同,只是它们只在所有元数据保存到数据库后才会触发。例如,您可能需要在模型创建后访问元数据。但由于元数据尚未保存到数据库(元数据将在 saved 事件中保存到数据库,并且该事件尚未触发),作业无法访问它们。通过使用 createdWithMetas 事件而不是 created 事件,可以解决这个问题。

有三种方法可以监听事件

1. 通过定义 $dispatchesEvents 属性

use App\Events\UserMetaSaved;
use Kodeine\Metable\Metable;
use Kodeine\Metable\HasMetaEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use Metable,HasMetaEvents;

    protected $dispatchesEvents = [
        'metaSaved' => UserMetaSaved::class,
    ];
}

2. 使用闭包

use Kodeine\Metable\Metable;
use Kodeine\Metable\HasMetaEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use Metable,HasMetaEvents;

    protected static function booted()
    {
        static::metaCreated(function ($user, $meta) {
            //
        });
    }
}

3. 观察者

class UserObserver
{
    public function metaCreated(User $user,$meta)
    {
        //
    }
}