Skip to content

📅 SAISON B Semaine 4 Épisode 4 - Projet en autonomie Jour 2 - Structuration MVC et Dynamisation des Pages

📚 Introduction

DeuxiĂšme jour de travail sur le projet oCoffee ! Aujourd’hui, j’ai avancĂ© sur la structuration de l’architecture MVC et la dynamisation des pages. Mon objectif Ă©tait de rendre les pages du site fonctionnelles de maniĂšre statique, puis de commencer Ă  les dynamiser avec des donnĂ©es JSON. Voici le bilan de la journĂ©e.

Note

Le dépÎt Github du projet est disponible ici.


Étape 1 : Structuration de l’architecture MVC

Contexte

Les vues pour la page d’accueil et le catalogue Ă©taient dĂ©jĂ  fournies dans le dossier d’intĂ©gration du projet, avec leurs styles CSS respectifs. Mon travail a consistĂ© Ă  :

  1. CrĂ©er les vues manquantes (page de dĂ©tails d’un cafĂ© et page de prĂ©sentation de la boutique).
  2. Configurer les routes et contrĂŽleurs pour chaque page.

Structure du Projet :

📁ocoffee/
│
├── 📁node_modules/          # Folder generated by npm (do not version)
│
├── 📁data/                            #Database folder
│   ├── create-db.sql
│   └── coffee-sample-data.json
│
├── 📁docs/                               # Project specifications folder                  
│   ├── 📁integration/
│   ├── 📁project-brief/
│   └── 📁project-design/
│
├── 📁public/                # Static files (CSS, JS, images)
│   ├── 📁css/               # Style sheets
│   ├── 📁images/            # Images for the site (logos, cafes, etc.)
│   └── 📁js/                # Client-side JavaScript scripts
│
├── 📁src/                   # Application source code
│   ├── 📁controllers/        # Controllers (business logic)
│   │   ├── home.controller.js
│   │   ├── catalog.controller.js
│   │   └── coffee-datails.controller.js
│   │
│   ├── 📁models/             # Models (interactions with the database)
│   │   ├── coffee.dataMapper.js       
│   │   └── databaseClient.js   # Connection to database    
│   │
│   ├── 📁routers/            # Express routes handlers
│   │   ├── home.router.js
│   │   ├── catalog.router.js
│   │   ├── coffee-details.router.js
│   │   └── index.router.js
│   │
│   └── 📁views/              # EJS views (templates)
│       ├── 📁partials/       # Reusable partials (header, footer)
│       │   ├── header.ejs
│       │   └── footer.ejs
│       ├── home.ejs            # Home page
│       ├── catalog.ejs         # Coffee catalogue page
│       └── coffee-details.ejs   # Coffee details page
│
├── index.js                  # Express app entry point
├── package.json            # Dependencies and npm scripts
├── package-lock.json         
├── .env                    # Environnement variables
├── .env.example                    # Public environnement variables
└── README.md               # Project documentation

Actions réalisées

  1. Création des wireframes pour les pages manquantes :
    • Page de dĂ©tail d’un cafĂ© : Affichage des informations spĂ©cifiques (nom, origine, prix, caractĂ©ristiques, etc.). Wireframe page de dĂ©tails d'un cafĂ©
  2. Développement des vues EJS de maniÚre statique :
    • RĂ©cupĂ©ration de la page d'intĂ©gration home.html et conversion en home.ejs.
    • RĂ©cupĂ©ration de la page d'intĂ©gration catalog.html et conversion en catalog.ejs.
    • CrĂ©ation de coffee-details.ejs pour la page de dĂ©tail d’un cafĂ©.
    • CrĂ©ation shop.ejs pour la page de prĂ©sentation de la boutique.
  3. Création des routes et contrÎleurs :

    • home.router.js et home.controller.js pour gĂ©rer la page d'accueil.
    • catalog.router.js et catalog.controller.js pour gĂ©rer les requĂȘtes liĂ©es aux cafĂ©s.
    • shop.router.js et shop.controller.js pour la page de prĂ©sentation de la boutique.
    • index.router pour regrouper tous les routeurs.

    Exemple sur la Home Page :

      <%- include('partials/header.ejs') %>
    
          <section id="about">
            <div>
                <h1>Votre spécialiste Haucloquois du café</h1>
                <p>oCoffee est un dĂ©taillant de cafĂ© et de produits associĂ©s Ă  la consommation du cafĂ© basĂ© dans la ville de Hauts-de-Cloques. Nous importons nos produits directement des producteurs, et nous les sĂ©lectionnons selon des critĂšres exigeants de qualitĂ©. oCoffee est reconnu Ă  l’échelle dĂ©partementale.</p>
                <a class="button" href="#">Découvrir notre catalogue</a>
            </div>
            <img src="./images/about.jpg" alt="Selection de nos meilleurs cafés oCoffee">
          </section>
    
          <section id="latest-products">
            <h2>Nouveautés</h2>
    
            <ul>
              <li>
                <article>
                  <img src="./images/coffees/100955890.png" alt="Ethiopian Yirgacheffe">
                  <div>
                    <h3>Ethiopian Yirgacheffe</h3>
                    <a class="button-outline" href="#">Voir le détail</a>
                  </div>
                </article>
              </li>
    
              <li>
                <article>
                  <img src="./images/coffees/100955890.png" alt="Ethiopian Yirgacheffe">
                  <div>
                    <h3>Ethiopian Yirgacheffe</h3>
                    <a class="button-outline" href="#">Voir le détail</a>
                  </div>
                </article>
              </li>
    
              <li>
                <article>
                  <img src="./images/coffees/100955890.png" alt="Ethiopian Yirgacheffe">
                  <div>
                    <h3>Ethiopian Yirgacheffe</h3>
                    <a class="button-outline" href="#">Voir le détail</a>
                  </div>
                </article>
              </li>
    
            </ul>
          </section>
    
      <%- include('partials/footer.ejs') %>
    
    /**
     * Controller for handling home page logic.
     * @module controllers/homeController
    */
    export default {
      /**
       * Renders the home page.
       * @function
       * @param {import('express').Request} req - Express request object
       * @param {import('express').Response} res - Express response object
      */
      displayHome: (req, res) => {
        res.render('home');
      },
    }
    
    import { Router } from "express";
    import homeController from "../controllers/home.controller.js";
    
    /**
     * Router for handling home page related routes.
     * @module routers/homeRouter
    */
    const homeRouter = Router();
    
    /**
     * GET /
     * Route for rendering the home page.
     * Calls the displayHome method from homeController.
    */
    homeRouter.get('/', homeController.displayHome);
    
    export default homeRouter;
    

    Router principal

    src/routers/index.router.js
    import { Router } from 'express';
    import homeRouter from './home.router.js';
    
    /**
    * Main router that combines all sub-routers for the application.
    * @module routers/indexRouter
    */
    const router = Router();
    
    /**
    * Use the home router for home page related routes.
    */
    router.use(homeRouter);
    
    export default router;
    
  4. Mise Ă  jour du fichier index.js :

    index.js
    /**
     * Main entry point for the Ocoffee application.
     * Sets up the Express server, view engine, static files, and routing.
    */
    
    import express from "express";
    import 'dotenv/config';
    import router from "./src/routers/index.router.js";
    
    // Get the port from environment variables
    const PORT = process.env.PORT;
    
    const app = express();
    
    /**
     * Set EJS as the view engine.
     * Views are located in the './src/views' directory.
    */
    app.set('view engine', 'ejs');
    app.set('views', './src/views');
    
    /**
     * Serve static files from the 'public' directory.
    */
    app.use(express.static('./public'));
    
    /**
     * Use the main router for handling all routes.
    */
    app.use(router);
    
    /**
     * Start the server and listen on the specified port.
     * Logs a message when the server is running.
    */
    app.listen(PORT, () => {
      console.log(`Server is running on http://localhost:${PORT}`);
    });
    

Étape 2 : Dynamisation des pages avec des donnĂ©es JSON

Objectif

Avant de me connecter Ă  une base de donnĂ©es PostgreSQL, j’ai dĂ©cidĂ© de simuler une base de donnĂ©es avec un fichier JSON contenant un Ă©chantillon de donnĂ©es sur les cafĂ©s. Cela me permet de tester le rendu dynamique des pages sans dĂ©pendre d’une base de donnĂ©es.

Actions réalisées

  1. Création du fichier data/coffee-sample-data.json :

    data/coffee-sample-data.json
    [
      {
        "reference": "100955890",
        "name": "Espresso",
        "description": "Café fort et concentré...",
        "origin": "Italie",
        "image": "100955890.png",
        "price": 20.99,
        "available": true,
        "coffee_attributes": ["CorsĂ©", "ÉpicĂ©"]
      },
      // ... (other coffees)
    ]
    
  2. Intégration des données JSON dans les contrÎleurs :

    Exemple sur la Home Page :

    src/controller/home.controller.js
    import coffees from '../../data/coffee-sample-data.json' with { type: 'json' };
    
    /**
     * Controller for handling home page logic.
      * @module controllers/homeController
    */
    export default {
      /**
       * Renders the home page with the three latest coffees.
        * Sorts the coffee data by reference in descending order and selects the top three.
        *
        * @function
        * @param {import('express').Request} req - Express request object
        * @param {import('express').Response} res - Express response object
        * @returns {void}
      */
      displayHome: (req, res) => {
        // Sort the coffees array by reference in descending order
        const sortedCoffees = coffees.toSorted((a, b) => b.reference - a.reference);
    
        // Select the three latest coffees
        const threeLatestCoffees = sortedCoffees.slice(0, 3);
    
        // Render the 'home' view, passing the three latest coffees to the template
        res.render('home', { coffees: threeLatestCoffees });
      },
    };
    
  3. Affichage dynamique dans les vues EJS :

    src/views/home.ejs
    <%- include('partials/header.ejs') %>
    
      <section id="about">
        <div>
            <h1>Votre spécialiste Haucloquois du café</h1>
            <p>oCoffee est un dĂ©taillant de cafĂ© et de produits associĂ©s Ă  la consommation du cafĂ© basĂ© dans la ville de Hauts-de-Cloques. Nous importons nos produits directement des producteurs, et nous les sĂ©lectionnons selon des critĂšres exigeants de qualitĂ©. oCoffee est reconnu Ă  l’échelle dĂ©partementale.</p>
            <a class="button" href="/Catalogue">Découvrir notre catalogue</a>
        </div>
        <img src="./images/about.jpg" alt="Selection de nos meilleurs cafés oCoffee">
      </section>
    
      <section id="latest-products">
        <h2>Nouveautés</h2>
    
        <ul>
          <!-- Replace hard coding by a for...of loop with data from home.controller context -->
          <% for( const coffee of coffees ) { %>
            <li>
              <article>
                <img src="./images/coffees/<%= coffee.image %>" alt="<%= `image de café ${coffee.name}` %>">
                <div>
                  <h3><%= coffee.name %></h3>
                  <a class="button-outline" href="/Catalogue/Cafe/<%= coffee.reference %>">Voir le détail</a>
                </div>
              </article>
            </li>
          <% } %>
        </ul>
      </section>
    
    <%- include('partials/footer.ejs') %>
    

Voir le code complet sur mon dépÎt Github.


Étape 3 : RĂ©solution d’un bug d’affichage

ProblÚme rencontré

En testant la page de dĂ©tail d’un cafĂ©, j’ai rencontrĂ© une erreur dans la console :

Refused to apply style from '<URL>' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.

Diagnostic

Cette erreur indiquait que le navigateur refusait d’appliquer le fichier CSS car il ne le reconnaissait pas comme une feuille de style. AprĂšs investigation, j’ai rĂ©alisĂ© que le problĂšme venait des chemins des fichiers statiques dans ma vue EJS.

Solution

Dans le fichier d’intĂ©gration HTML fourni, les chemins vers les fichiers CSS Ă©taient sous la forme ../css/style.css. Or, avec EJS et Express, les fichiers statiques doivent ĂȘtre rĂ©fĂ©rencĂ©s depuis le dossier public/ avec un chemin absolu :

src/views/coffee-details.ejs
<link rel="stylesheet" href="../css/style.css">
src/views/coffee-details.ejs
<link rel="stylesheet" href="/css/style.css">

Une fois cette petite correction effectuĂ©e, le style s’est appliquĂ© correctement.
J'ai modifié toutes les vues ejs en faisant attention aux chemins des fichiers statiques.


Bilan de la journée

Ce qui a bien fonctionné

✅ Structuration MVC : Les routes, contrĂŽleurs et vues sont maintenant bien organisĂ©s.
✅ Dynamisation des pages : Les donnĂ©es JSON sont correctement intĂ©grĂ©es et affichĂ©es.
✅ RĂ©solution du bug : J’ai compris l’importance des chemins des fichiers statiques dans un projet Express.

Difficultés rencontrées

⚠ Chemins des fichiers statiques : Une erreur simple mais qui m’a fait perdre du temps.

Objectifs pour demain

đŸ”č CrĂ©ation de la base de donnĂ©es PostgreSQL :

  • ImplĂ©menter le MPD créé hier.
  • Connecter l’application Express Ă  la base de donnĂ©es.

đŸ”č Remplacer les donnĂ©es JSON par des requĂȘtes SQL :

  • Utiliser pg pour interagir avec PostgreSQL.
  • Mettre Ă  jour les contrĂŽleurs pour rĂ©cupĂ©rer les donnĂ©es depuis la base de donnĂ©es.

Conclusion

Cette deuxiĂšme journĂ©e a Ă©tĂ© intense mais trĂšs formatrice. J’ai pu appliquer les concepts MVC, dynamiser mes pages et rĂ©soudre des problĂšmes techniques. Demain, je passe Ă  l’étape cruciale de la crĂ©ation et connection Ă  la base de donnĂ©es !