44. 实体Entity(二)配置实体基类
实体Entity(二)配置实体基类
配置实体基类是系统定义的一个用于配置实体的抽象基类,继承自实体基类,完成了配置实体的大部分通用功能,具体的配置实体往往会继承它,比如用户角色实体,这样写少量代码即可,类定义如下:
Drupal\Core\Config\Entity\ConfigEntityBase
实现了配置实体接口:
Drupal\Core\Config\Entity\ConfigEntityInterface
该接口继承了实体接口和第三方设置接口:
Drupal\Core\Entity\EntityInterface
Drupal\Core\Config\Entity\ThirdPartySettingsInterface
配置实体基类ConfigEntityBase被放置在配置组件中,和内容实体基类构成系统两大实体类型的基础,本主题详细介绍她:
配置依赖:
配置实体可以声明它需要的依赖,只有所需的依赖存在它才可以被安装,在配置卸载的过程中依赖概念也是有必要的,比如提供配置实体的模块被卸载,那么配置实体往往需要被删除;配置实体往往依赖它的提供者(模块),提供者不存在了,配置实体就应该被卸载。依赖系统在配置安装、卸载和同步期间被使用,确保有正确的依赖顺序关系。
配置实体可以在它的插件定义释文的config_dependencies键中声明依赖,所依赖的对象是这几种类型之一:
模块'module',主题'theme', 配置实体'config',内容实体 'content'
因此config_dependencies键是一个数组,键名为这几种类型之一,键值为对应的依赖值,如下所示:
array(
'config' => array('user.role.anonymous', 'user.role.authenticated'),
'content' => array('node:article:f0a189e6-55fb-47fb-8005-5bef81c44d6d'),
'module' => array('node', 'user'),
'theme' => array('seven'),
);
第一级键名为所依赖物的类型,每种类型下保存着被依赖的对象名,可以有多个,对象名规则为:
模块类型:对象名为模块名
主题类型:对象名为主题名
配置类型:对象名为配置实体对象名,如果是配置实体该名来自实体的getConfigDependencyName()方法
内容类型:系统中所有内容类型的信息都是实体,对象名为内容实体类型id+“:”+实体bundle+“:”+实体的UUID,同样来自实体的getConfigDependencyName()方法
在配置实体中以$this->dependencies属性保存依赖,在特征中声明,其结构如上,但多出一个键名:enforced,该键名下的值结构也如上,它代表强制的依赖,通常是不可被自动计算或特殊场景下的依赖,以静态方式指定,强制的依赖在保存配置实体时不被重新计算,而其他项在每次保存时都将被重新计算,综述$this->dependencies属性的结构如下:
array(
'config' => array('user.role.anonymous', 'user.role.authenticated'),
'content' => array('node:article:f0a189e6-55fb-47fb-8005-5bef81c44d6d'),
'module' => array('node', 'user'),
'theme' => array('seven'),
'enforced'=>array(
'config' => array(),
'content' => array(),
'module' => array(),
'theme' => array(),
)
);
配置实体用以下方法来处理依赖:
protected function addDependency($type, $name);
添加某类型的依赖,$type为类型名,$name为依赖对象名,在配置实体基类中被重写,对“core”和配置实体所在的模块不进行添加
protected function addDependencies(array $dependencies);
添加多个依赖,$dependencies的键名为类型名,键值为依赖对象名数组
public function getDependencies();
得到配置实体依赖,是将$this->dependencies和其中的enforced键合并的结果
protected function calculatePluginDependencies(PluginInspectionInterface $instance);
计算插件的依赖,$instance为插件实例,往往是插件集中的一个实例,注意该方法中调用的calculateDependencies方法和配置实体基类中的同名方法是不一样的,仅方法名相同,他们在不同接口中定义,前者返回的是配置依赖数据,而后者返回配置实体本身
public function calculateDependencies();
计算配置实体的依赖,通常在保存配置实体前调用,它为配置实体的$this->dependencies属性重新赋值,返回配置实体本身,确保正确实时的依赖关系,但其中的enforced项是不会被修改的,该方法只是计算依赖的通用方法,它依靠插件和第三方设置来判断,如果需要的依赖不能通过此获取,那么子类需要另外实现,再补充调用他,子类实现时使用addDependency($type, $name);来添加依赖
如果配置实体作为一个扩展((module, theme, or profile))的默认配置,那么该配置实体的依赖也是该扩展的依赖,需要写入扩展的info文件
系统定义了一个专门的配置实体依赖对象:
Drupal\Core\Config\Entity\ConfigEntityDependency
有两个构造参数:配置实体的配置对象名、配置实体中包含的数据
该类比较简单,主要用于辅助计算配置依赖,只有三个方法:
public function getDependencies($type):得到某类型的依赖
public function hasDependency($type, $name):判断是否有某依赖
public function getConfigDependencyName():得到配置实体的配置对象名
配置依赖的官方文档地址:
https://www.drupal.org/docs/8/api/configuration-api/configuration-entit…
配置依赖名:
getConfigDependencyName()得到的是配置依赖名,也就是配置实体的配置对象名,和简单配置对象的配置对象名是统一的。
格式为:配置前缀 +“.”+ 配置id
配置前缀为:模块名+“.”+配置实体释文中定义的config_prefix
如果没有定义config_prefix则以释文中的插件id代替
插件集:
在配置实体基类中多次涉及到插件集的操作,也就是EntityWithPluginCollectionInterface接口,关于插件集概念如下:
在许多情况下系统中一个插件类只实例化出一个实例对象,但一些可配置的插件类型,根据不同配置需要产生不同实例,比如块插件,块可能会出现在页面中多个地方,每个实例都有自己的配置,不同标题、内容等等,系统允许管理员针对不同配置为同一个插件类创建多个实例,由此产生了“插件集PluginCollection”这个概念,为了和集里面多个插件交互,插件系统使用插件集Plugin collections对象来管理多个实例,系统组件中提供了一个插件集对象的抽象基类:
\Drupal\Component\Plugin\LazyPluginCollection
在核心中提供了一个默认实现:
Drupal\Core\Plugin\DefaultLazyPluginCollection
默认实现的插件集对象的构造函数接收两个参数:
插件管理器:用来实例化插件,实例化时传入配置信息,其实插件管理器实现了插件工厂接口,系统中所有的插件都是可以传入配置信息的
配置信息:集里所有插件的配置信息,是一个数组,键名将做为插件的实例id
我们可以看到以上插件集类中都有“Lazy”字样,它是什么意思呢?它代表延迟实例化,插件集对象中保存了所有插件的配置信息,当需要某个插件时才依据配置信息实例化它,而不是马上全部都实例化了,这是由于性能原因,它和容器类似,只有需要时才实例化。
系统还实现了一个特殊的插件集对象:
Drupal\Core\Plugin\DefaultSingleLazyPluginCollection
一般来说插件集里面会管理多个插件,但有时只需要一个时则使用该对象,它只管理一个插件,这是由于延迟实例化带来的性能优势或其他目的。
系统为需要用到插件集的对象定义了一个接口:
Drupal\Core\Plugin\ObjectWithPluginCollectionInterface
里面只有一个方法:
public function getPluginCollections();
注意Collection是复数形式,该方法意为得到多个插件集,多个是什么意思呢?单个插件集对象里面可以管理多个插件,但当插件需要以某种方式分类时,就可以将每一类插件归为一个集,由此形成多个插件集,这带来更多的灵活性,比如块插件中,可以将可见的块和不可见的块分别放在两个集里面,这就是多个插件集的由来,该方法返回一个数组,键名为表示插件分类的属性名,键值为该分类下的插件集对象。
配置实体id:
配置实体的id是一个全局唯一的字符串,字符串’0’或空字符串是无效的id
配置安装与卸载:
配置的安装和卸载不是一个简单的过程,会同步处理依赖关系,可能会改动其他组件,因此这一过程是需要时间的,为此系统在配置实体基类中设置了两个属性:
$isSyncing:布尔值,表明配置实体在导入过程中是否处于创建、更新或删除状态
$isUninstalling:布尔值,在卸载过程中,表明配置实体是否处于正在删除的状态
关于配置安装、卸载、导入、导出本系列会有一个专门主题来讲解。
配置语言:
和简单配置对象一样,配置实体也有语言属性,用$langcode储存语言代码,默认为英语
第三方配置设置:
配置实体接口是继承了第三方设置接口:
Drupal\Core\Config\Entity\ThirdPartySettingsInterface
因此配置实体基类实现了第三方设置额外信息的功能,所谓第三方是指需要在配置实体里面储存和其紧密耦合的信息的模块,这些信息在配置实体中用$third_party_settings属性储存,键名为模块名,值为一个键值对数组,是模块需要的信息。
配置实体和内容实体间的不同:
在新建的实体中配置实体有id,而内容实体没有,见:https://www.drupal.org/node/2478811
配置实体中的配置信息导出到数组:
可以在配置实体类释文中指定config_export来说明需要导出那些配置项,这些项会和以下项合并:
[
'uuid' => 'uuid',
'langcode' => 'langcode',
'status' => 'status',
'dependencies' => 'dependencies',
'third_party_settings' => 'third_party_settings',
'_core' => '_core',
];
这样的合并操作中config_export指定的项优先级更高,该数组中键名是配置项的属性名,键值是导出的配置数组中对应的新键名,如果释文中没有指定config_export键,那么会寻找对应配置对象的类型化Schema定义中mapping属性的键名作为需要导出的项,该配置对象名为:配置实体的配置前缀+点号+配置id,程序代码为:
$entity_type->getConfigPrefix() . '.' . $this->id()
保存前操作:
如果配置实体实现了插件集接口:
Drupal\Core\Entity\EntityWithPluginCollectionInterface
那么保存插件集的配置信息。排除配置实体的uuid冲突。确保已经存在的配置实体uuid不被改变。当配置实体不处于同步状态时,计算配置依赖
缓存标签:
配置实体的通用缓存标签不同于内容实体(标签名为:实体类型id+“:”+实体id),而是:
“config:+配置依赖名”,其中配置依赖名为:配置前缀+“.”+配置id
保存和删除时只失效列表标签,自身标签的失效在配置系统里面已经进行了