Programmation

Le CASCADE DELETE en PHP avec PDO

Pour les développeur ayant suivi un cours sur Symfony, lors de la modélisation des entités, vous avez sans doute croisé le CASCADE DELETE quand vous aviez deux entité avec une relation oneToMany.

Exemple de situation où un cascade delete est utile

Par exemple une entité Category a une relation de un à plusieurs avec l’entité Product. Quand vous effacez une catégorie, et pour éviter que des produits se retrouvent sans catégorie, vous allez aussi effacer les produits correspondant à cette catégorie. Il y a effacement en cascade, l’effacement de la catégorie efface automatiquement les produits rattachés.

En SQL vous pouvez mettre une contrainte de CASCADE DELETE de cette façon :

CREATE TABLE utilisateurs (
    id INT PRIMARY KEY,
    nom VARCHAR(100)
);

CREATE TABLE commandes (
    id INT PRIMARY KEY,
    utilisateur_id INT,
    FOREIGN KEY (utilisateur_id) REFERENCES utilisateurs(id) ON DELETE CASCADE
);

Ce n’est pas avec Category et Product mais vous l’aurez compris. Si vous n’avez pas fait de contrainte, vous devriez le faire manuellement.

DELETE FROM commandes WHERE utilisateur_id = 1;
DELETE FROM utilisateurs WHERE id = 1;

C’est un peu fastidieux, et pas garanti dans la théorie, il peut se produire un événement qui fait que la seconde requête ne soit pas exécutée (même si c’est peu probable, mais si nous considérons une application de grande échelle et profesionnelle, on ne peut tolérer çà)

Donc pour garantir que les deux requêtes sont exécutées, nous devons utiliser le mécanisme de transaction.

Qu’est ce qu’une transaction?

Imaginez que vous retirez du cash à un ATM, vous entrez votre code vous récupérez votre carte, mais à la fin vous ne percevez pas vos billets et le ticket sort avec une erreur. Vous vous demandez si votre compte en banque ne s’est pas diminué de la somme que vous vouliez retirer, malgré le fait que vous n’avez pas perçu vos billets ! (rassurez vous ce n’est pas le cas !). le mécanisme de transaction fait que comme le s billets ne sont pas sortis, le débit sur votre compte n’est pas effectif.

Eh bien c’est le même mécanisme dans la requêtes SQL.

START TRANSACTION;

DELETE FROM commandes WHERE utilisateur_id = 1;
DELETE FROM utilisateurs WHERE id = 1;

COMMIT;

Dans MySQL, par défaut vous êtes en AUTOCOMMIT, mais dans l’absolu, une requête SQL doit avoir la forme ci-dessus.

Si une des requêtes échoue, il se produira un ROLLBACK, pour revenir à un état comme si rien ne s’est passé.

BEGIN;

DELETE FROM commandes WHERE utilisateur_id = 42;
DELETE FROM utilisateurs WHERE id = 42;

-- Si les 2 passent bien
COMMIT;

-- Si erreur ou condition non respectée
ROLLBACK;
// Dans la console SQL, vous pouvez explicitement faire un ROLLBACK pour annuler une requête si le COMMIT n'est pas invoqué

Le mécanisme de cascade avec PDO en PHP

function deleteQuestion(PDO $pdo, int $id): array
{
    try {
        // Démarrer la transaction
        $pdo->beginTransaction();

        // Supprimer d'abord les réponses
        $stmt = $pdo->prepare("DELETE FROM reponses WHERE fk_question = :id");
        $stmt->execute(['id' => $id]);

        // Puis supprimer la question
        $stmt = $pdo->prepare("DELETE FROM questions WHERE id = :id");
        $stmt->execute(['id' => $id]);

        // Tout est ok → commit
        $pdo->commit();

        return ['success' => true];
    } catch (Exception $e) {
        // En cas d'erreur → rollback
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }
        return ['success' => false, 'error' => $e->getMessage()];
    }
}

Si vous êtes codeur, cette façon de procéder paraitra plus simple :

Utilisation des vraies méthodes transactionnelles de PDO (beginTransaction, commit, rollBack).

Exécution séparée des requêtes (plus clair et plus sûr que tout mettre dans une seule string).

Retour structuré (['success' => true] ou ['success' => false, 'error' => ...]) pour facilement tester côté front.

Typage de la fonction (PDO $pdo, int $id : array) → un peu plus robuste.

Travaillez plus efficacement avec les workspace de VSCode

Je vous présente les workspaces qui vont vous permettre de travailler plus efficacement même si vous n’avez qu’un seul projet.

Je vais prendre pour exemple mes dossiers de formation par langage. J’enseigne le HTML/CSS, PHP, Python, Javascript et donc au moins 3 dossiers. J’aimerais lorsque je montre un exemple avoir accès à ces 3 dossiers.

Avant :

Soit j’ouvrais plusieurs fois le dossier pour trouver mon exemple de code, soit j’ouvrais plusieurs fenêtres (car j’ai tellement de codes que je ne me souviens plus)

Après :

Avec les workspaces, j’ai sous la main tous ces dossiers et je peux chercher facilement sans ouvrir de VSCode supplémentaires. Vous pouvez sauver votre configuration dans un fichier workspace et réouvrir exactement comme c’était la prochaine fois.

Les autres avantages des workspaces :

Des paramètres par workspace

Connaissez vous le setting.json dans .vscode (le fichier que vous aimez ignorer dans git), il contient par exemple alversion de l’interpréteur, le ty pe d’indentationi, le linting, thème de l’éditeur.

Extensions par workspace

je peux activer ou désactiver des extensions par workspaces !

Configuration de debug par workspace

On peut avoir un fichier launch.json pour lancer et déboguer avec les bon paramètres, NodeJs dans un projet, ou React dans un autre.

Multiroot workspace

On peut avoir plusieurs dossiers indépendants dans un même workspace, utile quand vous faites un monorepo par exemple : un back end en nodeJS, un front reactJS, avec un Golive qui ne réagit qu’au changement de fichier que dans le dossier front end.

Task spécifique au workspace

Le fichier tasks.json (build, test, script etc) permet de définir des tâches automatisées, qu’on peut voir dans le menu Terminal > Run Task

Les shells

Dans le terminal, vous pouvez ouvrir plusieurs shells, mais en l’absence de workspace, ce n’est pas mémorisé, saviez vous que vous pouvez changer la couleur du label du shell? Grâce au workspace, ce setting sera mémorisé.

Utilisation d’un task pour automatiser l’ouverture de terminaux

Voici le script

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Task A",
            "type": "shell",
            "command": "echo Running Task A",
            "presentation": {
                "group": "startup-group1",
                "panel": "dedicated",
                "reveal": "silent",
                "clear": true
            }
        },
        {
            "label": "Task B",
            "type": "shell",
            "command": "echo Running Task B",
            "presentation": {
                "group": "startup-group2",
                "panel": "dedicated",
                "reveal": "silent",
                "clear": true
            }
        },
        {
            "label": "Startup",
            "dependsOn": [
                "Task A",
                "Task B"
            ],
            "dependsOrder": "sequence", // <--- important: runs sequentially, not in parallel
            "runOptions": {
                "runOn": "folderOpen"
            }
        }
    ]
}

Version Linux

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Task A",
            "type": "shell",
            "command": "echo Running Task A",
            "presentation": {
                "group": "startup-groupA",
                "panel": "dedicated",
                "reveal": "silent",
                "clear": true
            }
        },
        {
            "label": "Task B",
            "type": "shell",
            "command": "echo Running Task B",
            "presentation": {
                "group": "startup-groupB",
                "panel": "dedicated",
                "reveal": "silent",
                "clear": true
            }
        },
        {
            "label": "Task C (Bash)",
            "type": "shell",
            "command": "echo Running Task C with Bash",
            "options": {
                "shell": {
                    "executable": "/bin/bash"
                }
            },
            "presentation": {
                "group": "startup-groupC",
                "panel": "dedicated",
                "reveal": "silent",
                "clear": true
            }
        },
        {
            "label": "Startup",
            "dependsOn": [
                "Task A",
                "Task B",
                "Task C (Bash)"
            ],
            "dependsOrder": "sequence",
            "runOptions": {
                "runOn": "folderOpen"
            }
        }
    ]
}

Pas besoin de trouver gitbash, car sous Linux bash est par défaut.

Comprendre le mot clé this

Une subtilité en Javascript que dorénavant les dév junior ne connaissent pas

En javascript, le mot clé this peut se comporter de façon inattendue. Pour les personnes qui sont habituées à programmer en Java ou en C++, le mot clé 10 représente l’objet lui-même.

En JavaScript, le mot clé this aussi représente un objet, mais cela dépend de sa position dans le code. Nous allons voir que dans une fonction qui fait appel au mot clé 10, dans un console.log par exemple, le mot clé this représente l’objet dans lequel il se trouve, ou non. Nous allons voir que dans une fonction qui fait appel au mot clé 10, dans un console.log par exemple, le mot clé this représente l’objet dans lequel il se trouve, ou non. Nous allons voir que dans une fonction qui fait appel au mot clé this , dans un console.log par exemple.

"use strict";

let utilisateur = {
  nom: "Alice",
  direNom: function() {
    console.log("dans direNom -> this.nom =", this.nom);

    function interne() {
      console.log("dans interne -> this.nom =", this.nom);
    }

    interne();
  }
};

utilisateur.direNom();

// sortie
dans direNom -> this.nom = Alice
dans interne -> this.nom = undefined   // ou Window.nom si non strict

Pourquoi donc this change de forme?

utilisateur.direNom()
Ici, this est lié à l’objet utilisateur, donc this.nom = "Alice".

Fonction interne()
Même si elle est définie à l’intérieur de direNom, elle est appelée comme une fonction simple (pas comme une méthode d’objet).
→ Dans ce cas, this ne fait plus référence à utilisateur.

  • En mode strict, this = undefined.
  • En mode non strict, this = window (dans un navigateur).

En bref la fonction direNom est une propriété de l’objet utilisateur, donc possède un this. La fonction interne() est une fonction non attachée à une propriété de l’objet utilisateur. En strict il vaut undefined, et en non strict il vaut window !

Comment contourner ce piège classique?

Méthode avec that = this

On a le très populaire that = this

"use strict";

let utilisateur = {
    nom: "Alice",
    direNom: function () {
        console.log("dans direNom -> this.nom =", this.nom);
        let that = this
        function interne() {
            console.log("dans interne -> this.nom =", that.nom);
        }

        interne();
    }
};

utilisateur.direNom();

Méthode avec un binding de contexte

Le binding de contexte permet de dire dans le fonction à quoi correspond le this

"use strict";

let utilisateur = {
    nom: "Alice",
    direNom: function () {
        console.log("dans direNom -> this.nom =", this.nom);

        function interne() {
            console.log("dans interne -> this.nom =", this.nom);
        }

        // on lie la fonction interne au contexte courant (this = utilisateur)
        let interneLie = interne.bind(this);

        interneLie();
    }
};

utilisateur.direNom();

Notez que l’on déclare une nouvelle variable pour faire le binding

Méthode avec une fonction flèche

Les fonction flèche n’ont pas leur propre this, donc ils héritent du this du parent.

"use strict";

let utilisateur = {
    nom: "Alice",
    direNom: function () {
        console.log("dans direNom -> this.nom =", this.nom);

        // fonction fléchée : hérite du this de direNom
        const interne = () => {
            console.log("dans interne -> this.nom =", this.nom);
        };

        interne();
    }
};

utilisateur.direNom();

A noter que ici on a une fonction définie dans une autre fonction, en programmation fonctionnelle on appelle cela une closure.

Pour aller plus loin :

7 arrow functions tricks to fix this issue

Tester une application ReactJS avec Vitest

Dans cet article nous allons mettre en place très simplement une application ReactJS avec un test. Nous allons partir de zéro, on va bootstrapper une application très simple et mettre en place Vitest et lancer notre premier test.

Installation de l’application

Nous allons utiliser Vite

npm create vite@latest react-vitest-demo

cd react-vitest-demo
npm install

Vitest fonctionne comme Jest mais avec les module ESM. J’ai eu des soucis à faire fonctionner Jest avec les modules ESM. Donc Vitest vient à point nommé.

Cependant on va utiliser des librairies de Jest (le framework de test) comme @testing-library/react et @testing-library/jest-dom

npm install -D vitest @testing-library/react @testing-library/jest-dom

ensuite il faut configurer le fichier de configuration de vite vite.config.js

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/setupTests.js'
  }
})

Plus spécifiquement il y a un fichier de setup, qui va initialiser jest-DOM pour avoir des matchers pratiques comme toBeInTheDocument(), dans src/setupTests.js

import '@testing-library/jest-dom'

Il manque un composant à installer jsdom

npm i -D jsdom

Création d’un composant à tester

On va créer un simple composant Hello.jsx

export default function Hello({ name }) {
  return <h1>Hello {name}!</h1>
}

Ainsi que le test du composant

import { render, screen } from '@testing-library/react'
import Hello from './Hello'

test('affiche le nom passé en prop', () => {
  render(<Hello name="Yvon" />)
  expect(screen.getByText(/Hello Yvon!/i)).toBeInTheDocument()
})

On va lancer le test avec la command npm test, donc il faut que dans le package.json, ce script soit présent.

"scripts": {
  "dev": "vite",
  "build": "vite build",
  "preview": "vite preview",
  "test": "vitest",
  "test:ui": "vitest --ui"
}

Pour lancer le test:

npm test

Le résultat

PS E:\react-vitest-demo> npm test

> react-vitest-demo@0.0.0 test
> vitest


 DEV  v3.2.4 E:/react-vitest-demo

 ✓ src/Hello.test.jsx (1 test) 16ms
   ✓ affiche le nom passé en prop 16ms

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  22:09:08
   Duration  675ms (transform 25ms, setup 70ms, collect 68ms, tests 16ms, environment 325ms, prepare 58ms)

 PASS  Waiting for file changes...
       press h to show help, press q to quit

Avoir un visuel de ce que vous testez

Pour ce faire il faut installer le package vitest/ui

npm run test:ui

Test d’un composant interactif (Compteur incrémental)

Code du composant Counter

import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  )
}

Code du composant de test du Counter

import { render, screen, fireEvent } from '@testing-library/react'
import Counter from './Counter'

test('incrémente le compteur quand on clique', () => {
  render(<Counter />)
  const button = screen.getByText('+1')
  fireEvent.click(button)
  expect(screen.getByText(/Count: 1/i)).toBeInTheDocument()
})

Test en ligne de commande

Test graphique

Mise en oeuvre des tests dans Github Actions

L’idée est d’automatiser le déploiement de votre application quand vous faites un git push, avouez que c’est super non? En effet à l’ancienne vous deviez vous connecter à votre terminal de serveur puis faire un git pull. Bien qu’il y ait les webhook de github, qui permettent de s’affranchir de cette étapes, ces derniers ne permettaient pas de faire des processus de déploiement plus sophistiqués. Cet article sur Github Action va vous montrer comment simplement mettre en oeuvre pour un projet front-end, ce processus de déploiement.

Quelle version de Laragon gratuite choisir ?

J’ai actuellement Laragon version 6, et j’en suis très content. cependant, une histoire de dingue est arrivée à son créateur, vous pouvez lire ici, et depuis il a décidé de mettre en payant son logiciel.

Ceux d’entre vous qui ont installé une version postérieur voient une popup demande d’entrer une clé. Il n’est pas obligatoire de le faire, mais cette alerte revient tout le temps.

Libre à vous de supporter le travail de ce monsieur, mais il est possible d’avoir une version gratuite et sans rappel de payer, c’est la version 6

Comment installer la version 6 de Laragon?

Pour installer la dernière version de Laragon, il faut aller sur le Github du projet, ensuite il faut aller sur la section release, et sélectionner la version 6. Des liens apparaitront pour télécharger l’exécutable.

Dans la page d’accueil du projet donc, faite CTRL + F et cherchez le mot “release”, cliquez sur le lien, vous tomberez sur la page des release. Sélectionnez dans la liste déroulante la version 6 et voilà !

Laragon n’est que sur Windows.

Pourquoi j’utilise Laragon?

J’ai utilisé pendant des années (plus de 10 ans) WAMP, et j’ai tout de suite adopté Laragon, car la configuration est plus ergonomique, on gagne du temps (détection de projet dans le répertoire www). ça me fait gagner du temps.

Paradoxalement, je suis aussi partisan de mettre en place à la main, une solution comme WAMP, et de surcroît sur Linux. Je vous mets le lien vers le tutoriel Administration Linux avec Nginx et PHP FPM

Sur MacOS, il y a moins de choix comme solution intégrée, je ne connais que MAMP.

Créer des alias sous Linux

Les alias permettent de remplacer des commandes longues à taper par des commandes plus courte ou plus facile à mémoriser.

Création d’un alias

la commande ls est pratique, et encore plus ls -l, qui liste les fichiers avec des information sur les droits et propriétaires.

C’est un peu long de taper ls -l, souvent on alias vers ll (parfois sur certaines distribution c’est déjà créé)

alias  // liste les alias

alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'


// aliaser ls -la en ll
alias ll='ls -la'
alias ls='ls --color=auto'

// autre exemple
alias authlog="sudo tail -f /var/log/auth.log"

Comprendre le CORS et les requêtes Preflight

Qu’est ce que le CORS?

CORS veut dire Cross Origin Resource Sharing ou en français partage des ressources inter origines. bon dit comme ça ça veut pas dire grand chose. En gros, quand vous faites une requêtes AJAX, vous le faites depuis (en formation informatique) votre poste local localhost. Imaginons que vous vouliez faire une requête AJAX vers le site OpenWeatherMap.org, vous voyez bien que le nom de domaine est différent de localhost. Eh bien on a là un cas de requêtes AJAX Cross Origin.

Pourquoi parle t on de CORS?

Le web est un monde ouvert où on peut faire à peu près n’importe quoi. Il y a des considération de sécurité, concept très important dans un monde ouvert. Ici avec le CORS on fait la distinction entre les requêtes AJAX internes et les requêtes AJAX venants d’un autre site web. Je trouve personnellement que c’est fantastique qu’il soit possible de partager des informations entre sites web.

Les requêtes AJAX internes

Quand vous développez un front en en Javascript (Javascript pur ou ReactJS ou Angular peu importe) vous faites des requêtes AJAX locales pour tirer des informations à afficher. Vous requêtez votre serveur qui est dans le même nom de domaine que le code Javascript qui fait la requête. Dans ce cas il n’est pas de problème de CORS, tout est sur un même domaine.

Ce cas de figure, c’est la majorité des applications modernes, donc vous n’êtes pas confronté au problème de CORS.

Les requêtes externes

Mais imaginez que vous développiez une application IOS ou Android, dans ce cas vous ferez face à des problème de CORS. En effet la requête réseau ne provient pas du site web du serveur, donc ce sera considéré comme une requête CORS. Si vous ne faites rien côté serveur vous n’allez pas pouvoir servir le contenu à l’application mobile.

Le problème du CORS se règle côté serveur et non côté client.

Ayez le réflexe de regarder du côté du serveur pour résoudre le problème de CORS. Vous ne pouvez rien faire du côté du client. Nous allons regarder un exemple avec un code PHP.

Supposons que le code serveur ci-dessous se trouve sur le domaine localhost:

http://localhost/index.php
echo json_encode(['message' => 'Bonjour']);

Voici le code côté client en javascript : http://localhost/caller.html

fetch('http://localhost/index.php')
.then(response => response.json())
.then( data => console.log(data))

Le fichier dans lequel réside le Javascript est dans le domaine localhost, donc pas de problème de CORS. Mais regardons le cas suivant

http://localhost/index.php
echo json_encode(['message' => 'Bonjour']);

Voici le code côté client en javascript : http://127.0.0.1/caller.html

fetch('http://localhost/index.php')
.then(response => response.json())
.then( data => console.log(data))

Cette fois ci nous avons u problème de CORS en effet localhost n’est pas pareil que 127.0.0.1 bien que d’un point de vu résolution de chemin ce soit la même chose !

Mise en place du CORS en PHP

Comme la solution est du côté du serveur, nous allons ajouter à la réponse du serveur des en-têtes pour permettre au CORS de fonctionner.

header('Content-Type: application/json');
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400');    // cache for 1 day

echo json_encode(['message' => 'Bonjour']);

Ce qui est important c’est le Access-Control-Allow-Origin, qui va permettre de faire du CORS. Ici on a mis un astérisque qui désigne tous les domaines, mais on peut restreindre à un domaine en particulier.

Les requêtes PREFLIGHT

Maintenant que vous savez faire du CORS affinons le sujet avec les requêtes Preflight. Elles sont envoyées par le navigateur pour “sonder” le serveur dans le cas de requêtes CORS. Le verbe HTTP est OPTIONS. Cette requête est automatiquement envoyée par le serveur, le développeurs front end n’a pas à s’en soucier.

Le serveur quand il reçoit cette requêtes OPTIONS doit répondre avec Access-Control-Allow-Method

header( 'Access-Control-Allow-Methods: GET, POST, OPTIONS' );

Installer une application API Platform (Symfony) React avec Symfony CLI

Si vous ne l’avez pas déjà fait téléchargez symfony CLI sur le site officiel. C’est un binaire donc en fonction de votre plateforme, ce n’est pas le même programme.

Un peit mot avnagt de commencer,ici on va installer API Platform en tant que bundle de Symfony, et ReactJS dans un répertoire indépendant. Symfony propose aussi d’installer ReactJS comme un greffon de Twig, personnellement je n’ai pas réussi à le faire marcher, les composants ne se renderisaient pas. Je préfère quand le front et le back sont séparés (pas de monorepo), car le webservice doit servir d’autres plateformes (mobile par exemple)

Démarrage du projet

Vérifiez que vous êtes en PHP 8.2 (Recommandé)

symfony new bookshop-api
cd bookshop-api

Etape importante installation du bundle:

symfony composer require api

Création de la base de donnée:

symfony console doctrine:database:create
symfony console doctrine:schema:create

// si vous avez des soucis sous MAMP pour créer la base de données, sachez que e port de MySQL n'est aps 3306 et 


Puis lancement du serveur avec Symfony CLI
symfony serve

Accéder à votre site

Symfony CLI va vous donner votre url pour le site. Il faut savoir qu’avec API Platform, vous n’avez pas de front end pour votre site. Le front end va être assuré par ReactJs qui sera complètement indépendant dans sa structure de fichiers d’API Platform.

http://localhost:8000/

Votre webservice est accessible à l’url http://localhost:8000/api ! cela intéresse ReactJS. Voici ce que vous verrez si vous accéder à cette url.

L’interface que vous voyez est Swagger, une librairie de documentation interactive de votre webservice. Il est important lorsque vous travaillez avec API Platform que vous devez oubliez ce que vous avez appris avec une application Symfony classique sauf pour les entités.

Création d’une entité Book

Copiez le code suivant (extrait de la documentation officielle)

<?php
// src/Entity/Book.php
namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

/** A book. */
#[ORM\Entity]
#[ApiResource]
class Book
{
    /** The ID of this book. */

    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    private ?int $id = null;

    /** The ISBN of this book (or null if doesn't have one). */
    #[ORM\Column(nullable: true)]
    public ?string $isbn = null;

    /** The title of this book. */
    #[ORM\Column]
    public string $title = '';

    /** The description of this book. */
    #[ORM\Column(type: 'text')]
    public string $description = '';

    /** The author of this book. */
    #[ORM\Column]
    public string $author = '';

    /** The publication date of this book. */
    #[ORM\Column]
    public ?\DateTimeImmutable $publicationDate = null;

    /** @var Review[] Available reviews for this book. */
    #[ORM\OneToMany(targetEntity: Review::class, mappedBy: 'book', cascade: ['persist', 'remove'])]
    public iterable $reviews;

    public function __construct()
    {
        $this->reviews = new ArrayCollection();
    }

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

Allez maintenant dans l’adresse de la documentation de votre API http://localhost:8000/api

Créez une seconde entité Review

<?php
// src/Entity/Review.php
namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use Doctrine\ORM\Mapping as ORM;

/** A review of a book. */
#[ORM\Entity]
#[ApiResource]
class Review
{
    /** The ID of this review. */
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    private ?int $id = null;

    /** The rating of this review (between 0 and 5). */
    #[ORM\Column(type: 'smallint')]
    public int $rating = 0;

    /** The body of the review. */
    #[ORM\Column(type: 'text')]
    public string $body = '';

    /** The author of the review. */
    #[ORM\Column]
    public string $author = '';

    /** The date of publication of this review.*/
    #[ORM\Column]
    public ?\DateTimeImmutable $publicationDate = null;

    /** The book this review is about. */
    #[ORM\ManyToOne(inversedBy: 'reviews')]
    public ?Book $book = null;

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

Voici ce que vous devriez voir dans la documentation

Les annotation Doctrines sont déjà présentes dans le code car je les ai déjà ajoutées. Vous devez les ajouter pour toute nouvelle entité que vous créez. C’et nécessaire pour faire la migration et ainsi créer des tables dans la base de données.

php bin/console make:entity --api-resource.  // permet d'annoter

Migration vers la base de données

Tapes les lignes suivantes pour faire la migration

bin/console doctrine:migrations:diff
bin/console doctrine:migrations:migrate

Si la migration des tables est faites sans problème nous allons pouvoir commencer !

Opération CRUD avec Swagger

Nous n’allons pas Postman pour faire nos requêtes AJAX mais directement dans Swagger, c’est l’intérêt de l’outil.

Allez dans Swagger, Book puis cliquez sur POST, une fenêtre se déroule, cliquez sur “Try it out”. Collez le json suivant dans le champs “Request body”

{
  "isbn": "9781782164104",
  "title": "Persistence in PHP with the Doctrine ORM",
  "description": "This book is designed for PHP developers and architects who want to modernize their skills through better understanding of Persistence and ORM.",
  "author": "Kévin Dunglas",
  "publicationDate": "2013-12-01"
}

Puis cliquez sur Execute.

Vérifiez que dans la table Book vous avez une entrée correspondante. Passez à l’insertion d’une review

{
  "book_id": "/books/1", // ou "/api/books/1
  "rating": 5,
  "body": "Interesting book!",
  "author": "Kévin",
  "publicationDate": "September 21, 2016"
}

Ici on a saisi directement l’id du Book, dnas la réalité, vous devez faire un GET des Book, puis lire l’id de celui que vous voulez faire une Review.

Introduction au scripting shell+

Eléments d’un script shell

Un script shell est un fichier texte rendu exécutable en ligne de commande. La première ligne du fichier contient une ligne spéciale appelée shebang #!, suivi du chemin absolu vers l’interpréteur shell, qui peut être bash sh ou zsh, voire même un interpréteur python

#!/bin/bash

#!/bin/zsh

#!/usr/bin/python

Si vous omettez le shebang, alors c’est le shell courant qui est utilisé, mais dans ce cas il n’y aucune garantie que le script est compatible avec votre shell courant, donc il est très conseillé de le spécifier.

Les variables

Une variable est en majuscule et en snake case

#!/bin/bash
MY_SHELL="bash"
NOM_SERVEUR=$(hostname)   // ou NOM_SERVEUR=`hostname`  ancienne syntaxe
echo "J'aime mon $MY_SHELL shell."

echo "J'aime mon ${MY_SHELL}ing shell." // la syntaxe avec accolade permet de concaténer

Généralement les nom de variable valide suivent la m^me règle que dans les langages de programmation

Contrôle d’exécution

Les tests (équivalent de if else)

Syntaxe :
[ condition-a-tester]
exemple :
[-e /etc/passwd]   // teste si le fichier /etc/passwd existe
Autres exemples :
-d NOM_FICHIER True si fichier est un répertoire
-e NOM_FICHIER True si le fichier existe
-f NOM_FICHIER True si le fichier existe et est un fichier ordi
-r NOM_FICHIER True si le fichier readable par moi
-s NOM_FICHIER True si le fichier existe et est non vide
-w NOM_FICHIER True si le fichier est writable par moi
-x NOM_FICHIER True si le fichier est exécutable par moi

-z STRING True si string est vide
-n STRING True si string est non vide
STRING1 = STRING2 égalité
STRING1 != STRING2 inégalité   # attention un seul signe égal !!

#Tests arithmétiques
arg1 -eq arg2  True si arg1 est égal à arg2
arg1 -ne arg2  True si arg1 est égal à arg2
arg1 -lt arg2  True si arg1 est less than à arg2
arg1 -le arg2  True si arg1 est less or equal à arg2
arg1 -gt arg2  True si arg1 est greater than à arg2
arg1 -ge arg2  True si arg1 est gretaer or equal à arg2

Branchement conditionnel

Syntaxe générale:
if [ condition-est-vraie ]
then
    commande 1
    commande 2
    commande 3
fi

# exemple :
#!/bin/bash
AGE=34
if [ "$AGE" -eq 18 ]; // ici il faut entourer AGE de guillements et préfixer AGE d'un signe dollar
then
        echo "vous avez ${AGE} vous êtes une personne mineure"
else
        echo "vous avez ${AGE} vous êtes une personne majeure"
fi


# multiple condition avec elif

#!/bin/bash

AGE=20

if [ "$AGE" -lt 18 ]; then
    echo "Vous êtes mineur."
elif [ "$AGE" -eq 18 ]; then
    echo "Vous avez exactement 18 ans."
else
    echo "Vous êtes majeur."
fi


# ET et OU

#!/bin/bash

AGE=20
CITOYEN="oui"

if [ "$AGE" -ge 18 ] && [ "$CITOYEN" = "oui" ]; then
    echo "Vous pouvez voter."
else
    echo "Vous ne pouvez pas voter."
fi


# avec CASE

#!/bin/bash

JOUR="samedi"

case "$JOUR" in
    "lundi"|"mardi"|"mercredi"|"jeudi"|"vendredi")
        echo "C'est un jour de travail."
        ;;
    "samedi"|"dimanche")
        echo "C'est le week-end !"
        ;;
    *)
        echo "Jour inconnu."
        ;;
esac

On va pousser le script un peu plus loin avec la récupération dynamique du jour, ainsi on n’a plus besoin de coder en dur.

Mais auparavant on va installer pour nous assurer sur le locale franançais est installé

locale

LANG=fr_FR.UTF-8
LANGUAGE=
LC_CTYPE="fr_FR.UTF-8"
LC_NUMERIC="fr_FR.UTF-8"
LC_TIME="fr_FR.UTF-8"
LC_COLLATE="fr_FR.UTF-8"
LC_MONETARY="fr_FR.UTF-8"
LC_MESSAGES="fr_FR.UTF-8"
LC_PAPER="fr_FR.UTF-8"
LC_NAME="fr_FR.UTF-8"
LC_ADDRESS="fr_FR.UTF-8"
LC_TELEPHONE="fr_FR.UTF-8"
LC_MEASUREMENT="fr_FR.UTF-8"
LC_IDENTIFICATION="fr_FR.UTF-8"
LC_ALL=

si vous ne voyez pas ça c'est que ce n'est pas installé. Faites la commande suivante :

Linux installer le locale français

Si vous êtes sous wsl, il se peut que vous soyez toujours dans le système anglais, nous allons installer le locale français.

sudo locale-gen fr_FR.UTF-8
sudo update-locale LANG=fr_FR.UTF-8
sudo reboot
# ou redémarrer votre shell (dans le cas de wsl également)
# et refaite locale
locale


Après faites la commande date 
$ date
sam. 08 mars 2025 16:17:23 CET
Pour avoir le jour 
$ date +%A
samedi
# voilà vous avez tout pour recorriger le programme

Nouveau script avec le jour de semaine dynamique :

#!/bin/bash

JOUR=$(date +%A)

case "$JOUR" in
    "lundi"|"mardi"|"mercredi"|"jeudi"|"vendredi")
        echo "C'est un jour de travail."
        ;;
    "samedi"|"dimanche")
        echo "C'est le week-end !"
        ;;
    *)
        echo "Jour inconnu."
        ;;
esac

Les boucles en shellscript

Boucle for

Sans doute le plus facile

#syntaxe générale
for VARNAME in ITEM1 ITEM2
do
   command 1
   command 2
done

# exemple

#!/bin/bash
for COULEUR in rouge vert bleu
do
        echo  "COULEUR: $COULEUR"
done

# variante

#!/bin/bash
for COULEUR in rouge vert bleu
do
        echo  "COULEUR: $COULEUR"
done

Générer une séquence pour la boucle for

#générer avec seq (séquence)

#!/bin/bash
for i in $(seq 1 10)
do
        echo $i
done

Exemple plus élaboré de script shell très utile

Supposons que nous voulions renommer des fichier images avec le nom du fichier avec la date du jour au formation numérique

Pour ce faire nous allons dans notre répertoire télécharger avec wget ou curl des images prise sur internet

wget -O image1.jpg http://source.com/imagealeatoire.jpg
l'argument -O permet de renommer le fichier sauvé
#!/bin/bash
# on liste les fichiers images avec la commande ls et on  mets le résultat dans une variables
IMAGES=$(ls *jpg)
DATE=$(date +%F)
for IMAGE in $IMAGES
do 
   echo "renommage de ${IMAGE} en ${IMAGE}-${DATE}"
   mv ${IMAGE} ${IMAGE}-${DATE}
done 

Le script marche mais n’est pas optimale car la date se rajoute à l’extension et nom au nom de fichier. Essayez de résoudre ce problème. (indice utiliser la fonction $(basename “$path”)

# solution

#!/bin/bash
IMAGES=$(ls *jpg)
DATE=$(date +%F)
for IMAGE in $IMAGES
do
        FILENAME="${IMAGE%.*}"
        EXT="${IMAGE##*.}"
        echo "renommage de $IMAGE en ${FILENAME}-${DATE}.${EXT}"
        mv ${IMAGE} ${FILENAME}-${DATE}.${EXT}
done

Boucle while





Paramètres positionnels

Quand vous exécutez un script vous pouvez passer des paramètres

$monscript.sh param1 param2 param3

Dans votre script vous pouvez y faire référence avec $1, $2 etc $0 représente le script lui-même.

#exemple de script pour archiver une utilisateur
echo "Executing script : $0"
echo "Archiving user : $1"
#lock the account
passwd -l $1

# create the archive of the home directory
tar cf /archvies/$[1}.tar.gz /home/${1}

#accès à tous les paramètres positionnels
for USER in $@   # suppose que tous les arguments sont des users
...

Lire les entrées claviers

#!/bin/bash
read -p "Entrez un nom utilisateur:  " USER
echo "Archivage de l'utilisateur: $USER"
...

Exercice : pratiquer le script d’archivage avec l’entrée au clavier, et au passage d’arguments multiples

Les fonctions

#!/bin/bash

greet_user(){
echo -n "Entre ton prénom "
read nom
echo "Bonjour $nom ! Comment vas tu $1?"

greet_user "$1"



#Exécuter le script 
$ ./greet.sh gros

Mettez en place une authentification JSON dans Symfony

Dans le parcours sur symfony, je n’ai pas parlé de l’authentification via webservice. On va aborder cet aspect dans cet article.

Se connecter via un webservice est intéressant à savoir si on veut développer un front indépendant de type ReactJs ou AngularJS , ou même une application mobile, votre symfony servant de backend. D’abord il faut ajouter quelques ligne dans votre security.yaml:

security.yaml

# config/packages/security.yaml
security:
    # ...

    firewalls:
        main:
            anonymous: lazy
            json_login:
                check_path: /jsonlogin
                username_path: security.credentials.email
                password_path: security.credentials.password
SecurityController : ajoutez ce code dans le controller

    /**
     * @Route("/jsonlogin", name="jsonlogin", methods={"POST"})
     */
    public function jsonlogin(Request $request): Response
    {
        $user = $this->getUser();

        return $this->json([
            'email' => $user->getEmail(),
            'roles' => $user->getRoles(),
        ]);
    }

Utiliser POSTMAN pour envoyer une requête de type POST et dont le content type est application/json vers la route jsonlogin

POSTMAN

Vous devez envoyer un Json, tel que dans l’image. (pas en tant que variable POST)

Le serveur va vous répondre avec un PHPSESSION_ID en retour. Pourquoi pas un Json Web Token? parce que basiquement c’est ce qui se passe. Mais le fonctionnement du PHPSESSION_ID est similaire, vous devez le renvoyer pour accéder à des partie du site web qui ncessitent un authentification.

Une fois la requêtes POST envoyée, si tout se passe bien, on reçoit comme prévu la réponse ci-dessus (voir le code controller plus haut). Et l’image ci-dessous nous montre le PHPSESSION_ID qu’on doit récupérer et sauver pour les reuq^tes subséquentes.

Pour sauver le Cookie (PHPSESSION_ID) cliquez dans POSTMAN le lien Cookie

Une modale va apparaître, vous devez entre le nom de domaine pour ce cookie

Une fois le domaine entré l ePHPSESSION_ID s’affiche

Vous êtes prêt pour faire une requête authentifiée !

Requête vers la page d’ajout de produit

Grâce à notre cookie sauvegardé, on aaccès à al page d’ajout de produit qui a besoin d’être authentifié

Requête GET vers la même page mais en ayant effacé les cookies

Regardez le code HTML, c’est celui de la page de login !

J’espère que ce petit tuto vous a plu et vous a permis de mieux comprendre le mécanisme d’authentification HTTP.

Note concernant la structure du json d’authentification

Dans le security yaml vous donnez un indice à Symfony sur la structure du json envoyé, par défaut la strucutre est:

#structure de base
{
    "email": "admin@gmail.com",
    "password": "123"
}

dans notre cas :
{
    "security": {
        "credentials": {
            "email": "admin@gmail.com",
            "password": "123"
        }
    }
}


# security.yaml
...
            json_login:
                check_path: /jsonlogin
                username_path: security.credentials.email
                password_path: security.credentials.password
...

Développeur apprenez Linux ! Ce n’est pas si difficile que ça.

Voici un liste de commande Linux pour débutant puis une seconde liste un peu plus intermédiaire

Liste de commande pour débutant en Linux

ls : liste les fichier et dossiers
cp : copier un fichier ou un dossier
mv : déplace ou renomme un fichier ou dossier
find : chercher un fichier ou des fichiers ou dossiers
pwd : savoir dans quel répertoire je me trouve actuellemnet
cat : affiche le contenu textuel d'un fichier
tail : affiche les n lignes de fin d'un fichier
head : afficher les n ligne de début d'un fichier
chown : change le propriétaire d'un fichier
chmod : change les droits d'accès d'un fichier
sudo : invoque le mode root (super utilisateur) pour avoir des privilèges élevés
su : change d'utilisateur
tar : archive des fichier, utile pour 
gzip, gunzip : compresse un fichier, généralement on compresse une archive, tar dispose d'un mode d'archivage avec compression
rm : efface un fichier ou un groupe de fichier ou un dossier de façon récursive.
touch : crée un fichier texte
mkdir : crée u fichier ou un répertoire
rmdir : efface un répertoire

Liste de commandes plus intermédiaire pour Linux

grep : permet de chercher les fichiers contenant une chaine de caractères
zcat : comme la commande cat mais pour les fichiers compressés
truncate : coupe le contenu d'un fichier, en spécifiant la position de découpe 0 pour vider le fichier
wget : télécharge une resource (http par exemple)
curl : utilitaire très connu pour des opération de transmission réseau
sed : utilitaire puissant travaillant en colonne, permet de découper verticalement un fichier
awk : un peu comme sed
ps : liste les process en cours d'exécution
jobs : liste les programmes s'exécutant en arrière plan
fg, bg : met un process en avant plan, bg met en arrière plan, ce qui libère le shell pour une autre commande
& : invoque une commande et la mets en arrière plan
> : dirige un contenu texte vers un fichier
>> : ajoute à la fin d'un fichier texte une chaine de texte
xargs : permet de chainer les commandes,la sortie d'une première commande sera en entrée de la seconde commande
| (pipe) : perme de chainer les commande.
adduser : 
chgrp : change le groupe d'appartenance d'un fichier
unlink : efface un fichier comme rm pour un fichier

chattr : rend immodifiable un fichier (même par root)
top : utilitaire montrant les ressources utilisées de l'ordinateur 
mount : permet d'ajouter un disque ou ue clé USB par exemple.
nohup : utilitaire qui permet d'exécuter une commande au long cours même si on quitte le shell
&& : chaine plusieurs commandes en série

Encore d’autres commandes Linux:

scp : copie un fichier
rsync : synchronise deux répertoires

scp text.txt user@12.45.21.111:~/.ssh    copie le fichier vers l'hôte distant et le met dans le répertoire /home/user/.ssh
ps aux : 
crontab : fichier contenant les tâche )à exécuter périodiquement

usermod : modifie les caractéristique d'un utilisateur, comme le rendre sudoable
chsh : changer de shell
groups : afficher les gourpes d'un utilisateur
finger : sert à afficher les informations de utilisateur connecté (comme pinky)

Exercez vous :

voici une liste d’exercices à faire pour vous exercer

  • créer un utilisateur
  • créer un groupe
  • ajouter un utilisateur à un groupe
  • changer le mot de passe d’un utilisateur
  • créer un script shel et l’exécuter
  • jailer un utilisateur
  • effacer un utilisateur
  • créer un utilisateur système (sans login)
  • créer un lien symbolique (raccourcis)

Apprendre Git en moins de 15 minutes ! L’essentiel

Dans cette vidéo vous allez apprendre moins de dix commandes Git, qui vont vous permettre de vous en sortir dans 80% des situations, c’est à dire qu’elles vont constituer votre routine de développeur.

Il est recommandé de commiter à la fin de la journée à minima, même si vous n’avez pas encore fini votre code, en effet si votre ordinateur venait à se faire voler, vous perdriez une journée de travail.

Des libellés plus lisibles sur votre hébergement O2switch sur vote liste de lunes

O2switch est un hébergeur français avec une formules très intéressante pour les étudiants en développement web. EN effet vous devez présenter (si vous faites un projet hors stage un site), et on attends de vous de savoir déployer en production, et non faire un github Pages ou un Heroku.

Je m’aperçois que beaucoup d’étudiant ne savent pas faire un simple FTP vers un serveur mutualisé ou VPS, par contre ils s’y connaissent en Docker! . Or je me rappelle que c’est un des premiers trucs que j’ai appris à faire. Je veux bien que vous travailliez avec des dockers, mais sachez au moins comment cela se passe sous le capot.

Je conseille aux étudiants de prendre un hébergement O2switch qui coûte 120 euros TTC environs, et qui permet d’avoir 5 VPS. Vous avez un hébergement par défaut, et 4 autres qu’ils appellent des lunes, qu’il faut créer. Je pars du principe que vous avez créé des lunes, et que vous avez accès via une liste déroulante, la fameuse liste déroulante que je vais customiser avec un script Javascript que je ferai exécuter avec Greasemonkey (ou Tampermonkey sous Chrome). Voilà à quoi ça ressemble de base :

o2switch  lune

Voila qui est bien plus pratique, car je ne retrouvais jamais mes sites, je devais me constituer des notes pour me repérer.

Je vous détaille donc comment j’y suis parvenu. Pour comprendre comment fonctionne Greasemonkey je vous envois vers ce tuto [xxx].

le but est ici de faire de la manipulation de DOM, on va remplacer les textes de la liste déroulante avec nos sites web. Le script Greasemonkey va s’exécuter une fois qu’on clique sur la liste déroulante, au passage l’interface web CPanel est codé en Angular. Mais cela n’influence pas notre script.

On a donc une liste déroulante en HTML qui est chargé de façon asynchrone, nous allons voir pourquoi tout à l’heure. Pour remplacer le texte des élément <li>, nous devons capturer l’élément HTML, parcourir ses éléments et remplacer avec innerHTML le contenu de ces <li>.

Greasemonkey permet d’injecter un script Javascript dans la page. Voici le code:

// ==UserScript==
// @name     Customize O2Switch
// @version  1
// @grant    none
// ==/UserScript==
let mapp = new Map()

mapp.set('exceret (huynh.odns.fr)',"site1.com")
mapp.set('sc1exceret (sc1exceret.universe.wf)',"site2.fr")
mapp.set('sc2exceret (sc2exceret.universe.wf)',"site3.com")
mapp.set('sc3exceret (sc3exceret.universe.wf)',"site4.com")
mapp.set('sc4exceret (sc4exceret.universe.wf)',"site5.com")


let handler = function(){
  
  let e =document.querySelector('#ddlAccounts_chosen')
  let f = e.querySelector('.chosen-results')

  
  f.children[0].innerHTML = mapp.get(f.children[0].innerHTML)
  f.children[1].innerHTML = mapp.get(f.children[1].innerHTML)
  f.children[2].innerHTML = mapp.get(f.children[2].innerHTML)
  f.children[3].innerHTML = mapp.get(f.children[3].innerHTML)
  
}

let body = document.querySelector('body')
body.addEventListener("click", handler, false);

On constitue notre objet Map qui est l’équivalent d’un tableau associatif PHP, chaque clé est associé une valeur le nom du domaine. Grâce à querySelector, je capture l’élément HTML, et à la fin du script j’ajoute un event listener qui s’exécute au clic, ce qui va bien car la liste déroulante se charge en asynchrone.

ce script n’est pas parfait car au chargement du Cpanel vous êtes dans la vue principale qui liste les 5 VPS, mais une fois que vous avez cliqué une des lunes, la liste se réduit aux 4 lunes décalant les index. Le script ci-dessus a été optimisé pour la page avec les 4 lunes. Il faudrait pouvoir détecter le contexte et proposer le bon affichage.

Une troisième façon de faire une jointure en SQL

J’avoue que cette méthode je pense l’avoir vu il y a très longtemps, mais je ne l’ai jamais utilisée.

La requête SQL de création de table

Nous allons d’abord créer deux tables pour faire la jointure.

CREATE TABLE `products` (
  `product_id` int NOT NULL,
  `product_name` varchar(255) NOT NULL,
  `brand_id` int NOT NULL,
  `category_id` int NOT NULL,
  `model_year` smallint NOT NULL,
  `list_price` decimal(10,2) NOT NULL,
  PRIMARY KEY (`product_id`),
  KEY `category_id` (`category_id`),
  KEY `brand_id` (`brand_id`),
  FULLTEXT KEY `product_name` (`product_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci


CREATE TABLE `categories` (
  `category_id` int NOT NULL,
  `category_name` varchar(255) NOT NULL,
  PRIMARY KEY (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

Première façon de faire une jointure FROM

La jointure implicite, après le FROM on liste les tables de la jointure, cette façon de faire n’est pas moins performante mais est moins claire.

select * 
from products P, categories C
where P.category_id = C.category_id 
AND P.product_id = 1

Seconde façon de faire une jointure INNER JOIN

Jointure explicite, je vous la recommande, elle permet de mieux appréhender les autres types de jointure (LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN)

C’est cette méthode qui est enseignée dans la formation SQL

SELECT * FROM products P
INNER JOIN categories C ON C.category_id = P.category_id
WHERE P.product_id = 1

Troisième façon de faire une jointure avec USING

Jointure à “l’ancienne”. J’ai vu il me semble cette syntaxe il y a 30 ans avec Microsoft Access…

SELECT * FROM products p JOIN categories c
USING(category_id) WHERE product_id = 1

On utilise quand même le mot clé JOIN sauf que la clause ON n’est pas présente.

Le Principe SOLID expliqué simplement – Dependency Inversion Principle

Des classes couplées

La classe appelante est couplée à la classe appelée, si on veut changer de manière de lire des données, il faut réécrire la classe appelante.

Des classes découplées

La classe appelante est découplée à la classe appelée, grâce à une interface, si on veut changer de manière de lire des données, il suffit lors de l’appel de la méthode de passer une autre classe appelée.

Ce qu’il faut retenir

Ici le plus important est que c’est l’interface qui est passée en paramètre de la méthode lors de sa définition MAIS pas de l’exécution de la méthode, à ce moment là on passe un objet(!) dont la classe implémente l’interface.

Comprendre le mot clé return dans une fonction

Le mot return permet de passer un valeur à l’appelant de la fonction

Le mot clé return est un des plus compliqués à expliquer en fait le mot clé rythme n’existe que dans une fonction et il sert à retourner la valeur au monde extérieur à l’appelant c’est-à-dire qui a appelé la fonction.

En effet une fonction est un ensemble de codes qui permet de faire des calculs et on obtient un résultat à la fin de ce calcul ce résultat eh bien il faut le stocker dans une variable et comme le col se déroule à l’intérieur de la fonction la seule façon de passer cette valeur ce résultat à une variable et d’utiliser le mot clé return en fait on peut imaginer que une fonction c’était comme un vase clos qui a eu une entrée et une sortie dans le return c’est la sortie on peut imaginer que c’est une boîte noire qui prend des paramètres en entrée et il va nous délivrer un résultat à la sortie.

Tutoriel Programmation : comment marche la boucle for

Dans la vidéo ci-dessous j’essaye de vous expliquer en détail le fonctionnement de la boucle for, sont fonction est le même quelquesoit le langage.

Une boucle est une machine à répéter du code

tout étudiant en informatique est souvent confronté à des difficultés pour comprendre la boucle fort parce que ça demande beaucoup d’efforts ça met en jeu beaucoup de concepts, je vais essayer à travers cette vidéo de vous les montrer, de la manière la plus simple possible . tout d’abord une boucle for permet de répéter un bout de code autant de fois qu’il le faut , si je veux faire une fois 2*1000 fois, ou 1000000 de fois, c’est une boucle for  qu’il me faut . et  c’est la raison d’être de nos machines, c’est de répéter une action alors vous me direz donc dans quel genre de situation on peut utiliser une boucle for ? en  théorie de la boucle for permet de parcourir les collections de données mise en pratique qu’est-ce que c’est ?  je vous le montre la syntaxe d’une boucle dans 2 langages très courants  le  javascript et le  PHP .

Décomposition d’une boucle for

Dans les quels que soient les langages, je vais vous en à 3 paramètres après le mot clé fort il y a d’abord le premier paramètre qui est initial c’est le début de la boucle le point de départ de la boucle le 2e paramètre représente la limite supérieure de la boucle virgule et le 3e paramètre Eh bien c’est le pas c’est à dire on la progression a de combien j’avance et entre les accolades nous avons le bout de code à répéter

On appelle ça un bloc de code ici c’est une simple ligne qui affiche la variable de lit mais on peut faire aussi complexe ce qu’on veut

La variable i va donc partir de la position 0 puis il va valoir 1,2,3,4 et 5 et va s’arrêter là, il ne va pas prendre la valeur 6 puisque la condition du milieu i < 6 le lui interdit

La boucle fort en l’utilise pas avec une variable i ,dans la réalité on utilise la boucle for lorsqu’on travaille avec des variables qui sont des collections, c’est quoi une collection ? une collection c’est une variable qui contient plusieurs valeurs en javascript ce sera un tableau et en PHP c’est un tableau également

Que serait un code sans notion de collection?

Si nous ne connaissons pas les collections ou les tableaux on va créer une variable pour contenir une valeur par exemple la variable $eleve va contenir Dupont, et si j’ai plusieurs élèves comment je fais? et bien on va devoir créer plusieurs variables $eleve1, $eleve2 etc, et c’est vraiment pas pratique ! La solution c’est d’utiliser donc un tableau, dans lequel on va déclarer une seule variable, de type tableau et dedans on met tous les prénoms séparés par une virgule.

Corollaire : la boucle FOR s’utilise presque toujours avec une variable de type collection

donc la boucle for s’utilise principalement avec une collection, en PHP ce sont des tableaux et idem en javascript, on va se servir de la boucle for pour parcourir le tableau. Un élément dans un tableau est repéré par sa position encore appelé index . Le premier élément a un index 0, le dernier élément a un index qui est égal à la taille du tableau (c’est à dire le nombre d’éléments du tableau moins 1).

Quelles sont les applications concrètes d’une d’une boucle for?

Par exemple lorsque vous êtes dans votre espace Amazon, et que vous voulez lister les commandes que vous avez déjà passées et si vous avez fait plusieurs commandes par le passé, ces commandes seront insérées dans des dans des tableaux,

Les onglets que vous avez ouverts sur votre navigateur par exemple ce sont des items contenus dans un tableau, donc si j’ai une dizaine d’onglets ouverts j’ai 10 éléments dans un tableau d’onglets.

Un menu de page web par exemple, aussi c’est ce sont des différents éléments d’un tableau.

Illustration graphique des index dans un tableau

Je vais essayer d’illustrer le l’histoire des index avec parking de supermarché voilà nous avons en parking avec des voitures des places des parkings numérotées et souvent il la place de parking numérotée 0 ça n’existe pas ! donc ça commence à 1,mais en informatique on commence pas 1, on commence à 0 donc sur l’exemple qu’on voit ici la voiture numéro un à la place de parking numéro un en fait en informatique ce sera l’index 0

En informatique on ne code pas en dur les valeurs, on aime bien que le code soit générique, qu’il qu’il puisse marcher dans toutes les situations. Dans l’exemple du tableau de prénoms, bien que nous ayons 3 éléments on ne va pas mettre le nombre 3 pour la longueur du tableau, mais on va mettre une une expression qui va représenter la longueur du tableau de façon symbolique, ceci va nous permettre de de faire marcher le script quel que soit le nombre d’éléments qu’on a dans notre tableau

Voilà pourquoi on utilise les variables c’est pour que notre code ait des emplacements dans lesquels les valeurs peuvent être diverses une fois qu’on a écrit le code on n’y touche plus le code doit marcher quelque soit les situations donc c’est important de ne pas coder en dur les variables

La variable i parcoure les index

L’astuce de la boucle FOR est donc de faire promener la variable i dans l’intervalle de valeur des index, ceci nous permet de parcourir tous les éléments d’un tableau.

Formulaire : checkbox envoie 1 si coché et 0 si non

En HTML, pour les checkbox, si la checkbox n’est pas checkée, elle n’envoit rien !

Comment faire pour envoyer quand même zéro lorsque la checkbox n’est pas cochée?

En effet

<?php

echo "vous êtes en train de soumettre un formulaire";
echo '<pre>';
print_r($_POST);
echo '</pre>';


echo $_POST['test'];

?>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <form action="<?= $_SERVER['PHP_SELF'] ?>" method="post">
        <label for="">Checkez SVP</label><br>
        <input type="hidden" name="toto" value="0">
        <input type="checkbox" name="toto" value="1"><br>
        <input type="submit" value="Soumettre">
    </form>
</body>

</html>

La solution relativement simple consiste à créer un input de type hidden donc invisible qui contient la valeur à envoyer dans tous les cas. Elle sera écrasée par la valeur de la checkbox quand cette dernière est cochée.

Quels langages, quelles technologies viser?

Quelle langage informatique viser, quelle technologie viser? quelles entreprises viser ? beaucoup de débutants se posent ces questions car faire ce choix n’est pas simple, par exemple de temps en temps je vois des gens qui recommandent d’apprendre le langage Java, est-ce vraiment pertinent? si votre but est de travailler dans une agence Web, je vous recommande d’apprendre le PHP et le JavaScript, parce que le Java, c’est dans des très gros logiciels typiquement en informatique de banque. Pourquoi cette distinction est importante?

Si vous travaillez dans une agence Web, vous allez travailler sur des projets de petite envergure entre trois mois et six mois, parfois plus neuf mois ou un an. Alors que si vous travaillez dans le langage Java, vous allez travailler sur des gros systèmes. Non seulement vous allez travailler dans un contexte énorme, mais en plus vous allez travailler sur les très longues durées, des années voire sans fin, ce n’est pas forcément du goût de tout le monde.

Je vous rappelle que ce billet est dans le contexte du développement web (on ne parle pas de jeux vidéos, développement de logiciel desktop…)

Quel langage de programmation choisir ?

Dans le monde du web il y a les langages back end (côté serveur) et front end (côté client ou navigateur). Dans le front end Javascript règne en maitre, il est complétté par le HTML et le CSS pour la mise en forme des pages. Côté serveur, c’est plus disputé, il y a énormément de langages plus ou moins populaire. PHP est très populaire, il y a aussi Python, Ruby, Java, C# et de nouveau Javascript.

Quand un novice demande quel langage il faut étudier, et je sais que pour ce novice le conseil est très important, car il va passer beaucoup de temps avec ce langage, j’entend des réponses plus ou moins réalistes.

La raison voudrait qu’on réponde PHP ou Javascript pour le back end, (car pour le front end y a pas photo pas de débat c’est javascript), mais j’entends aussi Python ou Java. Et désolé, mais c’est vraiment pas très réaliste, les gens qui répondent ça, travaillent-ils dans ces technologies? travaillent-ils ou ont-ils travaillé dans d’autres technologies?

En effet, vu le contexte de la demande, je trouve que ce n’est pas bon conseil de conseiller le Java pour faire du web. Qui dit Java dit Java EE, Hibernate, mais surtout une courbe d’apprentissage très très longue. Et surtout vous n’allez pas faire un site vitrine, ou un petit e-commerce avec Java. Java c’est fait pour des très gros logiciels en environnement bancaire notamment. c’est un langage considéré sûr pour des choses “sérieuses”, le PHP c’est pour faire mumuse. Plus sérieusement, à chaque problématique répond un langage. Si vous voulez faire un site de petite ou moyenne taille PHP ya pas photo. Pour des gros sites aussi c’est PHP. Par contre c’est ridicule d’utiliser Java EE et Hibernate pour faire un Prestashop, que tout le monde va s’approprier. La technicité est toute autre avec Java, alors non ne dites plus de bêtises, surtout si vous ne travaillez pas avec Java.

Quant au Python, malgré tout le buzz que la presse veut bien relayer, dans le monde du web, il cède la place à PHP. N’apprenez pas Python si vous voulez faire du web, vous allez rester au chômage longtemps. Python, c’est utilisé dnas l’IA, machine learning, etc, si vous voulez travailler dans ces domaine alors oui allez-y pour le Python et pas PHP.

Quant à Ruby il est trop confidentiel en France. On est en 2020, pariez sur PHP, merci.

Un truc simple à faire : Allez sur Indeed ou tout autre plateforme de job, et cherchez les offres dans ces différents languages par ville et comparez.

Quelle technologie viser?

Outre le fait de développer un logiciel en un langage pur sans faire appel à un framework, ceci prend du temps et n’est pas tout le temps justifié, il existe des frameworks qui vous facilitent le développement d’applications.

Si vous avez lu le premier paragraphe, vos choix se sont rétrécis, du moins pour le langage back-end. Maintenant, ne parlons que du PHP, il existe actuellement deux frameworks qui se détachent : Symfony et Laravel, et sont orientés objet de la façon la plus classique. Les deux sont très demandés , un petit plus pour Symfony en France, mais à l’échelle mondiale, c’est Laravel.

Mon opinion personnelle est que Symfony est un peu plus délicat à prendre en main pour un débutant que Laravel, mais quand on commence à le connaître, mais aussi quand on commence à comprendre les principes de la programmation orientée objet, (injection de dépendance, quelques pattern ORM, les closures) on arrive à se débrouiller pas mal avec, sans pour autant être un expert.

Je trouve que Laravel est plus terre à terre d’entrée de jeu, en particulier l’ORM Eloquent qui est beaucoup plus facile à appréhender que Doctrine.

Quelle entreprise viser?

Vous avez différents types d’entreprises qui recrutent des développeurs informatiques: agences web, SSII, département SI(système d’information) de grandes structures, éditeurs de logiciels, ceci c’est pour le salariat, à quoi il faut ajouter le status de freelance.

L’erreur que je rencontre le plus souvent chez les étudiant qui viennent d’obtenir leur certification (je parle de ceux qui sont en reconversion et non des étudiant en informatique), c’est qu’ils veulent se mettre en freelance pour engranger le plus rapidement de l’argent.

Parce qu’ils ont réussi un parcours, ne veut pas dire qu’ils sont prêts à l’emploi ! il y a une différence entre le niveau d’un étudiant diplômé et quelqu’un d’opérationnel. Là où on rencontre le plus souvent ce cas de figure, ce sont les étudiants en WordPress, qui se mettent en freelance pour proposer un site à 500 ou 1500 euros, ça peut sembler intéressant pour eux (au passage ils tirent les prix du marché vers le bas), mais savent-ils qu’il vont passer deux voire 3 semaines ou un mois pour le faire? Et si je vous disait que pour un site à 1500 euros, en agence, un développeur wordpress peut le torcher en un ou deux jours? vous la voyez la différence?

Le paradoxe de la pénurie de développeurs

Dans le média on nous rabâche sans cesse que l’on est en grande pénurie de développeurs, mais pourtant ce qu’on entend aussi c’est que les étudiants ou les développeur juniors ont du mal à trouver un poste (dans certains cas). D’où vient ce paradoxe? il semble que la réponse soit que le marché manque de développeurs certes, mais de développeurs expérimentés !

Aussi en réussissant un parcours certifiant ou diplômant pour les gens en reconversion, vous n’êtes qu’à mi-parcours, il reste encore du chemin à faire. Ce n’est pas de votre faute si à l’issue de votre parcours vous avez du mal à trouver un job, malheureusement les entreprises sont dans une logique économique, où il faut rentrer de l’argent, et ils préfèrent parier sur des profils plus expérimentés, ne pas prendre le risque. Mettez vous à l place d’u patron de bopite et vous comprendrez.

Ce qu’il manque au jeune développeur

Ce qu’il manque c’est des entreprises qui acceptent de jouer le jeu de montée en compétence du junior à terme, qu’ils capitalisent sur le junior, le forme afin qu’il devienne performant. Et du côté du junior, il doit jouer le jeu en acceptant un salaire qui ne soit pas mirobolant lors de la première année. Vous êtes payé pour monter en compétence que demander de plus?

Ce type d’entreprise existent rassurez-vous, il faut les trouver. En fait ce n’est pas une entreprise en particuliers, cela dépend de si vous avez un mentor qui veut bien vous faire monter en compétence, si le service informatique où vous êtes pratique cette montée en compétence.

Chez Formapedia nous prenons en compte ce paradoxe et nous accompagnons les juniors dans leurs premiers pas en entreprise.

[ninja_form id=2]