雲客Drupal8源碼分析之節點表單NodeForm

  節點表單是系統中使用最頻繁最重要的表單,她是建立在許多組件和概念之上的,內容廣泛,本篇意在起到一個指示和總結作用,幫助想直接操控節點表單的讀者明白需要知道些什麼,同時就節點表單本身進行介紹,這好似在爬山到了頂上,頂上並沒有多少東西,節點表單就是最終的應用,就其本身並沒有多少內容,因此本篇會很短,僅是一個綜合運用的總結,更多重要內容是在爬山的路上,沒有路上的內容將無法到達山頂,因此在閱讀本篇前需要先知道許多前置知識,這些本系列已發佈,這裏整理出來供讀者去學習:
《表單API》 :實體表單建立在基礎表單之上,本系列發佈過多篇表單相關主題,如示例、進階等,後續還會針對表單具體問題繼續發佈
《實體表單entity form》 :完成所有實體表單的相同工作,重點講述通用基類和實體表單運作流程
《實體表單顯示EntityFormDisplay》 :管控表單中哪些字段顯示,及其如何顯示,介紹了表單模式
《字段控件FieldWidget》 :負責單個字段的表單生成、值提取、表單錯誤顯示
《實體表單驗證(上下集)》 :結合類型化數據組件驗證表單、設置約束
《臨時儲存與消息服務》 :爲節點表單提供預覽數據的暫時存儲,內容相對簡單

節點表單建立在以上這些知識之上,是對她們的綜合運用,下文講述節點表單本身

節點表單設置:
節點添加表單的路由定義在node模塊的靜態路由定義文件中:
路由名:node.add
控制器爲:\Drupal\node\Controller\NodeController::add
路徑:'/node/add/{node_type}'

節點編輯、刪除路由定義在節點模塊的路由提供器中:
提供器類:\Drupal\node\Entity\NodeRouteProvider::getRoutes
路由名:“entity.node.edit_form”和“entity.node.delete_form”
路徑分別爲:
  '/node/{node}/edit'
  '/node/{node}/delete'
編輯、刪除路由均以通用的“_entity_form”方式設置,添加路由雖然以控制器方式指定,但並沒有什麼區別

添加和編輯所用表單類(在實體釋文中指定,這是本篇重點講述的內容):
  "Drupal\node\NodeForm"
刪除表單有兩個:
  Drupal\node\Form\NodeDeleteForm(直接刪除)
  Drupal\node\Form\DeleteMultiple(多步確認刪除)

得到節點表單:
和通用的實體表單一樣,是通過實體表單構建器產生,節點添加表單代碼示例:

        $node = \Drupal::entityTypeManager()->getStorage('node')->create([
            'type' => 'article',
        ]);
        $form = \Drupal::service('entity.form_builder')->getForm($node);
        return $form;

在控制器中執行以上代碼,這將顯示文章節點的添加表單,如果是編輯表單則如下:

$node = \Drupal::entityTypeManager()->getStorage('node')->load(1);
$form = \Drupal::service('entity.form_builder')->getForm($node, 'edit');
return $form;

如果想得到刪除表單,僅需將以上代碼的‘edit’改爲‘delete’即可,getForm方法的第二個參數是表單的操作名,或者稱爲表單模式,其值是節點實體釋文定義中表單處理器的子鍵名(鍵值是對應的表單類),改爲‘delete’後代碼將返回該實體的刪除確認表單,注意這不是直接刪除實體,而是提供用戶操作界面,如需在代碼上刪除實體應該調用實體對象的刪除方法,這兩種刪除方式區別在於有沒有刪除日誌等

節點表單類:
刪除表單比較簡單,本篇僅介紹添加和編輯表單,她們採用同一個表單類:
  \Drupal\node\NodeForm
這裏將該類稱爲節點表單,她繼承自內容實體表單基類,大部分表單功能由基類提供,詳見本系列《實體表單entity form》主題,節點表單類則繼續提供了預覽等功能,對各方法介紹如下:
public static function create(ContainerInterface $container)
實例化表單,因爲在父類中實現了容器注入接口,所以節點表單對象被該方法實例化,傳入的私有臨時儲存工廠用於實例化私有臨時儲存對象以暫時性儲存表單預覽數據

public function form(array $form, FormStateInterface $form_state)
節點表單會處理添加、編輯、預覽返回三種情況,如果進入的url類似如下:
  http://www.dp.com/zh-hans/node/add/article?uuid=107fc58d-acf5-4558-ac42-7cab5599e440
則表示當前頁面是從預覽頁面返回的,預覽的數據之前已經填寫過,以整個表單狀態對象的方式被保存在私有臨時儲存中,以“node_preview”作爲集名,以實體的uuid作爲鍵名,注意保存的是之前的表單狀態對象,如果是預覽返回方式則恢復用戶數據並設置表單重建,這裏在表單狀態對象上設置“has_been_previewed”爲true,含義是已經被預覽過,這是爲了當系統設置爲必須預覽時,標記已經預覽,後續可依據此值來判斷是否顯示保存按鈕。
該方法提供了很多渲染元素,如$form['meta']將顯示在表單頁面的右上角,菜單等模塊也默認添加了表單,這些比較簡單不再詳述,可參見鉤子:
  hook_form_BASE_FORM_ID_alter()
具體鉤子函數如:
  menu_ui_form_node_form_alter

protected function actions(array $form, FormStateInterface $form_state)
在該方法中設置了預覽按鈕的提交處理器,見下,這裏解釋一下以下代碼:
  $node->type->entity->getPreviewMode();
這裏$node->type是節點實體的一個字段,屬於引用字段,$node->type->entity會執行引用字段對象的魔術方法:
  \Drupal\Core\Field\FieldItemList::__get
返回節點類型實體對象(Drupal\node\Entity\NodeType),方法getPreviewMode是節點類型實體對象上的方法,其值是我們在內容類型結構管理中設置的“提交前預覽”項的值,通過此值來判斷是否顯示保存、預覽按鈕,配置可參考以下地址:
  /admin/structure/types/manage/article
該值對應三個常量:
 DRUPAL_DISABLED:禁止,值爲0
 DRUPAL_OPTIONAL:可選,值爲1
 DRUPAL_REQUIRED:必選,值爲2
這些產量定義在系統模塊的system.module文件中,在許多地方被使用,我們在開發中遇到類似這樣的選擇時,爲了統一起見,可直接使用這些常量

public function preview(array $form, FormStateInterface $form_state)
該方法是預覽按鈕的提交處理器,將表單狀態對象保存到私有臨時存儲中,並跳轉到預覽頁面,預覽頁面的路由是“entity.node.preview”,注意預覽過程中節點實體並沒有被保存,換句話說就是尚未執行$node->save();方法

public function save(array $form, FormStateInterface $form_state)
執行實體保存,添加日誌信息,顯示提示消息,刪除預覽數據;如果保存成功且用戶有訪問實體視圖權限,頁面將跳轉到視圖頁面,否則轉到首頁


作者語:
  本篇是雲客drupal8源碼分析第100篇,也將作爲2018-2019春節前的最後一篇發佈,該系列總字數已超過60萬字,雖取名爲源碼分析,實則也是開發者教程,可視爲與官網文檔平行的中文文檔項目,完全原創並非翻譯,許多時候和官方英文文檔也形成互補,官網沒有或模糊的知識點可以在這裏找到詳細解釋,內容均來自源代碼解讀,目前已覆蓋了drupal8系統核心大部分知識,還在繼續直至全部介紹完成;在這個值得紀念一下的里程碑時刻,想和讀者朋友們閒談三個方面的話題:中文文檔貢獻、難的潛在價值、drupal發展趨勢。
  首先是呼籲更多的朋友們加入drupal的中文文檔工作,將drupal介紹給中國的初學者,不管您對drupal理解深度如何,也不管寫的是什麼內容,離散零星的,或者成系列的,我相信一定是有用的,一定會在某一個時刻幫助到某一個人,很多小夥伴把這種行爲稱爲貢獻,但我想強調一點,這是雙贏的,給大家分享一件雲客身邊的事,昨晚孩子媽媽帶了一個紅糖饅頭回家,因爲只有一個,所以兩個還在上幼兒園的孩子一人一半,他們沒見過這種饅頭,非常高興,吃的津津有味,我在一旁看着他們發呆,姐姐突然停下來,掰了一塊餵過來,兩眼閃亮亮的,這是把僅有的半個饅頭掰了一塊塞到爸爸嘴裏,弟弟跟着也這樣做了,瞬間感覺很幸福很放心,不是每個小孩都會如此,這讓我想起一些事,在送女兒上幼兒園的路上,會經過一座天橋,時常遇見一位四五十歲的乞丐,沒有雙手盤地而坐,他總是很高興的大聲唱歌,人在清晨遇到一位生活不幸的人還在樂觀的高歌,便會燃起對生活的珍惜和對不幸者的同情,因此很多時候會給女兒一點零錢讓她給人家拿去,開始她不敢,畏畏縮縮的,次數多了就不怕了,後來會主動找我要錢給人家,時間久了對殘疾的不幸理解的也深了,要的也多了,後來我會拉住她,然後告訴她這些錢可以買到什麼她想要的東西,如果給了就不能買了,儘管她不捨得,但還是會給,我想正是因爲類似這樣的事情培養了她的善良,讓她可以將不多的饅頭分一些放到爸爸嘴裏,對於一個爸爸而言,孩子是否善良和勤奮是第一等心事,有這兩者長大後他們一定不會差,一個隨心的善舉,看似沒有回報,卻解決這麼大的一樁心事,這種贈與成了雙贏。
  小女孩可以爲自己覺得該做的事情放棄自己喜歡的玩具零食,這可能是天性,回到成年人身上,爲了一些有意義的事情犧牲一點時間,則更多的可能是權衡,我想說這也會得到極大的回報,人若想有所成就,就必須和社會建立協作,在此之前必須讓社會認識您,知道您會什麼,靠不靠譜,作爲開發人員,無疑通過寫作技術分享這樣的方式是很不錯的,讓需要您才華的人知道您在哪裏,能夠找到您,開放自己變得有機會,在這些機會中您比別人更容易找到實行夢想的途徑,寫作過程中也會夯實自己的知識體系,對不知道的點窮追不捨,因爲您寫作的內容是要給大衆看的,不會允許自己敷衍,不懂裝懂、掩耳盜鈴是不可能的,這在技術上會讓自己成長,成長了機會也來了離夢想還遠嗎?這些好處都真實發生在雲客身上,實際上回報遠不止於此,會出現各種間接的良性循環,感動的甚至有讀者直接在QQ上給雲客發紅包,沒有任何要求,這種敬意讓自己感覺到存在的價值,在這裏真誠呼籲大家來寫下drupal的方方面面,讓她變得更加容易,對於自己而言則無心插柳,柳可能成蔭。
  提到drupal的難,社區裏面有一張drupal學習曲線對比玩笑圖,可能把初學者嚇的望而生畏,但也可能把勇者挑動的躍躍欲試,在此我想說應該理性的看待這個“難”,drupal既沒有圖中形容的那麼不可征服,當然也不會太簡單,她的難是合理的,在雲客的互聯網開發技術羣裏,主題文檔系列作者晴空用鋤頭和挖掘機來討論這個問題,如果您選擇了鋤頭的簡單,那麼可能您正在修一條小路,如果您欲開山劈地、搭建橋樑隧道那麼無論如何您不會去選擇鋤頭的簡單,挖機機械纔是您需要的,但您需要先去學習它們,在使用上它們相比之下肯定難一些,但這是合理的“難”,其背後往往蘊藏着一些不容易看到的巨大價值,那麼drupal的這些不容易看到的價值是什麼呢?這裏列舉其中一個:大型項目的後期成本。
  面對項目,如果您選擇自己開發一個系統,開始時一定是順風順水的,但當規模達到一定程度,需要十幾人協作或數百人協作的時候,問題就來了,這個時候系統已發展的很複雜,由於各種原因也會導致初期考慮不足,欠下技術債,後面加入的開發人員必須先專門學習您的系統才能工作,這很難,需要很多時間,您需要支付薪資,從項目角度看,這個學習成本還是沒有繞過去,更糟糕的是開發者在沒有極大利益爲前提下是不希望去學習的,道理很簡單,因爲學了只能在一處使用,價值不大,對職業前景幫助不大,這是對個人而言的,對公司而言,形成對極大代價培養的員工的高度依賴,這成本很高,且風險很大,規模和人才等都會出現死穴,然而使用drupal這些問題會得到極大改善,她成熟、標準、已經做了很多、強大靈活、人才儲備多,便開始顯現其價值;偉大有影響力的項目都需要衆多協作者,就像幾個人不可能造出大飛機、航母,如果有締造大項目的雄心那麼應該挑戰合理的困難,先爬到巨人的肩上,借勢而爲。
  最後我們聊聊趨勢,這裏想告訴drupaler一個好消息:歐盟決定資助十四款開源軟件的安全審計,CMS系統僅drupal入列,且這十四款軟件中drupal預算排名第二,這傳達了一種信心,將推動drupal發展,提升安全性,對於在drupal上投入精力的小夥伴前途又光明瞭一分,詳見:
https://www.zdnet.com/article/eu-to-fund-bug-bounty-programs-for-14-open-source-projects-starting-january-2019/?from=timeline
  回顧計算機歷史,會發現很多東西一直在細分,最開始設計的計算機是一體的,後來細分爲硬件和軟件,軟件又細分爲操作系統和應用軟件,然後繼續細分,這個過程中每一次細分,在那一個點只會保留幾個出類拔萃的代表供全部人使用,CPU架構就那幾種,操作系統就那幾種,WEB服務器就那幾種,編程語言就那幾種,您是否相信CMS也會就那幾種?然後某領域應用的模塊也會就那幾種?雲客是趨向於相信的,因爲有個底層原因:在相同的平臺上才能保證協作接口的一致性,只有一致才能進行大規模協作,才能提高文明的總規模。這是每一次細分只能保留少數幾個的根本原因,如果保留了很多,那麼他們一定有相同的標準接口,比如瀏覽器、播放器等, CMS出現標準接口可能爲時尚早,因此drupal應能成爲被保留下來的那少數幾種之一。
  大自然好像一直在要求生命去做能量最大化的事情,不斷擴大規模,關於此吳軍老師的科技史綱六十講裏面有很多很具說服力的論述,如果您相信這一點,就會知道一致性多麼重要,就會趨向於相信drupal會成爲web系統中的linux,既然如此,提前去投入可能是不錯的選擇。

                                                                                                             2019年1月24日 雲客 於中國深圳

 

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

 

 

 

 

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