kodeine / laravel-meta
为Eloquent模型提供流畅的元数据,就像它是模型上的一个属性。
Requires
- php: >=7.3
- ext-json: *
- illuminate/database: ^8.0|^9.0|^10.0|^11.0
- illuminate/events: ^8.0|^9.0|^10.0|^11.0
- illuminate/support: ^8.0|^9.0|^10.0|^11.0
Requires (Dev)
- phpunit/phpunit: ^9.5|^10.5
README
Metable Trait添加了将元数据访问为模型属性的能力。Metable是流畅的,就像使用eloquent模型属性,您可以设置或取消设置元数据。按照文档了解详细信息。
变更日志
安装
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有一些不兼容的更改,如下所示
-
Laravel 7或更低版本不支持。
-
移除了以下方法:
__get
、__set
、__isset
。如果您已经定义了这些方法中的任何一个,那么您的模型中可能类似这样:class User extends Model{ use Metable{ __get as __metaGet }
您需要移除方法中的
as
运算符。 -
移除了遗留的getter。在旧版本中,如果您有一个名为
getSomething()
的方法,那么您可以通过$model->something
访问此方法的返回值。现在不再是这样,您必须调用$model->getSomething()
。 -
添加了新的方法
setAttribute
,它覆盖了父方法。 -
将
getMetaDefaultValue
方法重命名为getDefaultMetaValue
。 -
getMeta
方法的第二个参数现在是元数据为null时的默认值。 -
移除了
whereMeta
方法,改为使用scopeWhereMeta
。例如:User::whereMeta($key,$value)->get();
-
移除了
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
的数组来设置默认值。设置默认值有两个副作用
- 如果元数据属性不存在,将返回默认值而不是
null
。 - 如果您尝试将元属性设置为默认值,则元表中的行将被删除,按照规则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 元数据触发多个事件,允许您钩入以下事件:metaCreating
、metaCreated
、metaSaving
、metaSaved
、metaUpdating
、metaUpdated
、metaDeleting
和 metaDeleted
。监听器应该期望两个参数,首先是模型实例,其次是事件发生的元数据名称。要启用事件,您需要将 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 事件一样,事件监听器应该期望一个参数。事件名称:createdWithMetas
、updatedWithMetas
、savedWithMetas
。这些事件的行为与默认的 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) { // } }