Aller au contenu

Serveur - PHP Frameworks

Les frameworks PHP#

Les frameworks (en général) permettent un gain de temps de développement et de maintenance, notamment:

  • en gérant nos propres URLs
  • en structurant le code (respect d’une architecture MVC par exemple)
  • en simplifiant le code (authentification, accès bdd, formulaire, etc.)
  • finalement, en gérant la majeure partie du développement à notre place

Le choix du framework est par contre plus délicat, et sera à faire en fonction des besoins du projet. Parmi les plus utilisés:

Ainsi que des frameworks PHP ultra-minimalistes:

FlightPHP#

Ce framework ultra-minimaliste n’est pas strictement basé sur l’architecture MVC, mais il permet de s’en rapprocher et surtout de comprendre assez rapidement le rôle d’un framework.

Installation#

  • Téléchargez la librairie
  • Ajoutez un fichier .htaccess (configuration Apache)
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php [QSA,L]
    
  • Créez/modifiez le fichier index.php
    <?php
    require 'flight/Flight.php';
    Flight::route('/', function () {
      echo 'hello world!';
    });
    Flight::start();
    ?>
    
  • (Configurez votre serveur web pour pointer vers ce dossier) et accédez via http://localhost

Doc officielle

Bonnes pratiques#

  • Utilisez un dossier views pour les différentes vues de votre site (page ou morceaux de pages HTML)
  • Utilisez un dossier assets pour les ressources statiques (CSS, JavaScript, images, etc.)

Exercice - Création d’une TodoList#

Première étape, on crée une route (URL) /todos qui appellera la méthode index de la classe Todos (controller)

./index.php

<?php
// charge le controller
require './controllers/Todos.php';
// creation de la route /todos
Flight::route('/todos', [new Todos(), 'index']);
?>

Cette méthode index crée un tableau de todos vide (pour l’instant), et envoie ce tableau à la vue todos

./controllers/Todos.php

<?php
class Todos {
  public function index () {
    $todos = [];
    Flight::render('todos', ['todos' => $todos]);
  }
}
?>

Notre vue todos se contente d’afficher le tableau des todos (s’il y en a), et créé également un formulaire pour en ajouter de nouveaux.

./views/todos.php

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <h1>Todos</h1>
  <?php if (sizeof($todos) > 0) { ?>
    <ul>
      <?php foreach ($todos as $todo) { ?>
        <li><?= $todo ?></li>
      <?php } ?>
    </ul>
  <?php } else { ?>
    <p>No todos yet</p>
  <?php } ?>
  <form action="/todos/add" method="post">
    <label>
      New todo
      <input type="text" name="todo">
    </label>
    <input type="submit" value="Add todo">
  </form>
</body>
</html>

Ajouter un todo#

On note que lors de la validation du formulaire, les données sont envoyées à l’URL /todos/add en mode POST. Créons alors cette route, qui appelle la méthode add de notre controller:

./index.php

<?php
// charge le controller
require './controllers/Todos.php';
// creation des routes
Flight::route('/todos', [new Todos(), 'index']);
Flight::route('POST /todos/add', [new Todos(), 'add']);
?>

Dans notre controller, cette méthode doit alors créer un nouveau todo, et sauvegarder cette information. C’est à ce moment là que les models de l’architecture MVC nous sont utiles. Un model est une abstraction de notre modèle de données, par exemple une base de données. C’est ce que l’on va utiliser ici.

Tout d’abord, créez une base de données todos, qui contient une table todos avec 2 champs : id (int) et text (text ou varchar). Puis, configurer l’extension PDO pour Flight dans index.php (il faut aussi activer l’extension PDO dans votre php.ini)

./index.php

<?php
Flight::register('db', 'PDO', array('mysql:host=localhost;dbname=todos', 'root', 'root'));
?>

Notre modèle va alors utiliser cette configuration, puis exécuter une requête SQL

./models/Todo.php

<?php
class Todo {
  public function __construct () {
    $this->db = Flight::db();
  }
  public function add ($todo) {
    $sql = 'INSERT INTO todos (id, text) VALUES (NULL, :todo)';
    $stmt = $this->db->prepare($sql);
    $stmt->bindParam(':todo', $todo);
    $stmt->execute();
  }
}
?>

Dans notre controller, on peut alors appeler cette méthode add() en lui passant la valeur reçue en POST si elle existe. Et on redirige vers l’URL /todos, car on ne souhaite pas rester sur /todos/add.

./controllers/Todos.php

<?php
require './models/Todo.php';

class Todos {
  public function __construct () {
    $this->Todo = new Todo();
  }
  public function index () {
    $todos = [];
    Flight::render('todos', ['todos' => $todos]);
  }
  public function add () {
    if (isset($_POST['todo'])) {
      // appel du modèle
      $this->Todo->add($_POST['todo']);
    }
    Flight::redirect('/todos');
  }
}
?>

Maintenant que l’on a des todos, il faut également penser à mettre à jour notre méthode index qui doit les afficher. Pour cela, on crée d’abord une nouvelle méthode getAll() dans notre modèle.

./models/Todo.php

<?php
class Todo {
  ...
  public function getAll () {
    $sql = 'SELECT id, text FROM todos';
    $result = $this->db->query($sql, PDO::FETCH_ASSOC);
    $data = [];
    if ($result) {
      foreach($result as $r) {
        $data[] = $r;
      }
    } else {
      echo 'SQL error';
    }
    return $data;
  }

}
?>

Que l’on utilise depuis notre controller:

./controllers/Todos.php

<?php
class Todos {
  public function index () {
    $todos = $this->Todo->getAll();
    Flight::render('todos', ['todos' => $todos]);
  }
}
?>

Et on pense à mettre à jour la vue, car un todo est composé de deux champs: id et text

...
  <h1>Todos</h1>
  <?php if (sizeof($todos) > 0) { ?>
    <ul>
      <?php foreach ($todos as $todo) { ?>
        <li><?= $todo['text'] ?></li>
      <?php } ?>
    </ul>
  <?php } else { ?>
    <p>No todos yet</p>
  <?php } ?>
...

Supprimer un todo#

Pour supprimer un todo:

  • dans la vue: création d’un lien vers /todos/remove/{id}

./views/todos.php

...
  <h1>Todos</h1>
  <?php if (sizeof($todos) > 0) { ?>
    <ul>
      <?php foreach ($todos as $todo) { ?>
        <li><?= $todo['text'] ?> <a href="/todos/remove/<?= $todo['id'] ?>">X</a></li>
      <?php } ?>
    </ul>
  <?php } else { ?>
    <p>No todos yet</p>
  <?php } ?>
...
  • création d’une nouvelle route /todos/remove/{id}

./index.php

<?php
// charge le controller
require './controllers/Todos.php';
// creation des routes
Flight::route('GET /todos', [new Todos(), 'index']);
Flight::route('POST /todos/add', [new Todos(), 'add']);
Flight::route('GET /todos/remove/@id', [new Todos(), 'remove']);
?>
  • dans le controller, création d’une méthode remove
    • appelle le modèle
    • redirige vers /todos

./controllers/Todos.php

<?php
require './models/Todo.php';

class Todos {
  ...
  public function remove ($id) {
    $this->Todo->remove($id);
    Flight::redirect('/todos');
  }
}
?>
  • dans le modèle, création d’une méthode remove
    • supprimer le todo de la base de données

./models/Todo.php

<?php
class Todo {
  ...
  public function remove ($id) {
    $sql = 'DELETE FROM todos WHERE todos.id = :id';
    $stmt = $this->db->prepare($sql);
    $stmt->bindParam(':id', $id);
    $stmt->execute();
  }
}
?>