tkeer / flattable
将多个表合并为一个扁平的超级表。
Requires
- php: ^8.0
- illuminate/config: >8.0
- illuminate/database: >8.0
- illuminate/support: >8.0
Requires (Dev)
- laravel/legacy-factories: ^1.0
- orchestra/testbench: ^6.0|^5.2|^4.8|^3.8.6|^3.7.8|^3.6.7|^3.5.4
- phpunit/phpunit: ^6.5|^7.5|^8.4|^9.0
README
Laravel Flattable

它允许您通过简单的配置来管理非规范化表。
只需在模型中添加基于数组的配置,它将自动同步您的非规范化表。
简介
您当前在Laravel应用程序中是否有非规范化表,或者计划添加一个,这个包可以帮助您保持非规范化表与源表同步。
使用flattable,您可以将多个表合并为一个大型表,并通过以下方式提高性能:
最小化连接和子查询的需求,预先计算聚合值,即在数据修改时计算,而不是在选择时计算
您只需要创建一个扁平表,在相关模型中添加配置,然后一切都将自动开始工作。
安装
使用Composer安装此包
composer require tkeer/flattable
Laravel版本兼容性
用法
- 将
Flattable特质添加到您的模型中 - 实现
flattableConfig方法并添加您的配置
通过示例学习
通过示例更容易解释。有关更详细的示例,请参阅测试
示例数据库结构
- 我们有书籍、出版商、国家表
- 一本书属于一个出版商
- 一个出版商属于一个国家
我们想在书的扁平表(books_flattable)中获取书籍、书籍的出版商和书籍出版商的国家数据
由于书是这里的主要表,我们将在书的模型中添加扁平配置,并将type设置为primary,更多关于类型请在此。
为了解释这个问题,我们将把我们的配置分为三个部分。有关书籍的详细配置,请参阅测试中book模型的第一个配置条目。
1. 书籍在书的扁平表中
当相关书籍更新或删除时,也会更新/删除
在Book模型的getFlattableConfig()方法中
public function getFlattableConfig(): array { [ [ 'columns' => [ //flattable column => 'source model column' 'name' => 'name', 'published_at' => 'published_at', 'publisher_id' => 'publisher_id', 'book_id' => 'id' ], // type of relationship b/w flattable and model 'type' => 'primary', // how to find related entry in the flattable table 'wheres' => [ // key is flattable column // value is column of source table (book) 'book_id' => 'id', ], 'flattable' => 'books_flattable', ] ] }
2. 书的扁平表中的出版商
当书的出版商更改时,也会更新扁平表中的新出版商
扩展上面的扁平配置,并在changes键下添加出版商的配置。
public function getFlattableConfig(): array { [ [ 'flattable' => 'books_flattable', ... 'changes' => [ // foreign colum name // we will update changes data only if this column is update(dirty) 'publisher_id' => [ 'columns' => [ 'publisher_first_name' => 'first_name', 'publisher_last_name' => 'last_name', ], // talbe name of the source 'table' => 'publishers', ] ] ] ] }
3. 出版商的国家在书的扁平表中
[
//inside pubilsher config of books flattable
...
'changes' => [
'country_id' => [
'columns' => [
'publisher_country_name' => 'name',
'publisher_country_id' => 'id',
],
'where' => [
'id' => 'country_id'
],
'table' => 'countries'
]
]
]
您可以使用changes属性进行多层嵌套,即changes属性中的changes属性。
截至目前,添加了配置,书籍的任何更改都将自动更新书籍的扁平化。即使书籍的出版商发生变化,扁平化也会自动更新为新的出版商数据。
如果出版商本身也进行了更新,例如出版商的first_name更新了,或者出版商的国家更新了。为此,我们必须为Publisher和Country模型实现扁平化,并在两个模型中添加扁平化配置,配置type应为secondary。
见下文
在出版商更新时更新书籍的扁平化
在Publisher模型的flattableConfig()中
public function flattableConfig() { return [ [ 'columns' => [ 'publisher_first_name' => 'first_name', 'publisher_last_name' => 'last_name', ], 'wheres' => [ 'publisher_id' => 'id', ], 'type' => 'secondary', 'flattable' => 'books_flattable', ] ] }
在国家更新时更新书籍的扁平化
当删除国家时,为扁平化分配null值
在Country模型的flattableConfig()中
public function flattableConfig() { return [ [ 'columns' => [ 'publisher_country_name' => 'name', 'publisher_country_id' => 'id', ], 'wheres' => [ 'publisher_country_id' => 'id', ], 'type' => 'secondary', 'flattable' => 'books_flattable', ] ] }
出版商的扁平表中的书籍
到目前为止,我们已经考虑了一对一的关系,书籍属于一个出版商,出版商属于一个国家。
如果两个表之间存在一对一的关系怎么办。
例如,出版商可以拥有许多书籍,并且每当添加任何书籍时,我们希望在出版商的扁平化中添加这本书。
在Book模型中添加一个额外的扁平化配置,此关系的配置type应为many。
public function flattableConfig(): array { ... return [ [ 'columns' => [ 'id' => 'id', 'name' => 'name' ], // use type many when you want to store more than one entry in a column 'type' => 'many', 'wheres' => [ 'publisher_id' => 'publisher_id', ], //only delete from old if these keys have changed 'delete_from_old_keys' => ['publisher_id'], 'flattable' => 'publishers_flattable', // column name of the flaatable, in which the data should be stored. 'flattable_column_name' => 'books', ] ] }
扁平化配置说明
扁平化配置有以下属性
1. 列
一个数组,包含扁平化列和源表列的映射。
columns数组中的每个键都是扁平化列的名称,其值是源表列的名称。
[ 'columns' => [ 'book_id' => 'id', 'book_name' => 'name' ] ]
2. 条件
一个关联数组,包含映射扁平化中相关条目的条件。
子数组中的键是扁平化列的列名,其值是源表列的列名。
[ 'wheres' => [ 'book_id' => 'id' ] ]
3. 扁平化
扁平化的名称。
4. 变更
将相关表的数据包含到扁平化中。它应该是一个关联数组。
changes属性中每个数组的键是源表列的列名,其变化将加载扁平化中的相关数据。
5. 类型
它描述了扁平化和源表之间的关系类型
我们有三种类型
1. 主
创建、更新和删除对扁平化执行相同操作。
例如,书籍与books_flattable的关系
2. 次要
与主相同,但删除模型不会删除扁平化中的相关条目。相反,它将在扁平化中相关列中分配null值。
例如,出版商与books_flattable的关系。如果删除书籍的出版商,则books_flattable中的出版商属性将被设置为null。
如果您想要在扁平化中删除次要类型的条目,将deletes_primary标志设置为true。
3. 多
对于一对一关系。使用此类型,我们可以在扁平化中存储多个条目。
例如,书籍与publishers_flattable的关系,一个出版商可以有多本书籍。
6. 扁平化列名称
当类型为many时是必需的。它持有扁平化的列名,其中将存储json数据。
7. 从旧键中删除
当类型为many时是必需的。它持有列的名称,任何这些列的变化都将重新加载相关扁平化列的相关json数据。
8. 删除主键
主type自动从扁平化中删除条目,当主表中删除条目时,而次要类型将null值存储在扁平化中的相关条目中。
如果您想要删除次要类型的条目也删除相关的扁平化条目,将deletes_primary标志设置为true。
配置
禁用单个模型的扁平化
Book::disableFlattable(); $book = factory(Book::class)->create(); $bookFlattable = BookFlattable::where('book_id', $book->id)->first(); $this->assertNull($bookFlattable); Book::enableFlattable();
禁用所有模型的扁平化
发布扁平化配置
php artisan vendor:publish --provider="Tkeer\Flattable\FlattableServiceProvider" --tag="config"
在config/flattabe.php中将disabled设置为true。
return [ 'console' => [ 'run' => true ], 'disabled' => true ];
禁用控制台中的可展开功能
当脚本通过控制台运行时,您可以选择性地禁用可展开功能。
要禁用,请在 config/flattable.php 中将 console.run 设置为 false。
使用回调
如果现有选项都不适用于您的用例,您可以传递回调函数给 columns 和 wheres 配置。
对于 columns 回调,您将接收到模型作为参数,您应该返回一个数组,该数组将被存储在可展开中。
[ ... 'columns' => function (Country $country) { // when secondary row is deleted, it's data should be removed from flattable return [ 'publisher_country_name' => $country->exists ? $country->name ? null, 'publisher_country_id' => $country->exists ? $country->id ? null ]; } ... ]
对于 wheres 回调,您将接收到 QueryBuilder 和 Model 作为参数,您可以添加任意多的条件。
[ ... 'wheres' => function (Builder $db, Country $model) { $db->where('publisher_country_id', $model->id); } ... ]
填充可展开
您可以使用 flattable:fill 命令来填充您的可展开。
php artisan flattable:fill App\\Models\\Book
此命令将使用 Book 模型的默认配置来填充相关的可展开。


