420-5D3 : Connexion php avec Oracle

27 septembre 2023

EXEMPLE – D’une application php qui utilise le SGBD Oracle.


NOTE: Exercices à réaliser par l’étudiant en classe. Il faut programmer et adapter et exécuter les scripts suivants. Adapter les scripts en fonction du schéma de votre base de données.


1 – Lancer un conteneur php+apache+clientOracle

# Utilisation d'une image Docker php+Apache+ClientOracle
# Pour PHP8+ORI+Argon2
docker pull paliari/apache-php8-oci8:1.3.0-dev
$ docker run -itd --name php-oci -v $(pwd)/web:/var/www/html/public -p 80:80 paliari/apache-php8-oci8:1.3.0-dev

#---------------------------------------------------------------------------------------
# Pour PHP7+ORI
$ docker run -itd --name php-oci -v /Users/alain/docker.projets/web:/var/www/html -p 80:80 adrianharabula/php7-with-oci8

C\> docker run -itd --name php-oci -v C:\Users\Alain\web:/var/www/html -p 88:80 adrianharabula/php7-with-oci8

NOTE: Oracle propose des Dockerfiles pour bâtir des images en fonction des besoins des développeurs. Ces fichiers sont ici.


2 – Rédiger un script php de connexion à la BD

<?php
// Informations de connexion à la base de données Oracle
// Informations de connexion à la base de données Oracle
$db_username = 'etudiant';
$db_password = 'password';
$db_service = 'CSTJ4205D3';
$db_host = '192.168.2.51';

// Connexion à la base de données Oracle
$conn = oci_connect($db_username, $db_password, $db_host . '/' . $db_service);

if (!$conn) {
    die("Échec de la connexion à la base de données 🤪 : " . oci_error());
} else {
    print("Connexion au SGBD Oracle réussi 🤓 !");
}

?>

NOTE: Ce script doit-être dans le dossier racine Web du conteneur! Oui, je sais, vous le saviez déjà 🤪.


Tester le script de connexion:


3 – Exécuter une requête SQL Oracle simple avec php

<?php
// Inclure le fichier de configuration de la base de données
include('config.php');

// Requête SQL pour récupérer les albums de Tintin
// Auteur = Hergé = auteur_id = 1
# $sql = "SELECT titre FROM Albums";

$sql = "SELECT titre FROM Albums WHERE auteur_id = (SELECT auteur_id FROM Auteurs WHERE nom LIKE 'Herg%')";

// Exécuter la requête SQL
$result = oci_parse($conn, $sql);
oci_execute($result);
?>

<!DOCTYPE html>
<html>
<head>
    <title>Albums de Tintin</title>
</head>
<body>
  <hr/>
  <h1>Albums de Tintin</h1>
    <ul>
        <?php
        // Afficher les albums dans une liste
        while ($row = oci_fetch_assoc($result)) {
            echo '<li>' . htmlspecialchars($row['TITRE']) . '</li>';
        }
        ?>
    </ul>
</body>
</html>

<?php
// Fermer la connexion à la base de données
oci_close($conn);
?>

4 – Afficher la liste des albums par personnage

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Liste de tous les Albums</title>
    <!-- Liens Bootstrap CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
    <style>
        /* Style personnalisé pour l'espacement */
        .character {
            margin-top: 20px;
        }

        /* Style personnalisé pour la liste à puces */
        .album-list {
            padding-left: 20px;
        }

        /* Style personnalisé pour les albums impairs */
        .album-list li:nth-child(odd) {
            background-color: #f2f2f2; /* Couleur d'arrière-plan pour les albums impairs */
        }

        /* Style personnalisé pour les images des personnages */
        .character-image {
            max-width: 100px; /* Largeur maximale de l'image */
            height: auto; /* Ajuster la hauteur proportionnellement */
        }

        /* Style personnalisé pour le carré gris */
        .no-photo {
            width: 100px; /* Largeur du carré gris */
            height: 100px; /* Hauteur du carré gris */
            background-color: #ccc; /* Couleur de fond gris */
        }
    </style>
</head>
<body>
    <div class="container mt-5">
        <h1 class="text-center">Liste de tous les Albums</h1>
        <?php
        // Inclure le fichier de configuration de la base de données
        include('config.php');

        // Requête SQL pour récupérer tous les albums de tous les personnages
        $sql = "SELECT P.nom AS personnage, P.photo AS photo, A.titre AS album
                FROM Personnages P
                LEFT JOIN Albums_Personnages PA ON P.personnage_id = PA.personnage_id
                LEFT JOIN Albums A ON PA.album_id = A.album_id
                ORDER BY P.nom, A.titre";

        $result = oci_parse($conn, $sql);
        oci_execute($result);

        // Initialisation des variables pour suivre le personnage actuel
        $currentPersonnage = null;

        while ($row = oci_fetch_assoc($result)) {
            $personnage = htmlspecialchars($row['PERSONNAGE']);
            $album = htmlspecialchars($row['ALBUM']);
            $photo = htmlspecialchars($row['PHOTO']); // Source de la photo du personnage

            // Si le personnage actuel change, affichez le nouveau personnage
            if ($currentPersonnage !== $personnage) {
                // Fermez la liste précédente si ce n'est pas le premier personnage
                if ($currentPersonnage !== null) {
                    // Affichez le message si le personnage n'a pas d'albums
                    if (!$hasAlbum) {
                        echo '<p>Ce personnage n\'est pas dans les albums présents dans la base de données.</p>';
                    }
                    echo '</ul>';
                }

                // Réinitialisez la variable $hasAlbum
                $hasAlbum = false;

                // Affichez le nom du nouveau personnage avec une classe Bootstrap
                echo '<div class="character">';
                echo '<h2>' . $personnage . '</h2>';

                // Affichez la photo du personnage ou un carré gris s'il n'y a pas de photo
                if (!empty($photo)) {
                    echo '<img class="character-image" src="' . $photo . '" alt="' . $personnage . '">';
                } else {
                    echo '<div class="no-photo"></div>';
                }

                echo '<ul class="list-unstyled album-list">';
                $currentPersonnage = $personnage;
            }

            // Affichez l'album dans la liste à puces avec une classe Bootstrap
            echo '<li>' . $album . '</li>';
        }

        // Fermez la dernière liste à puce
        if ($currentPersonnage !== null) {
           echo '</ul>';
        }

        // Fermer la connexion à la base de données
        oci_close($conn);
        ?>
    </div>

    <!-- Liens Bootstrap JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js"></script>
</body>
</html>

Défi supplémentaire

Utiliser symphony pour programmer un formulaire permettant l’ajout d’un personnage dans la BD.

NOTE: Il faudra peut-être installer symphony dans le conteneur ou proposer une autre solution. Pas facile d’être en troisième année … 🥵

INDICE de réalisation:

// src/Controller/PersonnageController.php

use App\Entity\Personnage;
use App\Form\PersonnageType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class PersonnageController extends AbstractController
{
    /**
     * @Route("/ajouter-personnage", name="ajouter_personnage")
     */
    public function ajouterPersonnage(Request $request): Response
    {
        $personnage = new Personnage();
        $form = $this->createForm(PersonnageType::class, $personnage);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            // Sauvegardez le personnage en base de données
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($personnage);
            $entityManager->flush();

            return $this->redirectToRoute('accueil'); // Redirigez vers la page d'accueil ou une autre page
        }

        return $this->render('personnage/ajouter.html.twig', [
            'form' => $form->createView(),
        ]);
    }
}
{# templates/personnage/ajouter.html.twig #}

{% extends 'base.html.twig' %}

{% block title %}Ajouter un Personnage{% endblock %}

{% block body %}
    <h1>Ajouter un Personnage</h1>

    {{ form_start(form) }}
    {{ form_widget(form) }}
    <button type="submit" class="btn btn-primary">Ajouter</button>
    {{ form_end(form) }}
{% endblock %}
# config/routes.yaml
ajouter_personnage:
    path: /ajouter-personnage
    controller: App\Controller\PersonnageController::ajouterPersonnage