Skip to content

Commit 1870964

Browse files
marvil07paul-m
marvil07
authored andcommitted
Issue #1889842 by Mile23, eojthebrave, jlbellido, Lal_, damontgomery, marvil07: Port render_example to D8
1 parent d3216d1 commit 1870964

19 files changed

+1486
-0
lines changed

composer.json

+3
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,8 @@
88
"documentation": "https://api.drupal.org/api/examples",
99
"source": "http://cgit.drupalcode.org/examples"
1010
},
11+
"suggest": {
12+
"drupal/devel": "Some modules will be able to pretty-print PHP with this module."
13+
},
1114
"license": "GPL-2.0+"
1215
}

examples.module

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ function examples_toolbar() {
5858
'pager_example' => 'pager_example.page',
5959
'phpunit_example' => 'phpunit_example_description',
6060
'plugin_type_example' => 'plugin_type_example.description',
61+
'render_example' => 'render_example.description',
6162
'session_example' => 'session_example.form',
6263
'simpletest_example' => 'simpletest_example_description',
6364
'tabledrag_example' => 'tabledrag_example.description',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
show_block: false
2+
show_page: false
3+
note_about_render_arrays: false
4+
move_breadcrumbs: false
5+
reverse_sidebar: false
6+
wrap_blocks: false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
render_example.settings:
2+
type: config_object
3+
label: 'Render Example Settings'
4+
mapping:
5+
show_block:
6+
type: boolean
7+
show_page:
8+
type: boolean
9+
note_about_render_arrays:
10+
type: boolean
11+
move_breadcrumbs:
12+
type: boolean
13+
reverse_sidebar:
14+
type: boolean
15+
wrap_blocks:
16+
type: boolean

render_example/css/render_example.css

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.render_example--array {
2+
border-bottom: 2px solid #000;
3+
margin-top: 10px;
4+
padding-left: 5px;
5+
padding-top: 5px;
6+
}
7+
8+
.render_example--code {
9+
background: #f1f1f1;
10+
border: 1px solid #000;
11+
display: block;
12+
max-height: 300px;
13+
overflow: scroll;
14+
padding: 10px;
15+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: Render example
2+
type: module
3+
description: Provides examples demonstrating Drupal's Render API.
4+
package: Example modules
5+
core: 8.x
6+
dependencies:
7+
- drupal:block
8+
- drupal:node
9+
- drupal:user
10+
- examples:examples
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Define a new asset library which includes the CSS used to style the page
2+
# at examples/render_example/arrays. See how asset libraries are attached to
3+
# render arrays by reading the example code in
4+
# Drupal\render_example\Controller\RenderExampleController::arrays().
5+
render-example.library:
6+
version: 1.x
7+
css:
8+
theme:
9+
css/render_example.css: {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
render_example.description:
2+
title: Render Example
3+
description: Examples of building and altering render arrays.
4+
route_name: render_example.description
5+
expanded: TRUE
6+
7+
render_example.arrays:
8+
title: Building Render Arrays
9+
description: Building render arrays in controllers.
10+
route_name: render_example.arrays
11+
parent: render_example.description
12+
weight: -9
13+
14+
render_example.altering:
15+
title: Altering Render Arrays
16+
description: Using hooks and callbacks to alter render arrays.
17+
route_name: render_example.altering
18+
parent: render_example.description
19+
weight: -8

render_example/render_example.module

+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
<?php
2+
3+
/**
4+
* @file
5+
* Demonstrates using Drupal's Render API.
6+
*/
7+
8+
/**
9+
* @defgroup render_example Example: Render API
10+
* @ingroup examples
11+
* @{
12+
* The @link https://www.drupal.org/docs/8/api/render-api Render API @endlink
13+
* consists of two parts: one, structured arrays that provide data, and hints
14+
* about how that data should be rendered, and two, a rendering pipeline that
15+
* can be used to render these arrays into various output formats. This example
16+
* module looks at how to define content using render arrays, as well as how to
17+
* use alter hooks to manipulate render arrays created by other modules.
18+
*
19+
* For more on the rendering pipeline see @link
20+
* https://www.drupal.org/docs/8/api/render-api/the-drupal-8-render-pipeline The
21+
* Drupal 8 Render Pipeline @endlink.
22+
*
23+
* In order to ensure that a theme can completely customize the markup output
24+
* by Drupal, module developers should avoid directly writing HTML markup for
25+
* pages, blocks, and other user-visible output in their modules, and should
26+
* instead return structured "render arrays". Checkout the example code in
27+
* \Drupal\render_example\Controller\RenderExampleController::arrays() for an
28+
* explanation of how to define new renderable arrays. The output from that
29+
* code can be viewed at examples/render_example/arrays.
30+
*
31+
* One of the primary benefits of using arrays to define content instead of
32+
* strings of HTML is that arrays are easier to manipulate. There are dozens of
33+
* hooks, and other ways to gain access to and manipulate existing render arrays
34+
* during the rendering process both from within a module, and via a theme. As
35+
* a rule of thumb the process of rendering an array into HTML is delayed for as
36+
* long as possible. In most cases it's not until the variable containing the
37+
* content to be rendered is printed out in a Twig template file that it is
38+
* finally rendered.
39+
*
40+
* For examples of altering render arrays checkout the code in
41+
* render_example_preprocess_page() and render_example_preprocess_block(). There
42+
* is a form at examples/render_example/altering that can be used to turn these
43+
* features on and off if you would like to see the results of the array
44+
* altering code on your site.
45+
*
46+
* This module contains code that can display the render array used to build
47+
* each page, and/or block, as you navigate through a site as a way to show some
48+
* examples of real render arrays being used. This functionality requires that
49+
* the @link https://www.drupal.org/project/devel Devel module @endlink be
50+
* installed in order to work.
51+
*
52+
* Modules can also provide new render element types. A powerful way to
53+
* encapsulate complex display logic into a reusable widget. This can help to
54+
* cut down on code repetition, and allow other module developers to build off
55+
* of your work. See an example of a new render element definition by looking at
56+
* \Drupal\render_example\Element\Marquee.
57+
*
58+
* Forms are generated using a superset of the Render API. You can see examples
59+
* of how the Render API is used when creating forms in the fapi_example module.
60+
*
61+
* @see theme_render
62+
* @see \Drupal\Core\Render\RendererInterface::render()
63+
* @see \Drupal\Core\Template\TwigExtension::renderVar()
64+
*/
65+
66+
use Drupal\Core\Render\Element;
67+
68+
/**
69+
* Implements hook_theme().
70+
*/
71+
function render_example_theme() {
72+
return [
73+
// These theme hooks are both used by examples in
74+
// \Drupal\render_example\Controller\RenderExampleController::arrays().
75+
'render_example_add_div' => ['render element' => 'element'],
76+
'render_array' => ['render element' => 'element'],
77+
// This is used in combination with \Drupal\render_example\Element\Marquee
78+
// to define a new custom render element type that allows for the use of
79+
// '#type' => 'marquee' elements in a render array.
80+
'render_example_marquee' => [
81+
'variables' => [
82+
'content' => '',
83+
'attributes' => [],
84+
],
85+
],
86+
];
87+
}
88+
89+
/**
90+
* Example '#post_render' callback function.
91+
*
92+
* Post render callbacks are triggered after an element has been rendered to
93+
* HTML and can act upon the final rendered string.
94+
*
95+
* This function is made use of by one of the examples in
96+
* Drupal\render_example\Controller\RenderExampleController::arrays().
97+
*
98+
* @param string $markup
99+
* The rendered element.
100+
* @param array $element
101+
* The element which was rendered (for reference)
102+
*
103+
* @return string
104+
* Markup altered as necessary. In this case we add a little postscript to it.
105+
*
106+
* @see \Drupal\render_example\Controller\RenderExampleController::arrays()
107+
*/
108+
function render_example_add_prefix($markup, array $element) {
109+
$markup = $markup . '<div style="color:blue">This markup was added after rendering by a #post_render callback.</div>';
110+
return $markup;
111+
}
112+
113+
/**
114+
* Example '#pre_render' function.
115+
*
116+
* Pre render callbacks are triggered prior to rendering an element to HTML and
117+
* are given the chance to manipulate the renderable array. Any changes they
118+
* make will be reflected in the final rendered HTML.
119+
*
120+
* This function is made use of by one of the examples in
121+
* Drupal\render_example\Controller\RenderExampleController::arrays().
122+
*
123+
* @param array $element
124+
* The element which will be rendered.
125+
*
126+
* @return array
127+
* The altered element. In this case we add a #prefix to it.
128+
*
129+
* @see \Drupal\render_example\Controller\RenderExampleController::arrays()
130+
*/
131+
function render_example_add_suffix(array $element) {
132+
$element['#suffix'] = '<div style="color:red">' . t('This #suffix was added by a #pre_render callback.') . '</div>';
133+
return $element;
134+
}
135+
136+
/**
137+
* Implements hook_preprocess_page().
138+
*
139+
* Demonstrates using a preprocess function to alter the renderable array that
140+
* represents the page currently being viewed.
141+
*/
142+
function render_example_preprocess_page(&$variables) {
143+
// Only modify the 'altering' page.
144+
if (\Drupal::routeMatch()->getRouteName() != 'render_example.altering') {
145+
return;
146+
}
147+
148+
$config = \Drupal::config('render_example.settings');
149+
150+
// Preprocess hooks are invoked by the theme layer, and are used to give
151+
// modules a chance to manipulate the variables that are going to be made
152+
// available to a specific template file. Since content is still defined as
153+
// renderable arrays at this point you can do quite a bit to manipulate the
154+
// eventual output by altering these arrays.
155+
//
156+
// The $page variable in this case contains the complete content of the page
157+
// including all regions, and the blocks placed within each region.
158+
//
159+
// The actual process of converting a renderable array to HTML is started when
160+
// this variable is printed out within a Twig template. Drupal's Twig
161+
// extension provides a wrapper around the Twig code that prints out variables
162+
// which checks to see if the variable being printed is a renderable array and
163+
// passes it through \Drupal\Core\Render\RendererInterface::render() before
164+
// printing it to the screen.
165+
$page = &$variables['page'];
166+
167+
// Move the breadcrumbs into the content area.
168+
if ($config->get('move_breadcrumbs') && !empty($page['breadcrumb']) && !empty($page['content'])) {
169+
$page['content']['breadcrumb'] = $page['breadcrumb'];
170+
unset($page['breadcrumb']);
171+
$page['content']['breadcrumb']['#weight'] = -99999;
172+
173+
// Force the content to be re-sorted.
174+
$page['content']['#sorted'] = FALSE;
175+
}
176+
177+
// Re-sort the contents of the sidebar in reverse order.
178+
if ($config->get('reverse_sidebar') && !empty($page['sidebar_first'])) {
179+
$page['sidebar_first'] = array_reverse($page['sidebar_first']);
180+
foreach (Element::children($page['sidebar_first']) as $element) {
181+
// Reverse the weights if they exist.
182+
if (!empty($page['sidebar_first'][$element]['#weight'])) {
183+
$page['sidebar_first'][$element]['#weight'] *= -1;
184+
}
185+
}
186+
// This forces the sidebar to be re-sorted.
187+
$page['sidebar_first']['#sorted'] = FALSE;
188+
}
189+
190+
// Show the render array used to build the current page.
191+
// This relies on the Devel module's variable dumper service.
192+
// https://wwww.drupal.org/project/devel
193+
if (Drupal::moduleHandler()->moduleExists('devel') && $config->get('show_page')) {
194+
$page['content']['page_render_array'] = [
195+
'#type' => 'markup',
196+
'#prefix' => '<h2>' . t('The page render array') . '</h2>',
197+
// The devel.dumper service is provided by the devel module and makes for
198+
// and easier to read var_dump(). Especially if the companion Kint module
199+
// is enabled.
200+
'dump' => \Drupal::service('devel.dumper')->exportAsRenderable($page, '$page'),
201+
'#weight' => -99999,
202+
];
203+
204+
$page['content']['#sorted'] = FALSE;
205+
}
206+
}
207+
208+
/**
209+
* Implements hook_preprocess_block().
210+
*/
211+
function render_example_preprocess_block(&$variables) {
212+
// Only modify the 'altering' page.
213+
if (\Drupal::routeMatch()->getRouteName() != 'render_example.altering') {
214+
return;
215+
}
216+
217+
$config = \Drupal::config('render_example.settings');
218+
219+
// This example shows how you can manipulate an existing renderable array. In
220+
// this case by adding #prefix and #suffix properties to the block in order to
221+
// wrap a <div> around it.
222+
if ($config->get('wrap_blocks')) {
223+
$variables['content']['#prefix'] = '<div class="block-prefix"><p>' . t('Prefixed') . '</p>';
224+
$variables['content']['#suffix'] = '<span class="block-suffix">' . t('Block suffix') . '</span></div>';
225+
}
226+
227+
// Show the render array used to build each block if the Devel module is
228+
// installed and the feature is enabled.
229+
if (Drupal::moduleHandler()->moduleExists('devel') && $config->get('show_block')) {
230+
$variables['content']['block_render_array'] = [
231+
'#type' => 'markup',
232+
'#prefix' => '<h2>' . t('The block render array for @block_id.', ['@block_id' => $variables['plugin_id']]) . '</h2>',
233+
'dump' => \Drupal::service('devel.dumper')->exportAsRenderable($variables, $variables['plugin_id']),
234+
];
235+
}
236+
}
237+
238+
/**
239+
* @} End of "defgroup render_example".
240+
*/
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
render_example.description:
2+
path: '/examples/render-example'
3+
defaults:
4+
_controller: '\Drupal\render_example\Controller\RenderExampleController::description'
5+
requirements:
6+
_permission: 'access content'
7+
8+
render_example.altering:
9+
path: '/examples/render-example/altering'
10+
defaults:
11+
_form: '\Drupal\render_example\Form\RenderExampleDemoForm'
12+
_title: 'Alter pages and blocks'
13+
requirements:
14+
_permission: 'access content'
15+
16+
render_example.arrays:
17+
path: '/examples/render-example/arrays'
18+
defaults:
19+
_controller: '\Drupal\render_example\Controller\RenderExampleController::arrays'
20+
requirements:
21+
_permission: 'access content'

0 commit comments

Comments
 (0)