CsatolmányMéret
demo-8.x.1.0-dev.tar.gz2.13 KB
Az előző blogbejegyzésből megtudhattuk, hogyan is változott meg a modulok alapfelépítése Drupal 8-ban a Drupal 7-hez képest. Úgy döntöttem, a mostani bemutatómhoz is az előző hello modult fogom használni apróbb változtatások mellett, ezzel is bemutatva, hogy egy modulon belül milyen jól külön lehet választani a modul által szolgáltatott funkciókat a D8 új fájlstruktúrájában.
Az előző modulunk új neve demo lett és a routing.yml fájlban használt elnevezésekkel próbáltam egyértelműbbé tenni, hogy mi mit jelöl. Íme az új modul felépítése, amelyben már láthatóak az új fájljaink is, amelyeket ebben a leírásban meg fogunk nézni:
Vágjunk is bele
Ahogy az előző példában is láthattuk, elsőre talán semmi sem tűnik annyira egyszerűnek Drupal 8-ban, mint ahogy az a 7-esben volt előtte. Nem fogok kertelni, elsőre az űrlapok is ilyenek lesznek… A Symfony itt is megváltoztatta az űrlapok készítésének és hívásának módját, természetesen mindezt objektum-orientált alapokon.
Most kétféle űrlapot fogunk megnézni: a SimpleExampleForm-ot, amely egy egyszerű űrlap megvalósítását mutatja be, illetve a ConfigExampleForm-ot, amely olyan űrlapot mutat be, amellyel rendszerszintű beállításokat olvashatunk és menthetünk el (lásd Drupal 7-ben: system_settings_form()).
Szokásos első lépések
Vegyük fel a SimpleExampleForm-ot a routing.yml-be illetve a hook_menu()-be.
demo.module.php
<?php /** * @file * Provides hook implementations for the hello module. */ /** * Implements hook_menu(). */ function demo_menu() { $items['demo-form/simple-form-example'] = array( 'title' => 'Simple form', 'route_name' => 'formdemo.simple_form_example', 'weight' => 0, ); return $items; }
demo.rouiting.yml
formdemo.simple_form_example: pattern: 'demo-form/simple-form-example' defaults: _form: '\Drupal\demo\Form\SimpleExampleForm' requirements: _permission: 'access content'
Csak a releváns részeket másoltam ki, ugyanis sok új dolog most nincs itt számunkra. Amire felhívnám a figyelmet, hogy _content helyett, most _form -ot használunk a routing.yml-ben.
SimpleExampleForm.php
<?php /** * @file * Contains \Drupal\demo\Form\SimpleExampleForm. */ namespace Drupal\demo\Form; use Drupal\Core\Form\FormInterface; /** * Simple form example with validation and submit handler. */ class SimpleExampleForm implements FormInterface { /** * {@inheritdoc} */ public function getFormID() { return 'simple_example_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, array &$form_state) { $form['foo'] = array( '#type' => 'select', '#title' => t('Foobar'), '#default_value' => 'bar', '#description' => t('Trust me, "bar" will be the proper answer!'), '#options' => array( 'foo' => t('foo'), 'bar' => t('bar'), ), '#required' => TRUE, ); $form['actions']['#type'] = 'actions'; $form['actions']['submit'] = array( '#name' => 'op', '#type' => 'submit', '#value' => t('Save'), '#button_type' => 'primary', ); $form['actions']['cancel'] = array( '#name' => 'op', '#type' => 'submit', '#value' => t('Cancel'), ); return $form; } /** * {@inheritdoc} */ public function validateForm(array &$form, array &$form_state) { if ($form_state['values']['foo'] != 'bar') { form_set_error('foo', t('You should choose "bar"!')); } } /** * {@inheritdoc} */ public function submitForm(array &$form, array &$form_state) { if ($form_state['values']['op'] == t('Save')) { drupal_set_message(t('The form has been saved.')); } } }
Láthatjuk, hogy űrlapok készítéséhez a FormInterface-t kell implementálunk saját osztályunkban. Ez az interfész 4 függvényt szolgáltat számunkra, amelyeket kötelezőek vagyunk felüldefiniálni:
- getFormID() - saját egyedi nevet kell adnunk (prefixként még használható például modulunk neve is (demo_), amit ebben az egyszerű esetben kihagytam).
- buildForm() - az űrlapunk leírását tartalmazza, egy Form API tömbbel tér vissza.
- validateForm() - az űrlapunkhoz tartozó validáció, ugyanaz, mint Drupal 7-ben.
- submitForm() - az űrlap sikeres elküldésekor történő esemény leírása, ugyanaz, mint Drupal 7-ben.
Megszokhattuk már Drupal 7-ben is, hogy az űrlapunkhoz írhatunk saját függvényeket is, amelyek például kiszámolják az inputként kapott összeg ÁFÁ-val terhelt értékét. Ezeknek régen a .module vagy .inc fájlokban volt a helyük. Volt! Mostantól ezeknek a függvényeknek a helye ugyanabban az osztályban van, amely ezeket felhasználja.
A másik űrlapunk kódja is kísértetiesen hasonlít az előzőekben taglaltakra, hiszen a SystemConfigBase is a FormInterface-t implementálja. Az OOP szemlélet alapjának egyik fő gondolata, hogy ne kódoljuk le mindent újra és újra, dolgozzunk újrafelhasználható komponensekkel. Ezt nyújtja számunkra a SystemConfigBase kiterjesztése, amely olyan űrlapot definiál nekünk előre, amelynek alapból van egy „Beállítások mentése” funkciója. Számunkra egyetlen új és fontos property-je van, amelyet kiemelnék: a $configFactory… de csak a reklám után… azaz nézzük előbb a kódot:
ConfigExampleForm.php
<?php /** * @file * Contains \Drupal\demo\Form\ConfigExampleForm. */ namespace Drupal\demo\Form; use Drupal\system\SystemConfigFormBase; /** * Config form example that can read and store important settings. */ class ConfigExampleForm extends SystemConfigFormBase { /** * {@inheritdoc} */ public function getFormID() { return 'config_example_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, array &$form_state) { /** * Read default settings from file. * @see config/demo.form.settings.yml */ $config = $this->configFactory->get('demo.form.settings'); $form = parent::buildForm($form, $form_state); $form['example'] = array( '#type' => 'textfield', '#title' => t('Example'), '#description' => t('Get the default value from demo.form.settings.yml'), '#default_value' => $config->get('default'), '#required' => TRUE, ); return $form; } /** * {@inheritdoc} */ public function validateForm(array &$form, array &$form_state) { parent::validateForm($form, $form_state); } /** * {@inheritdoc} */ public function submitForm(array &$form, array &$form_state) { parent::submitForm($form, $form_state); // Save the new value. $this->configFactory->get('demo.form.settings') ->set('default', $form_state['values']['example']) ->save(); } }
Oké, megvagyunk, van getFormID()-nk, buildForm()-unk, validate… várjunk csak… mi volt az ott a buildForm()-ban?!
<span style="color: #0000ff;">$config</span> = <span style="color: #0000ff;">$this</span>-<span style="color: #66cc66;">&</span>gt;configFactory-<span style="color: #66cc66;">&</span>gt;get<span style="color: #66cc66;">(</span><span style="color: #ff0000;">'demo.form.settings'</span><span style="color: #66cc66;">)</span>;
Azt mondja, hogy: a $config értéke legyen az ezen objektum configFactory objektumának get paramétere által visszaadott érték (spoiler: ami egy configuration objektum lesz). De mi az a paraméter ott a get-ben?!
Amit ott a get() paraméteréül láthatunk, az egy Symfony settings.yml-re való hivatkozás. A Symfony-val újabb újdonságot kaptunk Drupal 8-ban, mégpedig, hogy a rendszer ilyen settings.yml fájlokkal is konfigurálható lett, ezzel is megkönnyítve a dev/staging/prod site-ok beállításának szinkronban tartását, költöztetését. (Mert mint tudjuk, sajnos nem mindenre jó kedvenc Drupal 7-es Features modulunk.)
Ilyen alapbeállításokat tartalmazó fájlokat tartalmazhatnak moduljaink is, amelyek általános helye a
modul_neve/config/modul_neve.(funkcio).settings.php
Miután bekértük e fájl tartalmát, a benne található változók értékét elérhetjük a $config objektum részeként, illetve mivel ezzel létrejött a rendszeren belül egy hivatkozás az adott változó-érték párosra, ezért rendszer szinten módosíthatjuk is azt (lásd submitForm()).
Az utolsó trükk mára
Szeretném a SimplExampleForm űrlapot egy másik oldalon vagy blokkban is megjeleníteni.
A drupal_get_form() fogja nyújtani a választ minden óhajunkra, ugyanis ennek segítségével bárhol és bármikor megjeleníthetünk egy adott űrlapot. Most már a kontrollerek és routerek mellett nem szükséges a drupal_get_form() használata ahhoz, hogy egy űrlapot egy oldalon megjelenítsünk, azonban blokkok esetében továbbra is hasznos lehet. A példánk a FormController.php-ban található, amelyből a fontosabb részeket emelném ki:
use Drupal\demo\Form\SimpleExampleForm;
A namespace használata, ahol a SimpleExampleForm-unk található.
class FormController implements ControllerInterface { public function formDemoDrupalGetFormPage() { // Creating a new SimpleExampleForm form object that described in our "Drupal\demo\Form\SimpleExampleForm" namespace. return drupal_get_form(new SimpleExampleForm()); } }
Illetve új SimpleExampleForm() objektum létrehozása a drupal_get_form() függvényben.
Pár beépített form típus ízelítőnek, amelyeket még kiterjeszthetünk
- SystemConfigFormBase
- ConfirmFormBase
- BulkFormBase
- FieldInstanceFormBase
- ViewsFormBase
Források
http://getlevelten.com/blog/ian-whitcomb/drupal-8-module-development-part-2-forms