Créer son framework PHP Objet

Créer son framework PHP Objet

Pour faire suite à un article que j’avais écrit il y a un peu plus de quatre ans maintenant sur la création d’un framework PHP, je vous propose de créer un framework PHP Objet en utilisant les principes MVC.

Lorsque je travaillais encore chez CBC Informatique, nous n’utilisions pas les principes de la programmation orientée Objet et nous préférions développer nous même les sites Web de nos clients plutôt que de s’appuyer sur des solutions toutes faites, afin de garder la maitrise de notre code. C’est dans cette optique que j’avais développé notre mini-framework/CMS.

Depuis presque 1 an maintenant,  je travaille chez Ibakus Europe et à nouvelle équipe nouvelle façon de travailler. Pour concevoir les nouvelles applications Web IBAKUS, nous utilisons la programmation orientée Objet et les principes du MVC. Nos applications gérant des données plutôt sensibles, il a été décidé de développer notre propre framework PHP Objet, afin de garder au maximum la main sur le code et pouvoir le modifier plus facilement.

Les bases du framework PHP Objet

D’abord, nous avons écrit une classe maîtresse que l’on a appelée Container. Elle nous permet entre autre d’initialiser le framework avec un fichier de configuration, de définir les différentes routes et de charger les différents Modèles et Contrôleurs.

Une classe abstraite Model définit les méthodes utilisées pour agir sur la base de données puis chacun de nos modèles étendent cette classe afin de gérer les spécificités qui leur sont propres.

Mon but n’étant pas de publier le code source de notre framework, je m’intéresserai uniquement aux méthodes CRUD de notre classe abstraite Model.

Structure de la classe abstraite Model

La classe abstraite Model est définie par deux propriétés $db et $table et cinq méthodes : get(), getDatas(), set(), delete() et save().

La propriété $db est une instance de la classe PDO établissant la connexion à notre base de données, $table quand à elle contient le nom de la table sur laquelle les opérations des méthodes save() et delete() vont être faites. Voici la structure de notre classe :

abstract class Model {
  protected $db;
  protected $table;

  public function __construct() {
    $this -> db = Container::getDb();
    $this -> table = $this;
  }

  /**
   * Un echo de $this retournera le nom de la table associée au modèle.
   * Par exemple 'pages' pour le modèle 'PagesModel'
   */
  public function __toString() {
    return strtolower(substr(get_class($this), 0, -5));
  }

  // GETTERS
  public function get($attr) {
    return $this -> $attr;
  }

  /**
   * Retourne tous les attributs de l'objet
   */
  public function getDatas() {
    $datas = array();
    foreach (get_object_vars($this) as $key => $value)
        $datas[$key] = $value;

    return $datas;
  }

  // SETTER
  public function set($attr, $data) {
    if (property_exists($this, $attr)
        $this -> $attr = $data;
  }

  // METHODES
  public function delete() {}

  public function save() {}
}

La méthode save()

cette méthode permet d’enregistrer l’objet dans la base de données, que ce soit pour son insertion ou lors de sa modification. Pour définir si l’on va faire un INSERT ou un UPDATE, on testera la valeur de l’attribut id de l’objet courant. Si elle n’est pas nulle on souhaite modifier l’objet, sinon on crée une nouvelle entrée dans la base.

public function save($type = null) {
  if ($this -> get('id') == null) {
    $query = 'INSERT INTO ' . $this -> get('table') . ' SET';
    $nbDatas = count($this -> getDatas());

    $i = 0;
    foreach ($this -> getDatas() as $key => $value) {
      $i++;
      $query .= ' ' . $key . ' = :' . $key;
      if ($i < $nbDatas)
        $query .= ',';
      else
        $query .= ';';
    }
  } else {
    $query = 'UPDATE ' . $this -> get('table') . ' SET';
    $nbDatas = count($this -> getDatas());

    $i = 0;
    foreach ($this -> getDatas() as $key => $value) {
      $i++;
      if ($key != 'id') {
        $query .= ' ' . $key . ' = :' . $key;
        if ($i < $nbDatas)
          $query .= ',';
      }
    } $query .= ' WHERE id = :id;';
  }
  $query = $this -> get('db') -> prepare($query);

  foreach ($this -> getDatas() as $key => $value)
    $query -> bindValue(':' . $key, $value);

  $executed = $query -> execute();

  if ($executed && $this -> get('id') == null)
    $this -> set('id', $this -> get('db') -> lastInsertId());

  return $executed;
}

La méthode delete()

Pour supprimer les données de l’objet enregistré, rien de vraiment compliqué, on execute simplement une requête préparée avec la classe PDO et on supprime l’enregistrement dont id correspond à l’attribut id de l’objet courant.

public function delete() {
  $query = $this -> get('db') -> prepare('DELETE FROM ' . $this -> get('table') . ' WHERE id = :id;');
  $query -> bindValue(':id', $this -> get('id'));

  return $query -> execute();
}

Pour finir : construire un CMS

Construire un CMS sur base d’une classe abstraite comme celle-ci permet d’écrire très simplement les différents modules dont on aura besoin.

Si l’on souhaite gérer des pages de contenu, il suffira d’écrire un modèle héritant de la classe Model, par exemple pagesModel et d’y définir les attributs de l’objet en regard de la structure de la table pages de la base de données.

Cette classe héritant de la classe abstraite, nous n’auront pas besoin de réécrire nos méthodes save() et delete() et l’on pourra se concentrer sur des méthodes permettant par exemple, de retourner un menu de navigation, des méta-tags pour le référencement naturel, etc.

Bien sûr, il faudra écrire un contrôleur permettant de traiter les données à passer au modèle, qui se chargera ensuite de les enregistrer en base de données, mais ça se fait rapidement  .

Là dessus, bonne semaine (et bonne année) !