josegonzalez / cakephp-version
CakePHP ORM行为,允许记录版本控制
Requires
- php: ^8.1
- cakephp/orm: ^5.0
Requires (Dev)
- cakephp/cakephp: ^5.0
- cakephp/cakephp-codesniffer: ^5.1
- php-coveralls/php-coveralls: ^0.4.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.5
README
版本
一个用于方便版本化数据库实体的CakePHP 4.x插件
安装
将以下行添加到您的应用程序的composer.json
"require": { "josegonzalez/cakephp-version": "dev-master" }
然后执行以下命令
composer update
或者直接运行以下命令而不更改您的composer.json
composer require josegonzalez/cakephp-version:dev-master
使用方法
在您的应用程序的config/bootstrap.php
中添加
Plugin::load('Josegonzalez/Version', ['bootstrap' => true]);
使用方法
运行以下模式迁移
CREATE TABLE `version` ( `id` int(11) NOT NULL AUTO_INCREMENT, `version_id` int(11) DEFAULT NULL, `model` varchar(255) NOT NULL, `foreign_key` int(10) NOT NULL, `field` varchar(255) NOT NULL, `content` text NULL, `created` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
请注意,如果要在应用程序中版本化任何可空字段,则
content
字段必须是可空的。
您还可以选择将类型为
integer
的version_id
字段添加到正在版本化的表中。这将存储给定页面的最新版本号。
如果您希望使用cakephp/migrations
创建表,则需要使用类似于以下内容的迁移
<?php use Phinx\Migration\AbstractMigration; class CreateVersions extends AbstractMigration { public function change() { $this->table('version') ->addColumn('version_id', 'integer', ['null' => true]) ->addColumn('model', 'string') ->addColumn('foreign_key', 'integer') ->addColumn('field', 'string') ->addColumn('content', 'text', ['null' => true]) ->addColumn('created', 'datetime') ->create(); } }
将以下行添加到您的实体中
use \Josegonzalez\Version\Model\Behavior\Version\VersionTrait;
然后将在实体类中包含该特质
class PostEntity extends Entity { use VersionTrait; }
通过以下方式在您想要应用行为的模型中附加行为
public function initialize(array $config) { $this->addBehavior('Josegonzalez/Version.Version'); }
无论通过插入还是更新持久化实体时,该实体也会被持久化到version
表中。您可以通过以下代码访问特定版本
// Will contain a generic `Entity` populated with data from the specified version. $version = $entity->version(1);
您可以选择检索所有版本
$versions = $entity->versions();
存储额外元数据
cakephp-version
触发一个事件Model.Version.beforeSave
,您可以选择处理它以附加有关版本的额外元数据。
将必要的额外字段添加到您的迁移中,例如
CREATE TABLE `version` ( `id` int(11) NOT NULL AUTO_INCREMENT, `version_id` int(11) DEFAULT NULL, `model` varchar(255) NOT NULL, `foreign_key` int(10) NOT NULL, `field` varchar(255) NOT NULL, `content` text, `created` datetime NOT NULL, `custom_field1` varchar(255) NOT NULL, /* column to store our metadata */ `custom_field2` varchar(255) NOT NULL, /* column to store our metadata */ PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
然后定义一个事件监听器来处理事件并传递额外的元数据,例如
use Cake\Event\Event; use Cake\Event\EventListenerInterface; class VersionListener implements EventListenerInterface { public function implementedEvents() { return array( 'Model.Version.beforeSave' => 'insertAdditionalData', ); } public function insertAdditionalData(Event $event) { return [ 'custom_field1' => 'foo', 'custom_field2' => 'bar' ]; } }
然后您可以将事件监听器附加到项目中,例如
use App\Event\VersionListener; use Cake\Event\EventManager; $VersionListener = new VersionListener(); EventManager::instance()->on($VersionListener);
请注意,处理此事件还可以允许您修改/覆盖插件生成的值。这可以提供有用的功能,但请确保如果您的事件监听器返回的数组键名为version_id
、model
、foreign_key
、field
、content
或created
,则这是预期的行为。
将user_id作为元数据存储
将user_id
作为额外元数据存储,最简单的方法是结合使用Muffin/Footprint。上面的insertAdditionalData()
方法可能如下所示
/** * @param \Cake\Event\Event $event * * @return array */ public function insertAdditionalData(Event $event) { $data = [ ... ]; if ($event->data('_footprint')) { $user = $event->data('_footprint'); $data += [ 'user_id' => $user->id, ]; } return $data; }
使用FootprintAwareTrait
的任何控制器将然后提供_footprint
数据到模型层,以便此事件回调使用。
Bake集成
如果您使用'bootstrap' => true
加载插件,则可以使用该插件通过正确命名的数据库表自动检测使用情况。为此,只需创建一个表,其模式如上所述,命名为您想要修订的表名加上后缀_versions
。例如,要修订以下表
CREATE TABLE `posts` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `category_id` int(11) DEFAULT NULL, `user_id` int(11) DEFAULT NULL, `status` varchar(255) NOT NULL DEFAULT 'published', `visibility` varchar(255) NOT NULL DEFAULT 'public', `title` varchar(255) NOT NULL DEFAULT '', `route` varchar(255) DEFAULT NULL, `content` text, `published_date` datetime DEFAULT NULL, `created` datetime NOT NULL, `modified` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
创建以下表
CREATE TABLE `posts_versions` ( `id` int(11) NOT NULL AUTO_INCREMENT, `version_id` int(11) NOT NULL, `model` varchar(255) NOT NULL, `foreign_key` int(11) NOT NULL, `field` varchar(255) NOT NULL, `content` text, `created` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
您可以使用以下bake命令为此创建迁移
bin/cake bake migration create_posts_versions version_id:integer model foreign_key:integer field content:text created
您还希望将此迁移中的
content
字段设置为可空的,否则您将无法修订可空的字段。
要跟踪posts
表中的当前版本,您可以为该表创建一个迁移以添加version_id
字段
bin/cake bake migration add_version_id_to_posts version_id:integer
配置
有五种行为配置可以使用
versionTable
:(默认:version
)用于存储版本化数据的表名。在版本化多种类型的实体时,使用不同的表可能很有用。versionField
: (默认:version_id
) 用于存储当前版本的版本化表中字段的名称。如果缺失,插件将继续正常工作。additionalVersionFields
: (默认['created']
) 将公开的版本化表的附加或自定义字段。默认以version_
为前缀,例如'version_user_id'
对应于'user_id'
。referenceName
: (默认:数据库表名称) 用于在版本表中识别记录的区分符。onlyDirty
: (默认:false) 设置为 true 以仅对脏属性进行版本控制。