雲客Drupal源碼分析之臨時儲存與消息服務

前言:臨時儲存與消息服務之間並沒有什麼直接關聯,由於她們都是系統基礎組件,內容也比較簡單,爲後續主題做準備,所以放在一起講解。

臨時儲存概述:
臨時儲存用來儲存一些臨時性的數據,超期後會被刪除,比如節點在保存前的預覽數據,她和緩存不一樣,她是臨時性的、不能被重建的數據,依據被儲存的數據在用戶間能否互相訪問又分爲私有和共享。

私有臨時儲存:
用戶之間不共享數據,只能訪問或操作自己的數據,已登錄用戶使用用戶id(整數)做隔離,未登錄用戶使用會話id做隔離。
服務id: tempstore.private
類:Drupal\Core\TempStore\PrivateTempStoreFactory
服務定義:

  tempstore.private:
    class: Drupal\Core\TempStore\PrivateTempStoreFactory
    arguments: ['@keyvalue.expirable', '@lock', '@current_user', '@request_stack', '%tempstore.expire%']
    tags:
      - { name: backend_overridable }

該服務使用了有期限限制的鍵值對儲存服務(詳請見本系列相關介紹),服務id:keyvalue.expirable,在默認情況下最終會使用有期限限制的數據庫鍵值對儲存服務(服務id:keyvalue.expirable.database),此默認行爲可以在站點服務配置文件(\sites\default\ services.yml)中更改,配置鍵:factory.keyvalue.expirable,其值爲一個數組,鍵名是集名,鍵值爲該集要使用的鍵值儲存服務的id,爲所有集名指定默認服務時使用keyvalue_expirable_default做鍵名,如果不進行配置則系統默認使用服務keyvalue.expirable.database,在底層數據庫中,鍵值儲存系統傳入的集名追加了前綴:“tempstore.private.”。

鎖服務用以確保在多個請求同時執行某個操作時只有一個請求能夠執行,詳見本系列鎖服務主題

臨時儲存超期時間默認爲7天,這在覈心服務定義文件(core.services.yml)中以秒指定:
tempstore.expire: 604800
在站點服務配置文件裏面可以修改默認值,服務參數設置裏添加修改即可,單位爲秒

通過以下代碼,我們可以得到私有臨時儲存對象,在該對象上進行私有臨時數據的操作:
$store = \Drupal::service(' tempstore.private')-> get($collection);
該私有臨時儲存對象類定義爲:
\Drupal\Core\TempStore\PrivateTempStore
通過該類可見系統使用了用戶id或會話id在鍵值集的鍵名中,以確保代碼只能操作當前用戶的數據,換句話說用戶只能操作自己的數據,可用方法如下:
$store->get($key);
得到數據
$store->set($key, $value)
設置並保存數據,會使用鎖以排斥併發操作,值可以是標量數據、數組、對象等
$store->getMetadata($key)
得到數據的元數據,返回一個數組轉化的標準對象,只有兩個屬性:owner的值是用戶id或會話id,updated是數據被創建時的主請求的請求時間戳
$store->delete($key)
刪除數據,會使用鎖以排斥併發操作

共享臨時儲存:
和私有臨時儲存不同,共享臨時儲存允許用戶去操作其他用戶的數據,定義如下:
服務id:tempstore.shared
類:Drupal\Core\TempStore\SharedTempStoreFactory
定義:

  tempstore.shared:
    class: Drupal\Core\TempStore\SharedTempStoreFactory
    arguments: ['@keyvalue.expirable', '@lock', '@request_stack', '%tempstore.expire%']
    tags:
      - { name: backend_overridable }

和私有臨時儲存一樣,同樣使用了有時間期限限制的鍵值儲存系統、相同的超期時間、鎖服務,這裏不再贅述,在底層鍵值集使用“tempstore.shared.”做前綴,使用方法如下:
$store = \Drupal::service(' tempstore.private')-> get($collection, $owner = NULL);
參數$owner是被操作的共享數據的所有者,值爲用戶id或會話id,如果省略將使用當前用戶id或會話id
該代碼返回共享臨時儲存對象,類定義如下:
\Drupal\Core\TempStore\SharedTempStore
從該類可見,任意用戶可以使用相同的key去存儲或取回數據,這不像私有臨時儲存那樣每個用戶的key值都不一樣,意味着只要有key值就能獲取共享的數據,從而實現數據共享,但依然會將用戶信息儲存在元數據中,這會帶來一些特殊用途,共享臨時儲存對象可用方法如下:
$store->get($key);
得到數據,而不管所有者是誰
$store->getIfOwner($key)
得到數據,如果所有者不是傳入的所有者,那麼返回空值
$store->set($key, $value)
以傳入的所有者的名義保存數據
$store->setIfNotExists($key, $value)
在數據不存在時以傳入的所有者的名義保存數據
$store->setIfOwner($key, $value)
在數據不存在時以傳入的所有者的名義保存數據,或者數據存在且所有者和傳入的所有者相同時才保存數據
$store->getMetadata($key)
得到數據的元數據,返回一個數組轉化的標準對象,只有兩個屬性:owner的值是數據所有者的用戶id或會話id,updated是數據被創建時主請求的請求時間戳
$store->delete($key)
刪除數據,而不管所有者是誰,會使用鎖以排斥併發操作
$store->deleteIfOwner($key)
刪除數據,只有數據所有者和傳入的所有者相同時才刪除

消息服務:
消息服務用於在頁面之間傳遞運行時消息,比如表單驗證錯誤時的頁面提示、上一個頁面的操作結果提示等等,並非用戶與用戶之間互發的站內消息,而是同一個用戶的跨頁面系統提示消息,通常只顯示一次,然後刪除,這將替換原來的以下函數:

drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE)
drupal_get_messages($type = NULL, $clear_queue = TRUE)

這兩個消息函數在drupal8.5版本中棄用,9.0時會移除。
消息服務定義如下:

  messenger:
    class: Drupal\Core\Messenger\Messenger
        arguments: ['@session.flash_bag', '@page_cache_kill_switch']

這是建立在會話閃存包對象上的,詳見本系列會話相關主題,閃存包對象有個鮮明特點就是用後即毀,但也提供peek類方法(偷瞥一眼方法,即取回數據後不損毀數據),消息分爲三類:狀態、警告、錯誤,所有的消息都儲存在這三類下,獲取消息服務如下:
$messenger = \Drupal::service('messenger');
一般來說這樣的獲取方法用在鉤子、靜態方法等地方,如果是自定義服務,最佳做法是以參數傳入,消息對象有以下可用方法:
$messenger->addError($message, $repeat = FALSE)
添加錯誤消息,參數$message可以是字符串,也可以是\Drupal\Core\Render\Markup對象,在內部使用Markup對象保存,添加消息時最佳實踐是以大寫字母開頭並以句點結束,注意我們應該使用t函數翻譯之後再傳入,她內部不會自動翻譯;參數$repeat表示如果消息已經存在,是否重複添加,默認不重複
$messenger->addStatus($message, $repeat = FALSE)
添加狀態消息,同上
$messenger->addWarning($message, $repeat = FALSE)
添加警告消息,同上
$messenger->addMessage($message, $type = self::TYPE_STATUS, $repeat = FALSE)
按類型添加消息,以上三個方法均使用該方法,很少直接使用,當直接調用該方法時,類型請按常量傳遞是個好習慣,從該方法可知有消息提示的頁面不會被緩存
$messenger->all()
查看所有消息,但不刪除消息,返回一個數組,鍵名是消息類型,鍵值是消息構成的索引數組
$messenger->messagesByType($type)
按類型查看消息,但不刪除,返回一個由該類型消息構成的數組
$messenger->deleteAll()
刪除並返回全部消息
$messenger->deleteByType($type)
按類型刪除消息,返回被刪除類型的全部消息

程序可以調用以上方法去操作消息,系統會使用消息塊去顯示被添加的消息,因爲閃存包的用後即毀特性,所以這些消息只顯示一次,如果頁面沒有添加消息區塊(塊id:system_messages_block)則不會顯示,具體代碼請見:
\Drupal\system\Plugin\Block\SystemMessagesBlock
\Drupal\Core\Render\Element\StatusMessages

爲了使用方便,系統還提供了一個消息服務特徵:
\Drupal\Core\Messenger\MessengerTrait
當我們的類需要消息服務時可以引用該特徵

爲了向後兼容,系統提供了一個過渡消息類:
\Drupal\Core\Messenger\LegacyMessenger
在該類中,在有消息服務存在時將使用消息服務,否則採用以前的辦法(引用會話變量);這將在drupal9.0移除,不應該直接實例化她,而應該使用以下代碼代替:
\Drupal::messenger();
移除後此代碼會改爲返回消息服務對象

 

我是雲客,【雲遊天下,做客四方】,聯繫方式見主頁,歡迎轉載,但須註明出處

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章