Bonjour à tous

J'ai un soucis au niveau du form login que j'essaye de faire en php en mvc.

Mon navigateur affiche comme soucis :

Erreur fatale : Erreur non interceptée : classe "App\Controllers\login" introuvable dans C:\xampp\htdocs\location\routes\Route.php:48 Stack trace : #0 C:\xampp\htdocs\location\routes\Router .php(33) : Router\Route->execute() #1 C:\xampp\htdocs\location\public\index.php(26) : Router\Router->run() #2 {main} lancé en C :\xampp\htdocs\location\routes\Route.php à la ligne 48

Pourtant j'ai bien l'impression que mes namespace sont bon , je ne voie pas ou est le soucis .... , Pouvez vous m'aidez ?

Voila mon Controllers/login.php

<?php

namespace App\Controllers;

use App\Models\login;

class ConnexionController   extends Controller {

    public function afficherFormulaireConnexion() {
        require 'views/login.php';
    }

    public function verifierConnexion() {
        if(isset($_POST['username']) && isset($_POST['password'])) {
            $username = htmlspecialchars($_POST['username']);
            $password = htmlspecialchars($_POST['password']);
            //$post = new Post($this->getDB());
            $utilisateur = new login($this->getDB()); 
            $utilisateur->setUsername($username);
            $utilisateur->setPassword($password);

            if($utilisateur->verifierConnexion()) {
                // Connexion réussie, rediriger vers une autre page
                header('Location: home.php');
                exit;
            } else {
                // Mauvais nom d'utilisateur ou mot de passe, afficher un message d'erreur
                $errorMessage = 'Nom d\'utilisateur ou mot de passe incorrect';
                require 'views/login.php';
            }
        } else {
            // Données du formulaire manquantes, afficher le formulaire de connexion
            $this->afficherFormulaireConnexion();
        }
    }

}

Mon Models/login.php

<?php

namespace App\Models;

class login extends Model {

    private $username;
    private $password;

    public function setUsername($username) {
        $this->username = $username;
    }

    public function setPassword($password) {
        $this->password = $password;
    }

    public function verifierConnexion() {

        $req = $this->query('SELECT * FROM users WHERE username = ?');
        $req->execute(array($this->username));

        if($donnees = $req->fetch()) {
            if(password_verify($this->password, $donnees['password'])) {
                // Mot de passe correct, la connexion est réussie
                return true;
            } else {
                // Mot de passe incorrect
                return false;
            }
        } else {
            // Nom d'utilisateur introuvable
            return false;
        }
    }
}

Mon views/login.php

<h1>Connexion</h1>
    <?php if(isset($errorMessage)) { ?>
        <p><?php echo $errorMessage; ?></p>
    <?php } ?>
    <form method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>">
        <label for="username">Nom d'utilisateur :</label>
        <input type="text" name="username" id="username"><br><br>
        <label for="password">Mot de passe :</label>
        <input type="password" name="password" id="password"><br><br>
        <input type="submit" value="Se connecter">
    </form>

3 réponses


Hello,

Le soucis ne se situe pas dans les codes que tu nous a donné car c'est dans la classe Route qu'il essaye de trouver une classe login dans le namespace App\Controllers.

Par contre je remarque plusieurs chose dans le code qui ne vont pas :

nom de la classe

Le nom pour une classe doit commencer avec une majuscule. Cela fait partie des conventions du PSR (les recommendations officiel pour PHP). Donc la classe login pour le model (et le fichier qui va avec) devrait être Login. Dans le même sujet des PSR, il y a l'accolade pour les classes, méthodes et fonctions qui se mets sur la ligne suivante.

ancienne syntaxe de tableau

Tu utilise array() pour créer un tableau mais on peut depuis un moment utiliser les [] pour créer un tableau. La syntaxe avec les [] existe dans la majorité des langages donc autant ne pas ajouter une charge mental de traduction entre PHP et un potentiel nouveau langage.

utilisation de htmlspecialchars pour des entrées en base

Pour éviter eds soucis plus tard et parcequ'utiliser cette fonction comme ça ne protège rien en plus de faire des dégats sur les données sauvegarder. Il est préférable de ne pas utiliser htmlspecialchars pour des données qui seront insérées en base. Article sur Zest de Savoir.

Donc pour ton code tu peux récupérer directement les données du formulaire.

le nom login pour ton model

Ce nom au vu de l'utilisation que tu en fait ne semble pas bon. Il sert à la fois pour vérifier les informations de connexion et pour représenter un utilisateur. Avec les principes SOLID et surtout le S qui signifie Single Responsability, une classe ne doit faire qu'une et une seul chose et la on voit bien qu'elle fois au moins 2 choses.

Il faudrait donc une classe User qui représente l'utilisateur et une classe Auth (ou Authentication) qui permet de vérifier les données.

else-less

Pour le coup c'est plus pour t'apprendre qu'il est préférable d'éviter les else quand on peut. Et je peux te dire que l'on peut plus que l'on ne le pense ^^. Dans ton cas par exemple sur la méthode verifierConnexion tu pourrais enlever des imbrications de if juste en inversant les conditions et du coup en quittant la méthode avant le reste via return ou exit. Pareil dans la classe login du model.

chemin relatif dans les require

PHP à une façon bizarre de require les fichiers et c'est pour ça qu'il est préférable de toujours partir du fichier ou l'on se trouve en utilisant la constante __DIR__ qui permet d'avoir le chemin complet (chemin absolu) depuis la racine du système. require __DIR__ .'/mon/fichier.php' (par exemple)

Voici ce que ça donnerai en suivant les recommandations :

Le controller

<?php

namespace App\Controllers;

use App\Services\Auth;

class AuthController extends Controller
{
    public function afficherConnexion()
    {
        require __DIR__ . '/../../views/login.php';
    }

    public function traiterConnexion()
    {
        $username = $_POST['username'] ?? null;
        $password = $_POST['password'] ?? null;

        $errors = [];
        if (empty($username) || empty($password)) {
            $errors[] = 'Veuillez remplir tous les champs';
        }

        $authService = new Auth();
        $user = $authService->verifieCredentials($username, $password);
        if ($user === null) {
            $errors[] = 'Mauvais identifiants';
        }

        if (!empty($errors)) {
            header('Location: /login.php?errors=' . urlencode(serialize($errors)), true, 302);
            exit;
        }

        $authService->connecte($user);
        header('Location: /');
        exit;
    }
}

Le service Auth

<?php

namespace App\Services;

use App\Models\User;
use DateTimeImmutable;
use PDO;

class Auth
{
    public function __construct(private readonly PDO $db)
    {
    }

    public function verifieCredentials(string|null $username, string|null $password): User|null
    {
        $reqSelectUser = $this->db->prepare('SELECT id, username, email, password, created_at FROM users WHERE username = :username');
        $reqSelectUser->execute([':username' => $username]);

        $user = $reqSelectUser->fetch();
        if ($user === false) {
            return null;
        }

        if (!password_verify($password, $user['password'])) {
            return null;
        }

        return new User(
            id: $user['id'],
            username: $user['username'],
            email: $user['email'],
            password: $user['password'],
            createdAt: new DateTimeImmutable($user['created_at']),
        );
    }

     public function connecte(User $user): void
    {
        // Vérifie si la session est déjà démarrée.
        $_SESSION['auth'] = [
            'id' => $user->getId(),
            'username' => $user->getUsername(),
            'email' => $user->getEmail(),
        ];
    }
}

Le model User

<?php

namespace App\Models;

use DateTimeImmutable;

class User extends Model
{
    public function __construct(
        private readonly int $id,
        private string $name,
        private string $email,
        private string $password,
        private readonly DateTimeImmutable $createdAt,
    ) {    
    }

    public function getId(): int
    {
        return $this->id;
    }

    public function getName(): string
    {
        return ucwords($this->name);
    }

    public function getEmail(): string
    {
        return strtolower($this->email);
    }

    public function getPassword(): string
    {
        return $this->password;
    }

    public function setPassword(string $password): void
    {   
        $this->password = password_hash($password, PASSWORD_DEFAULT, ['cost' => 14]);
    }

    public function getCreatedAt(): DateTimeImmutable
    {
        return $this->createdAt;
    }
}

Enfin j'aimerai savoir si déjà tu suis une vidéo ou un cours et si oui lequel ?

J'ai suivie pas mal de tuto mais pas pour le form login j'ai voulu le faire de moi meme .

Ceux de nord coder et grafikart.

J'ai mtn regarder une autre video et il fait pas du tout pareil que toi , j'ai l'impression tu complique la choses.

j'ai l'impression tu complique la choses.

C'est pas de compliquer en fait c'est d'être flexible. La si tu pense que c'est compliquer attends de voir la vrai façon de faire des projets un peu plus conséquant :D En fait il faut des foit voir plus loin et il y a des principes qui existe en POO qui justement aide à ne pas se retrouver bloquer.

Si jamais tu veux plus d'explication en dehors de ce sujet, je suis sur le discord.