<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="https://uname.pingveno.net/blog/index.php/feed/rss2/xslt" ?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title># uname -a - Mot-clé - drupal 8</title>
    <link>https://uname.pingveno.net/blog/index.php/</link>
    <atom:link href="https://uname.pingveno.net/blog/index.php/feed/tag/drupal%208/rss2" rel="self" type="application/rss+xml" />
    <description>Le blog de uname.pingveno.net</description>
    <language>fr</language>
    <pubDate>Wed, 01 Apr 2026 16:19:15 +0200</pubDate>
    <copyright>Mathieu Pellegrin</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>Dotclear</generator>
          <item>
        <title>Drupal 8 / 9 / 10 : Programmatically render a view with contextual and exposed filters input</title>
        <link>https://uname.pingveno.net/blog/index.php/post/2024/03/10/Drupal-8-/-9-/-10-%3A-The-right-way-to-programatically-render-a-view-while-setting-exposed-and-contextual-filters-input</link>
        <guid isPermaLink="false">urn:md5:28fceab459140a8a74e0ec4b7befc8fc</guid>
        <pubDate>Sun, 10 Mar 2024 19:45:00 +0100</pubDate>
        <dc:creator>Mathieu</dc:creator>
                  <category>Informatique</category>
                          <category>drupal</category>
                  <category>drupal 10</category>
                  <category>drupal 8</category>
                  <category>drupal 9</category>
                  <category>php</category>
                <description>&lt;p&gt;&lt;strong&gt;Exposed Input&lt;/strong&gt; and &lt;strong&gt;Contextual Input&lt;/strong&gt; are two different ways of providing input to Drupal Views.&lt;/p&gt;

&lt;p&gt;Contextual filters work with an ordered list of parameters, while Exposed Input works with a form that has a couple name/value for every input parameter.&lt;/p&gt;          &lt;h2&gt;Contextual Filters&lt;/h2&gt;

&lt;p&gt;The right way to render a view result with &lt;strong&gt;contextual filters&lt;/strong&gt; is to generate a render array:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
$render_array = [
  '#type' =&amp;gt; 'view',
  '#name' =&amp;gt; 'YOUR_VIEW_NAME',
  '#display_id' =&amp;gt; 'YOUR_VIEW_DISPLAY',
  '#arguments' =&amp;gt; [CONTEXTUAL_FILTER_1, CONTEXTUAL_FILTER_2, ...],
];&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can then send the render array to a Twig variable, or render it programatically:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
$result = \Drupal::service('renderer')-&amp;gt;render($render_array);
return $result-&amp;gt;__toString();&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are using the &lt;code&gt;__toString()&lt;/code&gt; function to get the rendered HTML because the result returned by Drupal Render service is an object containing cache metadata.&lt;/p&gt;

&lt;h2&gt;Exposed Filters&lt;/h2&gt;

&lt;p&gt;The right way to render a view result with &lt;strong&gt;exposed filters&lt;/strong&gt; is to generate a render array, and set the &lt;code&gt;'#view#'&lt;/code&gt; parameter with a view object where you can initialize the filters:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
$view = \Drupal\views\Views::getView('YOUR_VIEW_NAME');
$view-&amp;gt;setExposedInput([
    'YOUR_FILTER_NAME' =&amp;gt; 'YOUR_FILTER_VALUE',
]);
$render_array = [
  '#type' =&amp;gt; 'view',
  '#name' =&amp;gt; 'YOUR_VIEW_NAME',
  '#view' =&amp;gt; $view,
  '#display_id' =&amp;gt; 'YOUR_VIEW_DISPLAY',
  '#arguments' =&amp;gt; [CONTEXTUAL_FILTER_1, CONTEXTUAL_FILTER_2, ...],
];&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can then send the render array to a Twig variable, or render it programatically:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
$result = \Drupal::service('renderer')-&amp;gt;render($render_array);
return $result-&amp;gt;__toString();&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are using the &lt;code&gt;__toString()&lt;/code&gt; function to get the rendered HTML because the result returned by Drupal Render service is an object containing cache metadata.&lt;/p&gt;

&lt;h2&gt;Leaked Metadata and Early Rendering&lt;/h2&gt;

&lt;p&gt;If you render a view while rendering a controller output that is suppose&amp;nbsp; to provide its own cache metadata (&lt;code&gt;CacheableJsonResponse&lt;/code&gt; for instance), and run on the error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
LogicException: The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early.&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just wrap the rendering in a render context:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
$context = new Drupal\Core\Render\RenderContext\RenderContext();
$html = \Drupal::service('renderer')-&amp;gt;executeInRenderContext($context, function () {
  $render_array = [
    '#type' =&amp;gt; 'view',
    '#name' =&amp;gt; 'YOUR_VIEW_NAME',
    '#display_id' =&amp;gt; 'YOUR_VIEW_DISPLAY',
    '#arguments' =&amp;gt; [CONTEXTUAL_FILTER_1, CONTEXTUAL_FILTER_2, ...],
  ];
  $result = \Drupal::service('renderer')-&amp;gt;render($render_array);
  return $result-&amp;gt;__toString();
});
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Sources&lt;/h2&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;https://drupal.stackexchange.com/a/295496&quot;&gt;https://drupal.stackexchange.com/a/295496&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://www.drupal.org/docs/drupal-apis/render-api/render-arrays&quot;&gt;https://www.drupal.org/docs/drupal-apis/render-api/render-arrays&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://api.drupal.org/api/drupal/10/search/setExposedInput&quot;&gt;https://api.drupal.org/api/drupal/10/search/setExposedInput&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://www.lullabot.com/articles/early-rendering-a-lesson-in-debugging-drupal-8&quot;&gt;https://www.lullabot.com/articles/early-rendering-a-lesson-in-debugging-drupal-8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
        
              </item>
          <item>
        <title>Drupal 8 : create a custom Rule Action</title>
        <link>https://uname.pingveno.net/blog/index.php/post/2016/07/27/Drupal-8-%3A-create-a-custom-Rule-action</link>
        <guid isPermaLink="false">urn:md5:4028da17989c185a5f86e2d3f8a25968</guid>
        <pubDate>Wed, 27 Jul 2016 10:56:00 +0200</pubDate>
        <dc:creator>Mathieu</dc:creator>
                  <category>Hacks</category>
                          <category>action</category>
                  <category>drupal</category>
                  <category>drupal 8</category>
                  <category>module</category>
                  <category>php</category>
                  <category>rules</category>
                <description>          &lt;p&gt;Warning : the Rule plugin for Drupal 8 was not considered stable when I wrote this post.&lt;/p&gt;

&lt;h3&gt;1. Drupal 8: the new modules paradigm&lt;/h3&gt;

&lt;p&gt;Drupal 8 modules structure changed, and many modules are now using the new API.&lt;/p&gt;

&lt;p&gt;No more plain old functions name like hook_something, no more obscurous PHP for menu entries. Instead, Object Oriented programming, YAML configuration files, magic comments, and Symfony routing.&lt;/p&gt;

&lt;p&gt;Let's give it a try, let's make our first simplest module.&lt;/p&gt;

&lt;h3&gt;2. Base module configuration&lt;/h3&gt;

&lt;p&gt;If you already know how to do this, jumb to next section.&lt;/p&gt;

&lt;p&gt;Create a directory for your module, for instance &lt;strong&gt;mymodule&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Create an info file in YAML format : &lt;strong&gt;mymodule/mymodule.info.yaml&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;
name: 'My Module'
type: module
core: 8.x
package: Custom&lt;/pre&gt;

&lt;p&gt;You don't need more! You don't need routing as you will plug into Rules.&lt;/p&gt;

&lt;h3&gt;3. File names and Namespaces&lt;/h3&gt;

&lt;p&gt;Create the &lt;strong&gt;RulesAction&lt;/strong&gt; directory and its parents: &lt;strong&gt;mymodule/src/Plugin/RulesAction/&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a PHP file for your class: &lt;strong&gt;MyAction.php&lt;/strong&gt;. The class will be loaded with the autoload system.&lt;/p&gt;

&lt;p&gt;Edit the file you just created, and specify the namespace at the beginning of the file:&lt;/p&gt;

&lt;pre&gt;
/**
 * @file
 * Contains \Drupal\mymodule\Plugin\RulesAction\MyAction.
 */
namespace Drupal\mymodule\Plugin\RulesAction;
use Drupal\rules\Core\RulesActionBase;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;The namespace must correspond to your module name and class name!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;4. Rule Action specifications and parameters&lt;/h3&gt;

&lt;p&gt;Comments are very important as they are also specifications. You will define your Action id, description, and parameters. For instance, here is a copied sample from the predefined action DataSet:&lt;/p&gt;

&lt;pre&gt;
/**
 * Provides a 'My action' action.
 *
 * @RulesAction(
 *   id = &quot;rules_myaction&quot;,
 *   label = @Translation(&quot;Set a data value&quot;),
 *   category = @Translation(&quot;Data&quot;),
 *   context = {
 *     &quot;data&quot; = @ContextDefinition(&quot;any&quot;,
 *       label = @Translation(&quot;Data&quot;),
 *       description = @Translation(&quot;Specifies the data to be modified using a data selector, e.g. 'node:author:name'.&quot;),
 *       allow_null = TRUE,
 *       assignment_restriction = &quot;selector&quot;
 *     ),
 *     &quot;value&quot; = @ContextDefinition(&quot;any&quot;,
 *       label = @Translation(&quot;Value&quot;),
 *       description = @Translation(&quot;The new value to set for the specified data.&quot;),
 *       default_value = NULL,
 *       required = FALSE
 *     )
 *   }
 * )
 */
&lt;/pre&gt;

&lt;p&gt;The Rule id is &lt;strong&gt;rules_myaction&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The category of the action in the dropdown menu is &lt;strong&gt;Data&lt;/strong&gt; and it will be labeled &lt;strong&gt;Set a data value&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The current action will have two parameters : the data that will be changed, and the corresponding value.&lt;/p&gt;

&lt;h3&gt;5. Rule Action callback&lt;/h3&gt;

&lt;p&gt;Again, no more plain callback, the function &lt;strong&gt;doExecute&lt;/strong&gt; will be called to execute your Action:&lt;/p&gt;

&lt;pre&gt;
class MyAction extends RulesActionBase {

  /**
   * Executes the Plugin.
   *
   * @param mixed $data
   *   Original value of an element which is being updated.
   * @param mixed $value
   *   A new value which is being set to an element identified by data selector.
   */
  protected function doExecute($data, $value) {
    $typed_data = $this-&amp;gt;getContext('data')-&amp;gt;getContextData();
    $typed_data-&amp;gt;setValue($value);
  }

  /**
   * {@inheritdoc}
   */
  public function autoSaveContext() {
    // Saving is done at the root of the typed data tree, for example on the
    // entity level.
    $typed_data = $this-&amp;gt;getContext('data')-&amp;gt;getContextData();
    $root = $typed_data-&amp;gt;getRoot();
    $value = $root-&amp;gt;getValue();
    // Only save things that are objects and have a save() method.
    if (is_object($value) &amp;amp;&amp;amp; method_exists($value, 'save')) {
      return ['data'];
    }
    return [];
  }

}&lt;/pre&gt;

&lt;p&gt;The class name has to correspond to your file name.&lt;/p&gt;

&lt;p&gt;In this sample, the parameter &lt;strong&gt;$value&lt;/strong&gt; will be set to &lt;strong&gt;$data&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;6. Troubleshooting&lt;/h3&gt;

&lt;pre&gt;
Uncaught PHP Exception Drupal\\Component\\Plugin\\Exception\\PluginException: &quot;Plugin (rules_myaction) instance class &quot;Drupal\\tbh_system\\Plugin\\RulesAction\\MyAction&quot; does not exist.&quot;&lt;/pre&gt;

&lt;p&gt;Your namespace/classname/filename/directoryname is probably wrong.&lt;/p&gt;

&lt;h3&gt;Source&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://fago.gitbooks.io/rules-docs/content/extending_rules/rules_action_plugins.html&quot; hreflang=&quot;en&quot;&gt;Drupal 8 Rules Action documentation&lt;/a&gt;&lt;/p&gt;</description>
        
              </item>
      </channel>
</rss>
