{"componentChunkName":"component---src-templates-post-jsx","path":"/en/inbound-outbound-processing","result":{"data":{"markdownRemark":{"html":"<h1>Understanding Inbound and Outbound Processing in Drupal: Principles and Examples</h1>\n<h2>Introduction</h2>\n<p>In a Drupal site, when a user interacts with the system (for example, by accessing a URL, submitting a form, or consuming an API), Drupal processes the request through an entry and exit cycle — this is what we call <strong>Inbound</strong> and <strong>Outbound</strong> processing.</p>\n<p>These two mechanisms allow Drupal to:</p>\n<ul>\n<li>Interpret incoming data (inbound),</li>\n<li>Modify outgoing data (outbound),</li>\n<li>And centralize processing logic via services or hooks.</li>\n</ul>\n<p>Let us look at all of this in detail with concrete examples.</p>\n<h2>1. Inbound Processing: Handling What Comes In</h2>\n<p><strong>Inbound Processing</strong> applies to everything the user sends to the system:</p>\n<ul>\n<li>The requested URL,</li>\n<li>Query parameters (<code class=\"language-text\">GET</code>, <code class=\"language-text\">POST</code>),</li>\n<li>Data submitted in a form or API call.</li>\n</ul>\n<h3>Goal</h3>\n<ul>\n<li>Rewrite paths or parameters,</li>\n<li>Apply transformation or security logic,</li>\n<li>Decode values before they are used by the system.</li>\n</ul>\n<h3>Example: Modifying an Incoming URL</h3>\n<p>Imagine we want to redirect paths <code class=\"language-text\">/products</code> to <code class=\"language-text\">/product</code> while keeping Drupal's internal logic intact.</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token keyword\">use</span> <span class=\"token package\">Symfony<span class=\"token punctuation\">\\</span>Component<span class=\"token punctuation\">\\</span>HttpKernel<span class=\"token punctuation\">\\</span>Event<span class=\"token punctuation\">\\</span>RequestEvent</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">use</span> <span class=\"token package\">Symfony<span class=\"token punctuation\">\\</span>Component<span class=\"token punctuation\">\\</span>EventDispatcher<span class=\"token punctuation\">\\</span>EventSubscriberInterface</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">InboundPathSubscriber</span> <span class=\"token keyword\">implements</span> <span class=\"token class-name\">EventSubscriberInterface</span> <span class=\"token punctuation\">{</span>\n\n  <span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getSubscribedEvents</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">[</span><span class=\"token single-quoted-string string\">'kernel.request'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token punctuation\">[</span><span class=\"token single-quoted-string string\">'onKernelRequest'</span><span class=\"token punctuation\">,</span> <span class=\"token number\">30</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">public</span> <span class=\"token keyword\">function</span> <span class=\"token function\">onKernelRequest</span><span class=\"token punctuation\">(</span>RequestEvent <span class=\"token variable\">$event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token variable\">$request</span> <span class=\"token operator\">=</span> <span class=\"token variable\">$event</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">getRequest</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token variable\">$path</span> <span class=\"token operator\">=</span> <span class=\"token variable\">$request</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">getPathInfo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token variable\">$path</span> <span class=\"token operator\">===</span> <span class=\"token single-quoted-string string\">'/products'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token variable\">$request</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token property\">server</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">set</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'REQUEST_URI'</span><span class=\"token punctuation\">,</span> <span class=\"token single-quoted-string string\">'/product'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Here, we use the <code class=\"language-text\">kernel.request</code> event to intercept the URL before Drupal resolves the router.</p>\n<h2>2. Outbound Processing: Manipulating What Goes Out</h2>\n<p><strong>Outbound Processing</strong> occurs when Drupal generates a response (HTML, JSON, etc.). It is often used to:</p>\n<ul>\n<li>Modify generated links (<code class=\"language-text\">Url::fromRoute()</code>),</li>\n<li>Dynamically rewrite outgoing URLs,</li>\n<li>Add HTTP headers, or modify the JSON structure.</li>\n</ul>\n<h3>Example: Dynamic Link Rewriting</h3>\n<p>Suppose you want to transform all <code class=\"language-text\">/user/ID</code> links into <code class=\"language-text\">/profile/ID</code> during HTML rendering:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token keyword\">use</span> <span class=\"token package\">Drupal<span class=\"token punctuation\">\\</span>Core<span class=\"token punctuation\">\\</span>PathProcessor<span class=\"token punctuation\">\\</span>OutboundPathProcessorInterface</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">use</span> <span class=\"token package\">Symfony<span class=\"token punctuation\">\\</span>Component<span class=\"token punctuation\">\\</span>HttpFoundation<span class=\"token punctuation\">\\</span>Request</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">use</span> <span class=\"token package\">Drupal<span class=\"token punctuation\">\\</span>Core<span class=\"token punctuation\">\\</span>Render<span class=\"token punctuation\">\\</span>BubbleableMetadata</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">OutboundPathProcessor</span> <span class=\"token keyword\">implements</span> <span class=\"token class-name\">OutboundPathProcessorInterface</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">public</span> <span class=\"token keyword\">function</span> <span class=\"token function\">processOutbound</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$path</span><span class=\"token punctuation\">,</span> <span class=\"token operator\">&amp;</span><span class=\"token variable\">$options</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> Request <span class=\"token variable\">$request</span> <span class=\"token operator\">=</span> <span class=\"token constant\">NULL</span><span class=\"token punctuation\">,</span> BubbleableMetadata <span class=\"token variable\">$bubbleable_metadata</span> <span class=\"token operator\">=</span> <span class=\"token constant\">NULL</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token function\">strpos</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$path</span><span class=\"token punctuation\">,</span> <span class=\"token single-quoted-string string\">'/user/'</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">===</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> <span class=\"token function\">str_replace</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'/user/'</span><span class=\"token punctuation\">,</span> <span class=\"token single-quoted-string string\">'/profile/'</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$path</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">return</span> <span class=\"token variable\">$path</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Declaration in <code class=\"language-text\">services.yml</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">services</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">my_module.path_processor.outbound</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">class</span><span class=\"token punctuation\">:</span> Drupal\\my_module\\OutboundPathProcessor\n    <span class=\"token key atrule\">tags</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> <span class=\"token punctuation\">{</span> <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> path_processor_outbound<span class=\"token punctuation\">,</span> <span class=\"token key atrule\">priority</span><span class=\"token punctuation\">:</span> <span class=\"token number\">100 </span><span class=\"token punctuation\">}</span></code></pre></div>\n<h2>When to Use Inbound vs Outbound?</h2>\n<table>\n<thead>\n<tr>\n<th>Situation</th>\n<th>Inbound</th>\n<th>Outbound</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Modify the path before it is resolved</td>\n<td>Yes</td>\n<td>No</td>\n</tr>\n<tr>\n<td>Modify a link before displaying it</td>\n<td>No</td>\n<td>Yes</td>\n</tr>\n<tr>\n<td>Rewrite URL parameters</td>\n<td>Yes</td>\n<td>Yes</td>\n</tr>\n<tr>\n<td>Add HTTP headers</td>\n<td>No</td>\n<td>Yes</td>\n</tr>\n<tr>\n<td>Handle conditional redirection</td>\n<td>Yes</td>\n<td>No</td>\n</tr>\n</tbody>\n</table>\n<h2>Combined Use: A Typical Multilingual Site Scenario</h2>\n<ul>\n<li>Inbound: intercept the URL <code class=\"language-text\">/fr/products</code> to route to <code class=\"language-text\">/en/product</code>.</li>\n<li>Outbound: generate properly translated links in menus (<code class=\"language-text\">/fr/products</code>, <code class=\"language-text\">/en/product</code>...).</li>\n</ul>\n<p><code class=\"language-text\">PathProcessorManager</code> orchestrates these operations in Drupal Core.</p>\n<h2>Debugging &#x26; Best Practices</h2>\n<ul>\n<li>Use <code class=\"language-text\">\\Drupal::logger()</code> to trace processed paths.</li>\n<li>Prioritize your Symfony event subscriptions (execution order is critical).</li>\n<li>Enable route caching in production but disable it during development.</li>\n</ul>\n<h2>Conclusion</h2>\n<p>The <strong>Inbound</strong> and <strong>Outbound</strong> systems in Drupal are powerful tools for controlling the flow of HTTP data. Whether you are building a multilingual site, a headless site, or simply want to customize your site's paths, these hooks give you fine-grained control over data entry and exit — without modifying Drupal core.</p>","excerpt":"Understanding Inbound and Outbound Processing in Drupal: Principles and Examples Introduction In a Drupal site, when a user interacts with the system (for…","frontmatter":{"date":"2025-05-12","metaDate":"2025-05-12","title":"Inbound & Outbound Processing","tags":["Drupal","Core feature","HTTP requests","Module development"],"path":"/inbound-outbound-processing","cover":{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAgABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDAf/EABgBAQADAQAAAAAAAAAAAAAAAAEAAgME/9oADAMBAAIQAxAAAAGFUXry00TZ3QspQJ//xAAaEAACAwEBAAAAAAAAAAAAAAAAAQIREhBB/9oACAEBAAEFAkaHJElzNjKtynz3KP/EABURAQEAAAAAAAAAAAAAAAAAABEg/9oACAEDAQE/ASP/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAcEAABAwUAAAAAAAAAAAAAAAAQAAERISIxUaH/2gAIAQEABj8CMMtPCkXcVBkf/8QAHhAAAgMAAgMBAAAAAAAAAAAAAREAITFBYVGRodH/2gAIAQEAAT8hZ1G5HqMYYAI+u4QAQArFeYCEJsem3oXE0h+okjAUT5gFqV1Oz5P/2gAMAwEAAgADAAAAEG/1AP/EABcRAQEBAQAAAAAAAAAAAAAAAAEAESH/2gAIAQMBAT8QOLsOFpf/xAAWEQEBAQAAAAAAAAAAAAAAAAABACH/2gAIAQIBAT8QUsmRv//EAB0QAQEBAAICAwAAAAAAAAAAAAERACExQVFxgZH/2gAIAQEAAT8Q7n40muBl+L9zGsUp+B1hiI64eHDhoAAxxgAFphZEYThEesxg+Bc8cBL3zdxtVcdtQKKHpv/Z","aspectRatio":0.625081788440567,"src":"/static/1d4893aa934642fb4398940d90f06b8a/88110/inbound-outbound.jpg","srcSet":"/static/1d4893aa934642fb4398940d90f06b8a/0b320/inbound-outbound.jpg 480w,\n/static/1d4893aa934642fb4398940d90f06b8a/60b32/inbound-outbound.jpg 960w,\n/static/1d4893aa934642fb4398940d90f06b8a/88110/inbound-outbound.jpg 1920w,\n/static/1d4893aa934642fb4398940d90f06b8a/522de/inbound-outbound.jpg 2866w","srcWebp":"/static/1d4893aa934642fb4398940d90f06b8a/d1a9d/inbound-outbound.webp","srcSetWebp":"/static/1d4893aa934642fb4398940d90f06b8a/bc3bf/inbound-outbound.webp 480w,\n/static/1d4893aa934642fb4398940d90f06b8a/39337/inbound-outbound.webp 960w,\n/static/1d4893aa934642fb4398940d90f06b8a/d1a9d/inbound-outbound.webp 1920w,\n/static/1d4893aa934642fb4398940d90f06b8a/f0a30/inbound-outbound.webp 2866w","sizes":"(max-width: 1920px) 100vw, 1920px"},"resize":{"src":"/static/1d4893aa934642fb4398940d90f06b8a/c4f3a/inbound-outbound.jpg"}}}}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"pathSlug":"/inbound-outbound-processing","locale":"en","prev":{"fields":{"locale":"en"},"frontmatter":{"path":"/drupal-architectures","title":"Monolithic, Decoupled, and Progressively Decoupled Drupal: Which Architecture to Choose?","tags":["Drupal 10","Drupal 11","Architecture","Conception","Strategy"]}},"next":{"fields":{"locale":"en"},"frontmatter":{"path":"/drupal-cms","title":"Drupal CMS 1.0 (Starshot): A New Era for Website Creation","tags":["Drupal 11","News","Drupal CMS","UX"]}}}}}