<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kevin Wenger</title>
    <description>The latest articles on DEV Community by Kevin Wenger (@wengerk).</description>
    <link>https://dev.to/wengerk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F224779%2Fb4b2d867-0caa-4de1-a207-1fc13205a23d.png</url>
      <title>DEV Community: Kevin Wenger</title>
      <link>https://dev.to/wengerk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wengerk"/>
    <language>en</language>
    <item>
      <title>Drupal 8 — Differences between Configuration API &amp; State API</title>
      <dc:creator>Kevin Wenger</dc:creator>
      <pubDate>Fri, 26 Jun 2020 07:02:59 +0000</pubDate>
      <link>https://dev.to/wengerk/drupal-8-differences-between-configuration-api-state-api-4g31</link>
      <guid>https://dev.to/wengerk/drupal-8-differences-between-configuration-api-state-api-4g31</guid>
      <description>&lt;p&gt;Before getting into the main subject, be aware that this article has been first write for the Blog of Antistatique — Web Agency in Lausanne, Switzerland. A place where I work as Full Stack Web Developer.&lt;/p&gt;

&lt;p&gt;Feel free to read it here or check it out there: &lt;a href="https://antistatique.net/en/we/blog/2016/06/14/drupal-8-differences-between-configuration-api-state-api" rel="noopener noreferrer"&gt;https://antistatique.net/en/we/blog/2016/06/14/drupal-8-differences-between-configuration-api-state-api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Retrieve all the code on my Gist: &lt;a href="https://gist.github.com/Sudei/822510d2a069331a4bbe84ef55570705" rel="noopener noreferrer"&gt;https://gist.github.com/Sudei/822510d2a069331a4bbe84ef55570705&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy reading.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;The other day, I faced a serious problem. On importing the configuration on my production environment. all the configurations files saved for my module were overridden by the configuration on my development environments.&lt;/p&gt;

&lt;p&gt;What I did was very simple to understand:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The customer change his configuration on the website, such as API Key of Campaign Monitor,&lt;/li&gt;
&lt;li&gt;I create a new feature, push it on production and I use the drush cex command to export all the configuration on development env,&lt;/li&gt;
&lt;li&gt;I use the drush cim command to import the configuration on my production env,&lt;/li&gt;
&lt;li&gt;The web site contain now the configuration of my development environments because every configuration is exported/imported on the Configuration API.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A solution could be to use the same configuration on the production &amp;amp; development environments.&lt;br&gt;
But it’s not possible in our case, we should sync the local database with the production one — it’s against productivity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AwHrziizU2h3kH93KuVh1rw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AwHrziizU2h3kH93KuVh1rw.png" alt="I took the problem upside."&gt;&lt;/a&gt;&lt;/p&gt;
I took the problem upside.



&lt;p&gt;On my old days with Drupal 7 I used to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;variable_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content_types&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and port this to Drupal 8 using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;\Drupal&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;content_types&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s fine and it works but later when I run a drush config-import &lt;code&gt;drush cim&lt;/code&gt; on my production server, it erase (reset) the specific configuration of my production server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration&lt;/strong&gt; is a place to &lt;strong&gt;store information&lt;/strong&gt; that you want to &lt;strong&gt;synchronize from development to production&lt;/strong&gt;. This information is often created during site building and is not typically generated by regular users during normal site operation.&lt;/p&gt;

&lt;p&gt;You should use the &lt;strong&gt;State API&lt;/strong&gt;, not Configuration API, for storing local variables that shouldn’t travel between instances.&lt;/p&gt;



&lt;h2&gt;
  
  
  Typical usage of State API
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Get a value:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$val = \Drupal::state()-&amp;gt;get('key');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Get multiple key/value pairs:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$pairs = \Drupal::state()-&amp;gt;getMultiple($keys);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Set a value:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\Drupal::state()-&amp;gt;set('key','value');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Set multiple values:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\Drupal::state()-&amp;gt;setMultiple($keyvalues);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Delete a value:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\Drupal::state()-&amp;gt;delete('key');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Typical usage of Configuration API
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Retrieve configuration as readonly:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$config = \Drupal::config('mymodule.foo');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Get a value:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$val = $config-&amp;gt;get('key');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The configuration object that was obtained and used in the previous examples does not allow you to change configuration. If you want to change configuration, you will instead need to get the configuration object by making a call to getEditable() on the configuration factory:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$config =\Drupal::service('config.factory')-&amp;gt;getEditable('mymodule.foo');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Set a value:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$config-&amp;gt;set('enabled', 1);
// Save the configuration
$config-&amp;gt;save();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Delete a value:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$config-&amp;gt;clear('bar.boo')-&amp;gt;save();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;The State API provides a place for developers to store information about the system's state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;State information differs from configuration in the following ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is specific to an individual environment.&lt;/li&gt;
&lt;li&gt;You will never deploy to deploy it between environments.&lt;/li&gt;
&lt;li&gt;You can reset a system, losing all state. Its configuration remains.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We try out a lot of other solution wihtout success:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using the flags &lt;code&gt;--skip-module&lt;/code&gt; or &lt;code&gt;--partial&lt;/code&gt;  of &lt;code&gt;drush cim&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Hooking the Event like &lt;code&gt;ConfigEvents::DELETE&lt;/code&gt; and the &lt;code&gt;$event-&amp;gt;stopPropagation();&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Currently it is the most elegant solution we found to solve our problem.&lt;br&gt;
However, opinions differ greatly within the community about this use case of State API.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And you what do you think ?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AcX7VeRhC09Pd6RYdKirH2Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AcX7VeRhC09Pd6RYdKirH2Q.png" alt="What is next ?"&gt;&lt;/a&gt;&lt;/p&gt;
What is next ?






&lt;br&gt;&lt;br&gt;
More information about:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/variable_set/7.x" rel="noopener noreferrer"&gt;Drupal 7 - Variable Set&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/variable_get/7.x" rel="noopener noreferrer"&gt;Drupal 7 - Variable get&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/developing/api/8/state" rel="noopener noreferrer"&gt;Drupal 8 - Sate API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/developing/api/8/state" rel="noopener noreferrer"&gt;Drupal 8 - Configuration API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>drupal</category>
    </item>
    <item>
      <title>How to create a custom Autocomplete using the Drupal 8 Form API</title>
      <dc:creator>Kevin Wenger</dc:creator>
      <pubDate>Fri, 26 Jun 2020 07:02:49 +0000</pubDate>
      <link>https://dev.to/wengerk/how-to-create-a-custom-autocomplete-using-the-drupal-8-form-api-3b1j</link>
      <guid>https://dev.to/wengerk/how-to-create-a-custom-autocomplete-using-the-drupal-8-form-api-3b1j</guid>
      <description>&lt;p&gt;In this article, I will &lt;strong&gt;not explain&lt;/strong&gt; how to &lt;strong&gt;customise/alter an Autocomplete Field Widget&lt;/strong&gt; - which should only be used on from using the Drupal Admin UI.&lt;/p&gt;

&lt;p&gt;Here I will try to expose you a &lt;strong&gt;step by step&lt;/strong&gt; guide which explains how you can create a custom Autocomplete field &lt;strong&gt;using the Drupal 8 Form API Core feature&lt;/strong&gt; - An autocomplete that you could use in your own Drupal frontend applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o_m6NTG5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6dzuhaq1q7d4v3wa6f2q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o_m6NTG5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6dzuhaq1q7d4v3wa6f2q.gif" alt="Example of custom Autocomplete using the Drupal 8 Form API"&gt;&lt;/a&gt;&lt;/p&gt;
This is what you will be able to achieve at the end of this story



&lt;p&gt;If you are looking for resources which explains how to implement Views to alter an Autocomplete Field, please &lt;a href="https://www.drupal.org/docs/7/modules/entity-reference/using-a-view-to-display-the-elements-in-the-autocomplete-widget"&gt;refer to this excellent guide&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Truth can only be found in one place: the code &lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1- The autocomplete form element
&lt;/h2&gt;

&lt;p&gt;The other day, I was asked to create a custom Autocomplete for a project which uses a custom Form build using the Drupal 8 Form API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pCwC3LX6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/v8daaxjja6dcs51kf3dd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pCwC3LX6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/v8daaxjja6dcs51kf3dd.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first sight, you may be interested to use the &lt;code&gt;#entity_autocomplete&lt;/code&gt; field type - it seems exactly what you need.&lt;br&gt;
Unfortunately, this is not. Indeed, the &lt;code&gt;#entity_autocomplete&lt;/code&gt; doesn't allow you any customisation.&lt;/p&gt;

&lt;p&gt;So, you will need the old folk's &lt;code&gt;#textfield&lt;/code&gt; and his cousin attribute &lt;code&gt;#autocomplete_route_name&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;#autocomplete_route_name&lt;/code&gt; attribute will allow you to define a route to handle the autocomplete business logic (data you will return given the user input).&lt;/p&gt;

&lt;p&gt;You also may add the &lt;code&gt;#autocomplete_route_parameters&lt;/code&gt; attribute, this one gives you the possibility to send a fixed unalterable parameter to your &lt;code&gt;#autocomplete_route_name&lt;/code&gt;, you may use it to fix the number of results to return.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Define autocomplete route
&lt;/h2&gt;

&lt;p&gt;Now you know how to create the autocomplete form, but you will need a route to manage the logic which will fetch data &amp;amp; return them.&lt;br&gt;
How? By simply adding the reference to the route — where data will get retrieved from — to your &lt;em&gt;my_module.routing.yml&lt;/em&gt; file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Be careful to use the same route name (here &lt;code&gt;my_module.autocomplete.articles&lt;/code&gt;) in your previous &lt;code&gt;#autocomplete_route_name&lt;/code&gt;.&lt;br&gt;
Also, be sure to change permission according to your own needs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3 - Add Controller and return JSON response
&lt;/h2&gt;

&lt;p&gt;Now having a routing &amp;amp; a form, you have to define your custom controller, with the &lt;code&gt;handleAutocomplete&lt;/code&gt; method.&lt;br&gt;
Well, it's precisely this method that makes sure that the proper data gets collected and properly formatted once requested by Drupal.&lt;/p&gt;

&lt;p&gt;Let's dig deeper and see how we can precisely deal with specific JSON response for our &lt;code&gt;textfield&lt;/code&gt; element.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setup an &lt;em&gt;ArticleAutoCompleteController&lt;/em&gt; class file under &lt;em&gt;my_module/src/Controller/ArticleAutoCompleteController.php&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;Then, extend the &lt;code&gt;ControllerBase&lt;/code&gt; class and setup your handle method (in our case &lt;code&gt;::handleAutocomplete&lt;/code&gt; see &lt;code&gt;my_module.routing.yml&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That's &lt;strong&gt;pretty much all the hocus-pocus that you need&lt;/strong&gt; to have an autocomplete based on a textfield of Drupal 8.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NBR0lCzi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1s3sdbuvt0bio5oz0dfb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NBR0lCzi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1s3sdbuvt0bio5oz0dfb.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;For the most curious of you, here are some sources of additional information that inspired the creation of this article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purushotam Rai&lt;/strong&gt; (24 November, 2016). Implementing #autocomplete in Drupal 8 with Custom Callbacks&lt;br&gt;
See on &lt;a href="https://www.qed42.com/blog/autocomplete-drupal-8"&gt;https://www.qed42.com/blog/autocom...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stijn Berkers&lt;/strong&gt; (28 February, 2018). How to produce a custom auto-complete field in drupal 8&lt;br&gt;
See on &lt;a href="https://www.lucius.digital/en/blog/drupal-module-conditional-redirect-released-on-drupal-org"&gt;https://lucius.digital/en/blog/drupal...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make-me-alive&lt;/strong&gt; (4 May, 2014). Adding autocomplete for text-field&lt;br&gt;
See on &lt;a href="https://drupal.stackexchange.com/questions/200038/adding-autocomplete-for-text-field"&gt;https://drupal.stackexchange.com/.../..&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stijn Berkers&lt;/strong&gt; (18 July, 2018). How to add autocomplete to text fields in drupal 8: defining a custom route&lt;br&gt;
See on &lt;a href="https://www.optasy.com/blog/how-add-autocomplete-text-fields-drupal-8-defining-custom-route"&gt;https://www.optasy.com/blog/how-add-autocom...&lt;/a&gt;&lt;/p&gt;

</description>
      <category>drupal</category>
      <category>api</category>
      <category>form</category>
    </item>
    <item>
      <title>Drupal 8 — How to translate the Config API</title>
      <dc:creator>Kevin Wenger</dc:creator>
      <pubDate>Fri, 26 Jun 2020 07:02:39 +0000</pubDate>
      <link>https://dev.to/wengerk/drupal-8-how-to-translate-the-config-api-3obc</link>
      <guid>https://dev.to/wengerk/drupal-8-how-to-translate-the-config-api-3obc</guid>
      <description>&lt;p&gt;Before getting into the main subject, be aware that this article has been first write for the Blog of Antistatique — Web Agency in Lausanne, Switzerland. A place where I work as Full Stack Web Developer.&lt;/p&gt;

&lt;p&gt;Feel free to read it here or check it out there: &lt;a href="https://antistatique.net/en/we/blog/2018/05/01/drupal-8-how-to-translate-the-config-api"&gt;https://antistatique.net/en/we/blog/2018/05/01/drupal-8-how-to-translate-the-config-api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Retrieve all the code on Gist: &lt;a href="https://gist.github.com/WengerK/5c7f3df9aa5c27a95cd8a29b72b28a19"&gt;https://gist.github.com/WengerK/5c7f3df9aa5c27a95cd8a29b72b28a19&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy reading.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;As you probably already know, I live in Switzerland and - beside chocolate &amp;amp; cheese - this country has one another singularity: 4 official national languages. As result, more than 90% of our web creations need to be &lt;strong&gt;localized in at least 2 languages&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
This peculiarity makes us &lt;strong&gt;experts in the creation of multilingual websites&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When creating applications using Drupal 8, there are many cases when the &lt;strong&gt;configuration forms containing data have to be managed by the client&lt;/strong&gt;. The most concrete case is - for example - all the links of the social networks must be different according to the language.&lt;/p&gt;

&lt;p&gt;I will explain here the whole process to enable configuration translation with a &lt;code&gt;ConfigFormBase&lt;/code&gt; form.&lt;br&gt;
I will go through the creation of the structure and the schema generation as well as the activation of the translation system.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Every solution to every problem is simple. It's the distance between the two where the mystery lies. &lt;br&gt;&lt;br&gt;
— Derek Landy, Skulduggery Pleasant&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you do not know the Drupal 8 Config API system yet, check it out &lt;a href="https://antistatique.net/en/we/blog/2016/06/14/drupal-8-differences-between-configuration-api-state-api"&gt;Drupal 8 - Differences between Configuration API &amp;amp; State API&lt;/a&gt;. You may also find more help directly on the &lt;a href="https://www.drupal.org/docs/8/api/configuration-api"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

This article is for experienced Drupal 8 developers.
&lt;h2&gt;
  
  
  Assets
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Give me matter and I will build a world out of it. &lt;br&gt;&lt;br&gt;
— Immanuel Kant&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before explaining how it all works, you can download all the sample files below.&lt;/p&gt;

&lt;p&gt;This article example is testable via the &lt;a href="https://antistatique.net/sites/default/files/my_module.zip"&gt;downloadable test module here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To help you understand this article, &lt;strong&gt;2 translatable configuration forms&lt;/strong&gt; will be created in our example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first one is a simple form demonstrating the translation system of several types of fields:

&lt;ul&gt;
&lt;li&gt;Text - &lt;em&gt;translatable&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Select - &lt;em&gt;untranslatable&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Checkbox - &lt;em&gt;untranslatable&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Checkboxes - &lt;em&gt;untranslatable&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Radios - &lt;em&gt;untranslatable&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Textarea - &lt;em&gt;translatable&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;CKeditor - &lt;em&gt;translatable&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;ol&gt;
&lt;li&gt;The second is a complex form, demonstrating the translation system via mapping and structure in sequence:

&lt;ul&gt;
&lt;li&gt;Nested fields with multiple children - &lt;em&gt;translatable&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Entity reference field - &lt;em&gt;untranslatable&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Textarea with preprocess in sequence (then stored as array) - &lt;em&gt;translatable&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;As you can notice, several fields are "untranslatable". It's not a deliberate choice, but the Core Drupal requires this, and that's normal! Fields that are not translatable are fields called "key" -&amp;gt; "value". It is therefore normal to be unable to translate keys since they &lt;strong&gt;have their own Business Logic&lt;/strong&gt;. As for the values, they are translatable via the &lt;a href="https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21StringTranslation%21StringTranslationTrait.php/trait/StringTranslationTrait"&gt;standard translation function exposed by the Core&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup default values
&lt;/h2&gt;

&lt;p&gt;We have 2 files because we have 2 different configurations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SettingsForm&lt;/strong&gt; -&amp;gt; &lt;code&gt;my_module.settings.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SettingsAdvancedForm&lt;/strong&gt; -&amp;gt; &lt;code&gt;my_module.settings_advanced.yml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These structure files are always found in the &lt;code&gt;config/install&lt;/code&gt; folder of the module.&lt;br&gt;
They correspond to the &lt;strong&gt;initialization of the configuration&lt;/strong&gt;, ie the default values. These files are not mandatory by default in Drupal 8, but are required once we want to make our configuration translatable.&lt;/p&gt;

&lt;p&gt;These files must be named in a very specific way, depending on the name of the corresponding configuration. You can find this name &lt;strong&gt;in the array of the &lt;code&gt;getEditableConfigNames&lt;/code&gt;&lt;/strong&gt; method of your configuration forms.&lt;/p&gt;

&lt;p&gt;Let's see what the definition of the structure of our 2 forms looks like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SettingsForm&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;SettingsAdvancedForm&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Did you notice &lt;strong&gt;both content files correspond to what we save in database&lt;/strong&gt;?! All the fields saved in the database must be there.&lt;br&gt;
In addition, the structure of your configuration is also represented in this file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SettingsForm&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;title: ''                # simple text field
select: ''               # select field
checkbox: FALSE          # boolean checkbox
checkboxes: { }          # array of checkboxes
radios: ''               # the value selected from radios
message: ''              # content of textarea
ckeditor:
  value: ''              # ckeditor content
  format: 'basic_html'   # ckeditor format
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;SettingsAdvancedForm&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;site:                   # array containing our data
  title: ''             # simple text field (nested)
  content:
    value: ''           # ckeditor content
    format: basic_html  # ckeditor format
mails: { }              # Values, formated as array, transformed from the textarea
entity_reference: ''    # entity reference field
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Setup the schema
&lt;/h2&gt;



&lt;p&gt;The schema is &lt;strong&gt;a single file&lt;/strong&gt;, regardless of how many configurations your module depends on.&lt;br&gt;
This file contains the tree structure corresponding to the previous step, but this time we don't add the default value to each key, but its type and a label.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yJEb1Qpm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hy5e9qm5mcbzq5wdokpx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yJEb1Qpm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hy5e9qm5mcbzq5wdokpx.png" alt="Cheatsheet formats and types usable in a Drupal schema.yml 8."&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
Cheatsheet formats and types usable in a Drupal schema.yml 8.



&lt;p&gt;Thanks to the schema configuration, we can declare which key is translatable and which is its Label in the interface of translation for the configuration!&lt;/p&gt;

&lt;p&gt;Are you wondering why we need to provide a complete schema when we do not use all the keys for translation? Well &lt;strong&gt;the schema is not used only for translations&lt;/strong&gt; !&lt;br&gt;
For example, when you edit a configuration, the forms will use the schema to "type-cast" the data, which ensures that a field defined as a boolean in your schema is a boolean and not a string when it's manipulated.&lt;br&gt;
In addition, this file is used for the &lt;strong&gt;automatic generation of the translation form&lt;/strong&gt;, hence the need to add a Label to each key.&lt;/p&gt;

&lt;p&gt;The schema must be created directly in the &lt;code&gt;config/schema&lt;/code&gt; folder and must be named following the module name:&lt;code&gt;my_module.schema.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is what the schema file of our 2 forms looks like:&lt;/p&gt;

&lt;p&gt;In short, the schema system, just like the structure file, is &lt;strong&gt;optional&lt;/strong&gt; as long as you do not need to translate your configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Activate the translation
&lt;/h2&gt;

&lt;p&gt;Once you have created your structure file and schema file, you just have to declare to the translation system which forms expose the translations.&lt;/p&gt;

&lt;p&gt;You just need to create the &lt;code&gt;my_module.config_translation.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;This file contains &lt;strong&gt;all the configuration exposed by the translation form&lt;/strong&gt;.&lt;br&gt;
Each form must define a title, the path to access the form and finally all the configuration keys that it exposes.&lt;/p&gt;

&lt;p&gt;You can now access the forms from the menu:&lt;br&gt;
Configuration &amp;gt; Regional and language &amp;gt; Configuration translation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a translation tab
&lt;/h2&gt;

&lt;p&gt;Now that your form is translatable, it is sometimes disconcerting to access it throught the "Configuration translation" page, hidden behind 3 levels of links. It would be much more convenient to access this page from a &lt;strong&gt;"Local task"&lt;/strong&gt;, exactly like the other pages and settings that Core Drupal 8 offers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e256VYa1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6107gnkhzbcf1v0jt8q8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e256VYa1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6107gnkhzbcf1v0jt8q8.png" alt="Local task - Basic Site Translation"&gt;&lt;/a&gt;&lt;/p&gt;
Local task - Basic Site Translation 



&lt;p&gt;By default, the translation system will generate a "Local task" - or a tab - for the translations of your form, but you may not see it, because to see this action you need to have at least 1 "Local task". I admit it's a little far-fetched, but here's a workaround.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new "Local task" in your module using the &lt;code&gt;my_module.links.task.yml&lt;/code&gt; file at the root of your module.&lt;/li&gt;
&lt;li&gt;Add an entry for each configuration form exposing translations.&lt;/li&gt;
&lt;/ol&gt;



&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;For the most curious, here are some sources of additional information that inspired the creation of this article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gábor Hojtsy&lt;/strong&gt; (29 october 2015). Configuration translation development.&lt;br&gt;
Retrieved from &lt;a href="http://hojtsy.hu/blog/2014-may-26/drupal-8-multilingual-tidbits-16-configuration-translation-development"&gt;hojtsy.hu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alex Tkachev&lt;/strong&gt; (16 décembre 2014). Drupal 8 configuration management.&lt;br&gt;
Retrieved from &lt;a href="https://www.amazeelabs.com/en/blog/drupal8-configuration-management-part1"&gt;amazeelabs.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>drupal</category>
      <category>i18n</category>
    </item>
    <item>
      <title>Refactoring — an ode to code</title>
      <dc:creator>Kevin Wenger</dc:creator>
      <pubDate>Wed, 24 Jun 2020 13:51:53 +0000</pubDate>
      <link>https://dev.to/wengerk/refactoring-an-ode-to-code-184d</link>
      <guid>https://dev.to/wengerk/refactoring-an-ode-to-code-184d</guid>
      <description>&lt;p&gt;What is refactoring? Should you redo your whole project? How can you proceed?&lt;/p&gt;

&lt;p&gt;This article will give you an &lt;strong&gt;overall&lt;/strong&gt; explanation of &lt;strong&gt;refactoring&lt;/strong&gt; in software development.&lt;br&gt;
We will &lt;strong&gt;explore&lt;/strong&gt; the theory and then &lt;strong&gt;present&lt;/strong&gt; some examples from real life.&lt;br&gt;
But, as I always say, no explanation is complete without clarifying the benefits and challenges first.&lt;/p&gt;

&lt;p&gt;Let's get to it, shall we?&lt;/p&gt;
&lt;h2&gt;
  
  
  What is it?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jpCPhvXX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1y1go7psnllgme531ftx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jpCPhvXX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1y1go7psnllgme531ftx.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Refactoring refers to independent techniques and steps to improve code that has already been written.&lt;/p&gt;

&lt;p&gt;To make it short, refactoring is the &lt;strong&gt;art of increasing the maintainability of a piece of code&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies. &lt;br&gt; —  C.A.R. Hoare&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But don't get me wrong, having to refactor your own codebase is not bad. It doesn't make you a poor-skilled developer.&lt;br&gt;
Actually, during your career you will always be refactoring code (yours or others).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Technical debt is a complete part of the development process&lt;/strong&gt;, as nicely stated &lt;a href="https://antistatique.net/fr/nous/bloggons/2015/05/22/la-dette-technique"&gt;in this article from Marc Friederich &amp;amp; Gilles Doge&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;On a standard 101-key keyboard, there are 100 keys that increase technical debt, and only one key that reduces it. &lt;br&gt; — Josh Wulf&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;During a refactoring process, you might be doing a lot of changes, adding new Classes, renaming, reorganising. But remember, &lt;strong&gt;at the end of your journey you won't ever be altering the observable behaviour of the code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;First, refactoring is &lt;strong&gt;not debugging&lt;/strong&gt;. Your code needs to be running in the first place.&lt;br&gt;
Of course, during a refactoring process you may find bugs. The moment that you start dealing with them, you've stopped refactoring and started bug fixing, which is another mindset.&lt;/p&gt;

&lt;p&gt;Second, refactoring is &lt;strong&gt;not about performance&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;I was speaking with a young developer the other day who was trying to convince me that refactoring a codebase makes it obviously faster. &lt;/p&gt;

&lt;p&gt;It is a very common misconception that bad code automatically leads to performance leaks. The performance of your code is not the goal of a refactoring process - nor even what you should expect out of it.&lt;/p&gt;

&lt;p&gt;Finally, refactoring is &lt;strong&gt;not adding features&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;When you are refactoring a part of your code, you should not change its behaviour, otherwise you are no longer refactoring.&lt;/p&gt;
&lt;h2&gt;
  
  
  Should you do it?
&lt;/h2&gt;

&lt;p&gt;People who have been using your app will have no idea something changed behind the scenes.&lt;/p&gt;

&lt;p&gt;You did not fix bugs, you did not make it faster, you did not add any new feature.&lt;/p&gt;

&lt;p&gt;So, you may ask me "why should I refactor then?".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If an application that was written for a long time and remained then untouched is working as expected, if there's no conflict with any other system, if no features need to be added in the future,&lt;br&gt;
then it can be the ugliest code in the world: it doesn't need to be refactored.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, the answer is quite simple. &lt;strong&gt;Well-structured code will make it so much easier to add new features and new capabilities in the future&lt;/strong&gt;. And, it will make it easier to start analysing performance or overall improving the application. &lt;/p&gt;

&lt;p&gt;By improving the code quality, you will also improve the overall team efficiency, certainly save a fair amount of money and make your developers happy to work on that codebase - or at least I hope so.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's called technical debt, because it's like taking out a loan. You can accomplish more today than you normally could, but you end up paying a higher cost later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you face tedious difficulty getting approval on spending time for refactoring - because the benefits aren't immediately apparent - remember that &lt;strong&gt;you're not refactoring for your end-user, you're refactoring to get the future roadblocks out of your way&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  How do we do it ?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;For non-developer people, this part may be more tricky. &lt;br&gt;Fly, you fools !&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bored of reading theory? Alright - me too - let's dig into some real-life examples.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TbQ0MvLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/57f035l07dxnccca40ok.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TbQ0MvLS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/57f035l07dxnccca40ok.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. &lt;br&gt; — Martin Golding&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is no such thing as a set of rules or a specific order that anyone can just follow, but there is a set of techniques to help you refactor code. Here I will drop some of my favourites and easy ones to try to use in every project.&lt;/p&gt;

&lt;p&gt;One more thing, if I could give you one piece of advice, and share insight on one thing it would be this one simple sentence: "&lt;strong&gt;Never refactor a production code that does not have unit tests&lt;/strong&gt;". &lt;/p&gt;

&lt;p&gt;The main reason is maybe pretty obvious, but let me say it out loud again:  without unit tests, you will end up with broken functionalities that are nearly impossible to fix because you won't be able to figure out what's happening anymore.&lt;/p&gt;

&lt;p&gt;So please, if you have to refactor something, first make sure it is covered by tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gg8QVtjB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tkqtj33ud55b1vmvsv9x.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gg8QVtjB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tkqtj33ud55b1vmvsv9x.jpg" alt="Where are the tests?"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Conditional Guard Clauses (return early)
&lt;/h4&gt;

&lt;p&gt;To keep readability in functions and methods, it's wise to return early if simple conditions apply that can be checked at the beginning of a method. Then, when it's hard to determine the normal flow of code execution, try to isolate checks.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;It's &lt;strong&gt;better to return early, keeping indentation and brain power needed to follow the code low&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Isolate all special checks and edge cases into separate clauses and place them before the main checks. Ideally, you should have a flat list of conditionals, one after the other.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Assignments to Parameters
&lt;/h4&gt;

&lt;p&gt;Sometimes, you will need to alter a given parameter value inside your own method body.&lt;br&gt;
If this parameter is passed via reference, then after the parameter value is changed inside the method, this value is passed to the argument that called this method.&lt;br&gt;
Very often, this occurs accidentally and leads to unfortunate effects. Even if parameters are usually passed by value (and not by reference), this coding quirk may be weird to those who are unaccustomed to it.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Use a local variable instead of altering the parameter.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Replace Array with Object
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Arrays&lt;/code&gt; are an excellent tool for storing data and collections of a single type.&lt;br&gt;
But if you use an array like post office boxes, storing the username in box 1 and the user's address in box 14, you will someday be very unhappy that you did that way.&lt;/p&gt;

&lt;p&gt;You have an array that contains various types of data.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Replace the array with an object that will have separate keys for each element.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Plus, using &lt;code&gt;Object&lt;/code&gt; over &lt;code&gt;Array&lt;/code&gt;, you will be able to apply properties assertions, I would suggest everybody to take a look at the &lt;a href="https://www.php.net/manual/en/class.arrayaccess.php"&gt;&lt;code&gt;ArrayAccess&lt;/code&gt; implementations&lt;/a&gt; which is great to replace object-like &lt;code&gt;Array&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Replace Magic Number with Symbolic Constant
&lt;/h4&gt;

&lt;p&gt;Magic numbers or magic values are encountered in the source code but have no obvious meaning.&lt;br&gt;
This "anti-pattern" makes it harder to understand the program and thus refactor the code.&lt;/p&gt;

&lt;p&gt;Often, a simple Find &amp;amp; Replace won't work on those values, as the same data may be used for different purposes in different places, meaning that you will have to verify each line that uses this value.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Replace this number with a constant that has a human-readable name explaining the meaning of the number.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Consolidate Conditional Expression
&lt;/h4&gt;

&lt;p&gt;When your code contains a lot of alternating operators that perform identical actions, it is not clear why the operators are split up.&lt;/p&gt;

&lt;p&gt;The main purpose of consolidation is to extract the conditionals to separate methods for more clarity.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Consolidate all these conditionals in a single expression.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Use the language capabilities
&lt;/h4&gt;

&lt;p&gt;Often, developers forget some awesome capabilities of the programming language they use.&lt;br&gt;
Many of these features can save you a lot of effort. Take a look at the next examples and notice how it can be easy to achieve the same result by using the type &lt;code&gt;hinting&lt;/code&gt; methodology.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Could be changed to a simpler method with the same capabilities&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Inline Temp
&lt;/h4&gt;

&lt;p&gt;Prevent usage of temporary variable when necessary. For example, when you have a temporary variable that is assigned the result of a simple expression and nothing more.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Replace the references to the variable with the expression itself.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  What else ?
&lt;/h4&gt;

&lt;p&gt;I would like to end with a few more quick tips on better coding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a new array form &lt;code&gt;[ ]&lt;/code&gt; instead of the old &lt;code&gt;array()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;===&lt;/code&gt; operator instead of &lt;code&gt;==&lt;/code&gt; unless it is important to not check for the &lt;code&gt;dataType&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use prefix &lt;code&gt;is/has&lt;/code&gt; with functions that return boolean ex: &lt;code&gt;isAdmin($user)&lt;/code&gt;, &lt;code&gt;hasPermission($permission, $user)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Organise class methods with public methods at the top&lt;/li&gt;
&lt;li&gt;Always apply the single responsibility concept to your classes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wzN3zhyO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m0kh8jgu7tis1qjowmwy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wzN3zhyO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m0kh8jgu7tis1qjowmwy.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;For the most curious of you, here are some sources of additional information that inspired the creation of this article.&lt;/p&gt;

&lt;p&gt;Sourcemaking (23 August, 2019). Refactoring &lt;br&gt;
See on &lt;a href="https://sourcemaking.com/refactoring"&gt;https://sourcemaking.com/refactoring&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Refactoring Guru (23 August, 2019). Refactoring Guru &lt;br&gt;
See on &lt;a href="https://refactoring.guru/refactoring"&gt;https://refactoring.guru/refactoring&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mohamed Aladdin (19 August, 2018). Refactor Your PHP legacy Code (real projects examples) &lt;br&gt;
See on &lt;a href="https://medium.com/hackernoon/refactor-your-php-legacy-code-real-projects-examples-da9edf03ff4b"&gt;https://medium.com/hackernoon/refactor-your-php...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Josh Wulf (15 April, 2018). There is no good coding, only good refactoring &lt;br&gt;
See on &lt;a href="https://medium.com/@sitapati/there-is-no-good-coding-only-good-refactoring-487f322b5987"&gt;https://medium.com/@sitapati/there-is-no-good-...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fionna Chan (11 October, 2018). Code Refactoring — How to Write Better Code &lt;br&gt;
See on &lt;a href="https://medium.com/@fionnachan/code-refactoring-how-to-write-better-code-d1aeab549597"&gt;https://medium.com/@fionnachan/code-ref...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thomas Deniffel (20 April, 2019). Brutal Refactoring)&lt;br&gt;
See on &lt;a href="https://medium.com/@tdeniffel/brutal-refactoring-31b5cc4d4512"&gt;https://medium.com/@tdeniffel/brutal-refactorin...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Samuel Roze (21 August, 2018). Refactoring the right way: regional, not global&lt;br&gt;
See on &lt;a href="https://medium.com/@sroze/refactoring-the-right-way-regional-not-global-692643b1947e"&gt;https://medium.com/@sroze/refactoring-the...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Omar El Gabry (02 October, 2017). Refactoring — The Hygienic Habit&lt;br&gt;
See on &lt;a href="https://hackernoon.com/refactoring-the-hygienic-habit-b2ee0f5528ba"&gt;https://hackernoon.com/refactori...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Shawn McGrath (22 August, 2016). The Exceptional Beauty of Doom 3's Source Code&lt;br&gt;
See on &lt;a href="https://kotaku.com/the-exceptional-beauty-of-doom-3s-source-code-5975610"&gt;https://kotaku.com/the-except...&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt; &lt;em&gt;The copyright for CommitStrip is held by &lt;a href="http://www.commitstrip.com"&gt;CommitStrip&lt;/a&gt; and is licensed to CommitStrip.&lt;/em&gt; &lt;/small&gt;&lt;/p&gt;

</description>
      <category>refactorit</category>
    </item>
    <item>
      <title>Drupal 8 parameters upcasting for REST resources</title>
      <dc:creator>Kevin Wenger</dc:creator>
      <pubDate>Wed, 24 Jun 2020 13:51:20 +0000</pubDate>
      <link>https://dev.to/wengerk/drupal-8-parameters-upcasting-for-rest-resources-24oo</link>
      <guid>https://dev.to/wengerk/drupal-8-parameters-upcasting-for-rest-resources-24oo</guid>
      <description>&lt;p&gt;What is parameters-upcasting? How does it work for REST resources? How can you implement it? &lt;/p&gt;

&lt;p&gt;By reading those lines, I presume readers already know how to &lt;a href="https://www.drupal.org/docs/8/api/restful-web-services-api/custom-rest-resources"&gt;create a custom REST resources&lt;/a&gt; and may already know how to implement a custom &lt;a href="https://www.drupal.org/docs/8/api/routing-system/parameters-in-routes/parameter-upcasting-in-routes"&gt;parameters-upcasting for Routes &amp;amp; Controllers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article will give you an &lt;strong&gt;in-depth&lt;/strong&gt; how-to of &lt;strong&gt;upcasting&lt;/strong&gt; for Drupal 8 REST resources. &lt;/p&gt;

&lt;p&gt;We will &lt;strong&gt;briefly&lt;/strong&gt; explore the theory and when parameters-upcasting should be used.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Any fool can write code that a computer can understand. Good programmers write code that humans can understand.&lt;br&gt; - Martin Fowler&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;During my exploration of Drupal 8 and REST resources, I discover many articles explaining the parameters-upcasting paradigm for the Routes/Controllers system but none for the REST resource.&lt;br&gt;
Let's fix this, shall we?&lt;/p&gt;
&lt;h2&gt;
  
  
  What is upcasting?
&lt;/h2&gt;

&lt;p&gt;Sometimes your routes may contain one or more named parameters (also called a "slug" or sometimes a "path parameter").&lt;br&gt;
 Those variables will then be available in the Controller method by their name (here &lt;code&gt;$node&lt;/code&gt;).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;In most PHP code, the name of the variable does not matter but here it does: the name of the method argument must match the slug. Conversely, if the method argument name matches the name of the slug, the parameter will be passed in, irrespective of the order of arguments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then it would be awesome to have a sub-system capable of converting those parameters into an actual object according to our need into our Controller(s) or REST Resources.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This feature already exists into Drupal 8's route framework. It's called &lt;strong&gt;Parameters Upcasting&lt;/strong&gt; (may also be called &lt;strong&gt;parameters converters&lt;/strong&gt;). &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ParamConverter&lt;/code&gt; system takes care of converting those parameters to an object instance automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should I implement parameter(s) upcasting ?
&lt;/h2&gt;

&lt;p&gt;By using Parameters upcasting, you will keep logic out of the controllers/resources, that's what we call &lt;strong&gt;decoupling&lt;/strong&gt;.&lt;br&gt;
A powerful tool we have for making change easier and code more maintainable is decoupling. When we say two pieces of code are “decoupled”, we mean a change in one usually doesn't require a change in the other. When you change some feature, the fewer places in code you have to touch, the easier it is.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In programming the hard part isn’t solving problems, but deciding what problems to solve.&lt;br&gt; - Paul Graham&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Parameter upcasting may also improve the readability and robustness of you code by encouraging Type hinting of Controller/Resources methods.&lt;/p&gt;

&lt;p&gt;Finally, by decoupling logic, you will be able to let Drupal check and validate the provided entity for you in one single place.&lt;/p&gt;

&lt;p&gt;Well, Drupal 8 lands with many built-in parameter converters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Drupal\Core\ParamConver\EntityConverter&lt;/code&gt; : Parameter converter for upcasting entity IDs to full objects.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Drupal\Core\ParamConver\EntityRevisionParamConverter&lt;/code&gt; : Parameter converter for upcasting entity revision IDs to full objects.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Drupal\Core\ParamConver\MenuLinkPluginConverter&lt;/code&gt;: Parameter converter for upcasting menu entity ids to full objects.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Drupal\ctools\ParamConverter\TempstoreConverter&lt;/code&gt;: Parameter converter for pulling entities out of the tempstore.
This is particularly useful when building non-wizard forms (like dialogs) that operate on data in the wizard and 
getting the route access properly.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Drupal\jsonapi\ParamConverter\EntityUuidConverter&lt;/code&gt;: Parameter converter for upcasting entity UUIDs to full objects.
Be aware JSON:API maintains no PHP API since its API is the HTTP API. This class may change at any time and this will break any dependencies on it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How can I implement upcasting for REST resources ?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies.&lt;br&gt; — C.A.R. Hoare&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, you will need to create a custom &lt;code&gt;ParameterConverter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Parameter converters are being managed by the &lt;code&gt;ParamConverterManager&lt;/code&gt;. To implement new parameter converters, you should implement the &lt;code&gt;ParamConverterInterface&lt;/code&gt; interface.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As Parameter converters are services, you will need to add an entry to your &lt;code&gt;example.services.yml&lt;/code&gt; to declare a new &lt;code&gt;ParamConverter&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In contrast to standard routes, REST Resources uses Plugin annotations to specify the route URL. Therefore, if your custom &lt;code&gt;ParamConverter&lt;/code&gt; requires specific route option(s), you will not be able to &lt;a href="https://www.drupal.org/docs/8/api/routing-system/parameters-in-routes/using-parameters-in-routes"&gt;configure your parameters upcasting as usual&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Indeed, you will need to create and override the &lt;code&gt;FooBarConverter::getBaseRoute()&lt;/code&gt; method and alter the route(s) with those specific option(s).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In this example, my named parameter is called &lt;code&gt;foobar_placeholder&lt;/code&gt; and the first argument on the callback should be named the same as the slug name (&lt;code&gt;foobar_placeholder&lt;/code&gt;).&lt;/p&gt;



&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;For the most curious of you, here are some sources of additional information that inspired the creation of this article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal API Doc&lt;/strong&gt; (16 April 2019). How upcasting parameters works.&lt;br&gt;
Retrieved from &lt;a href="https://www.drupal.org/docs/8/api/routing-system/parameters-in-routes/how-upcasting-parameters-works"&gt;drupal.org/docs/8/api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal API Doc&lt;/strong&gt; (16 April 2019). Parameter upcasting in routes.&lt;br&gt;
Retrieved from &lt;a href="https://www.drupal.org/docs/8/api/routing-system/parameters-in-routes/parameter-upcasting-in-routes"&gt;drupal.org/docs/8/api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal API Doc&lt;/strong&gt; (17 February 2020). Using parameters in routes.&lt;br&gt;
Retrieved from &lt;a href="https://www.drupal.org/docs/8/api/routing-system/parameters-in-routes/using-parameters-in-routes"&gt;drupal.org/docs/8/api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal API Doc&lt;/strong&gt; (29 October 2018). Custom REST Resources.&lt;br&gt;
Retrieved from &lt;a href="https://www.drupal.org/docs/8/api/restful-web-services-api/custom-rest-resources"&gt;drupal.org/docs/8/api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal API Doc&lt;/strong&gt; (16 April 2019). Implementing custom parameter converters.&lt;br&gt;
Retrieved from &lt;a href="https://www.drupal.org/docs/8/api/routing-system/parameters-in-routes/implementing-custom-parameter-converters"&gt;drupal.org/docs/8/api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal Core Issue Queue&lt;/strong&gt; (29 Apr 2020). Make it possible to link to an entity by UUID.&lt;br&gt;
Retrieved from &lt;a href="https://www.drupal.org/node/2353611"&gt;drupal.org/project/drupal/issues&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drupal Core Issue Queue&lt;/strong&gt; (16 April 2019). Upcast request arguments/attributes to full objects.&lt;br&gt;
Retrieved from &lt;a href="https://www.drupal.org/project/drupal/issues/1798214"&gt;drupal.org/project/drupal/issues&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>drupal</category>
      <category>rest</category>
      <category>api</category>
    </item>
    <item>
      <title>MacOS — Trigger Notification Center when long running commands finishes</title>
      <dc:creator>Kevin Wenger</dc:creator>
      <pubDate>Wed, 24 Jun 2020 13:23:00 +0000</pubDate>
      <link>https://dev.to/wengerk/macos-trigger-notification-center-when-long-running-commands-finishes-4oci</link>
      <guid>https://dev.to/wengerk/macos-trigger-notification-center-when-long-running-commands-finishes-4oci</guid>
      <description>&lt;p&gt;Before getting into the main subject, be aware that this article has been first write for the Blog of Antistatique — Web Agency in Lausanne, Switzerland. A place where I work as Full Stack Web Developer.&lt;/p&gt;

&lt;p&gt;Feel free to read it here or check it out there: &lt;a href="https://antistatique.net/fr/node/343"&gt;https://antistatique.net/fr/node/343&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Retrieve all the code on my Gist: &lt;a href="https://gist.github.com/Sudei/ad0c1330966522c05f504d71d29f675b"&gt;https://gist.github.com/Sudei/ad0c1330966522c05f504d71d29f675b&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy reading.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;As a developer, I often run commands that take a while to finish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git pull&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;composer install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm install&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Considering that I am not a very patient person, I get really bored waiting for these commands to finish, so during that time I usually switch to some other occupation such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checking Twitter/Tech/Hacking websites,&lt;/li&gt;
&lt;li&gt;Making &amp;amp; (sometimes) drinking coffee,&lt;/li&gt;
&lt;li&gt;Playing &lt;a href="http://apps.thecodepost.org/trex/trex.html"&gt;T-Rex Runner&lt;/a&gt; - The hidden endless running game of Chrome.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;15 minutes later, I finally come back to my terminal with a cold coffee and I discover that I forgot to &lt;code&gt;cd&lt;/code&gt; in the correct folder. Repeat for another 15 minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Isn't there a better way?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Work is hard. Distractions are plentiful. And time is short. &lt;br&gt;&lt;br&gt;
— Adam Hochschild, American author, journalist, and lecturer&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Solution N°0 - The Junior Professor
&lt;/h3&gt;

&lt;p&gt;Waiting by watching some Gifs right on the terminal with &lt;a href="https://github.com/vdemedes/gifi"&gt;Gifi&lt;/a&gt;.&lt;br&gt;
One of my favourite solutions but not enough "cool" for some people.&lt;/p&gt;
&lt;h3&gt;
  
  
  Solution N°1 - The Middle-Earth Paradigm
&lt;/h3&gt;

&lt;p&gt;Making all tools faster and developers more patient.&lt;br&gt;
That would work in a parallel universe where magic exists, maybe.&lt;/p&gt;
&lt;h3&gt;
  
  
  Solution N°2 - The Luminous Fish Effect
&lt;/h3&gt;

&lt;p&gt;Use a short script that uses &lt;code&gt;terminal-notifier&lt;/code&gt; &amp;amp; append it to each command such as&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git pull repo@github.com | notify-me
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's pretty cool and do the job but ... I'm lazy and I don't want to append anything to my commands or predict if my command is a long-running command or not before even running it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Solution N°3 - The Friendship Algorithm
&lt;/h3&gt;

&lt;p&gt;What about trying another approach ? Instead of trying to detect long-running commands, we could simply send a notification when the CLI is not in the foreground.&lt;br&gt;
Mmmh, sounds good but is that possible ? With iTerm &amp;amp; OSX 10.9+, you can do this !!&lt;/p&gt;

&lt;p&gt;1) Create a new command named &lt;code&gt;notify&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch /usr/local/bin/notify &amp;amp;&amp;amp; chmod +x /usr/local/bin/notify
vim /usr/local/bin/notify
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;2) Copy and paste this system script inside:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;3) Add a custom function named &lt;code&gt;f_notifyme&lt;/code&gt; and expose it to iTerm using &lt;code&gt;PS1&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vim ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;4) Copy and paste the function&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;5) We did it ! Finally, reload the source file of your terminal &lt;code&gt;source ~/.zshrc&lt;/code&gt; and enjoy !&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QrnvU38s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/focu7lni7za3encq6j92.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QrnvU38s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/focu7lni7za3encq6j92.jpeg" alt="Enjoy your new notification cli system !"&gt;&lt;/a&gt;&lt;/p&gt;
Enjoy your new notification cli system !



&lt;p&gt;All images copyright of their respective owners.&lt;br&gt;
Big thanks to @Antistatique for the review &amp;amp; @gratisography for images.&lt;/p&gt;

</description>
      <category>macos</category>
      <category>cli</category>
      <category>command</category>
      <category>iterm</category>
    </item>
  </channel>
</rss>
