Check out the new Drupal 8 blog post by our Drupal developers with really useful technical details - from devs for devs! However, if you are not a developer and would like to know something about Drupal Development in 7 and 8 in a "light" style, welcome to view another blog post with a presentation.
Hello, everyone! The release of Drupal 8 is almost here, but its beta version is already vailable for use. So let's explore Drupal 8 together.
Creating pages and menus in Drupal 8
Probably, the first hook for everyone to implement was hook_menu (). It’s hard to believe but hook_menu() is removed from Drupal 8. The main task of hook_menu() is creating menus and pages. The new version has a new routing system to replace hook_menu (). To create a page in Drupal 8, you need to create a your_module.routing.yml file in the module folder. The content of this file looks about like this:
example_mod.mypage: path: '/cust-page' defaults: _controller: '\Drupal\example_mod\Controller\ExampleModuleController::pagecontent' _title: 'My page' requirements: _permission: 'idevels example conf'
- example_mod.mypage - the route name;
- path - the page path. You can use dynamic properties with the help of braces (for example, path: '/cust-page/{node}');
- _controller - a method responsible for the page display;
- _title - page title;
- _permission - the rights that are required for access.
The next step is to create a page controller. To do this, create a src/Controller/ExampleModuleController.php file;
The contents of the file:
example_mod.mypage: path: '/cust-page' defaults: _controller: '\Drupal\example_mod\Controller\ExampleModuleController::pagecontent' _title: 'My page' requirements: _permission: 'idevels example conf'
- example_mod.mypage - the route name;
- path - the page path. You can use dynamic properties with the help of braces (for example, path: '/cust-page/{node}');
- _controller - the method responsible for the page display;
- _title - the page titile;
- permission - the rights that are required for access;
The next step is to create a page controller. To do this, create a src/Controller/ExampleModuleController.php file.
The contents of the file:
'markup', '#markup' => t('My first page!!!'), ); return $build; } }
The result will look like this::
Please note that the name of the controller class name and its method should match those specified in your_module.routing.yml.
In Drupal 7, to create a menu item in hook_menu, you had to add the following line: 'type'=> MENU_NORMAL_ITEM. It looked about like this: 'type' => MENU_NORMAL_ITEM . It looked about like this:
function your_module_menu(){ $items = array(); $items['page_example'] = array( 'title' => 'Title', 'description' => '', 'page callback' => '_page_example', 'access callback' => TRUE, 'type' => MENU_NORMAL_ITEM, 'menu_name' => 'main-menu', // вказуємо меню у якому буде створено посилання на сторінку ); return $items; }
To create a menu item for a page in Drupal 8, you need to create a file named your_module.links.menu.yml.
The content of this file looks about like this:
example_mod.mypage: title: 'Link to my page' description: 'example' route_name: example_mod.mypage weight: 100 #If menu_name is omitted, the "Tools" menu will be used. menu_name: main
The result of the above actions:
Creating blocks in Drupal 8
In Drupal 7, you used hook_block_info and hook_block_view hooks for creating blocks. It looked about like this:
/**
* Implements
hook_block_info(). */ function your_module_block_info() { $blocks = array(); $blocks['BLOCK1'] = array( 'info' => t('BLOCK NAME'), ); return $blocks; } /** * Implements hook_block_view(). */ function your_module_block_view($delta = '') { $block = array(); switch ($delta) { case 'BLOCK1': $block['subject'] = ''; $block['content'] = t(‘Block content’); break; } return $block; }
In Drupal 8, these hooks are removed. So, to create a block, you need to create a your_module/src/Plugin/Block/MyBlock.php file. The file content looks like this:
<?php /** * @file * Contains \Drupal\internetdevels\Plugin\Block\AboutLvivBlock. */ namespace Drupal\example_mod\Plugin\Block; use Drupal\Core\Block\BlockBase; /** * @Block( * id = "myblock", * admin_label = @Translation("MyBlock") * ) */ class MyBlock extends BlockBase { public function build() { return array( '#markup' => '<div class="myblock1"> <b><p>Creating a custom block defined by your module involves the following steps:</p></b> <li>Create a block plugin using annotations</li> <li>Extend the Drupal\Core\Block\BlockBase class.</li> <li>Implement the necessary methods from the Drupal\Core\Block\BlockPluginInterface interface depending on your use case</li> </div>', ); } }
So, to create a block, you need to:
- create a block plug-in using annotations;
- in the block class, make a single class extension Drupal\Core\Block\BlockBase;
- implement the necessary interface methods Drupal\Core\Block\BlockPluginInterface depending on your case;
Pay attention to lines 13-14. In them, you should specify the ID and the title of the block.
You can output a block programmatically in this way:
'markup', '#markup' => $block['#markup'], ); return $build; } }
Implementing the functionality of hook_init () on Drupal 8 with EventSubscriber
In Drupal 8, hook_init() is removed. If the module should perform pretty early changes, in response to a request you must use event handlers.
Here is a list Drupal 8 core events:
- KernelEvents::CONTROLLER - a controller event that only occurs once when the controller was found to handle the request;
- KernelEvents::EXCEPTION - an exception event that occurs when you have a uncaught exception;
- KernelEvents::FINISH_REQUEST - occurs when the response to the request has been generated;
- KernelEvents::REQUEST - an event that occurs at the beginning of your request sending;
- KernelEvents::RESPONSE - occurs when a response to the request has been created;
- KernelEvents::TERMINATE - termination event that occurs when the request has been sent;
- KernelEvents::VIEW - occurs when the value that is returned by the controller is not the response object.
Let's do a redirect from My page (/cust-page) to My page (/pagewithblock) to see how it all works.
First you need to create a file of services your_module.services.yml:
services: example_mod_subscriber: class: Drupal\example_mod\EventSubscriber\ExampleSubscriber tags: - { name: event_subscriber }
Then create a your_module/src/EventSubscriber/MyExampleSubscriber.php file which will handle the events.
The content of this file looks as follows:
getRequest()->getPathInfo() == '/cust-page') { $url = \Drupal::url('example_mod.mypage2'); $event->setResponse(new RedirectResponse($url)); } } /** * {@inheritdoc} */ static function getSubscribedEvents() { $events[KernelEvents::REQUEST][] = array('checkForRedirection'); return $events; } }
The getSubscribedEvents() method returns an array of names of events. The array keys are the names of the events, and values can be:
- a name of the method for callback (the default priority is 0));
- an array that consists of a method name for callback and a priority;
- an array of arrays with names of methods and their priorities, or priority = 0 if not set.
The checkForRedirection (GetResponseEvent $event) method is a method that is called according to the set event.
In line 16, check the address of the page to which we you going. With line 17, form the url of the page to which you want to make a redirect (example_mod.mypage2 is the name of the route of the page to which you make a redirect). In line 18, set a response to the event, in this case it’s an object of RedirectResponse class with a link as a parameter.
Adding files of scripts and css styles in Drupal 7 is easy to do through hook_init(). It looks like this:
function your_module_init() { drupal_add_js(drupal_get_path('module','module_name') . '/script.js'); drupal_add_css(drupal_get_path('module','module_name') . '/style.css'); }
In Drupal 8, adding scripts, styles, and libraries can be made with hook_page_attachments(). First you need to create a file describing libraries your_module/your_module.libraries.yml
my_lib: version: 1.x css: theme: css/example-style.css: {} my_lib: - library name version: 1.x - version css: - specify that you add css css/example-style.css: {} - the path to the necessary file
Then implement hook_page_attachments ():
function example_mod_page_attachments(array &$attachments) { $attachments['#attached']['library'][] = 'example_mod/my_lib'; }
As you can see, the library has been successfully added. You can also combine scripts and style files into a single library.
Example:
my_lib: version: 1.x css: theme: css/example-style.css: {} js: your_script.js: {}
More information can be found here.
Creating Forms in Drupal 8
To create forms in Drupal 7, hook_form() was used. It looked about like this:
function example_form($form, &$form_state) { $form['fieldset'] = array( '#type' => 'fieldset', '#title' => t('firstcolumn'), '#collapsible' => TRUE, '#collapsed' => FALSE, '#description' => t('Field description'), ); $form['fieldset']['field1'] = array( '#type' => 'textfield', '#title' => t('Field title'), '#size' => 40, '#maxlength' => 50, '#required' => TRUE, '#element_validate' => array('example_form_validate'), ); $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'), '#prefix' => '<div class="form-actions"> ', '#suffix' => '</div>', '#tree' => TRUE, ); return $form; }
In Drupal 8, forms are created in a different way. So let's see how to create a form in Drupal 8.
First you need to create a your_module/src/Form/MyExampleForm.php file, in which the form will actually be created.:
'email', '#required' => TRUE, ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), '#name' => 'form-submit', ); return $form; } /** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { //here the validation of the entered data is made } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { //actions when sending the form } }
In the getFormId() method, return a form identifier. For creating forms, the buildForm() is responsible, where its elements are actually created.The form validation should be implemented in the validateForm() method.
Next, add the following lines to your_module.routing.yml file:
example_mod.form: path: '/myform' defaults: _form: '\Drupal\example_mod\Form\MyExampleForm' _title: 'Example form' requirements: _permission: 'idevels example conf'
More information on creating forms in Drupal 8 can be found here and here.
hook_cron () in Drupal 8
I would also like to provide a simple example of hook_cron() work on Drupal 8. Let cron add the nid of this node in brackets to the title of all new nodes. I chose this example to kill two birds with one stone. First, we will see how cron works, and second, we will learn to receive and to change the values of the node fields.
Here’s how the hook implementation looks:
function example_mod_cron() { $nodes[] = node_load_multiple(); $expires = \Drupal::state()->get('example_mod.cron_last_run', REQUEST_TIME); foreach ($nodes[0] as $node) { $nid = $node->nid->value; $time = $node->created->value; $title = $node->title->value; if ($time > $expires) { $new_title = $title . '(' . $nid . ')'; $node->setTitle($new_title); $node->save(); } } \Drupal::state()->set('example_mod.cron_last_run', REQUEST_TIME); }
Let's see in more detail which line is responsible for which action. In line (2), we create an array in which, using node_load_multiple() function, we load all nodes. Using line (3), we get the value of the last cron running. In lines (5), (6), (7) we get the values of the required fields. With line (10) we set the necessary value of the node title, in line (11) we save the node using the save() method. And finally we set current time in the value of the last cron run. As you see, everything is very easy.
More information about hook_cron() in Drupal 8 is available here.
Using your own twig pattern with hook_theme()()
As is known, in Drupal 8, instead of Phptemplate templates, Twig templates are used. So let’s see how, using hook_theme(), to make Drupal use its own template. For example, let's replace the 'block__system_menu_block template with your own, let’s call it custom-menu-template.html.twig. Setting your own template looks like this:
function bartik_theme($existing, $type, $theme, $path) { return array( 'block__system_menu_block' => array( 'template' => 'custom-menu-template', ), ); }
By default, the option of debugging template files is disabled. To enable this feature, you need to set this in the sites/default/services.yml file:
twig.config: debug: true
To output variables, you can use the Devel module. Now you can display information about the variables using the dump() and kint() functions. kint() displays information in a fairly readable way for a programmer:
Our Drupal website development company hopes these Drupal 8 tips will make your coding easier and more fruitful. Good luck!
PS. Find examples of modules in the attached files.