默认内容实体创建流程:

• 执行实体类的preCreate方法

• 为要创建的实体补充uuid值

• 判断bundle值的存在性

• 实例化一个空的实体对象

• 用值初始化实体对象,如果没有提供值,将采用默认值

• 如果提供了没有字段定义的值,也会为实体赋值该属性

• 执行实体类型层面和实体层面的钩子:field_values_init

• 强制实体为新的(即便传了id值也被认为是新的)

• 执行实体对象的postCreate方法

• 执行实体类型层面和实体层面的创建钩子create

创建涉及钩子及执行顺序如下:

• 字段值初始化钩子:$entityTypeId . ‘_field_values_init’ 和’entity_field_values_init’

• 创建钩子:$entityTypeId . ‘_create’ 和’entity_create’

注意创建实体后并不会被自动保存,如需保存需要显式调用save方法

默认内容实体加载流程:

• 如果储存处理器中有静态缓存,那么直接使用静态缓存,否则继续

• 从持久缓存中加载,默认为数据库表cache_entity,若有直接使用

• 从储存中加载实体

• 对id进行消毒处理

• 从基本表和版本表中查询数据

• 如果有数据表及数据版本表则从中加载数据

• 从专用表中加载数据

• 用加载的数据库记录值实例化实体对象

• 执行钩子:entity_storage_load及$entityTypeId . ‘_storage_load’

• 将加载的实体缓存到持久缓存

• 执行实体类定义的postLoad方法

• 执行实体加载钩子entity_load及实体类型加载钩子$entityTypeId . ‘_load’

• 设置储存处理器的静态缓存

加载涉及钩子及执行顺序如下:

• 实体加载钩子 entity_storage_load

• 实体类型储存加载钩子:$entityTypeId . ‘_storage_load’

• 实体加载钩子entity_load

• 实体类型加载钩子$entityTypeId . ‘_load’

注意钩子的执行顺序,这和默认的“先类型层面再实体层面”是相反的

默认内容实体保存流程:

• 开启数据库事务,如果各表不同步可以全部回滚

• 执行保存前逻辑doPreSave:

• 将实体对象各字段对象中为空的条目去除,然后提取值更新内部值数组($values属性)

• 更新版本id

• 执行检查,如果实体已经存在而实体被标记为新,那么抛出错误

• 如果实体存在,那么为$entity->original赋值,其为原始未改变的实体

• 执行实体对象本身的保存前逻辑(preSave方法),默认为检查是否经过数据验证和id是否符合要求

• 执行保存前钩子“presave”(实体类型级别和实体级别两个钩子)

• 执行检查:实体不为新时,id不允许改变;在不建立新版本时不允许版本id改变

• 执行保存逻辑doSave:

• 执行检查:如果在执行保存前逻辑后实体仍然被标记为新,那么执行强制为新(有id也是新)

• 如果实体为新,那么设置为新版本,并将所有翻译的更新旗标置为NULL以表示未进行手工翻译

• 设置翻译更新旗标,如果某翻译有变化设置为true,表示已经进行了手工翻译

• 进行数据库储存,执行sql内容储存处理器的doSaveFieldItems方法,并给新实体的id和版本id赋值

• 执行保存后逻辑doPostSave:

• 执行翻译钩子translation_insert或translation_delete

• 如果实体是可静态缓存的,那么重置实体处理器内部缓存

• 将实体设置为非新

• 执行实体对象的保存后逻辑,默认有失效缓存标签、将移除的翻译删去、将新建的翻译状态改为存在

• 执行更新或插入钩子

• 设置实体原id,也就是执行实体的setOriginalId方法

• 执行unset($entity->original);

• 在以上过程中如果出现异常那么回滚数据库事务,并记录日志,抛出实体储存异常,否则进入后续步骤

• 在从数据库得到更新前禁用从库

• 返回保存状态标识:如果失败为false,否则依据是保存还是更新返回常量SAVED_NEW 或SAVED_UPDATED

保存涉及钩子及执行顺序如下:

• 保存前钩子,钩子名:$entityTypeId . ‘_presave’ 和’entity_presave’

• 保存后翻译钩子:translation_insert或translation_delete

• 更新钩子:$entityTypeId . ‘_update’ 和’entity_update’ 或插入钩子:$entityTypeId . ‘_insert’ 和’entity_insert’ ,这在保存后执行

在执行以上钩子时,如果钩子是:presave、insert、update则会执行实体中字段对象的相应方法,这允许实现一些高级功能,如引用字段、实体保存后字段对象再次更新数据库值

默认内容实体删除流程:

• 开启数据库事务

• 执行实体类的静态方法:preDelete,在节点实体中将删除搜索索引

• 执行删除前钩子predelete

• 执行删除逻辑doDelete

• 执行实体各字段对象的delete()方法

• 执行doDeleteFieldItems方法进行数据库真实删除

• 重置储存处理器的内部缓存

• 执行实体类的postDelete方法

• 执行删除钩子delete

• 删除方法没有返回值

• 以上流程出现异常则回滚数据库,记录日志、抛出实体储存异常

• 在从库得到更新前禁用从库

删除涉及钩子及执行顺序如下:

• 删除前钩子,钩子名:$entityTypeId . ‘_predelete’ 和’entity_predelete’

• 删除后钩子,钩子名:$entityTypeId . ‘_delete’ 和’entity_delete’

默认内容实体版本删除流程:

• 加载实体,如果不存在,则不用删除

• 检查是否为默认版本,默认版本不可被删除,这应在实体上删除,否则数据库将产生碎片数据

• 执行实体字段对象的deleteRevision方法

• 删除版本表数据

• 删除版本数据表数据

• 删除专用表的版本表数据

删除版本涉及钩子及执行顺序如下:

• 删除版本钩子,钩子名:$entityTypeId . ‘_revision_delete’ 和’entity_revision_delete’

实体翻译创建流程:

实体的翻译并不是直接创建的,而要先建立一个源语言的实体对象,然后在这个对象基础上进行建立,因此内容实体基类的createTranslation方法接受一个实体对象,创建流程如下:

• 从源语言实体上得到翻译语言实体

• 过滤出可翻译字段

• 用传入的值初始化翻译语言实体

• 执行翻译创建钩子

翻译创建流程涉及的钩子及执行顺序如下:

• 实体类型翻译创建钩子:$entityTypeId . ‘_translation_create’

• 实体翻译创建钩子:’entity_translation_create’

注意创建的翻译并没有保存,这需要显式调用save方法,在实现翻译创建钩子时需要明白她可能不会被保存