1. 程式人生 > >雲客Drupal8原始碼分析之實體Entity(二)配置實體基類

雲客Drupal8原始碼分析之實體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-entity-dependencies

配置依賴名:

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
儲存和刪除時只失效列表標籤,自身標籤的失效在配置系統裡面已經進行了


我是雲客,【雲遊天下,做客四方】,微訊號:PHP-world,歡迎轉載,但須註明出處,討論請加qq群203286137