Ramatou Adamou Issa

Ramatou Adamou Issa

  • Experiences
  • Formation
  • Musics
  • Blog

›Recent Posts

Recent Posts

  • Watchtower, container for updating docker images
  • PHP8 (Migrating existing PHP7 project to PHP8)
  • What news in Symfony 5
  • Command Query Segregation Responsibility (CQRS)
  • AFUP conference feedbacks

Watchtower, container for updating docker images

February 9, 2021

Ramatou Adamou Issa

Docker containers (update docker images using watchtower)

I found this interesting article here today and decide to implement it in my PHP project github repository

For those who already read my article, about some PHP8 new features implementation, the source code link is already available. You just need to update the repository.

git pull origin master
  • Changes added
docker-composer.yml

services:
  watchtower:
    container_name: watchtower
    hostname: watchtower
    image: containrrr/watchtower:latest
    restart: always
    environment:
      TZ: "Europe/Paris"
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_NOTIFICATIONS: "slack"
      WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL: "https://hooks.slack.com/services/XXX/YYY/ZZZ"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      
    ....  

Watchtower allows you to keep all your docker images up to date. it:

  • Search for the newest versions of your docker images
  • Update your current images and containers
  • remove unused images
  • send Slack notification

Enjoy <3 <3

PHP8 (Migrating existing PHP7 project to PHP8)

February 5, 2021

Ramatou Adamou Issa

PHP8 (Migrating existing PHP7 project to PHP8)

The latest PHP version is released on November 26, 2020. This version comes with a lot of new features and improvements. In this article, I will implement some of these new features in an existing PHP project.

Project Link

You can download the code source from this github link

Implemented PHP8 features


  1. PHP8 match expression, RFC


Php8 comes with a new expression match that replaces switch in the older versions. match expression has a lot of advantages compared to traditional PHP switch cases. Some of those advantages are

  • match expression offer shorter code block
  • it does not require break
  • there is no type coercion

Code implementation

Here, in this code, the ship parameter is passed through the createForm The ship object type is instantiated depending on this parameter.

  • Older PHP version
    public function createFromData(array $data): ?AbstractShip
    {     
        switch ($data['team']) {
            case 'empire':
                $ship = (new Ship())
                    ->setJediFactor($data['jedi_factor']);
                break;
            case 'rebel':
                $ship = new RebelShip();
                break;
            case 'broken':
                $ship = new BrokenShip();
                break;
            case 'bounty hunter':
                $ship = new BountyHunterShip();
                break;
            default:
                $ship = (new Ship())
                    ->setJediFactor($data['jedi_factor']);

        }   
    }
  • What we got with PHP8 match
     public function createFromData(array $data): ?AbstractShip
    {
        if (!isset($data['team'])) {
            return null;
        }

        $ship = match ($data['team']) {
            'rebel' => new RebelShip(),
            'broken' => new BrokenShip(),
            'bounty hunter' => new BountyHunterShip(),
             default => (new Ship())->setJediFactor($data['jedi_factor'])
        };
     
    }

  1. Constructor properties promotion, see RFC


As in Javascript, PHP8 introduces the use of syntactic sugar to define class constructor. Below is the new implementation.

Code implementation

  • Before
   private $jsonFixturesLoader;

    public function __construct(LoaderInterface $jsonFixturesLoader)
    {
        $this->jsonFixturesLoader = $jsonFixturesLoader;
    }
  • After
      public function __construct(
        private LoaderInterface $jsonFixturesLoader
    ){}

  1. Named arguments


It is now totally possible to name an argument passed to a function or method call.

Code implementation

  • Before
    $battleResult = $battleManager->battle(
    $ship1,
    $ship1Quantity,
    $ship2,
    $ship2Quantity,
    $battleType
);
  • After
$battleResult = $battleManager->battle(
        ship1: $ship1,
        ship1Quantity: $ship1Quantity,
        ship2: $ship2,
        ship2Quantity: $ship2Quantity,
        battleType: $battleType
);

  1. Non-capturing catches


In PHP8, whenever you wanted to catch an exception, you can omit the catch exception variable

Code Implementation

  • Before
     try {
            $jsonContents = \Safe\file_get_contents($this->filename);

            return \Safe\json_decode($jsonContents, true);
        } catch (FilesystemException $e) {
            throw new ReadFileException(\Safe\sprintf(
                'Impossible to read this file %s',
                $e->getMessage()
            ));
        }
  • After
try {
            $jsonContents = \Safe\file_get_contents($this->filename);

            return \Safe\json_decode($jsonContents, true);
        } catch (FilesystemException ) {
            throw new ReadFileException(\Safe\sprintf('Impossible to read this file %s', 'er'));
        }

Here the $e variable is omitted.

What news in Symfony 5

January 28, 2020

Ramatou Adamou Issa

Introduction

It's been too long since my last post, on CQRS. Today I'm going to list some new features that Symfony 5 brings us.

Upgrade Symfony Version from 4.4 to 5

During the update of my project from Symfony 4.3 to Symfony 5, I learned a little detail about Composer.json file. In fact, my composer.json file has an extra object in which I had specified the version of my current Symfony.

{
    "extra": {
        "symfony": {
            "id": "02C1TW989CK77ZA7B2H4HC9WAG",
            "allow-contrib": true,
            "require": "4.3.*"
        }
    }
}

Theses few lines ("require": "4.3."), locked the Symfony version to the latest version of 4.3. This means that when you run composer update like this

composer update symfony/*

All updated versions of components will be the latest version of Symfony 4.3, which means 4.3.9. So with these lines of code, your composer update will never update your Symfony version to 4.4.

Also, knowing that Symfony minor version never breaks backward compatibility, before upgrading to 5, it is necessary to upgrade 4.3 to 4.4. In this case, you can be able to fix all deprecated before using a new major version.

The other features are coming soon...

Command Query Segregation Responsibility (CQRS)

December 17, 2019

Ramatou Adamou Issa

Introduction

CQRS, stand for Command query responsibility segregation, is a design pattern that involve a complete separation between reading and writing data in your application. The command is responsible of writing data and the query stand for reading. The first thing that come in mind when you read this little definition is:

Why do I need to implement this design pattern? Still, there is already CRUD pattern which stand for creating, reading, updating and deleting data.

As Martin Fowler explain it very well in his tutorial here, CQRS become very useful when your are dealing with a very sophisticated behavior. beside, the CRUD pattern is not enough when we need to store data that's different from the data we provided.

CQRS and Domain Driven Development implementation.

As, I'm passionate of using design pattern as soon as it is possible during my application development process, I join CQRS with Hexagonal Architecture. pattern.

The little example is a template application. it's only goal is to be used for creating, deleting and updating template. The application architecture is like this.

  1. Application

    • CreateTemplateController
    • UpdateTemplateController
  2. Domain

    • Command
      • CreateTemplate
      • CreateTemplateHandler
      • UpdateTemplate
      • UpdateTemplateHandler
    • Query
      • GetTemplateDataProvider
      • GetTemplateHandler
      • GetTemplateQuery
  3. Infrastructure(nothing in this folder for this example)

Command part Code

All controllers are implemented following the one action, one controller pattern. This mean that in each controller, there is only one magic method (__invoke), that implement all the logic.

Create Template Controller

<?php
    namespace AppBundle\Application;
    
    use Symfony\Component\Validator\ConstraintViolationListInterface;
    use AppBundle\Domain\Command\CreateTemplate;
    use AppBundle\Domain\DTO\TemplateDTO;
    use AppBundle\InputException;
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

    class CreateTemplateController extends AbstractController
    {
        /**
         * @ParamConverter("template", converter="fos_rest.request_body")
         */
        public function __invoke(string $id, TemplateDTO $template, ?ConstraintViolationListInterface $validationErrors)
        {
            if ($validationErrors && \count($validationErrors) > 0) {
                throw InputException::create(InputException::TEMPLATE_NOT_FOUND, (array) $validationErrors);
            }
    
            $template = $this->getCreateTemplate()->execute($template, $id);
    
            return $this->getApiSuccessResponse(['template' => $template]);
        }
    
        private function getCreateTemplateCommand(): CreateTemplate
        {
            return  $this->get('app.domain.cqrs.create.template.command');
        }
    }

Create Template Command

<?php

namespace AppBundle\Domain\Command\Template;

use AppBundle\Domain\Command\CommandInterface;
use AppBundle\Domain\DTO\TemplateDTO;
use AppBundle\Domain\Factory\TemplateDTOFactory;
use AppBundle\Exception\InputException;

class CreateTemplate implements CommandInterface
{
    /**@var TemplateDTOFactory*/
    private $templateDTOFactory;
    /** @var CreateTemplateHandler */
    private $createTemplateHandler;

    public function __construct(
        TemplateDTOFactory $templateDTOFactory,
        CreateTemplateHandler $createTemplateHandler
    ) {
        $this->templateDTOFactory = $templateDTOFactory;
        $this->createTemplateHandler = $templateDTOFactory;
    }

    public function execute(object $templateDTO, ?string $objectIdentifier): object
    {
        if (!$templateDTO instanceof TemplateDTO) {
            throw InputException::create(InputException::TEMPLATE_NOT_FOUND, [
                \sprintf("Invalid template body parameter")
            ]);
        }

        $template = $this->createTemplateHandler->handle($templateDTO);

        return $this->templateDTOFactory->create($template);
    }
}

CreateTemplateHandler

<?php

namespace AppBundle\Domain\Command\Template;

use Doctrine\ORM\EntityManagerInterface;
use AppBundle\Domain\DTO\TemplateDTO;
use AppBundle\Domain\Factory\TemplateFactory;
use AppBundle\Domain\Query\TemplateType\TemplateTypeDataProvider;
use AppBundle\Entity\Template;
use AppBundle\Entity\TemplateType;
use AppBundle\Exception\InputException;

class CreateTemplateHandler
{
    /** @var EntityManagerInterface */
    private $entityManager;
    /** @var TemplateFactory */
    private $templateFactory;
    /** @var TemplateTypeDataProvider */
    private $templateTypeDataProvider;

    public function __construct(
        EntityManagerInterface $entityManager,
        TemplateFactory $templateFactory,
        TemplateTypeDataProvider $templateTypeDataProvider
    ) {
        $this->entityManager = $entityManager;
        $this->templateFactory = $templateFactory;
        $this->templateTypeDataProvider = $templateTypeDataProvider;
    }

    public function handle(TemplateDTO $templateDTO): Template
    {
        try {
            /** @var Template $template */
            $template = $this->TemplateFactory->create($templateDTO);
            $templateTypeIdentifier = $templateDTO->getTemplateType()->getIdentifier();

            $templateType = $this->TemplateTypeDataProvider->getItem(
                TemplateType::class, $templateTypeIdentifier
            );

            if(!$templateType) {
                throw InputException::create(InputException::_NOT_FOUND, [
                    \sprintf(
                        "There is no type for this  template corresponding to %s",
                        $templateTypeIdentifier
                    )
                ]);
            }

            $template->setTemplateType($templateType);
            $this->entityManager->persist($template);
            $this->entityManager->flush();

            return $template;
        } catch (\Exception $exception) {
            throw InputException::create(InputException::ING_DOCTRINE_ERROR, [$exception->getMessage()]);
        }
    }
}

Query Part

GetTemplateDataProvider

<?php

namespace AppBundle\Domain\Query\Template;

use AppBundle\Entity\Template;

class TemplateDataProvider
{
    private $getTemplateHandler;

    public function __construct(GetTemplateHandler $getTemplateHandler)
    {
        $this->getTemplateHandler = $getTemplateHandler;
    }

    public function supports(string $resourceClass): bool
    {
        return Template::class === $resourceClass;
    }

    public function getItem(string $resourceClass, string $identifier)
    {
        if (!$this->supports($resourceClass)) {
            throw new \Exception("ResourceClassNotSupportedException");
        }

        $template  = $this->getTemplateTypeHandler->handle((new GetTemplateQuery())->setId($identifier));

        return $template;
    }
}

TemplateHandler

<?php

namespace AppBundle\Domain\Query\Template;

use Doctrine\ORM\EntityManagerInterface;
use AppBundle\Entity\Template;
use AppBundle\Exception\InputException;

class GetTemplateHandler
{
    /** @var EntityManagerInterface */
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function handle(GetTemplateQuery $templateQuery): Template
    {
        $templateRepository = $this->entityManager->getRepository(Template::class);
        $template = $templateRepository->findOneBy(['id' => $templateQuery->getId()]);

        if(!$template instanceof Template) {
            throw InputException::create(
                InputException::EMAIL_NOT_FOUND,
                [
                    \sprintf(
                        "Unable to find template with id %s",
                        $templateQuery->getId()
                    )
                ]
            );
        }

        return $template;
    }
}

GetTemplateQuery

<?php

namespace AppBundle\ing\Domain\Query\Template;

class GetTemplateQuery
{
    private $id;

    public function getId(): string
    {
        return $this->id;
    }

    public function setId(string $id): self
    {
        $this->id = $id;

        return $this;
    }
}

Et voila :). have Fun

AFUP conference feedbacks

October 27, 2019

Ramatou Adamou Issa

Introduction

In order to promote knowledge sharing within PHP community, AFUP organise every year a PHP forum. This year, I was able to attend Paris's PHP Forum that took place between 24th and 25th of october. I'd like to share in this article the main topics of the last day of this forum.

Aggressive PHP Quality Insurance in 2019

During his presentation, Ocramus share with us some very useful tools to ensure code quality in production

There are several tools to ensure code quality such as:

  1. Psalm

Psalm is a static analysis tool for finding errors in PHP programs. You can install it with composer

 composer require --dev vimeo/psalm:^3

See full documentation on Github

  1. Phpunit (make program robust by unit testing)

The faster way to install phpunit is by downloading PHP Archive (Phar)

 $ wget https://phar.phpunit.de/phpunit-8.4.phar
 $ chmod +x phpunit-8.4.phar

see full documentation here

  1. Behat (To add functional testings)

Behat is a framework that allow coding functional tests.Easy to install and execute.

Installation

php composer.phar require --dev behat/behat
vendor/bin/behat -V

Full documentation on behat official website here

  1. Phpspec

A php toolset to drive emergent design by specification. Phpspec can be added in the composer file like this:

{
    "require-dev": {
        "phpspec/phpspec": "^4.0"
    },
    "config": {
        "bin-dir": "bin"
    },
    "autoload": {"psr-0": {"": "src"}}
}

The full Phpspec documentation can be found here

  1. Doctrine coding Standard

The doctrine coding standard is a PHP_CodeSniffer used on Doctrine projects. The doctrine coding standard can be use to validate a set of rules specified to validate Php code.

Basic usage

composer global require doctrine/coding-standard
phpcs --standard=Doctrine /path/to/some/file/to/sniff.php
phpcbf --standard=Doctrine /path/to/some/file/to/sniff.php

Full doctrine standard documentation here

  1. Phpbench

A PHP benchmark framework.

Installation

Download the phar and public key with curl as follow.

$ curl -o phpbench.phar https://phpbench.github.io/phpbench/phpbench.phar
$ curl -o phpbench.phar.pubkey https://phpbench.github.io/phpbench/phpbench.phar.pubkey

Make the phar executable and add it to the global path as below

$ chmod 0755 phpbench.phar
$ sudo mv phpbench.phar /usr/local/bin/phpbench
$ sudo mv phpbench.phar.pubkey /usr/local/bin/phpbench.pubkey

The full Phpbench documentation can be found here

  1. Analysis and logging tools

    1. Tideways
    2. Sentry
    3. Instana
    4. Datadog
  2. API Validator tools original website

composer require lezhnev74/openapi-psr7-validator
  1. Backward compatiblity checker tool full documentation

A tool that can be used to check BC (Backward Compatibility) between to PHP versions

Installation

composer require --dev roave/backward-compatibility-check

Install with docker

docker run --rm -v `pwd`:/app nyholm/roave-bc-check
  1. Security checker tool

    1. Security advisories (Fulle documentation can be found here)

Ensure that your application doesn't install dependencies with know vulnerabilities. Installation:

    composer require --dev roave/security-advisories:dev-master
  1. Composer checker & composer unused checker
    composer require maglnet/composer-require-checker
    composer require  icanhazstring/composer-unused

Final words:

A good program is a program that: 1. Keep everything up to date 2. is stable 3. is Fast 4. is nice 5. is working

News in Symfony 4.4 Console Output

October 22, 2019

Ramatou Adamou Issa

Table Display Improvement

Symfony console component already implemented a feature to display tables in the console output. See the link below. Display table in symfony Console

Symfony 4.4 added a new method in Table class to display horizontally(setHorizontale)

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class SomeCommand extends Command
{
    public function execute(InputInterface $input, OutputInterface $output)
    {
        $table = new Table($output);
        $table
            ->setHeaders(['ISBN', 'Title', 'Author'])
            ->setRows([
                ['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'],
                ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'],
                ['960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'],
                ['80-902734-1-6', 'And Then There Were None', 'Agatha Christie'],
            ])
        ->setHorizontal()
        $table->render();
    }
}

This will display table horizontally like:

| ISBN    | 99921-58-10-7      | 971-5-0210-0         | 960-425-059-0           | 80-902734-1-6            |                       
| Title   | Divine Comedy      | A Tale of Two Cities | The Lord of the Rings   | And Then There Were None |
| Author  | Dante Alighieri    | Charles Dickens      | J. R. R. Tolkien'       | Agatha Christie          |

With SymfonyStyle, you can use the horizontal style directely;

use Symfony\Component\Console\Style\SymfonyStyle;

protected function execute(InputInterface $input, OutputInterface $output)
{
    $io = new SymfonyStyle($input, $output);
    $io->horizontalTable(
        ['ISBN', 'Title', 'Author'],
        [
            // ... the rows ...
        ]
    );
}

Table SymfonyStyle List Display

When you are using Symfony Style, you can also display a list with Separator like this:

use Symfony\Component\Console\Helper\TableSeparator;

$io->definitionList(
    ['Version' => '4.4.0'],
    ['Long-Term Support' => 'Yes'],
    new TableSeparator(),
    'Timeline',
    ['End of maintenance' => '11/2022'],
    ['End of life' => '11/2023']
);

The output of this is:

-----------------   --------
Version             4.4
Long-Term Support   Yes
-----------------   --------
TimeLine
End of maintenance  11/2022
End of life         11/2023
-----------------  --------

Symfony 4.4 News

October 13, 2019

Ramatou Adamou Issa

Rehashed Password

Symfony 4.3 added a new feature (native password Encoder). Because of the fast-paced nature of hashing algorithm, it becomes less and less recommended to select a default hashing algorithm. Even the PHP function:

password_hash

use a default robust hashing algorithm to encrypt password more efficiently even if it also offer the possibility to use the crypt algorithm for the hashing see documentation here

That's why Symfony 4.3 added a feature that allow to select auto hashing encoder in security configuration. That way, Symfony will choose the more efficient algorithm during the encoding of the user password.

see the default Encoding implementation example below:

    # config/packages/security.yaml
    security:
        # ...
        encoders:
            App\Entity\User:
                algorithm: 'auto'
                cost: 12

See the native Password Encoder documentation here

Now, Symfony 4.4 also bring the possibility to rehashed the password with a best existing hashing algorithm. In practice the entity user provider will only need to implement PasswordUpgraderInterface.

 providers:
    users:
        entity:
            class: 'App\Entity\User'
            property: 'username'
          

Interface to Implement

    Symfony\Component\Security\Core\User\PasswordUpgraderInterface.

This interface implement the only one method that rehash the password before saving it in the database. See the full documentation on Github

Phpunit Assertion for Email

In Symfony 4.4, the components Mailer and Mime (introduced in Symfony 4.3), come with some new phpunit assertions to test emails.

See the code below

    // tests/Controller/DefaultControllerTest.php
    namespace App\Tests\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
    
    class DefaultControllerTest extends WebTestCase
    {
        public function testSomething()
        {
            $client = static::createClient();
            $client->request('GET', '/newsletter-signup');
            // ...
    
            $this->assertEmailCount(2);
            $this->assertEmailIsQueued($this->getMailerEvent(0));
    
            $email = $this->getMailerMessage(0);
            $this->assertEmailHeaderSame($email, 'To', 'fabien@symfony.com');
            $this->assertEmailTextBodyContains($email, 'Welcome to Symfony!');
            $this->assertEmailAttachementCount($email, 1);
        }
    }

How To Use Git stash command in a very advanced way

May 24, 2019

Ramatou Adamou Issa

Git Stash

For very long time, I'm using only two commands of git stash.

git stash
git stash pop 

Fortunately, git stash has some useful commands also.

You can stash with a saving message with the command

git stash save "your message"

List all your stashes

git stash list

Apply the stash to a select repository

git stash apply stash@{n}

Pop specific stash from the stack

git stash pop stash@{n}

Show the summary of the latest or specific stash

git stash show
get stash show stash@{n}

Delete a specific stash

git stash drop stash@{n} 

You can also stash untracked files

git stash save -u

Or clear stash

git stash clear

JMAP ( A mondern Email Protocol)

May 8, 2019

Ramatou Adamou

JMAP, A modern Email Protocol

JMAP is the new email protocol that address shortcomings of earlier e-mail protocols and that is designed to fit modern age. It is a the protocol that offer a new use to use and modern API for modern email clients.

JMAP Protocol in use


  1. JMAP is developed by the large email developers community of IEFT. it offer an an easy to use and modern API.

  2. It is free and open source standard.

  3. JMAP is robust, more general and more general protocol that handle a large collection of use cases.

Continue reading this article here

ES6 - Templates Literals - Object Literals - Classes

May 7, 2019

Nicolás Bevacqua

Template Literal (string interpolation)

String declaration


    `example with a ${variable}`

Interpolation with valid Js expression


    `${variable * 3} is the result`      

Interpolation with tagged templates


    fn`test, ${$test} and ${test2} `      

See more examples here

Object Literal

Property value shorthand

    {foo : foo} or just {foo}     

Compute property name

    {[prefix + 'End']: 'test prefix'} 
    
    //prefix = 'pref',  result will be {prefEnd: 'test prefix'}      

See more examples here

Next →
Ramatou Adamou Issa
Ramatou Adamou Issa
HomeExperiencesFormation
Social Networks
InstagramTwitterChat
Accounts
Gallery photoBlogGitHubStar
Copyright © 2025 Ramazaki