Suggested Topics Flashcards
[Security] SQL : Example
db_query(“INSERT INTO {video_files} (fid, status, dimensions) VALUES (%d, %d, ‘%s’)”, $video[‘fid’], VIDEO_RENDERING_PENDING, $video[‘dimensions’]);
%d for integer values and %s for string values. You can also use %f for a floating point value, %b for binary data and %% just to insert a percent symbol
3 aspects of hook_initi()
Cached page doesn’t run this hook
When this hook is called, all modules are already loaded in memory
It happens after bootstrap mode
3 aspects of hook_boot()
Even cached page executes this hook
This hook is called before modules or most include files are loaded into memory.
It happens while Drupal is still in bootstrap mode.
[CSS] CSS selector precedence.
Precedence is evaluated according to these rules:
Inline CSS takes precedence over any other CSS (outdated form of styling, typically still used in email templating).
More specific selectors take precedence over less specific ones.
ID selectors take precedence over class selectors.
[jQuery] Drupal specific jQuery code sample what will execute only once for each page.
$('#some_element', context).once('mybehavior', function () { // Code here will only be applied to $('#some_element') // a single time. });
[Library] Including the jQuery library in a page.
Include the jQuery library in a page
Use a preprocess function to attach like
[‘#attached’][‘#library’][] = ‘mytheme/mylibraryname’;
[Git] Squashing multiple git commits into one commit while rebasing.
git rebase -i master
[Git] Committing all changes made inside a directory.
git add .
git commit -m “Commit message.”
[PHP] Abstract class.
PHP 5 introduces abstract classes and methods. Classes defined as abstract may not be instantiated, and any class that contains at least one abstract method must also be abstract. Methods defined as abstract simply declare the method’s signature - they cannot define the implementation.
abstract class AbstractClass {
class ConcreteClass1 extends AbstractClass {
class ConcreteClass2 extends AbstractClass {
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue(‘FOO_’) .”\n”;
$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue(‘FOO_’) .”\n”;
[Theming] hook_preprocess_hook()
Twig renders everything automatically so there is no need to call drupal_render() or theme() within a preprocess function. Instead, render arrays should be passed to the template since this allows for much more customization than an already-rendered HTML string.
// Drupal 8 - passing a render array to the template. $variables['table'] = [ '#theme' => 'table', '#header' => $header, '#rows' => $rows, ];
// Before, unnecessary call to drupal_render(). $variables['teaser'] = drupal_render($node_teaser);
// After, with drupal_render() removed. $variables['teaser'] = $node_teaser;
[Theming] Difference between hook_preprocess_html() and template_preprocess_page(&$variables)
mytheme_preprocess_page(&$vars) {
$vars[‘variable’] = ‘string’; // $variable will be available in page.tpl.php
}
mytheme_preprocess_html(&$vars) {
$vars[‘variable’] = ‘string’; // $variable will be available in html.tpl.php
}
mytheme_preprocess_custom_theme_function(&$vars) {
$vars[‘variable’] = ‘string’; // $variable will be available in the template you specified in mymodule_theme() (custom-theme-template.tpl.php)
}
[Theming] Theme template suggestion
You enable Twig Debugging in sites/default/services.yml.
parameters:
twig. config:
debug: true
[Coding standard] What goes between “namespace” and “use” statements
Empty line between “namespace” and “use” statements
[API] Custom code that is going to execute after node insert
use Drupal\node\Entity\Node; /** * Implements hook_ENTITY_TYPE_insert(). */ function mymodule_node_insert(Node $node) {
[API] Custom code that is going to execute after node delete
hook_ENTITY_TYPE_delete
[API] Watchdog logging
hook_watchdog() is gone. For a module to implement a logger, it has to register a service tagged as logger. eg services:
logger.mylog:
class: Drupal\mylog\Logger\MyLog
tags:
- { name: logger }
This class must implement \Psr\Log\LoggerInterface. like this:
namespace Drupal\mylog\Logger;
use Drupal\Core\Logger\RfcLoggerTrait;
use Psr\Log\LoggerInterface;
class MyLog implements LoggerInterface { use RfcLoggerTrait;
/** * {@inheritdoc} */ public function log($level, $message, array $context = array()) { // Do stuff }
}
D8 - procedural
// Logs a notice
\Drupal::logger(‘my_module’)->notice($message);
// Logs an error
\Drupal::logger(‘my_module’)->error($message);
[API] Block annotation
Creating a custom block defined by your module involves the following steps:
Create a block plugin using annotations
Extend the Drupal\Core\Block\BlockBase class.
Implement the methods from the Drupal\Core\Block\BlockPluginInterface interface needed for your use case.
namespace Drupal\fax\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/** * Provides a 'Fax' block. * * @Block( * id = "fax_block", * admin_label = @Translation("Fax block"), * ) */ class FaxBlock extends BlockBase { // Override BlockPluginInterface methods here. }
[API] Retrieving settings using the configuration API
Reading configuration
Configuration is read using the get() method. This can be used in several ways. To read a piece of configuration, just provide its key.
$config = \Drupal::config(‘system.maintenance’);
$message = $config->get(‘message’);
Calls to \Drupal::config() can also be chained.
$message = \Drupal::config(‘system.maintenance’)->get(‘message’);
To read nested configuration, separate the keys with the ‘.’ character.
$enabled = \Drupal::config(‘system.performance’)->get(‘cache.page.enabled’);
You can read configuration at any level, if there is configuration nested underneath your level, it will be returned as an array.
$page_cache = \Drupal::config(‘system.performance’)->get(‘cache.page’);
This would return an array with two keys - ‘enabled’ and ‘max_age’.
To return all the data in a config object, just call get() with no arguments.
Also, you can return all configuration keys available on the system or just those keys starting with a particular substring ($prefix).
$keys = \Drupal::service(‘config.factory’)->listAll($prefix = “”);
[Tests] Choosing the right base class
Drupal 8 comes with various automated testing options to choose from. Most of those are part of core testing framework.
- Unit tests
- Kernel tests
- Functional tests
It is also possible to use external framework like behat with scenarios in gherkin syntax. Read more about different types of testing in core here.
[Security] SQL injection
db_query(“INSERT INTO {video_files} (fid, status, dimensions) VALUES (%d, %d, ‘%s’)”, $video[‘fid’], VIDEO_RENDERING_PENDING, $video[‘dimensions’]);
[Caching] Cache context and cache tag (hard)
The service ID is standardized. It always begins with cache_context., followed by the parents of the cache context, finally followed by the name of the cache context. So, for example: cache_context (mandatory prefix) + route (parents) + book_navigation (this cache context’s name):
cache_context.route.book_navigation:
class: Drupal\book\Cache\BookNavigationCacheContext
arguments: [‘@request_stack’]
tags:
- { name: cache.context }
This defines the route.book_navigation cache context.
[Caching] Dynamic page caching
Drupal 8 provides the Dynamic Page Cache module that is recommended for websites of all sizes. It caches pages minus the personalized parts, and is therefore useful for all users (both anonymous & authenticated).
Disabling while developing
In example.settings.local.php, this section can be found:
/**
* Disable Dynamic Page Cache.
*
* Note: you should test with Dynamic Page Cache enabled, to ensure the correct
* cacheability metadata is present (and hence the expected behavior). However,
* in the early stages of development, you may want to disable it.
*/
# $settings[‘cache’][‘bins’][‘dynamic_page_cache’] = ‘cache.backend.null’;
Uncomment the commented-out line to disable the dynamic page cache. But please do pay attention to the comment!
[Views] Contextual parameters
Contextual Filters in Drupal 8 are similar to the Drupal 7 with advance feature and more dynamic compared to normal filter. A Contextual Filter provides more convenient way to fetch the data either from variables sent programmatically or URL.
Configuration update for an existing module
If your module is making a data model change related to configuration, then you need to properly update your data model. The four steps are:
Update your configuration schema YML file so that it reflects your new data model. This will make sure that people that install your module after you made the change will get the correct schema. See the Configuration Schema documentation for details on that. Make sure any configuration items provided by your module in the config/install and config/optional directories have been updated, so that people installing your module will get correct configuration. Write a hook_update_N() function. This will update configuration items for existing users of your module who already had it installed before you made the change so that they can continue to function. This is described below. Write tests to ensure the code in your hook_update_N() correctly modifies the configuration. This will make sure that people who have an older version of your module installed can successfully update to the new version. See https://www.drupal.org/docs/8/api/update-api/writing-automated-update-tests-for-drupal-8 for details.
/**
* Add fruit to the default configuration for example.module.
*/
function example_update_8001() {
$config_factory = \Drupal::configFactory();
$config = $config_factory->getEditable(‘example.configuration’);
$config->set(‘fruit’, [‘apple’, ‘banana’, ‘mango’]);
$config->save(TRUE);
}
Multilingual blocks and menus
To translate custom block/menu content try the follwing:
Install and enable your desired languages in Admin > Config > Regional and Language > Languages
Enable the content translation module
Go to Admin > Config > Regional and language > Content language and translation
Select under Custom language settings the option ‘Custom block’
Select all options in the newly added page section ‘Custom block’
Go to Structure > Block lay-out > Custom block library
Select in the column ‘operations’ the option ‘translate’
You should get a page ‘Translations of [block-name]’ with the currently enabled languages
Click add in the column ‘operations’ to create a translation of the block
for views:
1) Go to Structure > View (domain.com/admin/structure/views)
2) Select the view you want to create and instead of clicking edit, click the arrow for the the dropdown menu and click “translate”.
3) Add translations for each language.
4) When you are adding each language, make sure you add the menu item translation in the subsettings below view title: DISPLAYS > PAGE DISPLAY SETTINGS > PAGE DISPLAY OPTIONS.
5) Click SAVE TRANSLATION.
Setting up entity specific commenting
Commenting is a field
Structure of a *.info.yml file
name: Hello World Module
description: Creates a page showing “Hello World”.
package: Custom
type: module
core: 8.x
Structure of a *.routing.yml file (book example)
book.routing.yml
Each route is defined by a machine name, in the form of module_name.route_name.
#
book.render:
# The path always starts with a leading forward-slash.
path: ‘/book’
# Defines the default properties of a route.
defaults:
# For page callbacks that return a render array use _controller.
_controller: ‘\Drupal\book\Controller\BookController::bookRender’
# Require a permission to access this route.
requirements:
_permission: ‘access content’
book.export:
# This path takes dynamic arguments, which are enclosed in { }.
path: ‘/book/export/{type}/{node}’
defaults:
# Because this route does not return HTML, use _controller.
_controller: ‘\Drupal\book\Controller\BookController::bookExport’
requirements:
_permission: ‘access printer-friendly version’
# Ensure user has access to view the node passed in.
_entity_access: ‘node.view’
options:
# Enable the admin theme for this route.
_admin_route: TRUE
hook_theme()
Step #1: Define hook_theme in .module file Create a [module].module file if it doesn't already exist, and add code that defines each of your twig templates. The key of each item in the array is what you will need to call the template later. Do not use dashes in the file name.
function test_twig_theme($existing, $type, $theme, $path) {
return [
‘my_template’ => [
‘variables’ => [‘test_var’ => NULL],
],
];
}
Step #2: Call the Template In the place where you are returning your render array (whether from a controller method that is called from your router yml file, or wherever), make a call to your twig template. Below is an example from a testing module that is called from the routing yml file in the module. (need more info on this part)
/**
- @file
- Contains \Drupal\test_twig\Controller\TestTwigController.
- /
namespace Drupal\test_twig\Controller;
use Drupal\Core\Controller\ControllerBase;
class TestTwigController extends ControllerBase { public function content() {
return [ '#theme' => 'my_template', '#test_var' => $this->t('Test Value'), ];
}
}
Step #3: Create Twig Template
In your module, inside of the templates folder, create your twig template. The name of the file has to match what you put into hook_theme() (replace underscores with dashes). In this case, the file name would be my-template.html.twig.
Here is the file I used to test:
<p>Test twig template!</p>
<p>test_var: {{ test_var }}</p>
passing variables by reference
Sometimes it’s useful to pass arguments by reference, so that changes made by actions also apply to the arguments of the calling code later on. To make this possible, rules supports passing arguments to rules in a array.
So the example
The difference between dynamic queries and static queries
for static:
$select = db_query(‘SELECT field1, field2 FROM {table_one} t1 INNER JOIN {table_two} t2 ON t1.id = t2.id INNER JOIN {table_three} t3 ON t3.tbl_three_id = pcl.tbl_three_id’);
for dynamic:
$select = db_select(‘table_one’, ‘t1’);
$select->join(‘table_two’, ‘t2’, ‘t2.id = t1.id’);
$select->join(‘table_three’, ‘t3’, ‘t3.tbl_three_id = t2.tbl_three_id’);
$select = $select->fields(‘t1’, array(‘field1’, ‘field2’));
$select = $select->execute();
static queries
for static:
$select = db_query(‘SELECT field1, field2 FROM {table_one} t1 INNER JOIN {table_two} t2 ON t1.id = t2.id INNER JOIN {table_three} t3 ON t3.tbl_three_id = pcl.tbl_three_id’);
for dynamic:
Drupal Behaviours work
Behaviors:
Drupal’s official JavaScript documentation suggests that modules should implement JavaScript by attaching logic to Drupal.behaviors. Here is an example taken from that page:
Drupal.behaviors.exampleModule = { attach: function (context, settings) { $('.example', context).click(function () { $(this).next('ul').toggle('show'); }); } };
Drupal core will call attached behaviors when the DOM (the object representation of the HTML) is fully loaded, passing in two arguments:
context: which contains the DOM.
settings: which contains all the settings injected server side.
Search Index - View Modes
Content bundle option in the view modes
Multi-site folder structure
- sites
- site1
- modules
- custom
- contrib
- themes
- custom
- contrib
- files
- site1
t() method
Firstly, t() translates text at runtime if you have more than one language enabled. Depending on which placeholder you use, it runs different sanitization functions.
$good = t(‘Read about the t() function <a>here</a>’, array(‘@api’ => ‘https://api.drupal.org’));
$username . “‘s “ . t(‘Homepage.’);
t(‘Homepage de @user.’, array(‘@username’ => ‘Bob’));