PHP

Utiliser PHPMailer pour envoyer des emails avec un SMTP

Introduction à PHPMailer en PHP : Un Guide pour Envoyer des Emails en Toute Simplicité

Dans le développement web, l’envoi d’emails est une fonctionnalité souvent indispensable : confirmations d’inscription, réinitialisation de mot de passe, notifications, etc. PHP possède sa propre fonction native mail(), mais celle-ci reste assez limitée et complexe à configurer pour des envois avancés, en particulier avec des serveurs SMTP sécurisés. mail() est à proscrire aujourd’hui.

C’est là que PHPMailer entre en jeu. PHPMailer est une bibliothèque PHP populaire qui simplifie l’envoi d’emails et permet de se connecter facilement à des serveurs SMTP. Elle offre des fonctionnalités supplémentaires telles que l’envoi sécurisé via SSL/TLS, la gestion des pièces jointes, le formatage HTML des emails, et bien plus encore. Dans ce guide, nous vous montrerons comment intégrer PHPMailer dans vos projets PHP et vous guiderons pas à pas pour envoyer des emails en utilisant cette bibliothèque.

Pourquoi utiliser PHPMailer ?

PHPMailer présente plusieurs avantages par rapport à la fonction mail() :

  1. Simplicité d’utilisation : PHPMailer simplifie la configuration et l’envoi d’emails.
  2. Support SMTP avec Authentification : PHPMailer supporte les protocoles SMTP avec authentification, ce qui est plus sûr et essentiel pour éviter que les emails soient marqués comme spam.
  3. Support SSL et TLS : PHPMailer prend en charge les protocoles de sécurité SSL et TLS.
  4. Support HTML et Pièces Jointes : Ajoutez facilement des pièces jointes et formatez le contenu en HTML pour des emails professionnels.

C’est simple cela a toujours marché avec moi en SMTP, et quand il y a un problème d’envois, vous pouvez activer le mode DEBUG pour avoir des messages clairs.

Étape 1 : Installer PHPMailer avec Composer

La méthode la plus simple pour installer PHPMailer est d’utiliser Composer. Si vous n’avez pas encore installé Composer, vous pouvez le faire en suivant les instructions officielles sur le site de Composer.

Une fois Composer installé, ouvrez un terminal ou une invite de commande, placez-vous dans le répertoire de votre projet et exécutez la commande suivante :

composer require phpmailer/phpmailer

Composer téléchargera PHPMailer et l’ajoutera aux dépendances de votre projet.

Étape 2 : Envoyer un Email avec PHPMailer

Créons un script PHP simple pour envoyer un email en utilisant PHPMailer.

Configuration de base de PHPMailer

  1. Créez un fichier email.php dans votre projet.
  2. Ajoutez le code suivant pour configurer et envoyer un email :
<?php
// Charger automatiquement les dépendances de Composer
require 'vendor/autoload.php'; // ne pas oublier cette ligne très importante !

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

// Initialiser PHPMailer
$mail = new PHPMailer(true);

try {
    // Paramètres du serveur SMTP
    $mail->isSMTP();                                        // Utiliser SMTP
    $mail->Host = 'smtp.example.com';                       // Remplacez par le serveur SMTP
    $mail->SMTPAuth = true;                                 // Activer l'authentification SMTP
    $mail->Username = 'votre-email@example.com';            // Votre adresse email
    $mail->Password = 'votre-mot-de-passe';                 // Votre mot de passe
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;     // Activer TLS (ou 'ssl' pour SSL)
    $mail->Port = 587;                                      // Port SMTP, 587 pour TLS ou 465 pour SSL

    // Expéditeur et destinataire
    $mail->setFrom('votre-email@example.com', 'Nom de l\'Expéditeur');
    $mail->addAddress('destinataire@example.com', 'Nom du Destinataire');

    // Contenu de l'email
    $mail->isHTML(true);                                    // Activer HTML
    $mail->Subject = 'Sujet de l\'email';
    $mail->Body    = '<h1>Bonjour!</h1><p>Ceci est un email envoyé depuis PHPMailer.</p>';
    $mail->AltBody = 'Ceci est un email envoyé depuis PHPMailer.'; // Version texte brut

    // Envoyer l'email
    $mail->send();
    echo 'Email envoyé avec succès';
} catch (Exception $e) {
    echo "L'email n'a pas pu être envoyé. Erreur : {$mail->ErrorInfo}";
}
?>

Délivrabilité des emails

Il existe des services qui offrent des SMTP gratuits, mais la délivrabilité est aléatoire. Par exemple le SMTP de Mailjet n’envoit pas toujours des email, alors qu’un SMTP comme Gmail est beaucoup plus fiables. Mais vous ne pouvez pas modifier l’email de l’expéditeur, alors que Mailjet le permet.

wordpress cURL error 60: SSL certificate problem: unable to get local issuer certificate

Récemment j’ai eu droit en voulant activer mon thème Astra, je me suis heurté à l’erreur suivante :

cURL error 60: SSL certificate problem: unable to get local issuer certificate

Ce n’est pas un problème du thème Astra

Ce n’est pas un problème de votre hébergeur

J’ai fait 2 aller retours vers le hébergeur 02Switch, qui est très bien, réactif, mais n’a pu me solutionner mon problème, se contentant de dire que chez eux tout va bien. Bien sûr je ne savais pas quel était le vrai problème, je sentais que c’était un problème du serveur du site, et pas de celui d’Astra, comme me le suggérait l’hébergeur.

La solution est ailleurs

Ce n’est seulement qu’après avoir vu la petite vidéo d’Astra montrant que (tout plugins désactivés, le problème persistait, en effet en allant sur Outil > Santé du site, il y avait une alerte d’erreur critique concernant REST API, en gros les appels vers d’autres serveurs échouaient à cause du certificat.

En googlant un peu plus sur Internet, j’ai trouvé la solution sur cette page :

Le problème était que le certificat de WordPress, le fichier ca-bundle.crt localisé dans wp-includes/certificates, datait de 2016…

La solution consistait à télécharger un certificat plus récent sur ce lien le fichier ca-cert.pem. Le soucis c’est que ce fichier ne nommait pas pareil, pas de panique il suffit juste de copier le contenu texte de ce fichier et de remplacer l’ancien contenu intégralement du fichier ca-bundle.crt et le tour est joué.

Installer PHP 8.1 sur votre macintosh pour MAMP

MacOS est un dérivé de FreeBSD, donc contient déjà un serveur apache, mais c’est tout.

MAMP est une solution de développement intégré comme WAMP, Laragon ou encore XAMP.

Les version nouvelles de PHP sortant, il faut se mettre à jour. Nous allons voir comment mettre à jour la version de PHP avec Homebrew.

Mettre à jour HomeBrew

Ici il s’agit d’avoir la dernière version de Homebrew Core. Parfois vous avez le message suivant

Warning: homebrew/core is shallow clone. To get complete history run:
  git -C "$(brew --repo homebrew/core)" fetch --unshallow

Cela veut dire qu’il faut avoir tout le code source de Homebrew, il faut taper la commande suivante (ça prend pas mal de temps), mais si vous ne le faites pas et que vous voulez installer une nouvelle version de PHP (ou de tout autre logiciel, vous n’arriverez pas). Exécutez la commande Git, shallow veut dire creux, en fait pour sauver de l’espace, tout n’était pas téléchargé.

it -C "/chemin/vers/homebrew/core" fetch --unshallow

Si vous n’avez pas ce message ce n’est pas grave, vous êtes en bonne voie. Patientez un bon moment pendant que cette commande s’exécute.

Installer la nouvelle version de PHP

brew install php@8.1

Cela va télécharger PHP dans le répertoire /usr/local/Cellar/php@8.1/lib, et dans /usr/local/opt/php/php8.1 qui est en fait un raccourci vers le premier répertoire, une fois dans le répertoire PHP localisé, vous avez deux sous répertoires, /httpd et /php.

Allez dans Cellar/php/ copier le répertoire php8.1 nouvellement créé, vers MAMP dans Application/MAMP/bin/PHP

Si le dossier PHP que vous avez collé ne s’appelle pas php8.1, renommez le comme ça car cela va permettre à MAMP de la reconnaitre au redémarrage. Redémarrez MAMP et sélectionnez la nouvelle version de PHP, par défaut seules les deux dernières versions de PHP sont montrées dans la liste déroulante.

Copier le fichier libphp.so

Démarrez le serveur Apache, vous allez voir une erreur, car il manque encore une manipulation à faire, il faut le fichier libphp.so.

Ce fichier est à récupérer dans le répertoire usr/local/lib/http/modules et à mettre dans /MAMP/bin/php/php8.1/modules

Redémarrez MAMP, normalement tout est bon.

php

Configurer Xdebug avec Visual Studio Code

Pour ceux qui ne veulent pas dépenser 250 euros pour avoir une license de PHPStorm, il reste Visual Studio Code, qui est gratuite. Cet IDE s’est imposé comme un IDE à tout faire, ce qui en fait un outil très intéressant pour toucher à tout type de langages (même Solidity). Nous allons voir comment configurer XDebug pour fonctionner avec VSCode.

Qu’est que Xdebug?

Xdebug est une extension bas niveau qui permet de débugger pas à pas votre code PHP.

Pour savoir débugger est important?

Quand vous avez un grand projet, inutile de faire des var_dump, echo ou print, il faut absolument passer pas un debugger, vous deviendrez un meilleur codeur. Typiquement un projet Symfony avec des milliers de fichier potentiellement, on ne s’en sort pas avec des echo !

Comment le debug est déclenché?

Le serveur web reçoit l’instruction de débugger via un cookie spécial envoyé par le navigateur, via une extension Chrome (donc pas dispo avec Firefox par exemple quoique l’on peut trouver si l’on veut un équivalent). Le setup risque d’être un peu long mais cela en vaut vraiment le coup !

Quelle version de Xdebug faut il installer?

En fait il faut aller voir le tableau de correspondance pour trouver la paire de logiciel PHP/Xdebug qui fonctionne. Le site officiel possède un tableau de compatibilité version de PHP et version de XDebug, soyez à jour ! J’ai fait plusieurs tutos sur Xdebug sur ce site, et je fais un nouveau tuto pour remettre à jour les versions qui marchent, et aussi les façons de configurer ont changé, donc il était temps de remettre à jours les connaissances avec les dernières version des tous les logiciels PHP 8.x et Xdebug 3.x

Allez sur le site officiel pour télécharger le zip, attention, il y a différentes versions pour une même version de Xdebug. Pour windows il faut choisir la thread sae, 64 bits.

Où configurer le Xdebug?

Il faut aller dans le fichier php.ini, attention, il y a deux version de php.ini, une pour la version CLI (en ligne de commande) et une pour la version web, à deux endroits différent, utiliser phpinfo(); CTRL+F de php.ini et vous aurez le chemin du fichier. Collez ce texte en fin de fichier.

[xdebug]
zend_extension="C:\laragonwamp\bin\php\php-8.1.10-Win32-vs16-x64\ext\php_xdebug-3.1.5-8.1-vs16-x86_64.dll"
xdebug.mode=debug
xdebug.client_host=127.0.0.1
xdebug.client_port=9003
xdebug.start_with_request=yes
xdebug.idekey=XDEBUG_ECLIPSE

N’oubliez pas de recharger Apache !

Installer l’extension Chrome Xdebug

Comme nous avons vu plus tôt, c’est le navigateur qui envoit un en-tête spécial pour déclencher XDebug. Regardez la section COOKIE lorsque le script suivant est exécuté:

<?php
phpinfo();

Et coté navigateur en regardant les en-têtes envoyés :

Regardez la section COOKIE, on a bien la même chose envoyée par le navigateur. Ceci est possible grâce à l’extension Xdebug pour Chrome (faites une recherche sur Google) qui envoit automatiquement ce cookie. Installons le. Vérifiez ensuite que le petit insecte est au vert (actif), sinon cliquez dessus.

Fichier de configuration dans VScode et plugin Xdebug pour PHP

Attention ce n’est pas fini ! mais bientôt ! Puisque nous débuggons sous VSCode, nous allons ajouter un plugin dédié et un fichier de configuration pour VSCode. Tout d’abord, le plugin, installez le plugin, entre PHP DEBUG dans la barre de recherche des plugins. Installez celui avec la mention « Debug support for PHP with XDebug »

Le fichier de configuration

Cliquez sur l’icône de débug sous VSCode, puis Add Configuration, un ficheir JSON va s’ouvrir, collez le code ci-dessous

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9003
        }
    ]
}

Testez votre script

Maintenant créez un fichier PHP dans un virtualhost, mettez un point d’arrêt sur une ligne, cliquez sur Listen to Xdebug, et chargez la page dans votre navigateur !

Mode pas à pas

Installe Xdebug sur MacOs

Pour les MacOs, le fichier Xdebug est à installer avec PECL

>pecl install xdebug
Build process completed successfully
Installing '/usr/local/Cellar/php/8.2.1/pecl/20220829/xdebug.so'
install ok: channel://pecl.php.net/xdebug-3.2.0
Extension xdebug enabled in php.ini

Localisez l’endroit où se trouve Xdebug de suite après l’installation, le chemin est normalement affiché, recopiez le pour le mettre dans le fichier php.ini,

Installer Xdebug pour Linux

La procédure est à peu près la même que pour MacOs, utilisez PECL pour installer Xdebug, recopiez le chemin

php

Débugger sous VSCode en PHP

Il vous faut installer le plugin PHP Debugger de Felix Becker

Configurez XDebug dans le php.ini comme d’habitude (PHPstorm)

Cliquez sur Listen for XDebug

Mettez un breakpoint où vous voulez et lancez la page web.

Pour Débugger avec le serveur interne de PHP

zend_extension = C:\laragon\bin\php\php-7.2.19-Win32-VC15-x64\ext\php_xdebug-2.6.1-7.2-vc15-x86_64.dll
[xdebug]
xdebug.remote_enable = 1
xdebug.profiler_enable = off
xdebug.profiler_enable_trigger = 1
xdebug.remote_port=9000
xdebug.remote_handler=dbgp
xdebug.profiler_output_name = "cachegrind.out.%u.%H.%R"
xdebug.profiler_output_dir = "c:/laragon/tmp"
xdebug.show_local_vars=0
xdebug.remote_autostart=1

Il faut mettre dans le php.ini la configuration suivante pour Xdebug en plus :

xdebug.remote_autostart=1
php

Doctrine et ses 4 façons de requêter la base de données

DQL Doctrine Query Langage

$query = $this->em->createQuery(
    "
    SELECT p
    FROM AppBundle\Entity\RedditPost p
    WHERE p.id > :id
    "
)->setParameter('id', 50);

$data = $query->getResult();

Mais on ne peut splitter la requête simplement, alors qu’avec le query builder c’est possible:

// it is still DQL, but now it is painful

var $someConditional = false;

if ($someConditional === true) {
    $query = $this->em->createQuery(
        "
        SELECT p
        FROM AppBundle\Entity\RedditPost p
        WHERE p.id > :id
        "
    )->setParameter('id', 50);
} else {
    $query = $this->em->createQuery(
    "
        SELECT p
        FROM AppBundle\Entity\RedditPost p
    "
    );
}

$data = $query->getResult();

Query Builder

C’est mieux avec le query builder, plus facile de paramétrer sa requête, tout est à base de méthode objet.

// using Doctrine's Query Builder

var $someConditional = false;

$query = $this->getDoctrine()->getRepository('AppBundle:RedditPost')->createQueryBuilder('p');

if ($someConditional === true) {
    $query
        ->where('p.id > :id')
        ->setParameter('id', 50)
    ;
} 

$data = $query->getQuery()->getResult();

https://codereviewvideos.com/course/doctrine-databasics/video/dql-vs-doctrine-query-builder

$query = $this->getDoctrine()
    ->getRepository('AppBundle:RedditPost')
    ->createQueryBuilder('p')

createQueryBuilder('p') implicitly creates the equivalent:

    SELECT p
    FROM AppBundle\Entity\RedditPost p

C’est la raison pour laquelle on n’a pas besoin de SELECT et FROM explicite

Native Query

Ressemble beaucoup au SQL, la notion de resultSetMapping est centrale.

use Doctrine\ORM\Query\ResultSetMapping;

$rsm = new ResultSetMapping();
// build rsm here

$query = $entityManager->createNativeQuery('SELECT id, name, discr FROM users WHERE name = ?', $rsm);
$query->setParameter(1, 'romanb');

$users = $query->getResult();

https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/native-sql.html

On peut utiliser le resultSetMappingBuilder pour construire des requêtes Native Query

use Doctrine\ORM\Query\ResultSetMappingBuilder;

$sql = "SELECT u.id, u.name, a.id AS address_id, a.street, a.city " . 
       "FROM users u INNER JOIN address a ON u.address_id = a.id";

$rsm = new ResultSetMappingBuilder($entityManager);
$rsm->addRootEntityFromClassMetadata('MyProject\User', 'u');
$rsm->addJoinedEntityFromClassMetadata('MyProject\Address', 'a', 'u', 'address', array('id' => 'address_id'));

Raw SQL

On met du pur SQL dans un repository Doctrine

    public function getEvoplusStatusCountByMonthByCommercial(int $idUser, $start, $end)
    {
        $conn = $this->getEntityManager()->getConnection();

        $sql = "select count(*) as count, M.ID_ETAT_MATRICE, EM.LIBELLE_ETAT_MATRICE from MATRICE M 
inner join ETAT_MATRICE EM on 
M.ID_ETAT_MATRICE = EM.ID_ETAT_MATRICE 
where 
CONTRAT_DATE_SIGNATURE BETWEEN '$start' AND '$end'
AND USR_ID = $idUser GROUP by M.ID_ETAT_MATRICE; ";

        $stmt = $conn->prepare($sql);
        $stmt->execute();
        $res = $stmt->fetchAll();

        return $res;
    }

Cette méthode est ma préférée, vou sl’aurez compris je ne suis pas un fan des ORM, c’est tellement plus facile de faire des requêtes SQL, et tant pis si on n’a pas d’objet en résultat, manipuler des tableaux associatifs n’est pas si difficile.

Wordpress

Créer une page personnalisée dans WordPress

Page de statistique (par exemple)

Création des pages php

Dans le menu du thème, il faut créer une page statistique.php

Ajout dans functions.php le lien vers la page dans le menu

Dans le fichier functions.php il faut insérer dynamiquement les instructions pour charger dans le menu administration de WordPress le lien vers la page statistique

//statistique de jeu 

function stat_setup_menu(){
    add_menu_page( 'Statistiques Franchise', 'Statistiques', 'manage_options', 'export-stat', 'stat_init' );
}
function stat_init(){
    include(get_template_directory().'/statistiques.php');
}
add_action('admin_menu', 'stat_setup_menu');
logo laravel

Les variable d’environnement dans Laravel

Il faut utiliser la librairie Dotenv, cependant pas besoin de la charger avec un use

env('LA_CLE')  // La clé qui se trouve dans le fichier .env
#fichier .env
LA_CLE=lavaleurcorrespondante

Attention si vous n’arrivez pas à lire la clé, il est vraisemblable que le problème soit du côté du cache

php artisan config:clear    // devrait suffire
php artisan cache:clear     // si ça ne marche toujours pas 

https://stackoverflow.com/questions/51987140/laravel-accessing-env-variables

logo laravel

Le routing dans laravel

Route prenant un paramètre

Mais vous voudriez aussi gérer le cas où le paramètre eput être optionnel, dans ce cas créer les deux routes (un avec et un sans)

Route::get('/products','ProductController@getProducts');

Route::get('/products/{type}','ProductController@getProducts')->named('produits');

Ensuite dans le controller gérez le paramètre optionnel

    public function getProducts($type = 'chemise'){
        $product = DB::table('products')
            ->where('type','=',$type)
            ->where('status','=','1')
            ->get()
            ->toArray();
        return response()->json([$product][0]);
    }

Ainsi si vous passez la route '/products', vous aurez les chemises, et si vous passez la route '/products/pantalon' vous aurez les pantalons, de même '/products/chemise' vous renverra aussi les chemises.

logo laravel

Injection de dépendance dans Laravel

Qu’est ce que c’est?

L’injection de dépendance, un mot bine effrayant pour désigner quelque chose de très simple , c’est de passer en paramètre d’une fonction un objet, et ce de façon « automatique », le moteur de Laravel se chargeant d’injecter dans la fonction automatiquement.

 class Mailer
{
    protected $mailer;   
    function __construct(PHPMailer $mailer)
    {
        $this->mailer = $mailer;
    }
    public function sendMail($recipient,$content,$subject){
      //...code envoi email
    }
}

Maintenant supposons que nous soyons dans un e méthode de controller appelée NotifyLogin, qui envoit un mail à l’administrateur lorsque quelqu’un se connecte.

use Illuminate\Http\Request;
use use App\Helper\Mailer;

class LoginController extends Controller
{
    public function __construct(){}
    public function notifyLogin(Request $request, Mailer $mailer){
    $email = $request->email;

    $mailer->sendMail($email,'Un utilisateur s\'est connecté','Connexion');
    
    }
}

On voit que on injecte $request, mais aussi $mailer, il n’est pas besoin d’instancier avec new, Laravel le fait automatiquement pour nous. Ceci est rendu possible parce qu’en amont, le constructeur de la class Mailer a lui-même utilisé l’injection de dépendance pour s’instancier. AInsi de proche en proche le framework arrive à fournir à la méthode notifyLogin le $mailer avec un minimum de travail de notre part, et en plus notre code est plus lisible et mieux organisé.

logo laravel

Laravel et logging

Le logging consiste en la sauvegarde de chaines de textes dans un fichier. Basiquement c’est l’idée, on peut affiner ceci. Le fichier de log sert surtout à aider le debug, et ceci en mode production.

Laravel et Monolog

Monolog est une librairie bien connue en PHP pour logger. elle est bien intégrée à Laravel.

Où se trouve le fichier de log de Laravel ?

la grande question ! il se trouve (Laravel 7) dans le dossier /storage/logs/laravel.log.

Comment logger une entrée?

use Illuminate\Support\Facades\Log;

Log::info('Someone tried login : ' . $request->query->get('email'));

Est ce que Monolog permet de logger les requêtes SQL?

Non. Pour ce faire il faut utiliser la facade Debug (DB)

use Illuminate\Support\Facade\Debug;
...
DB::enablQueryLog()
php

Streamer une image en PHP

Qu’est qu’un stream?

un stream est un flux, c’est à dire un envoi continu d’information. Utilisé dans le monde de la vidéo ou de la musique, la lecture d’un stream est le fait de lire sans attendre la fin du téléchargement du fichier, dans un but but de rapidité bien entendu. Dans notre exemple, il s’agit de télécharger l’image sous la forme d’un flux.

Par rappor à la méthode classique d’inclusion d’une image en HTML

<img src="chemin/vers/image.png" />

On va mettre à la place un fichier PHP

<img src="myimage.php" />

Qui aura pour but de montrer l’image in fine, mais au travers d’un fichier PHP. Et ceci est très intéressant car il va nous permettre de faire beaucoup de choses.

Le besoin est par exemple de savoir combien de fois l’image a été téléchargée, car grâce au PHP on peu implémenter facilement ce code, car si on parse les log du serveur web, c’est fastidieux, alors que là c’est facile.

Script d’exemple

<?php
header('Content-type: image/jpeg');
$file = './streamimage.jpg';
$src = imagecreatefromjpeg($file);
$res = imagejpeg($src);
if($res){
    $handle = fopen('stat.txt','a+');
    $record = date('y-m-d H:i:s') . " " . $_SERVER['HTTP_REFERER'] .  "\n";
    fwrite($handle,$record);
    fclose($handle);
}
die;

Dans l’exemple ci-dessus, chaque fois que l’image est streamée, on logue dans un fichier l’heure et le referer.

Wordpress

Requêter des tables non WordPress

Imaginez que vous devez faire quelquechose de custom, et que vous devez enregistrer des données dans une table non standard de WordPress, est-il possible d’utiliser les fonction de WordPress pour faire des opération CRUD? sans passer par PDO par exemple?

La réponse est OUI ! Je passe sur le fait de devoir faire une connexion vous même en récupérant les données de connexion à votre base de données.

Récupérer les identifiant de connexion dans une page

Il est facile de récupérer les identifiants de connexion quand vous formattez correctement votre page.

/**
 * The template for displaying all pages.
 *
 * Template Name: Page Classement
 * Visibility par
 * Template Post Type:  page_application
 *
 * Page template with minimal formatting, a fixed 940px container and right sidebar layout
 *
 * @package WordPress
 * @subpackage WP-Bootstrap
 * @since WP-Bootstrap 1.0
 */

//var_dump(DB_NAME, DB_USER, DB_PASSWORD, DB_HOST);

global $wpdb;
global $wp_query;

$results = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}classement ", OBJECT );
var_dump($results);

Le code ci-dessus est dans une page dans un thème (sous réserve que le thème soit actif, ce code marchera)

Vous n’avez pas besoin de faire de connexion, en utilisant l’objet global $wpdb, la connexion est déjà faite, $wpdb est l’objet connexion.

Utilisation de $wpdb

Le documentation officielle de cet objet est sur cette page.

Read

$results = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}classement ", OBJECT );

Insert

$wpdb->insert( 
    "{$wpdb->prefix}classement", 
    array( 
        'nom' => 'value1', 
        'temps' => 123, 
        'jeu' => 'Templiers', 
        'status' => 'enabled', 
        'created_at' => '2020-08-27 15:10:18', 
    )/*, 
    array( 
        '%s', 
        '%d', 
    ) */
);

Update

$wpdb->update( 
    'classement', 
    array( 
        'nom' => 'value1',   // string
        'position' => 'value2'    // integer (number) 
    )
)

Delete

$wpdb->delete( 'table', array( 'ID' => 1 ) );

Doctrine Query Builder

Il existe dans Symfony plusieurs façons de faire des requêtes SQL, dont l’une spécifique à Doctrine, l’utilisation de Query Builder est sans doute la plus utilisée. Notez qu’il y a aussi Native Query qui se veut ‘proche’ de SQL de base.

Requête simple avec Query Builder

Requête avec WHERE

$this->createQueryBuilder('u')
            ->andWhere('u.id_utilisateur_groupe = :id')
            ->andWhere('u.is_active = :is_active')
            ->setParameter('id', $idEquipe)
            ->setParameter('is_active', 1)
            ->getQuery()
            ->getResult()

Requête avec ORDER BY

$this->createQueryBuilder('u')
            ->andWhere('u.id_utilisateur_groupe = :id')
            ->andWhere('u.is_active = :is_active')
            ->orderBy('u.lastname','ASC')
            ->setParameter('id', $idEquipe)
            ->setParameter('is_active', 1)
            ->getQuery()
            ->getResult()
        ;

Reference : https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/query-builder.html

symfony

Memento Twig

Petit article pour consigner les techniques de Twig qu’on a trop tendance à oublier car peu utilisée, il est ici utilisé dans un contexte Symfony

Chercher l’url d’une route

{{ url('home') }} << ou un autre nom de route, ici on a le nom de domaine

Boucle for dans twig

    {% for user in users %}
        <li>{{ user.username|e }}</li>
    {% endfor %}

Comment dumper une variable

Vraiment très fondamental, le dump permet de voir ce que contient une variable, et c’est un raccourci très efficace dans la connaissance d’une librairie

{{ dump(app.request) }}

Ainsi l’exemple ci-dessus peut nous donner plein d’informations sur l’objet request et ainsi nous permettre dde récuérer des informations comme path_info ou des variable de paramétrage dans les fichier de configuration de Symfony.

#exemple de dump
public 'server' => 
    object(Symfony\Component\HttpFoundation\ServerBag)[16]
      protected 'parameters' => 
        array (size=41)
          'REDIRECT_STATUS' => string '200' (length=3)
          'HTTP_HOST' => string 'terrav2' (length=11)
          'HTTP_CONNECTION' => string 'keep-alive' (length=10)
          'HTTP_CACHE_CONTROL' => string 'max-age=0' (length=9)
          'HTTP_UPGRADE_INSECURE_REQUESTS' => string '1' (length=1)
          'HTTP_USER_AGENT' => string 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36' (length=121)
          'HTTP_ACCEPT' => string 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' (length=124)
          'HTTP_REFERER' => string 'http://terrav2/matrice/export' (length=33)
          'HTTP_ACCEPT_ENCODING' => string 'gzip, deflate' (length=13)
          'HTTP_ACCEPT_LANGUAGE' => string 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7' (length=35)
          'HTTP_COOKIE' => string 'PH..

# pour getter le hTTP_HOST par exemple :
{{ dump(app.request.server.get('HTTP_HOST')) }}

Comment accéder à un rôle d’un user

{{ app.user.roles[0] }}

Créer un lien hypertexte

{{ url('nomDeLaRoute',{ 'param':'value'}) }}

Accès aux variables de configuration de Symfony depuis Twig : Substitution de variable

Dans le fichier services.yaml :

parameters:
    pdf_folder: '%kernel.root_dir%/../public/medias/pdf'

Dans le fichier twig.yaml

twig:
    globals:
        pdf_path: '%pdf_folder%'

Dans le fichier template twig :

{{pdf_path}}

Accéder à une propriété d’une table liée

Il hy a la table Users qui contient le champ IdGroupe ,puis la table UtilisateurGroupe qui contient l’IdGroupe (jointure donc) et le libellé du groupe auquel on veut accéder

Le chainage est possible avec la notation pointée

A la fin on aura

{{user.idUtilisateurGroupe.getIdUtilisateurGroupe }}
php

Accélérez votre site web avec un cache Opcode

Toujours sur un serveur dédié, et sous Debian voici la procédure à faire pour accélérer votre site web:

  1. Installez APC : aptitude install php-apc
  2. Configurer le fichier  php.ini en éditant le ichier  « /etc/php5/conf.d/apc.ini » et en ajoutant: apc.enabled=1
    apc.shm_segments=1
    apc.shm_size=128
  3. Redémarrez Apache
  4. Créez une page web pour pourvoir monitorer les performance de ce cache (remplacez mysite par le bon répertoire de votre serveur) :gzip -dc /usr/share/doc/php-apc/apc.php.gz > /home/mysite/public_html/apc.php

Voilà c’est tout !

symfony

Test unitaire et fonctionnel avec Symfony

Pour lancer un test unitaire (cela suppose que vous avez installé ce qu’il faut pour lancer les tests):

./bin/phpunit
#pour lancer un test en particulier
./bin/phpunit tests/Utils/HelperTest.php   //indiquer le chemin complet

Pour les tests fonctionnels, on va faire comme si on avait un navigateur (mais ce n’est pas un vrai navigateur au sens où l’on démarre vraiment Google Chrome ou Firefox, pour ça il faut voir le plugin Panther)

Le cod eminimal pour ce genre de test est :

<?php
namespace App\Tests\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use App\Controller\SecurityController;

class RouteTest extends WebTestCase
{
    public function testLoginRoute()
    {

        $client = static::createClient();
        $client->request('GET', '/login');
        $this->assertEquals(200, $client->getResponse()->getStatusCode());
    }
}

En fait on se sert du code PHP directement pour faire le rendu logique de la page. Pour se logger on fera de la manière suivante :

    public function testAdminLoginToApp()
    {
       $client = static::createClient([], [
            'PHP_AUTH_USER' => 'moi@mail.com',
            'PHP_AUTH_PW' => 'monpass',
        ]);

        // go to dashboard
        $crawler = $client->request('GET', '/dashboard');
        $elem = $crawler->filter('html > body > div > h1');

        // Verify the text in h1 as a proof i'm in
        $this->assertEquals('Dashboard', $elem->text());

    }

A la création du client, on injecte les identifiant et mot de passe, et on est loggé. Ensuite on émule le crawler en lui passant une requête de type GET. Puis on va explorer le DOM en utilisant la fonction filter pour extraire un élément du DOM

Suivre une redirection

Il est possible de suivre une redirection :

        $crawler = $client->request('GET', '/dashboard');
        $crawler = $client->followRedirect();
        $elem = $crawler->filter('html > body > div > h1');

Les tests fonctionnels peuvent prendre du temps, à la différence des test unitaires, vous pouvez vous rendre compte du temps avec la commande shell suivante :

time ./bin/phpunit

Restreindre le coverage des tests

Dans le fichier phpunit.xml.dist, vous pouvez indiquer les répertoires dont les tests seront exécutés.

symfony

Symfony custom form validation

Cette méthode est intéressante pour affiner votre contrôle d’un champ de formulaire. Par exemple nous allons ajouter un contrôle d’unicité de numéro de téléphone. Nous allons créer depuis le terminal un validateur

Création du validateur

php bin/console make:validator

Un prompt vous demande le nom de la classe validateur

 The name of the validator class (e.g. EnabledValidator):
 > UniquePhoneValidator                                 

 created: src/Validator/UniquePhoneValidator.php
 created: src/Validator/UniquePhone.php

On doit avoir deux classes, UniquePhone qui va servir pour créer l’annotation et UniquePhoneValidator qui contient le code qui va faire le contrôle d’unicité proprement dit.

Ensuite l’entité sur laquelle cette vérification va se faire, imaginons qu’on ait une entité Contrat, importons la classe créée qui se trouve dans la répertoire validator

Préparation de la classe UniquePhone

Pour pouvoir utiliser les annotation plus tard, nous devons importer une classe

<?php

namespace App\Validator;

use Doctrine\Common\Annotations\Annotation\Target;//ajouté
use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD","ANNOTATION"}) // ajouté
 */
class UniquePhone extends Constraint
{
    /*
     * Any public properties become valid options for the annotation.
     * Then, use these in your validator class.
     */
    public $message = 'Le numéro de téléphone {{ value }} existe déjà.'; // modifié
}

Préparation de la classe UniquePhoneValidator

<?php

namespace App\Validator;

use App\Repository\MatriceRepository;//ajouté
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class UniquePhoneValidator extends ConstraintValidator
{
    private $matriceRepository;v // on a besoin du repository pour faire le check
    public function __construct(MatriceRepository $matriceRepository)
    {
        $this->matriceRepository = $matriceRepository;
    }
    public function validate($value, Constraint $constraint)
    {
        /* @var $constraint \App\Validator\UniquePhone */

        $existingPhone = $this->matriceRepository->findOneBy(['clientTelFixe' => $value]); // ajouté

        if(!$existingPhone){ // ajouté
            return;
        }
        // TODO: implement the validation here
        $this->context->buildViolation($constraint->message)
            ->setParameter('{{ value }}', $value)
            ->addViolation();
    }
}
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use App\Validator\UniquePhone;

Ensuite plus loin nous avons la propriété ( le champ) qui sera concernée par cette vérification.

    /**
     * @var string
     * @UniquePhone()
     * @ORM\Column(name="CLIENT_TEL_FIXE", type="string", length=50, nullable=false)
     */
    private $clientTelFixe;

    /**
     * @var string|null
     * @UniquePhone()
     * @ORM\Column(name="CLIENT_TEL_MOBILE", type="string", length=50, nullable=true)
     */
    private $clientTelMobile;

Remarquez que tout se fait par annotation, c’est Doctrine qui se charge de faire marcher ces annotations. Donc il suffit d’ajouter l’annotation@uniquePhone() aux deux propriétés de l’entité pour activer la vérification.

Contrainte sur une classe entière

Pour placer l’annotation sur une classe et non sur une méthode, vous devez modifier la classe de contraint UniquePhone

<?php

namespace App\Validator;

use Doctrine\Common\Annotations\Annotation\Target;//ajouté
use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD","ANNOTATION","CLASS"}) // modifié
 */
class UniquePhone extends Constraint
{
    /*
     * Any public properties become valid options for the annotation.
     * Then, use these in your validator class.
     */
    public $message = 'Le numéro de téléphone {{ value }} existe déjà.'; // modifié

    public function getTargets()
    {
        return self::CLASS_CONSTRAINT;  // ajouté
    }

}

On a modifié l’annotation Target pour ajouter CLASS, et on a ajouté la méhode getTargets() pour que le validator puisse retourner la classe. Et au dessus de l’entité, enlever les annotations au dessus des propriétés de l’entité pour mettre au dessus de la class.

* MyEntity 
* @UniquePhone()
....
class MyEntity
{
...

Modifier la classe UniquePhoneValidator, cette étape est très importante sinon le messagene s’affichera pas. $value représente désormais la classe, et plus le numéro de téléphone (évidemment),

class UniquePhoneValidator extends ConstraintValidator
{
    private $matriceRepository;

    public function __construct(MatriceRepository $matriceRepository)
    {
        $this->matriceRepository = $matriceRepository;
    }

    public function validate($value, Constraint $constraint)
    {
        /* @var $constraint \App\Validator\UniquePhone */

        // at matrice creation we do the check,
        if (is_null($value->getIdMatrice())) {
            $existingPhone = $this->matriceRepository->findOneBy(['clientTelFixe' => $value->getClientTelFixe()]);
        } else {
            // at edition we do not do the check
            return ;
        }

        if (!$existingPhone) {
            return;
        }


        // TODO: implement the validation here
        $this->context->buildViolation($constraint->message)
            ->atPath('clientTelFixe') // la propriété concernée par la contrainte, avec cette ligne le message d'erreur s'affichera
            ->setParameter('{{ value }}', $value->getClientTelFixe())
            ->addViolation();
    }
}

Note sur la vérification d’unicité

Cela fait beaucoup de travail pour une simple vérification d’unicité, je vous suggère de garder à l’idée qu’une vérification clientside peut être utile et plus simple, couplé à une requête Ajax.

php

Manipulez les dates en PHP

La façon la plus commune que j’ai vu jusqu’à ce jour de créer une date en PHP est:

$today = date('Y-m-d')

la fonction date() et la classe DateTime

Traditionnellement on utilise date(), mais il existe aussi une classe DateTime, d’une utilisation plus complexe (car orienté objet et possédant plus de méthode et attributs). Voyons comment créer une date avec cette classe :

Ajouter des jours

$date = new DateTime(); // date d'aujourd'hui
#ajouter une durée à un objet DateTime


# on ajoute  un DateInterval
$date = new DateTime('2020-06-01');
$date->add(new DateInterval('P10D'));// ajoute 10 jours
echo $date->format('Y-m-d') . "\n";//on formate pour pouvoir afficher

on le voit sur l’exemple de l’ajout de durée, l’écriture est un peu plus lourde?La documentation officielle de PHP vous donnera plus d’informations. Le framework Symfony utilise l’objet DateTime.

Enlever des jours

# soustraire une durée DateInterval à un objet DateTime
$date = new DateTime('2020-06-01');
$date->sub(new DateInterval('P10D'));// enlève 10 jours
echo $date->format('Y-m-d') . "\n";

Ajouter un mois

$today = date('Y-m-d');
$time = strtotime($today);
$expire_date = date('Y-m-d',strtotime('+ 1 month');

calculer les jours ouvrés

formater une date

formater selon la locale

strtotime() est votre ami

strtotime() est une fonction qui convertit une date en un temps UNIX, en seconde compté depuis le 1 Janvier 1970, ce jour est appelé EPOCH. Donc elle vous donne le nombre de secondes écoulées depuis EPOCH. Documentation officielle de strtotime()

strtotime est une fonction puissante, qui permet de convertir en temps UNIX une date même si elle exprimée dans différents formats.

Là où strtotime est très utile, c’est justement sa capacité à convertir en UNIX timestamp (ou temps UNIX) différents format de date, permettant ainsi de faire des manipulation de date.

Ajouter une journée à une date

Nous allons voir comment ajouter simplement une journée à une date

$today = date('Y-m-d');
$unjour = 3600 * 24;//24 heures en secondes
$tomorrow = date('Y-m-d',strtotime($today) + $unjour)

Conversion de format de date

$format_us = '2020/06/16';
$timestamp = strtotime($format_us );
$format_fr = date('d/m/Y',$timestamp);
echo $format_fr; // 16/06/2020
#à noter que strtotime() selon la documentation "essait" de lire une date, il peut arriver qu'il ne parvienne pas à le faire.
#il n'y a pas vraiment de conversion automatique, on se sert de strtotime pour normaliser une date, en le convertissant en secondes.

Ajouter un fuseau horaire à une date

Parfois Javascript n’arrive pas à instancier une date si le string de la date n’est pas bien formé. Par exemple :

#format date envoyé par php :
date = '2020-06-12 12:21:22'
var d = new Date(date) // null
#il faut formater la date
date = '2020-06-12T12:21:22'

# pour ce faire lorsque que vous avez une date en PHP du type :
'2020-06-12 12:21:22'd, il faut utiliser strtotime :
$date = date('Y-m-d\TH:i:s',strtotime($abo['2020-06-12 12:21:22']) )
echo $date; //2020-06-12T12:21:22

TODO:

étant donné un mois, trouver le premier jour du mois précédent

le dernier jour du mois précédent

à partir d’une date get le mois seulement

php

Débugger vos script PHP avec XDEBUG

XDEBUG est un add on très puissant pour débugger vos scripts Php. Il vous permet de connaitre le temps d’exécution d’un script, l’ordre dans lequel les fonctions s’enchainent, et permet de débugger via les éditeurs de code comme SublimeText ou PHPStorm ou VSCode. Dans le cas de SublimeText, il faut installer via Package install un plugin et configurer XDEBUG dans le fichier php.ini pour permettre de débugger depuis votre IDE, c’est ce qu’on appelle le remote debugging.

Configuration du  fichier php.ini

Aujourd’hui la plupart des installations php comportent Xdebug par défaut. Il suffit donc de configurer le fichier php.ini

Configurez votre section relative à Xdebug de cette façon :

[xdebug]
xdebug.remote_enable = 1
xdebug.profiler_enable = off
xdebug.profiler_enable_trigger = 1
xdebug.profiler_output_name = "cachegrind.out.%u.%H.%R"
xdebug.profiler_output_dir = "c:/wamp/tmp"
xdebug.show_local_vars=0

Ensuite dans l’url de votre browser ajoutez le paramètre GET  de cette façon :

http://example.com/?XDEBUG_PROFILE

Un fichier texte généré dans le répertoire c:/wamp/tmp et il est lisible avec le logiciel Wincachegrind.

Il peut se produire un message d’avertissement lorsque Wincache grind essai d’ouvrir et de parse le fichier grind, comme une duplication de clé, essayez avec une version plus ancienne. Ce projet n’est pas très activement maintenant, mais c’et le meilleur en tout cas pour nos besoins.

php

Comment se connecter à mysql en php?

Différentes méthodes de connexion à MySQL en PHP

Pour vous connecter à votre base de données, vous avez besoin du nom de la base de données, du nom de l’hôte qui héberge votre base de données, du nom de l’utilisateur qui a les droit de s’y connecter et du mot de passe bien évidemment.

Méthode âge de pierre

C’est la méthode que l’on apprend en premier lieu lorsqu’on apprend le PHP.

Cela se fait en deux temps : d’abord on crée un objet connexion à la base de données, et ensuite on fait la requête SQL et enfin on parcourt le tableau de résultats envoyés.

1/Définition des données de connexion

Nom de la base de données :  $db = ‘nom_base‘;

nom du serveur de la base de données : $host = ‘localhost’;  (le plus souvent)

nom de l’utilisateur :   $user = ‘username’;

et son mot de passe :  $pass = ‘password‘;

2/Instruction pour la connexion à la base de données:

@$conn = new mysqli($host,$user,$pass,$db);
if (mysqli_connect_errno())    {    echo 'Error  : could not connect to database. Try again';    exit;    }

Le @ signifie ne pas afficher de message d’erreur, je ne recommande pas de le mettre car il masque les erreurs et ne favorise pas le débuggage !

La seconde ligne tente la connexion et affiche un message d’erreur s’il y en a un.

Aujourd’hui (2020 en fait depuis des années déjà, il ne faut plus utiliser msqyli et encore moins mysql, qui ne sont pas sécure. Utiliser PDO à la place, c’est plus verbeux mais vous serez à la page et il y aura moins de risques.)

3/Exécution de la requête

Très important,c’est ce qui va vous faire parvenir les résultats.

$sql = “SELECT * FROM table LIMIT 10”;

Ici on sélectionne les 10 premiers résultat d’une table.

$result = $db->query($sql);

3/Parcourir le tableau associatif qui contient les enregistrements

Une fois que le résultat est retourné vous devez le parcourir ligne par ligne.

Pour ce faire on va s’aider de la boucle While.

while ($row = $result->fetch_assoc()){
   $result[]['nom'] = $row['nom']
// etc

}

Méthode Pro et actuelle avec PDO

Veuillez vous référer à cette page pour le tuto correspondant sur PDO.

php

Installer php 7.2 sous Mac OS

Le temps file, et les version antérieures de PHP ne seront plus supportées, par exemple de plus en plus de librairies exigent php 7.0 minimum, certes c’est présent dans les installation récentes, mais vous devez savoir aussi installer les versions de php 7.1, 7.2, 7.3, 7.4 par exemple. Voici un petit tuto sous Mac OS pour installer une version 7.2 de php. Ici PHP est installé en tant que module d’Apache.

Utiliser Homebrew pour installer php 7.2

Homebrew est un gestionnaire de package, un peu comme composer pour le php, mais pour le système Mac.

brew install php@7.2

Cette fonction va créer un répertoire dans usr/local/Cellar/php@7.2. Cellar est l’endroit où sont stockés les package Mac.

Changer la version de php pour la ligne de commande sous Mac OS

Vous n’êtes pas sensé ignorer qu’il existe deux version d’interpréteur sur une installation serveur, l’interpréteur php en ligne de commande, et l’interpréteur web.

echo 'export PATH="/usr/local/opt/php@7.2/bin:$PATH"' >> ~/.bash_profile
echo 'export PATH="/usr/local/opt/php@7.2/sbin:$PATH"' >> ~/.bash_profile

Cette commande bash va insérer une ligne dans votre fichier de configuration .bash_profile, pour le faire pointer sur la nouvelle version de php.

Changer la version de php pour le web

Pour ce faire il faut aller modifier le fichier de configuration d’Apache dans le cas où php est en mode module d’Apache (ce n’est pas fcgi). Décommentez tout autre ligne de chargement d’une autre version de php.

LoadModule php7_module  /usr/local/opt/php@7.2/lib/httpd/modules/libphp7.so

Vérifiez avec phpinfo() la version . Normalement c’est tout ce dont vous aurez besoin. En module pour apache, il n’est pas possible d’installer plusieurs versions de php en simultané (chose que fait facilement Nginx), mais il est possible sous Apache d’installer plusieurs version en simultané de php si on utilise fastCGI par exemple.

Attention, on n’a pas touché à php.ini, il peut y avoir des différences subtiles ! Pour cet exemple je suis passé de php 7.1.23 à php 7.2.23

Installer la version xdebug correspondante à PHP 7.2

Prochainement j’indiquerai comment mettre en place le module xdebug pour cette version de PHP.

Il faut installer le xDebug correspondant à la version de PHP 7.2, comme xDebug a été enlevé du dépôt Homebrew, il faut utiliser PECL pour l’installer.

pecl install xdebug
#Si ERROR: failed to mkdir /usr/local/Cellar/php@7.2/7.2.23/pecl/20170718
#créer à la main le répertoire, si création impossible , il s'agit surement d'un lien #symbolique,l'effacer et refaire mkdir

Pour savoir où xdebug.so a été installé (pour pouvoir paramétrer xDebug dans le fichier php.ini), comme vous avez utilisé Brew, il se trouve dans le répertoire Cellar :

/usr/local/Cellar/php@7.2/7.2.23/pecl/20170718/xdebug.so
#à la fin de l'installation ce message vous sera affiché.

Comment installer Composer le gestionnaire de package de PHP

Aujourd’hui tout lange de programmation moderne se doit d’avoir un gestionnaire de package, pour NodeJS on a NPM, pour C# on a Nugget, etc.

Installation de Composer sous Windows

Pour avoir les étapes d’installation, se référer à cet article relatif à l’installation de Composer.

Il suffit d’installer l’exécutable composer-setup.exe

Installation de composer sous Linux/MacOS

Il est préférable d’installer en ligne,

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
#vérification 
php -r "if (hash_file('sha384', 'composer-setup.php') === 'e0012edf3e80b6978849f5eff0d4b4e4c79ff1609dd1e613307e16318854d24ae64f26d17af3ef0bf7cfb710ca74755a') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
#exécution du fichier php qui va installer composer
php composer-setup.php
#effacement du fichier php qui nous a servi à installer composer
php -r "unlink('composer-setup.php');"

Le fichier composer.json

Ce fichier consigne tous les paquets qui sont installés, lisez les section require ou require-dev, ils listent les paquets qui seront installés dans le dossier vendor.

Composer a aussi un rôle de chargement des classes des librairies qui sont dans le dossier vendor, en effet il n’est pas simple d’accéder à des classes qui sont enfouis profondément dans ce répertoire.

L’autoloading dans composer

Dans notre répertoire de travail nous voulons pouvoir accéder aux classes depuis notre répertoire de travail

/app
   /controller
   /services
/vendor
  /librairie1
    /Query.php

Par exemple dans le répertoire controller de notre projet, nous voulons accéder à la classe Query.php, nous voyons le chemin pour y arriver, donc dans notre fichier controller :

use \librairies\Query
class UserController {
  $query = new Query()
}

Remarquez la correspondance entre le chemin et le use, il y a correspondance entre le chemin pour aller jusqu’à la classe et la syntaxe du use.

Erreurs qu’on peut rencontrer avec composer

Pas assez de mémoire pour exécuter composer

On utilise composer en ligne de commande, PHP dispose d’une variable d’environnement qui fixe le seuil maximal de mémoire autorisé pour exécuter des script php, et composer en réalité est un script php qui s’exécute ! Nous pouvons faire appel à la variable memory_limit de cette façon

>php -d memory_limit=512M /usr/local/bin/composer update
#note : PHP en ligne de commande est différent de PHP pour le serveur web !
#ou encore mieux exécuter sans limite de mémoire
php -d memory_limit=-1 /usr/local/bin/composer update

Note pour le framework Symfony :

S’il existe un fichier parameters.yaml.dist, composer va tenter de générer un parameters.yaml depuis ce dernier fichier, écrasant le parameters.yaml original, donc faites attention lorsque vous importez un projet existant !

php

Installer PHP 5.6 sur Mac OS

Comme nous nous dirigeons vers le futur, sur Mac OS Homebrew, PHP 5.6 n’est plus disponible. Or cette version de PHP était très utilisée, et quand vous récupérez des projets ancienc qui tournent sous cette version, ils risquent de ne pas tourner sur PHP 7 par exemple. Dans ce cas vous avez besoin de vous tourner vers la version PHP 5.6.

Seulement Homebrew officiellement ne fournit plus PHP 56. Mais il est quand même possible de l’installer avec une petite manipulation.

brew tap exolnet/homebrew-deprecated

brew install php@5.6

Ajoutez dans le fichier /etc/apache2/httpd.conf la ligne

LoadModule php5_module /usr/local/opt/php@5.6/lib/httpd/modules/libphp5.so

Et décommentez la ligne qui charge le module php7, redémarrez apache avec la commande suivante (vous aurez besoin de rentrer le mot de passe :

sudo apachectl restart

Ensuite pour vérifier la version de php surtout ne faites pas en ligne de commande php -v . ! En effet il existe deux version de PHP potentiellement, une version pour la ligne de commande et une version pour le serveur web.

Changer la version de PHP utilisée en ligne de commande

Là c’est un peu plus délicat. En faisant l’installation de PHP 5.6 via Homebrew, le binaire est installé dans le répertoire : /usr/local/Cellar/php@5.6/5.6.40/bin/

Pour exécuter PHP de ce répertoire et disposer de la version 56, indiquez le chemin complet :

/usr/local/Cellar/php@5.6/5.6.40/bin/php -v

PHP 5.6.40 (cli) (built: Apr 23 2019 11:14:34) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies

Un mois avec un framework PHP petite désillusion

La veille d’écrire ce post, cela faisait à peu près deux mois que je m’était mis sur Symfony 4 (j’ai eu aussi une petite période avec Symfony 2 par le passé mais moins investi)

Pourquoi ce tweet? comme souvent mes tweets répondent à l’émotion du moment, posons la question : pourquoi ce message ?

Mon background

Ingénieur non informatique de formation, j’ai commencé ma carrière dans l’industrie puis me suis tourné vers l’informatique il y a un peu plus de dix ans, je suis entré dans le développement web. Je suis autodidacte, et ces 3 dernières années j’ai un peu boosté mon niveau en devenant salarié et travaillant dans une équipe.

Je possède des compétences en Linux, le stack LAMP, un peu vieille école, c’est-à-dire the hard way is easier (rien ne vaut une bonne requête SQL). Je n’ai pas beaucoup de théorie sur l’informatique (algo etc), j’ai fait mes armes à l’école anglo-saxonne et web, cependant je suis passé par math sup/spé.

Mon premier framework avec lequel j’ai vraiment travaillé est AngularJS, ce fut fun, puis .Net, grosse montagne, trop grosse, mais j’ai apprécié la puissance de Visual Studio, j’ai enfin compris l’intérêt du typage statique dans un IDE, puis un petit détour par Java (pouah !), puis brièvement sur Laravel 5, et là je suis sur Symfony 4.

J’avais de grandes attentes, un framework digne du nom, qu’on arrête de se moque des développeurs PHP avec les appels BDD mélangé à du HTML, c’est un level up pour moi et surtout mon CV (compétence très demandée du moins en France, donc pérennité du boulot). Symfony 4 c’est aussi et indubitablement les meilleures pratiques en code, les meilleurs patterns, pas de doute, cela fera de moi un meilleur développeur !

Ce billet n’est pas une critique de Symfony et on alter ego Laravel, et je cible tous les frameworks serverside en général.

Ce qui suit n’engage que moi, et d’autres personnes peuvent penser différemment.

Ma philosophie du code

Ce qui m’attire dans le développement c’est la résolution de problème, augmenter la productivité des gens en leur fournissant des codes qui automatisent le travail rébarbatif. Chaque fois que j’arrive à faire quelques chose en code, j’ai un shoot d’adrénaline, une satisfaction qui égaye ma journée, et en informatique c’est quelque chose de constant (ça m’arrive au moins une fois par jour). J’aime trouver des solutions, créatives, détournées, parfois même en enlevant tout le code et utiliser un software qui fait le boulot, ça me satisfait.

Le développement informatique nous procure beaucoup de libertés, moi ce qui me plait le plus c’est de créer, j’avoue que une fois que le logiciel est créé, je n’ai pas envie de faire la maintenance, ou faire une TMA trop longtemps, ce n’est pas ma tasse de thé de rester avec un logiciel des années, ce qui me plait c’est la phase travaux neuf. (j’aime aussi améliorer un logiciel pourri si le temps m’est permis, optimiser une requête SQL afin de le faire tourner dix fois plus vite me procure autant de plaisir que les travaux neufs).

Bien sûr je ne suis pas un cador, mon code n’est pas parfait, je n’y arrive pas du premier coup, je ne suis pas un ingénieur 10X (MDR). Avec l’expérience j’arrive à produire un code pas trop dégueulasse, avec toujours de meilleures pratiques. Mes applis marchent et délivrent.

Le problème avec les frameworks

J’avoue c’est Symfony le déclencheur, cela aura sans doute été moins évident avec Laravel. Donc j’ai pu regarder pas mal de vidéo de Symfony et j’ai appris beaucoup de choses, j’ai aussi fait beaucoup en code sur un projet vrai, pas sur les exercices.

Je me suis rendu compte avec les tuto sur les formulaires Symfony (qui est LE PLUS morceaux du framework à mon avis) sont un très grosse montagne, mais en même temps qu’il n’y avait pas de grosse difficultés, le framework est bien pensé. On peut tout faire, mais le problème est que l’on peut tout faire à la mode Symfony. Donc il faut savoir, pas de secret.

Un framework dirigiste

En anglais on appelle cela un opinionated framework, un framework où il faut faire à leur façon. En fait les séries de vidéos très bien faites, montrent que c’est une série de recettes qu’il faut appliquer, il ya beaucoup de choses à savoir (le côté difficile) et en même temps ce n’est pas si compliqué si on sait comment faire.

Beaucoup de paramétrages

Symfony vient avec une série de fichiers YAML, une notation très succincte, qui permet de configurer l’environnement de l’application. Donc le paramétrage est un aspect très prégnant d’une application faite avec Symfony. De même les entités sont paramétrées avec des annotations Doctrine, qui définissent les relation entre les entités (miroir des tables de la base de données), mais ça je trouve plutôt pas mal car vous gagnez beaucoup de temps, mais il faut il y a beaucoup de chose à savoir !

Une fois qu’on respecte à la lettre les recettes, on s’aperçoit que finalement on a peu de liberté pour coder, puisque tout est réglé au millimètre. En fait votre seule liberté est dans la couche business.

Travailler avec un framework de grade entreprise, les contreparties

Un framework a une raison d’exister puisqu’il y a un marché, et ce marché c’est celui de l’entreprise, des moyennes et grosses applications. Il faut produire des applications robustes, dans un minimum de temps, et que cette application soit extensible. Et pour remplir ces objectifs, on ne peut pas faire autrement, on ne peut pas réinventer la roue à chaque fois.

Je n’ai plus l’impression d’être un artisan du web, mais plutôt un ouvrier qui va travailler selon des normes ISO, des process, je ne critique pas cela, car dès qu’on vise une certaine qualité logicielle, il faut passer par ces frameworks. Mais ce faisant on va faire toujours les mêmes choses.

C’est pour ça que j’ai abandonné l’idée de développer des connaissances en Java et C#, car de facto quand vous abordez des projets dans ces langages, vous vous retrouvez face à des léviathans.

Donc en bref, vous gagnez en bonne pratique et robustesse, qualité de l’application (bonne chose), mais c’est au détriment de la liberté.

Note : Ce n’est pas parce qu’un framework vous oblige à coder de telle façon qu’il n’est pas possible de sortir une application codée de façon dégueulasse.

Je ne sais pas où vous pouvez vous caser, mais le futur que vous envisagez n’est peut-être pas aussi intéressant que vous pensiez, faire des projets qui se ressemblent va finir par vous user, ce qui nous fait au problème suivant : trouverez vous le plaisir de coder si cela devient routinier?

PS : inutile de commenter, le débat peut se poursuivre sur Twitter.

Retour en haut