<?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: Abdelkarim ELAMEL</title>
    <description>The latest articles on DEV Community by Abdelkarim ELAMEL (@aelamel).</description>
    <link>https://dev.to/aelamel</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%2F537637%2F8e90230c-655d-46ba-a6e0-35a63e2f1800.png</url>
      <title>DEV Community: Abdelkarim ELAMEL</title>
      <link>https://dev.to/aelamel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aelamel"/>
    <language>en</language>
    <item>
      <title>Interacting with Redis Using Symfony 3.4</title>
      <dc:creator>Abdelkarim ELAMEL</dc:creator>
      <pubDate>Thu, 10 Dec 2020 11:15:57 +0000</pubDate>
      <link>https://dev.to/aelamel/interacting-with-redis-using-symfony-5802</link>
      <guid>https://dev.to/aelamel/interacting-with-redis-using-symfony-5802</guid>
      <description>&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AGidahp6xctG_6T3w.jpg" 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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AGidahp6xctG_6T3w.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hi, and welcome to another blog post related to &lt;strong&gt;Symfony&lt;/strong&gt; 😃&lt;/p&gt;

&lt;p&gt;Let’s start with a fact :&lt;/p&gt;

&lt;p&gt;In a big project, there is often some data that is not frequently changing and required to be loaded after being logged in. When the number of users and the number of data increases, this may cause some performance issues and might be annoying for end users.&lt;/p&gt;

&lt;p&gt;In these situations, many paths of optimizations are available:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimizing application code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimizing database (indexes, …)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caching&lt;/strong&gt; which we are going to focus on in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  There are many ways of caching:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Web caching:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It consists of caching a response for a defined amount of time, which can be done on the client-side(i.e: browser cache) or in the server-side. [&lt;a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching" rel="noopener noreferrer"&gt;Details&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data caching:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Data caching can avoid unnecessary repeated trips back to the database, it can be handy if the data is not changing frequently and the application is querying for the same data all the time. Some databases like MySQL and MariaDB have caching solutions that help speed up the process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application caching:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This type of caching is useful when your program uses a method that is very slow, application caching consists of storing the result of the slow method somewhere and use it for the upcoming requests which will speed up the processing time significantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key-Value data caching:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This way of caching relies on the same concept as application cache but it comes with the advantage of not losing data upon reboots or server failure.&lt;/p&gt;

&lt;p&gt;Among the popular key-value data caching databases, there is &lt;strong&gt;Redis&lt;/strong&gt; and &lt;strong&gt;Memcached&lt;/strong&gt; which are both in-memory databases.&lt;/p&gt;

&lt;p&gt;As you have noticed in the title of this post, we are going to interact with &lt;strong&gt;Redis&lt;/strong&gt; using a Symfony 3.4 application, so let’s get started 😃.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Project setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Create a blank Symfony project :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer create-project symfony/framework-standard-edition RedisSymfony3 "3.4.*"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding redis-bundle&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require snc/redis-bundle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing the bundle we need to enable it by adding the bundle class in the bundles array in &lt;code&gt;AppKernel&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$bundles = [
    ....
    new Snc\RedisBundle\SncRedisBundle(),
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enabling the bundle is not enough, a little configuration is required in order to communicate with Redis from our application.&lt;/p&gt;

&lt;p&gt;For that we need to add below code in our &lt;strong&gt;app/config/config.yml&lt;/strong&gt; file :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;snc_redis:
        clients:
            default:
                type: phpredis
                alias: default
                dsn: redis://hostname # (*)
                logging: '%kernel.debug%'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(*): The &lt;strong&gt;hostname&lt;/strong&gt; must be accessible within the network.&lt;/p&gt;

&lt;p&gt;We are all set now, we can fetch and store data in Redis.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Communicating with Redis&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;By installing redis-bundle, we get access to a Redis client class &lt;code&gt;Snc\RedisBundle\Client\Phpredis\Client&lt;/code&gt; which contains various methods (get, set, flush, …).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fetching all Redis keys.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to get all the keys stored in Redis, we use the &lt;strong&gt;keys&lt;/strong&gt; method with &lt;strong&gt;*&lt;/strong&gt; as an argument.&lt;/p&gt;

&lt;p&gt;Sample Code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;?php

namespace AppBundle\Controller;

use Snc\RedisBundle\Client\Phpredis\Client;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /** @var  Client */
    private $redisClient;

    public function __construct(Client $client)
    {
        $this-&amp;gt;redisClient = $client;
    }

    /**
     * @Route("/keys", name="keys")
     */
    public function indexAction()
    {
        $redisKeys = $this-&amp;gt;redisClient-&amp;gt;keys('*');
        return $this-&amp;gt;json(['keys' =&amp;gt; $redisKeys]);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Adding key/value pairs in Redis.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For setting a new key/value pair, there is the &lt;strong&gt;set&lt;/strong&gt; method :&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set(key, value)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Sample Code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace AppBundle\Controller;

use Snc\RedisBundle\Client\Phpredis\Client;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /** @var  Client */
    private $redisClient;

    public function __construct(Client $client)
    {
        $this-&amp;gt;redisClient = $client;
    }


    /**
     * @param $key
     * @param $value
     *
     * @Route("/create/{key}/{value}", name="create_key", methods={"GET"})
     * @return JsonResponse
     */
    public function createKeyAction($key, $value) {

        $this-&amp;gt;redisClient-&amp;gt;set($key, $value);
        return $this-&amp;gt;json([
            "status" =&amp;gt; Response::HTTP_OK
        ]);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Deleting a key/value pair from Redis.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For deleting a key, there is a delete method that accepts the key as the argument.&lt;/p&gt;

&lt;p&gt;Sample code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace AppBundle\Controller;

use Snc\RedisBundle\Client\Phpredis\Client;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /** @var  Client */
    private $redisClient;

    public function __construct(Client $client)
    {
        $this-&amp;gt;redisClient = $client;
    }

    /**
     * @param $key
     * @Route("/delete/{key}", name="delete_key", methods={"GET"})
     *
     * @return JsonResponse
     */
    public function deleteKeyAction($key) {
        $this-&amp;gt;redisClient-&amp;gt;delete($key);
        return $this-&amp;gt;json([
            "status" =&amp;gt; Response::HTTP_OK
        ]);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is also the possibility to remove a set of keys by a pattern like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$this-&amp;gt;redisClient-&amp;gt;delete($this-&amp;gt;redisClient-&amp;gt;keys($key."*"));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace AppBundle\Controller;

use Snc\RedisBundle\Client\Phpredis\Client;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /** @var  Client */
    private $redisClient;

    public function __construct(Client $client)
    {
        $this-&amp;gt;redisClient = $client;
    }

    /**
     * @param $key
     * @Route("/delete/like/{key}", name="delete_like_key", methods={"GET"})
     *
     * @return JsonResponse
     */
    public function deleteKeyLikeAction($key) {
        $this-&amp;gt;redisClient-&amp;gt;delete($this-&amp;gt;redisClient-&amp;gt;keys($key."*"));
        return $this-&amp;gt;json([
            "status" =&amp;gt; Response::HTTP_OK
        ]);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was it for this post, the full code is available &lt;a href="https://github.com/aelamel/RedisSymfony" rel="noopener noreferrer"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cheers 😄&lt;/p&gt;

</description>
      <category>redis</category>
      <category>cache</category>
      <category>performance</category>
      <category>symfony</category>
    </item>
    <item>
      <title>How to make push notifications without sockets</title>
      <dc:creator>Abdelkarim ELAMEL</dc:creator>
      <pubDate>Thu, 10 Dec 2020 11:05:35 +0000</pubDate>
      <link>https://dev.to/aelamel/how-to-make-push-notifications-without-sockets-19pn</link>
      <guid>https://dev.to/aelamel/how-to-make-push-notifications-without-sockets-19pn</guid>
      <description>&lt;p&gt;Nowadays, push notifications are a must have feature in every modern web / mobile application.&lt;/p&gt;

&lt;p&gt;Real time update notifications, asynchronous/long running task notification are great use cases for this feature. As an IT guy, you’ve probably tried or have implemented this feature in an application. If you haven’t, you’ve certainly asked yourself the following question: &lt;strong&gt;how this can be done ?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt; : There is different ways, each way has its advantages and drawbacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;First method : XHR Polling&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This method consists of making a repetitive HTTP call after certain amount of time in order to retrieve updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages&lt;/strong&gt;: simple to implement / debug, compatible with all browsers and architectures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drawbacks&lt;/strong&gt;: one way communication,inefficient and resource wasting (some calls may return an empty results since there is no update is made).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Second method: SSE events&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The second way consists of opening a persistent HTTP connection between the client and the server. When a change is made, the server sends data in which we call a &lt;strong&gt;Server Sent Event (SSE)&lt;/strong&gt; to the client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt; Native implementation in JS (EventSource), supported reconnection and state reconciliation mechanisms&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drawbacks&lt;/strong&gt;: One way communication, uses a persistent connection&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Third method: Websockets&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;WebSocket is a &lt;a href="https://en.wikipedia.org/wiki/Full-duplex" rel="noopener noreferrer"&gt;full-duplex&lt;/a&gt; protocol allowing a bidirectional communication between the server and the client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages&lt;/strong&gt;: full duplex communication&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drawbacks&lt;/strong&gt;: Long lived connections between the server and the client, no support for reconnection and state reconciliation.&lt;/p&gt;

&lt;p&gt;The real dilemma is the persistent connections which is not always possible with serverless plateformes and technologies using short lived connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, how can we achieve the same goal with a fancy solution ?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer : The Mercure protocol.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is Mercure ?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Mercure is a protocol allowing to push data updates to web browsers and other HTTP clients in a convenient, fast, reliable and battery-efficient way. It is especially useful to publish real-time updates of resources served through web APIs, to reactive web and mobile apps.&lt;/p&gt;

&lt;p&gt;Among the advantages of this protocol :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Native browser support ;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compatible with all existing servers and can work with old browsers (IE7+) using an &lt;strong&gt;EventSource&lt;/strong&gt; polyfill ;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Built-in connection re-establishment and state reconciliation ;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JWT-based authorization mechanism (securely dispatch an update to some selected subscribers) ;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Message encryption support ;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;More details can be found in the official website : &lt;a href="https://mercure.rocks/" rel="noopener noreferrer"&gt;https://mercure.rocks/&lt;/a&gt;&lt;/strong&gt;&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%2Fcdn-images-1.medium.com%2Fmax%2F2494%2F0%2AxVg8iMMyB2ndCOJM" 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%2Fcdn-images-1.medium.com%2Fmax%2F2494%2F0%2AxVg8iMMyB2ndCOJM" alt="**Overall overview**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Key concepts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;After this brief introduction, let’s dive into the involved components of this protocol.&lt;/p&gt;

&lt;p&gt;The first component is the &lt;strong&gt;Topic&lt;/strong&gt; which is the unit we &lt;strong&gt;publish&lt;/strong&gt; and &lt;strong&gt;subscribe&lt;/strong&gt; to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The publisher&lt;/strong&gt;: is responsible of sending updates to the &lt;strong&gt;hub&lt;/strong&gt;, he is also able to securely dispatch update to specific &lt;strong&gt;targets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The subscriber&lt;/strong&gt;: can be a server/client side application that subscribes to real-time updates from the &lt;strong&gt;hub&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The famous Hub&lt;/strong&gt;: is a server that handles subscription requests and distributes the content to subscribers when the corresponding topics have been updated.&lt;/p&gt;

&lt;p&gt;And last but not least, their is the &lt;strong&gt;target(s)&lt;/strong&gt; which can be a subscriber, or a group of subscribers.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;Now, after you’ve had an idea about the components, let’s see how they communicate each other.&lt;/strong&gt;
&lt;/h5&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Publishing :&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In order to send a message to a client application, the publisher issues a &lt;strong&gt;POST&lt;/strong&gt; request to the hub which afterwards dispatches the message to the subscriber(s) using a SSE.&lt;/p&gt;

&lt;p&gt;The request must be encoded using the &lt;strong&gt;application/x-www-form-urlencoded&lt;/strong&gt; format.&lt;/p&gt;

&lt;p&gt;The request body should contain at least the following data :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;topic&lt;/strong&gt;: the name of the topic which will receive the message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;data&lt;/strong&gt;: contains the content of the message.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to dispatch private updates, we can add the topic parameter to the request body which we contain the &lt;strong&gt;target(s)&lt;/strong&gt; allowed to receive the update.&lt;/p&gt;

&lt;p&gt;The publisher must present a valid &lt;strong&gt;JWT&lt;/strong&gt; that contains a claim named &lt;strong&gt;“mercure”&lt;/strong&gt;, this claim must contain a &lt;strong&gt;“publish”&lt;/strong&gt; key which is an array of the authorized targets to dispatch to.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;VERY IMPORTANT :&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The value of “mercure.publish” determines the capabilities of the publisher.&lt;/p&gt;

&lt;p&gt;if &lt;strong&gt;“mercure.publish”&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;is not defined, then the publisher is not allowed to dispatch any update ;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;contains an empty array, then the publisher is only allowed to dispatch public updates ;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;contains the reserved string * as an array value, then the publisher is authorized to dispatch updates to all targets ;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Subscribing :&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The subscriber / client subscribes to the hub URL in order to receive updates by using a GET request that contains the topic names to get updates from.&lt;/p&gt;

&lt;p&gt;A subscriber may need to be authorized to receive updates destined to specific targets. To receive these specific updates, the JWS presented by the subscriber must have a claim named &lt;strong&gt;mercure&lt;/strong&gt; with a key named &lt;strong&gt;subscribe&lt;/strong&gt; that contains an array of strings ;&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%2Fcdn-images-1.medium.com%2Fmax%2F2298%2F0%2AzGZJQ_uTSfgY9b9z" 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%2Fcdn-images-1.medium.com%2Fmax%2F2298%2F0%2AzGZJQ_uTSfgY9b9z"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Authorization :&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In order to ensure that both publishers / subscribers are authorized for private updates, a JWS (JSON Web Signature) must be provided ;&lt;/p&gt;

&lt;p&gt;There are 2 mechanisms to present the JWS to the hub :&lt;/p&gt;

&lt;p&gt;Using an &lt;strong&gt;Authorization&lt;/strong&gt; HTTP header :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Used if the publisher / subscriber is not a web browser.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The header contains a string Bearer followed by the JWS.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using a cookie :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Used if the publisher / subscriber is a web browser.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The browser should send a cookie named &lt;strong&gt;mercureAuthorization&lt;/strong&gt; which contain the JWS.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When using authorization mechanisms, the connection MUST use an encryption layer such as HTTPS;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Reconnection &amp;amp; State Reconciliation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The connection between the subscriber can be lost at any time and the user may not receive notifications about the changes that happened during that time.&lt;/p&gt;

&lt;p&gt;To avoid that, the subscriber should send the id of the last received update. This id should be sent from the hub and must be a Global unique identifier (i.e: GUID, UUID, …).&lt;/p&gt;

&lt;p&gt;During the reconnection, the subscriber will automatically re-connect to the hub (according to the SSE specifications).&lt;/p&gt;

&lt;p&gt;During this phase, the &lt;strong&gt;ID&lt;/strong&gt; should be sent in Last-Event-ID &lt;strong&gt;HTTP Header&lt;/strong&gt;. It can be also provided as a &lt;strong&gt;query parameter&lt;/strong&gt; (with the same name) during the &lt;strong&gt;discovery&lt;/strong&gt; in order to fetch any update dispatched between the initial resource generation by the publisher and the connection to the hub.&lt;/p&gt;

&lt;p&gt;If both HTTP Header and the query parameter are provided, the HTTP Header takes the precedence.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Encryption&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Relaying on HTTPS as an encryption is not totally secure, since the hub can be managed by a service provider and anyone who has access to the hub can see the content of all messages.&lt;/p&gt;

&lt;p&gt;To ensure a total privacy, the message must be encoded by the publisher before sending it to the publisher using Json Web Encryption. The subscriber must have knowledge of this key in order to decrypt the message. The exchange can be done by any relevant mechanism.&lt;/p&gt;

&lt;p&gt;A possible way of that is to send an encoded key in the key-set attribute during the discovery.&lt;/p&gt;

&lt;p&gt;I hope that it wasn’t borring for you and you’ve got a clear idea about the Mercure protocol.&lt;/p&gt;

&lt;p&gt;You can check an example in my github repository where i used a &lt;a href="https://github.com/aelamel/mercure-pushliser-sf" rel="noopener noreferrer"&gt;&lt;strong&gt;Symfony&lt;/strong&gt; backend as a publisher&lt;/a&gt; and a &lt;a href="https://github.com/aelamel/mercure-subscriber-react" rel="noopener noreferrer"&gt;&lt;strong&gt;React.js&lt;/strong&gt; web app as a subscriber&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>react</category>
      <category>pushnotification</category>
      <category>mercure</category>
    </item>
    <item>
      <title>How to setup environment variables for a React.js application for multiple environments</title>
      <dc:creator>Abdelkarim ELAMEL</dc:creator>
      <pubDate>Thu, 10 Dec 2020 09:41:49 +0000</pubDate>
      <link>https://dev.to/aelamel/how-to-setup-environment-variables-for-a-react-js-application-for-multiple-environments-5e6d</link>
      <guid>https://dev.to/aelamel/how-to-setup-environment-variables-for-a-react-js-application-for-multiple-environments-5e6d</guid>
      <description>&lt;p&gt;One build to rule them all&lt;/p&gt;

&lt;p&gt;Using environment variables in a client-side application is a bit tricky, but it becomes easy when you know how client-side applications work.&lt;/p&gt;

&lt;p&gt;When you are working on a web application (client-side), you will certainly need to communicate with one or many backends to retrieve /send some data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When you are in an enterprise-scale, the backend URLs will be different and they will depend on the environment where the application is running (dev, staging, ,UAT and production). This is reasonable, isn’t it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;So, how can we define the values depending on the environment?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short answer&lt;/strong&gt;: In many different ways.&lt;/p&gt;

&lt;p&gt;I’ll be brief in the first 2 methods and you will know why in a minute :)&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 1: Using dotenv module.
&lt;/h3&gt;

&lt;p&gt;This approach consists of using files prefixed with ‘.env’ containing environment variables in a key=value representation.&lt;/p&gt;

&lt;p&gt;The content of a file will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REACT_APP_API_URL=https://path/to/my/backend/api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each environment has its own specific file :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;.env&lt;/strong&gt; : for production environment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;.env.development&lt;/strong&gt; : for development environment&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to retrieve the value of the variable in your application’s code, you can find the value in the &lt;strong&gt;process.env&lt;/strong&gt; global variable, like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const App = () =&amp;gt; &amp;lt;h1&amp;gt;{process.env.REACT_APP_API_URL}&amp;lt;/h1&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using &lt;strong&gt;CRA (Create React App)&lt;/strong&gt;, you will find all the details about this is the official &lt;a href="https://create-react-app.dev/docs/adding-custom-environment-variables/"&gt;documentation&lt;/a&gt; since it uses the dotenv module internally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; You will have to install the dependency if you are not using &lt;strong&gt;CRA&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 2: Using npm scripts and Webpack.
&lt;/h3&gt;

&lt;p&gt;If you are not using CRA, which does some &lt;strong&gt;“MAGIC”&lt;/strong&gt; behind the scenes, you will have to do that &lt;strong&gt;“MAGIC”&lt;/strong&gt; by yourself ;)&lt;/p&gt;

&lt;p&gt;Nothing to be afraid of, &lt;strong&gt;CRA&lt;/strong&gt; uses webpack behind the scenes to bundle your application, it replaces the &lt;code&gt;process.env.REACT_APP_API_URL&lt;/code&gt; with the value in the .env file depending on the environment specified for the build.&lt;/p&gt;

&lt;p&gt;You can do the same thing with a small chunk of code.&lt;/p&gt;

&lt;p&gt;First, you’ll have to install &lt;a href="https://www.npmjs.com/package/webpack"&gt;webpack&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/webpack-cli"&gt;webpack-cli&lt;/a&gt; from npm :&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev webpack webpack-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After that, go to your package.json and set your environment variable for each npm script you have.&lt;/p&gt;

&lt;p&gt;I suppose that you know Webpack, so I won’t go into the details of the config files of each environment.&lt;/p&gt;

&lt;p&gt;It’s not over yet !!&lt;/p&gt;

&lt;p&gt;The application will not work since we are not telling webpack how the handle the process.env statements in our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const App = () =&amp;gt; &amp;lt;h1&amp;gt;{process.env.REACT_APP_API_URL}&amp;lt;/h1&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside your webpack configuration file, you will need to add an entry in the plugins list which will interpolate the expression and places the actual value of the environment variable.&lt;/p&gt;

&lt;p&gt;Now, you will be able to see the value printed on your web page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 3: Setting values in the deployment phase.
&lt;/h3&gt;

&lt;p&gt;Before going into the details, I would like to mention an issue with the previous methods.&lt;/p&gt;

&lt;p&gt;The issue is that you will have to build the application for every environment that you have since the values are injected at the build time.&lt;/p&gt;

&lt;p&gt;This is not ideal when you are dealing with multiple environments and you will have to store each build for each environment somewhere making it hard to manage (in a cloud and container point of view).&lt;/p&gt;

&lt;p&gt;The idea here is the have one &lt;strong&gt;“generic”&lt;/strong&gt; build which isn’t related to any environment and at the deployment phase, the environment-specific values will be injected into the application.&lt;/p&gt;

&lt;p&gt;Let’s see this in action :&lt;/p&gt;

&lt;p&gt;First of all, we will need a shell script that will be responsible for extracting the environment variables values and injecting them into a javascript file.&lt;/p&gt;

&lt;p&gt;This script is reading all the environment variables starting with &lt;code&gt;REACT_APP&lt;/code&gt; in the machine (server). It writes them in a .env file which is transformed into a JSON object placed in the &lt;code&gt;env-config.js&lt;/code&gt; in the &lt;code&gt;window._env_&lt;/code&gt; object that is accessible from the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#.env.sh

#!/bin/bash

#generate a .env file containing your environment variables
env &amp;gt;&amp;gt; .env

# Recreate config file
rm -rf ./env-config.js
touch ./env-config.js

# Add assignment 
echo "window._env_ = {" &amp;gt;&amp;gt; ./env-config.js

# Read each line in .env file
# Each line represents key=value pairs
while read -r line || [[ -n "$line" ]];
do
  # Split env variables by character `=`
  if printf '%s\n' "$line" | grep -q -e '='; then
    varname=$(printf '%s\n' "$line" | sed -e 's/=.*//')
    varvalue=$(printf '%s\n' "$line" | sed -e 's/^[^=]*=//')
  fi

  # Read value of current variable if exists as Environment variable
  value=$(printf '%s\n' "${!varname}")
  # Otherwise use value from .env file
  [[ -z $value ]] &amp;amp;&amp;amp; value=${varvalue}

  # Append configuration property to JS file
  echo "  $varname: \"$value\"," &amp;gt;&amp;gt; ./env-config.js
done &amp;lt; .env

echo "}" &amp;gt;&amp;gt; ./env-config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you will need to place the &lt;code&gt;env-config.js&lt;/code&gt; in the public folder of your application and import it in your &lt;code&gt;index.html&lt;/code&gt; (You can make another shell script that does this for you if you want to automate stuff)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;script src="%PUBLIC_URL%/env-config.js"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Accessing your environment variables will be like this :&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const App = () =&amp;gt; &amp;lt;h1&amp;gt;{window._env_.REACT_APP_API_URL}&amp;lt;/h1&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And that’s it, you are all set now!&lt;/p&gt;

&lt;p&gt;I hope that you’ve liked the post.&lt;/p&gt;

&lt;p&gt;Until next time, I would like to say: Stay Safe, Stay at home, and Keep coding.&lt;/p&gt;

&lt;p&gt;Cheers.&lt;/p&gt;

</description>
      <category>react</category>
      <category>12fa</category>
      <category>docker</category>
    </item>
    <item>
      <title>[Symfony]: Empty token storage when injecting service in an event listener</title>
      <dc:creator>Abdelkarim ELAMEL</dc:creator>
      <pubDate>Thu, 10 Dec 2020 09:38:22 +0000</pubDate>
      <link>https://dev.to/aelamel/symfony-empty-token-storage-when-injecting-service-in-an-event-listener-4fh7</link>
      <guid>https://dev.to/aelamel/symfony-empty-token-storage-when-injecting-service-in-an-event-listener-4fh7</guid>
      <description>&lt;p&gt;Another Symfony mistery&lt;/p&gt;

&lt;p&gt;You might have been struggling to fetch the logged-in user from a listener that includes a UserService class which contains the logic of fetching the logged-in user.&lt;/p&gt;

&lt;p&gt;Let's take the below code as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//UserService.php

&amp;lt;?php

namespace App\Service;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;


class UserService {

  private $tokenStorage;

  private $currentUser;

  /**
  * @required
  */
  public function setSecurityContext(TokenStorageInterface $tokenStorage) {
    $token = $tokenStorage-&amp;gt;getToken();
    if ($token) {
      $this-&amp;gt;currentUser = $token-&amp;gt;getUser();
    }
  }

  public function getCurrentUser() {
    return $this-&amp;gt;currentUser;
  }
}

?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//MyListner

&amp;lt;?php
namespace App\Listener;
use Doctrine\Persistence\Event\LifecycleEventArgs;

class MyListener {

  private $userService;

  public function __construct(UserService $userService) {
    $this-&amp;gt;userService = $userService;
  }

  public function onFlush(LifecycleEventArgs $args) {

    $currentUser = $this-&amp;gt;userService-&amp;gt;getCurrentUser();

    var_dump($currentUser); // prints NULL
  }

}
?&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why the currentUser is NULL ?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer: Doctrine listeners are called whenever a corresponding event occurs. Initialization of them may occur before the security context.&lt;/p&gt;

&lt;p&gt;You have two options here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The first one&lt;/strong&gt;: inject your TokenStorage directly in your Listener and retrieve the token inside your event handler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//MyListner

&amp;lt;?php
namespace App\Listener;
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;


class MyListener {

  private $tokenStorage;

  public function __construct(TokenStorageInterface $tokenStorage) {
    $this-&amp;gt;tokenStorage = $tokenStorage;
  }

  public function onFlush(LifecycleEventArgs $args) {

    $currentUser = $this-&amp;gt;tokenStorage-&amp;gt;getToken()-&amp;gt;getUser();

    var_dump($currentUser); // prints a UserInterface object
  }

}
?&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The second one&lt;/strong&gt;: Fetch the token inside the &lt;code&gt;getCurrentUser&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//UserService.php

&amp;lt;?php

namespace App\Service;

use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class UserService {

  private $tokenStorage;

  private $currentUser;

  public function __construct(TokenStorageInterface $tokenStorage) {
    $this-&amp;gt;tokenStorage = $tokenStorage;
  }


  public function getCurrentUser(TokenStorageInterface $tokenStorage) {
    $token = $tokenStorage-&amp;gt;getToken();
    if ($token &amp;amp;&amp;amp; is_null($this-&amp;gt;currentUser)) {
      $this-&amp;gt;currentUser = $token-&amp;gt;getUser();
    }

    return $this-&amp;gt;currentUser;
  }

}

?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hidden trick is that you have to call the &lt;code&gt;getToken&lt;/code&gt; method in order to get a fresh token.&lt;/p&gt;

&lt;p&gt;That was it, I hope this blog post was helpful.&lt;/p&gt;

&lt;p&gt;Cheers&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>dependencyinjection</category>
      <category>php</category>
    </item>
  </channel>
</rss>
