Apr 022017
 

This article is about the default admin_page, admin_block and admin_block_content templates which serves as the base of the content display on some system configuration pages such as the one on this image:

Screenshot of the configuration page on a Drupal 8 website

Screenshot of the configuration page on a Drupal 8 website

The code

Explanation

If you use admin_page, you will be able to define the column in which the blocks dwell: left or right.

If you use directly admin_block, there is only a single block and it will span over the full width of the region.

So all in all, here is a pseudo hierarchy to better understand how it works:

Mar 262017
 

I just switched my website to https for testing purpose. But changing the website’s URL to https:// is not sufficient to enable a fully secure browsing experience, as images in posts are still loaded from http://. Or more precisely, most modern browsers (FF or Opera for instance) are now clever enough to guess that the current website is on https:// so its contents should also be loaded with the same protocol, but there may be a possibility that other less advanced browsers are not doing this smart guess.

There are two possibilities:

  • install and activate a plugin such as the SSL Insecure Content Fixer. It will replace on the fly the protocols to https. The advantage is that your contents are not edited in the database. The drawback is that your website may be a little slower. (sorry I don’t have metrics)
  • the other method is to replace the src="http:// references in the post_content field from the wp_posts table by src="https:// by using SQL. For example, in phpMyAdmin:
    1. make a backup of the wp_posts table (or even better, your database)
    2. execute this query:
Feb 212017
 

Introduction

Delighted

hook_schema is one of those methods where you are happy to have a usable documentation on the api website. It is pretty much self-explanatory and you don’t have to look for hours on third parties websites to get some usable information. 🙂

  • hook_schema on api.drupal.org and don’t forget to select your Drupal version!
  • $DRUPAL_ROOT\core\lib\Drupal\Core\Database\database.api.php: another file which describes the Database API array structure!
  • Schema Reference on drupal.org for D7. Yeah, there is no D8 version of the docs… Hopefully, nothing has changed between D7 and D8.

After some research, I found the files which are responsible for schema to SQL statement conversion:

File location Method name
$DRUPAL_ROOT\core\includes\schema.inc drupal_install_schema (8.2.x)
$DRUPAL_ROOT\core\includes\database.inc (deprecated) db_create_table (8.2.x) (deprecated)
$DRUPAL_ROOT\core\lib\Drupal\Core\Database\Schema.php protected createTable (8.2.x)
$DRUPAL_ROOT\core\lib\Drupal\Core\Database\Driver\{mysql,sqlite,pgsql}\Schema.php
$DRUPAL_ROOT\core\lib\Drupal\Core\Database\Driver\{mysql,sqlite,pgsql}\Schema.php

The code

Feb 192017
 

Result

Rendered table from a render array

Rendered table from a render array

The code

Additional Information

Feb 182017
 

Instructions

I will be creating a dedicated module using Drupal Console for this event subscriber. But feel free to use your own if you already have one! (don’t forget to backup)

  1. Access the drupal root folder in command line.
  2. Generate a new module:
  3. Generate the event subscriber. We will subscribe to the kernel.request event:
  4. Current state:
  5. Install the module using either drupal module:install or drush pm-enable:
  6. Now, refresh your web page and on each request received server side, a message will tell you the event occurred!

Additional Information

  • Instructions made on Drupal 8.2.x.
  • Using Drupal Console, you can easily inject services such as the current_user one by answering yes when it asks if you want to load services from the container. Please check this article about service dependency injection: [Drupal] Service dependency injection in a service type class.
  • After editing your files, remember to run a cache rebuild either with drupal cache:rebuild or drush cache-rebuild.
  • Events documentation entry point: Events on Drupal 8. You will find a few core events here.
  • The callback function’s name can be changed to whatever you want.
Feb 162017
 

The code

Additional Information

Feb 162017
 

The code

Additional Information

  • Unlike service type class service dependency injection, there may be no need to implement an interface to be able to load the needed services, such as extending from ControllerBase. So if you are extending from a class which already has the dependency injection implementation, you can just override the create and __construct methods. Don’t forget to call parent methods if needed.
  • Think of the create method as the model used by the __construct of your class.
  • The create signature needs to respect the one of the implemented interface (use your IDE to check against the original declaration).
  • Originally made and tested on Drupal 8.2.x.
  • A convenient list of core services can be found here: https://api.drupal.org/api/drupal/core%21core.services.yml/8.2.x (don’t forget to select the Drupal version if you are not on 8.2.x).
  • Some classes such as ones extending BlockBase will need to implement interfaces to access this pattern:
Feb 152017
 

J’ai quitté volontiers l’industrie du jeu vidéo, ayant perdu toute motivation d’y travailler. L’entreprise dans laquelle j’avais passé plus de quatre ans à essayer de produire des jeux et des applications est sur le point de fermer définitivement. Un chapitre de ma vie est en train de se clore, j’imagine.

Avais-je dit que j’étais rentré en France il y a quelques mois ? Bon, ben c’est fait. J’avais la tête tellement dans le cul que j’ai oublié de le mentionner. Je n’ai rien trouvé de pertinent sur Montréal hormis des éventuels boulots de testeur dans le jeu et l’applicatif. Pour un game designer et développeur, ce n’est pas très sérieux et j’ai écouté les conseils de proches m’invitant à arrêter l’expérience.

Avec le recul, je pense pouvoir dire que se dédier aux jeux vidéo, dans l’état actuel du monde, c’est le mode difficile des carrières. J’ai côtoyé de nombreuses personnalités, des personnes sympathiques et ouvertes, et leurs contraires menteurs ou indolents. Mais surtout, j’y ai vu de la précarité. La mienne déjà, et surtout les autres et la pléthore de témoignages trouvables sur la toile. Et le temps qui défile, inlassablement.

Durant ce parcours du combattant, j’ai utilisé de nombreuses techniques et outils de développement :

  • développement logiciel : Virtools 5, Unity en UnityScript puis en C#, un coup de Java sur Android, Cocos2D-x en C++
  • art : Illustrator, Photoshop, Premiere Pro, After Effects, Blender, FLStudio
  • sites web : HTML5, PHP5 (OOP uniquement), CSS, LESS, un soupçon de Javascript et de jQuery, un chouilla de SQL, quelques notions d’Apache
  • IDE : Visual Studio, Xcode, Eclipse, Android Studio
  • outils divers : SVN, Git, Mercurial, SourceTree, JIRA, VirtualBox, 5 navigateurs desktop, 2 navigateurs mobiles

Une bonne partie d’entre eux appris en autodidaxie, par passion comme on pourrait le dire. Mais apparemment, cela ne suffit pas à convaincre lorsque j’avais voulu rentrer dans le rang après une longue période en indépendance. Trop généraliste ? Pas d’expérience ? Des entretiens foireux ? Les raisons m’empêchant de retourner à l’emploi dans ce secteur sont nombreuses et je n’ai pas le temps ni l’envie de les énumérer ici. Par contre, je n’ai pas vraiment essayé de tirer profit de mon réseau professionnel. Bien que réduit, il aurait pu aboutir à quelque chose, mais encore une fois, il s’agit de probabilités. Je suis du genre à vouloir expérimenter par moi-même, me prouver que je peux convaincre grâce à ce que j’ai fait par le passé, sans utiliser d’artifices. Et force est de constater que c’est un beau fail.

Et ensuite ?

Je reste intéressé par le jeu vidéo, mais de manière plus diffuse et personnelle ; ayant toujours des projets en cours et aimant réfléchir à des designs. Mais le travail en équipe, c’est terminé.

À partir d’aujourd’hui, je vais commencer à écrire des articles à propos de Drupal, l’outil qui va être dans quelques semaines mon principal centre d’intérêt technologique ! En effet, j’ai rejoint une formation de type Préparation Opérationnelle à l’Emploi Individuelle grâce à Pôle Emploi dans un organisme de formation qui s’appelle Trained People. Moi qui pensais ne plus vouloir y remettre les pieds, décidément.

L’écosystème Drupal est si différent de celui des outils du jeu vidéo. Déjà, l’approche open source m’a toujours attiré. Je me rends bien compte à quel point le jeu vidéo est un milieu basé sur le secret, où chacun veut protéger sa petite idée de peur de se faire voler l’idée du siècle. Bien sûr, tout n’est pas parfait, notamment sur Drupal et sa documentation imbuvable. Mais voir un tel effort collectif pour faire fonctionner des milliers de modules contribués gratuitement, ça reste un point qui me donne envie de mettre la main à la pâte.

Étrangement, malgré une expérience bien foireuse ici en intérim juste avant, tout se passe à merveille depuis décembre 2016, c’est-à-dire dès que je suis entré dans le processus de recrutement de la formation.

Jan 052017
 
Couldn't add widget removed

Couldn’t add widget removed

Enraged

After having spent more than a day on the matter, I have finally figured out how to remove the Couldn’t add widget block in the Overview Screen. This is the block which appears in place of the Google search bar on top of the recent apps list after you have disabled the Google app.

Step by step

  1. Open the Play Store.
  2. Install KISS Launcher.
  3. Enable the Google app.
  4. Update the Google app.
  5. Touch the Home button.
  6. Set the KISS Launcher as default launcher.
  7. Reboot in Safe Mode (the process may differ on your Android OS):
    1. press the power button,
    2. long touch on the Power Off button,
    3. touch OK.
  8. When the reboot is done, the Google bar should have returned in the Overview Screen.
    • On this step, the bar wasn’t interactable on my phone.
  9. Power off normally your device.
  10. Power on your device.
  11. When the reboot is done, the Google bar should still be in the Overview Screen.
  12. Go to Settings > Apps > ALL.
  13. Disable the Google app. Accept everything when it says it will uninstall updates and data.
  14. Touch the Home button.
  15. Wait a few seconds.
  16. Open the Overview Screen.
  17. Enjoy!

Additional Notes

  • I have succeeded two times on a nearly fresh install of Android 5.1 (Lollipop) on a Moto E.
  • I have updated a lot of native apps until the internal storage was full (yes, on the 1st gen Moto E 4GB, you cannot have all the default apps up to date with the tiny internal storage space).
  • Please refer to your device manual for Safe Mode reboot.
  • A lot of websites and user feedback will tell you to just restart in Safe Mode to remove the bar. It did not do the trick on my phone for some reason.
  • I had to try a lot of possibilities so I don’t remember exactly what are the triggers for the bar removal. My guess is a combination of the KISS Launcher as default launcher app, a Google App up to date before disabling, and reboots between Safe Mode and normal mode, and maybe a full internal memory.
  • The only apps disabled when the bar removed itself after the disabling were:
    • Assist (by Motorola)
    • Motorola Alert
    • Motorola Migrate
    • Help (by Motorola)
    • Email (the default Android app)
  • The only apps enabled but not up to date were:
    • Google Play Books
    • Google Play Movies & TV
    • Google Play Music
    • Google Play Newsstand
    • Google Street View
    • Maps – Navigation & Transit
    • Motorola Camera
    • Motorola FM Radio
  • The remaining apps were up to date.
  • Third party apps installed from the Play Store:
    • Amaze File Manager
    • SuperSU
  • Third party apps installed from the SD Card includes:
  • I did not remove KISS Launcher afterwards because I like it. But feel free to change to another launcher. I guess it will work.
  • Pour les francophones, la méthode démontrée ci-dessus indique comment retirer le bloc avec le message « Impossible d’ajouter le widget » dans l’écran « Overview » qui affiche la liste des applications récentes (gestionnaire de tâches).
  • The step by step needs to be more accurate so I am wishing to get some feedback.
Dec 162016
 

The code

The maths behind

To get the point where two lines intersect, we will do some maths. To the mathematicians who will come across this post, I’m truly sorry for the heart attacks or strokes you may experience by reading this post.

Ok, let’s take a look on the figure:

Study case. We can see two lines crossing in an 2D Euclidian space.

Figure 1

First, sorry, I was too lazy to make a proper figure using computer tools so I just put a scan. XD

Next, here are the definitions:

  • A & B: the two lines,
  • A_1, B_1: the arbitrary starting points of the two lines,
  • A_2, B_2: the arbitrary points which tells the direction of the two lines,
  • X: the intersection point,
  • O: the origin point.

Kewl. Now, what we want is the intersection point X between those two lines. In other words, we want to know the position which starts from either lines’ arbitrary starting point, added by the direction of the line multiplied by a scalar value. So in our figure 1, the X position is:

  • the A_1 position added by the components of \overrightarrow{A_1A_2} multiplied by an unknown which I named \lambda
  • the B_1 position added by the components of \overrightarrow{B_1B_2} multiplied by an unknown which I named \mu

In this case, it is clear that \lambda = \mu = 0.5 so it will be easy to check if our final formula is correct. 🙂

At the point of intersection, we know that:
\begin{array}{rcl} \overrightarrow{OX} = \overrightarrow{OA_1} + \lambda\times\overrightarrow{A_1A_2} & and & \overrightarrow{OX} = \overrightarrow{OB_1} + \mu\times\overrightarrow{B_1B_2} \end{array}

… which gives us:
\begin{array}{rcl} \overrightarrow{OA_1} + \lambda\times\overrightarrow{A_1A_2} & = & \overrightarrow{OB_1} + \mu\times\overrightarrow{B_1B_2} \\ \overrightarrow{OA_1} - \overrightarrow{OB_1} & = & \mu\times\overrightarrow{B_1B_2} - \lambda\times\overrightarrow{A_1A_2} \end{array}

But we can’t use this statement exactly like this to solve our equation as we cannot multiply and divide vectors in this raw format. Also we need to reduce the unkowns count to 1. So we will separate our equation into two equations with the magic of matrices (which I don’t understand well at the moment), one for the x component and one for the y:
\left\{\begin{array}{c}  \overrightarrow{OA_1}_x - \overrightarrow{OB_1}_x = \mu\times\overrightarrow{B_1B_2}_x - \lambda\times\overrightarrow{A_1A_2}_x \\   \overrightarrow{OA_1}_y - \overrightarrow{OB_1}_y = \mu\times\overrightarrow{B_1B_2}_y - \lambda\times\overrightarrow{A_1A_2}_y  \end{array}\right.

To make our equation more readable, we will use some shorthands:
\begin{array}{r}A_\alpha = \overrightarrow{A_1A_2}\end{array}\\  \begin{array}{r}B_\alpha = \overrightarrow{B_1B_2}\end{array}\\  \begin{array}{r}C = \overrightarrow{OA_1} - \overrightarrow{OB_1}\end{array}

… so:
\left\{\begin{array}{c}  C_x = \mu B_{\alpha x} - \lambda A_{\alpha x} \\   C_y = \mu B_{\alpha y} - \lambda A_{\alpha y}  \end{array}\right.

From this point, we can reduce the unknown count. In my case, I have chosen to keep \mu instead of \lambda:
\left\{\begin{array}{c}  C_x A_{\alpha y} = \mu B_{\alpha x} A_{\alpha y} - \lambda A_{\alpha x} A_{\alpha y} \\   C_y A_{\alpha x} = \mu B_{\alpha y} A_{\alpha x} - \lambda A_{\alpha y} A_{\alpha x}  \end{array}\right.\\  \begin{array}{rcl}  C_x A_{\alpha y} - C_y A_{\alpha x} & = & \mu B_{\alpha x} A_{\alpha y} - \lambda A_{\alpha x} A_{\alpha y} - (\mu B_{\alpha y} A_{\alpha x} - \lambda A_{\alpha y} A_{\alpha x}) \\  C_x A_{\alpha y} - C_y A_{\alpha x} & = & \mu B_{\alpha x} A_{\alpha y} - \lambda A_{\alpha x} A_{\alpha y} - \mu B_{\alpha y} A_{\alpha x} + \lambda A_{\alpha y} A_{\alpha x} \\  C_x A_{\alpha y} - C_y A_{\alpha x} & = & \mu B_{\alpha x} A_{\alpha y} - \mu B_{\alpha y} A_{\alpha x} \\  C_x A_{\alpha y} - C_y A_{\alpha x} & = & \mu (B_{\alpha x} A_{\alpha y} - B_{\alpha y} A_{\alpha x}) \\  \mu & = & \frac{C_x A_{\alpha y} - C_y A_{\alpha x}}{B_{\alpha x} A_{\alpha y} - B_{\alpha y} A_{\alpha x}}  \end{array}

And finally, you have to check if B_{\alpha x} A_{\alpha y} - B_{\alpha y} A_{\alpha x} = 0. This will happen if your two lines are parallel or if there is one line defined as a point such as A_1 = A_2 or B_1 = B_2; no solution exists in those cases.

Test 1

Kewl! Now let’s try it with the Figure 1:
\begin{array}{rcl}  \mu & = & \frac{(1 - 1) \times 1 - (2 - 4) \times 2}{2 \times 1 - (-3) \times 2} \\  \mu & = & \frac{4}{8} = 0.5  \end{array}

We can get the X position:
\left\{\begin{array}{l}  \overrightarrow{OX}_x = \overrightarrow{OB_1}_x + B_{\alpha x} \times \mu = 1 + 2 \times 0.5 = 2 \\  \overrightarrow{OX}_y = \overrightarrow{OB_1}_y + B_{\alpha y} \times \mu = 4 + (-3) \times 0.5 = 2.5  \end{array}\right.

Test 2

Ok done! Now let’s try with another figure:

Study case 2. We can see two lines crossing in an 2D Euclidian space.

Figure 2

\begin{array}{rcl}  \mu & = & \frac{((-2) - 2) \times (-1) - ((-2) - (-3)) \times 0}{(-1.5) \times (-1) - 1.5 \times 0} \\  \mu & = & \frac{4}{1.5} \approx 2.666  \end{array}

We can get the X position:
\left\{\begin{array}{l}  \overrightarrow{OX}_x = \overrightarrow{OB_1}_x + B_{\alpha x} \times \mu = 2 + (-1.5) \times 2.666 = -2 \\  \overrightarrow{OX}_y = \overrightarrow{OB_1}_y + B_{\alpha y} \times \mu = (-3) + 1.5 \times 2.666 = 1  \end{array}\right.