Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. PHP et MySQL
  3. Corrigé 7
Extrait - PHP et MySQL Entraînez-vous à développer une application collaborative
Extraits du livre
PHP et MySQL Entraînez-vous à développer une application collaborative Revenir à la page d'achat du livre

Corrigé 7

Prérequis

1.

c. et d.

Ce sont les réponses c et d qui conviennent le mieux. Une interface - au sens programmation - est une liste de fonctions avec un nom et une signature prédéfinie, sans implémentation. Il conviendra d’apporter une implémentation spécifique pour mettre en œuvre l’interface sous la forme d’une classe. On peut donc considérer qu’une interface est un contrat de développement à respecter.

2.

c.

La réponse c s’impose, la réponse b n’étant pas assez précise. Un constructeur est identifiable par son nom __construct (en PHP), il a pour rôle d’initialiser les champs du nouvel objet.

3.

b.

Réponse b, un design pattern est une méthode de conception standardisée. On trouve de catalogues entiers de patterns pour traiter différents besoins de conception logicielle, tels que le singleton (une seule instance d’une classe), la fabrique, la stratégie, le visiteur, l’itérateur, l’observateur…

4.

a.

Le mot-clé qui convient est implements. Les autres réponses ne correspondent pas à l’implémentation d’une interface, voire ne font pas partie des instructions du langage PHP.

5.

a.

C’est une grande chance que de disposer d’une telle API avec PHP. Elle permet de décrire des classes (à l’aide de ReflectionClass...

Corrigé 7.1 Structure du framework

 Voici les quatre lignes à ajouter pour afficher (dumper) les variables et stopper le script. Elles sont à retirer après le test !

/* 
* Run action 
*/ 
$route = $_SERVER['REQUEST_URI']; 
$target_action = FPLGlobal::get_action($route, FPLGlobal::$default_route); 
$model = FPLGlobal::get_request_data(); 
 
var_dump($route); 
var_dump($target_action); 
var_dump($model); 
die; 

L’affichage produit l’effet escompté ; l’URL est décodée en distinguant la zone, le contrôleur, l’action. Puisqu’il s’agit d’un GET, la query string est également décodée.

images/C07TP01.png

 Ces lignes peuvent être insérées avant l’instruction require_once. De toute façon, l’instruction die stoppe l’exécution du script.

echo "chemin du contrôleur : ".FPLGlobal::get_controller_path($target_action); 
die; 

Rappelons qu’il s’agit d’un chemin relatif au script « entrant », à savoir router.php, lui-même situé sous application/. Nous en déduisons que le répertoire controllers/ part aussi de ce dossier application/.

images/C07TP02.png

 Un masque d’expression régulière est utilisé pour identifier la présence de page template. Comme...

Corrigé 7.2 La fabrique de contrôleurs et l’injection de dépendances

 Les annotations consistent en du code PHP intégré sous forme de commentaires. Toutefois, c’est bien le moteur PHP qui les analyse.

/* 
* dicomponent.php 
*/ 
 
/** 
* Annotation pour injecter des dépendances au niveau du contrôleur 
*  
*/ 
class DIComponent extends Annotation 
{ 
   /** 
    * Liste de champs séparés par une virgule 
    * @var string 
    */ 
   public $field_names; 
 
   /** 
    * Liste de classes séparées par une virgule 
    * @var string 
    */ 
   public $class_names; 
} 

 Les deux fichiers main.php et dicomponent.php sont au même niveau dans l’arborescence fichier ; l’instruction d’inclusion est alors :

require_once 'dicomponent.php'; 

 C’est le système de réflexion qui est employé pour découvrir les aspects d’une classe (on parle d’ailleurs de programmation orientée aspect ou AOP).

// existence de dépendances au niveau du contrôleur 
$di_components = null; 
$ct_di = new ReflectionAnnotatedClass($cl_name); 
$ct_di_at...

Corrigé 7.3 Intégrer du scripting dans les vues

 Comme toujours, la documentation PHP est indispensable pour relire le programme, mais aussi pour alimenter l’aide contextuelle de l’IDE Eclipse.

/* 
* viewscript.php 
*/ 
 
class ViewScript  
{ 
   /** 
    * Code HTML du fragment à traiter par script de substitution 
    * @var string 
    */ 
   public $view_source; 
 
   /** 
    * Code HTML de sortie 
    * @var string 
    */ 
   public $view_html; 
 
   /** 
    * Tableau associatif de variables 
    * @var array 
    */ 
   public $view_context; 
 
   public function __construct() 
   { 
       $this->view_source=""; 
   } 
} 

 Mieux vaut que cette fonction reçoive un nom de fichier avec chemin, car elle peut être activée depuis plusieurs emplacements dans l’arborescence du site web (contrôleur, vue…).

public function set_view_source_from_file($filename) 
{ 
   $this->view_source = file_get_contents($filename); 
} 

 La fonction callback est anonyme (elle ne porte pas de nom). Elle...

Corrigé 7.4 Ajouter des traces

 Évidemment, ce fichier trace.php doit être inclus dans main.php. On remarque l’utilisation de DateTime pour formater correctement les millisecondes, ce que la fonction classique date() ne prend pas en charge.

/* 
* trace.php 
*/ 
class TraceLevel { 
   public const LEVEL_VERBOSE = 0; 
   public const LEVEL_INFO = 1; 
   public const LEVEL_WARNING = 2; 
   public const LEVEL_ERROR = 3; 
} 
 
interface TraceWriter { 
   /** 
    * Ecrit une trace 
    * @param string (GUID) $http_session_id 
    * @param string $message 
    * @param TraceLevel $level 
    */ 
   public function write_message($http_session_id,$message,$level=TraceLevel::LEVEL_VERBOSE); 
 
   /** 
    * Obtient la liste des traces 
    */ 
   public function get_trace(); 
} 
 
class SessionTraceWriter implements TraceWriter { 
   private const SESSION_TRACE_ID = "session_trace_id"; 
 
   public function get_trace() { 
       if(isset($_SESSION[SessionTraceWriter::SESSION_TRACE_ID])) 
           $trace = $_SESSION[SessionTraceWriter::SESSION_TRACE_ID]; 
       else { 
           $trace = array(); 
           $_SESSION[SessionTraceWriter::SESSION_TRACE_ID] = $trace; 
       } 
 
       return $trace; 
   } 
 
   public function write_message($http_session_id,$message,
$level=TraceLevel::LEVEL_VERBOSE) { 
       $d = new DateTime(); 
 
       $trace = $this->get_trace(); 
       $trace[] = array( 
           "message" => $message,  
           "level"=>$level,  
           "date"=>...

Corrigé 7.5 Une interface pour visualiser les traces

 Si la méthode get_trace() est ajoutée à l’interface, elle doit obligatoirement être implémentée dans SessionTraceWriter :

interface TraceWriter { 
   /** 
    * Ecrit une trace 
    * @param string (GUID) $http_session_id 
    * @param string $message 
    * @param TraceLevel $level 
    */ 
   public function write_message($http_session_id,$message,$level=
TraceLevel::LEVEL_VERBOSE); 
 
   /** 
    * Obtient la liste des traces 
    */ 
   public function get_trace(); 
 
   /** 
    * Efface les traces existantes 
    */ 
   public function clear_trace(); 
} 
 
class SessionTraceWriter implements TraceWriter { 
   private const SESSION_TRACE_ID = "session_trace_id"; 
 
   public function get_trace() { 
       ... 
   } 
 
   public function write_message($http_session_id,$message,$level=
TraceLevel::LEVEL_VERBOSE) { 
       ... 
   } 
 
   public function clear_trace() { 
       $_SESSION[SessionTraceWriter::SESSION_TRACE_ID] = array(); 
   } 
} 

 Il s’agit d’une méthode passe-plat (elle délègue le traitement). Mais rappelons que cette construction permet de choisir un autre canal pour enregistrer les traces (fichier, base de données, SNMP…) sans impacter le code utilisateur.

/** 
 * Efface les traces existantes 
 */ 
public static function clear_trace() { 
   self::init_writer(); 
   self::$trace_writer->clear_trace(); 
} 

 Il s’agit d’un...