上一教程:Drupal8模組開發之路由、控制器和菜單連結教程
在本教程中,我們將學習進一步的開發,我們可以在這個庫 (link is external)裡找到我們需要的沙箱模組程式碼範例,裡面兩個重要的新功能:區塊和表單。
為此,我們將建立一個自訂區塊來返回一些可配置的文本,在那之後,我們將建立 一個簡單的表單來列印輸出使用者提交到的資料到螢幕上。
不知道怎麼下載這個庫的同學看這裡:
Drupal8 區塊
在Drupal8裡,有一個很酷的新變化時,以往的Block(區塊) API 已經轉換成了外掛程式的形式(一個全新的概念),這意味著區塊將是可被重複使用的功能塊(在引擎下),
你現在可以在後台UI介面建立一個Block區塊,並在整個網站的任何地方重用它,你現在不會再局限於只能使用一次這個區塊。
讓我們先建立一個簡單的區塊來列印"Hello World"到螢幕上! 一般情況下,我們首先需要在模組根資料夾下的src/Plugin/Block目錄下建立一個class類
檔案DemoBlock.php,我們這裡暫且把這個新的區塊命名為"DemoBlock", 所以你最終在這個檔案中,看到的代碼會是像這樣:
| 代碼如下 |
複製代碼 |
<?php namespace DrupaldemoPluginBlock;
use DrupalblockBlockBase; use DrupalCoreSessionAccountInterface; /** * Provides a 'Demo' block. * * @Block( * id = "demo_block", * admin_label = @Translation("Demo block"), * ) */ class DemoBlock extends BlockBase { /** * {@inheritdoc} */ public function build() { return array( '#markup' => $this->t('Hello World!'), ); } /** * {@inheritdoc} */ public function access(AccountInterface $account) { return $account->hasPermission('access content'); } }
|
像所有其他的class類檔案一樣,我們要先在開始時先聲明類的命名空間。然後,我們使用BlockBase類以便於我們等下可以繼承和擴充它,以及也需要使用AccountInterface類以便於讓我們可以擷取當前登入的使用者。然後接下來的一些代碼你肯定沒有在Drupal 7見過,這就是:annotations注釋。
Annotations注釋是一個PHP發現工具,使用這些注釋,我們可以讓Drupal知道我們想註冊一個新的區塊(@ Block),我們設定了Id號:demo_block 和admin_label :Demo block(這些注視將會通過注視翻譯系統被drupal識別)。
接下來,我們在DemoBlock類裡擴充下BlockBase類,我們將實現兩個方法(都是最常見的),build()方法是最重的,因為它返回一個可列印的區塊資訊數組,access()方法控制查看此區塊的存取權限,這裡傳遞給它的參數是AccountInterface類的一個執行個體,在這裡,實際傳遞的就是目前使用者資訊參數。
另外一個有趣的事情需要注意的是,我們不再像以前一樣使用全域t()函數直接翻譯文本了,但是我們會繼承使用父類的t()方法,所以你看到的是$this->t().
就是這樣,你現在可以清空緩衝,然後進入區塊的配置頁,最酷的是你現在已經成功建立了一個區塊,並且你可以把這個區塊放在任何網站裡你設定的regions地區。
Drupal 8 區塊配置
現在我們已經知道了如何建立一個新的區塊,讓我們進一步學習下如何用API為它添加配置表單,我們將讓你可以編輯此區塊,給你一個文本輸入框,讓你可以輸入一個名字,然
後前台就會顯示"Hello 名字"來替換 "Hello World".
首先,我們需要定義一個文字框,所以在我們的DemoBlock類裡,我們可以添加一個新的方法叫做blockForm():
| 代碼如下 |
複製代碼 |
/** * {@inheritdoc} */ public function blockForm($form, &$form_state) { $form = parent::blockForm($form, $form_state); $config = $this->getConfiguration(); $form['demo_block_settings'] = array( '#type' => 'textfield', '#title' => $this->t('Who'), '#description' => $this->t('Who do you want to say hello to?'), '#default_value' => isset($config['demo_block_settings']) ? $config['demo_block_settings'] : '', ); return $form; }
|
這個表單API應該看起來很熟悉,似乎和以往的drupal 7裡的差不多,然而,細看之下,你會發現有一些新的東西在裡面,首先,我們從父類裡擷取$form數組(所以我們是在已存在
的表單基礎上新增建立我們的欄位),標準的面向對像,然後,我們通過BlockBase類定義的getConfiguration()方法來擷取配置資訊,並且我們把demo_block_settings的值作為了
#default_value的預設值.
接下來,到了我們要對我們傳遞的欄位值進行提交處理並儲存進區塊配置裡的時候了:
| 代碼如下 |
複製代碼 |
/** * {@inheritdoc} */ public function blockSubmit($form, &$form_state) { $this->setConfigurationValue('demo_block_settings', $form_state['values']['demo_block_settings']); }
|
這個方法也存在於DemoBlock類裡,它被用於儲存demo_block_settings的值(請注意保持鍵名的一致性)
最後我們需要調整我們的build()方法,讓它在列印Hello時包含name名字:
| 代碼如下 |
複製代碼 |
/** * {@inheritdoc} */ public function build() { $config = $this->getConfiguration(); if (isset($config['demo_block_settings']) && !empty($config['demo_block_settings'])) { $name = $config['demo_block_settings']; } else { $name = $this->t('to no one'); } return array( '#markup' => $this->t('Hello @name!', array('@name' => $name)), ); }
|
現在,這應該看起來相當容易,我們擷取區塊的配置資訊,如果我們的欄位值存在,我們就把它列印出來,如果不存在,就列印"to no one", 你現在可以清空緩衝後,編輯區塊,填寫一個值,然後儲存,然後你就能在前台看到" Hello + 名字值"了。
Drupal 8 表單
最後,我們將在本教程中,探討如何建立一個簡單的表單,由於空間的限制,我不會覆蓋它的組態管理(通過表單提交儲存值),相反,我將舉例說明一個簡單的表單設定,然後讓提交的值簡單的列印在螢幕上,以示範它可以正常工作。
在Drupal 8 裡,表單定義函數都在一個class類裡被組織在一起,所以讓我們定義一個簡單的DemoForm類,在src/Form/DemoForm.php中:
| 代碼如下 |
複製代碼 |
<?php /** * @file * Contains DrupaldemoFormDemoForm. */ namespace DrupaldemoForm; use DrupalCoreFormFormBase; class DemoForm extends FormBase { /** * {@inheritdoc}. */ public function getFormId() { return 'demo_form'; } /** * {@inheritdoc}. */ public function buildForm(array $form, array &$form_state) { $form['email'] = array( '#type' => 'email', '#title' => $this->t('Your .com email address.') ); $form['show'] = array( '#type' => 'submit', '#value' => $this->t('Submit'), ); return $form; } /** * {@inheritdoc} */ public function validateForm(array &$form, array &$form_state) { if (strpos($form_state['values']['email'], '.com') === FALSE ) { $this->setFormError('email', $form_state, $this->t('This is not a .com email address.')); } } /** * {@inheritdoc} */ public function submitForm(array &$form, array &$form_state) { drupal_set_message($this->t('Your email address is @email', array('@email' => $form_state['values']['email']))); } }
|
除了OOP思想的改變,一切應該看起來像以前的drupal 7 一樣熟悉。Form API 仍然基本沒有什麼變化(除了一些新的表單元素的加入和相關class類的封裝),所以會發生什嗎?
首先,我們使用了命名空間的類和核心的FormBase類,所以接下來我們就可以在我們自己的DemoForm類裡擴充它,然後我們實現了4個方法,其中3個應該是很熟悉的。 getFormid()方法是新增的並且是必須要有的,這個方法用於簡單的返回form的機器名稱,buildForm()方法也是必須要有的,它用於構建一個表單,怎麼用?其實就和你之前在drupal 7中的構建方法差不多,validateForm()方法是可選的,它像drupal 7裡一樣,用於驗證表單提交資料,最後,submitForm()方法用於處理提交的表單資料,一切是不是很合乎邏輯組織。
所以,我們想用這個表單實現什嗎?我們有一個email郵件欄位(Drupal 8的新表單元素),我們希望使用者填寫它,預設情況下,Drupal會檢查是否輸入了一個正確的郵箱格式的值,但在我們的驗證函式裡我們會確保它是一個合法的帶.com尾碼的郵箱地址,如果不是,我們會在欄位上設定了一個錯誤提示,最後提交處理,然後列印一個提示訊息在網頁上。
為了使用這個表單,我們需要做最後一件事,就是提供為這個表單提供一個路由,所以請編輯demo.routing.yml檔案,並增加以下代碼:
| 代碼如下 |
複製代碼 |
demo.form: path: '/demo/form' defaults: _form: 'DrupaldemoFormDemoForm' _title: 'Demo Form' requirements: _permission: 'access content'
|
這應該看起來很熟悉,因為我們之前有篇文章介紹過怎麼路由一個簡單頁面,唯一最大的區別是, 在 defaults下面,我們用_form替代了之前的_content,並為_form指定了一個表單類,
這個類就是剛剛我們建立的。
清空緩衝後就可以輸入地址導航到demo/form,然後就可以看到這個表單並測試它。
如果你熟悉以前drupal 7中的drupal_get_form,也知道怎樣載入一個表單的方式,因此,你就可以使用drupal 8中的全域Drupal類 (link is external),比如formBuilder()方法來擷取一個表單,像這樣
| 代碼如下 |
複製代碼 |
| $form = Drupal::formBuilder()->getForm('DrupaldemoFormDemoForm'); |
然後你就可以返回$form 並渲染輸出了。
結論
在這篇文章中,我們繼續探索了Drupal 8模組開發的兩個新的話題:區塊和表單。我們已經看到了如何建立我們自己的區塊(然後你就可以在區塊管理介面建立新區塊)。我們還學會了如何添加和儲存一個自訂的配置值(這個值你可以在稍後使用它)。在表單的話題中,我們看到了一個簡單的FormBase類的實現,我們用來把使用者提交的資料列印到螢幕上。