Menu
Coddy logo textTech

Service de location de véhicules

Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy — leçon 91 sur 91.

challenge icon

Défi

Facile

Construisons un système de Service de Location de Véhicules qui gère une flotte de véhicules, suit les locations des clients et calcule les tarifs en fonction du type de véhicule. Ce défi complet réunit l'héritage, les interfaces, l'encapsulation et le patron de conception État (State pattern) pour créer une application réaliste de gestion de location.

Vous organiserez votre code sur sept fichiers :

  • VehicleState.php — Définissez une interface VehicleState qui représente les différents états dans lesquels un véhicule peut se trouver. Incluez deux méthodes : getStatus(): string et canRent(): bool. Ensuite, créez trois classes implémentant cette interface :
    • AvailableState — retourne "Available" et true
    • RentedState — retourne "Rented" et false
    • MaintenanceState — retourne "Maintenance" et false
  • Vehicle.php — Incluez le fichier VehicleState. Créez une classe abstraite Vehicle avec la promotion de constructeur pour licensePlate (string, public readonly), brand (string, public readonly), et dailyRate (float, protected). Stockez l'état actuel dans une propriété privée, par défaut à AvailableState. Implémentez :
    • getState(): VehicleState — retourne l'état actuel
    • setState(VehicleState $state): void — modifie l'état
    • getStatus(): string — délègue au getStatus() de l'état
    • canRent(): bool — délègue au canRent() de l'état
    • abstract calculateCost(int $days): float — chaque type de véhicule calcule différemment
    • getType(): string — retourne le nom de la classe en utilisant static::class
  • Vehicles.php — Incluez le fichier Vehicle. Créez trois classes de véhicules concrètes :
    • Car — étend Vehicle ; calculateCost() retourne dailyRate * days
    • Motorcycle — étend Vehicle ; calculateCost() retourne dailyRate * days * 0.8 (20% de réduction)
    • Van — étend Vehicle avec un paramètre supplémentaire $mileageRate (float) ; calculateCost(int $days, int $miles = 0) retourne (dailyRate * days) + (mileageRate * miles)
  • Customer.php — Créez une classe Customer avec la promotion de constructeur pour id (int, public readonly) et name (string, public readonly). Suivez l'historique des locations dans un tableau privé. Implémentez :
    • addRental(string $vehiclePlate, float $cost): void — ajoute à l'historique
    • getRentalCount(): int — retourne le nombre de locations
    • getTotalSpent(): float — retourne la somme de tous les coûts de location
  • Rental.php — Incluez les fichiers Vehicle et Customer. Créez une classe Rental qui lie un client à un véhicule. Utilisez la promotion de constructeur pour customer (Customer, public readonly), vehicle (Vehicle, public readonly), days (int, private), et optionnellement miles (int, private, par défaut 0). Implémentez :
    • calculateTotal(): float — si le véhicule est un Van, passez miles à calculateCost() ; sinon passez simplement days
    • complete(): string — calcule le total, l'ajoute à l'historique du client, définit le véhicule sur AvailableState, retourne "Rental completed: $[total]" (2 décimales)
  • RentalService.php — Incluez les fichiers Rental et Vehicles. Créez une classe RentalService qui gère la flotte. Stockez les véhicules dans un tableau privé indexé par la plaque d'immatriculation. Implémentez :
    • addVehicle(Vehicle $vehicle): void — ajoute à la flotte
    • findVehicle(string $plate): ?Vehicle — retourne le véhicule ou null
    • getAvailableVehicles(): array — retourne les véhicules où canRent() est true
    • rentVehicle(Customer $customer, string $plate, int $days, int $miles = 0): string|Rental — si le véhicule n'est pas trouvé, retourne "Vehicle not found" ; s'il n'est pas disponible, retourne "Vehicle is not available" ; sinon, définit le véhicule sur RentedState et retourne un nouvel objet Rental
    • setMaintenance(string $plate): string — définit le véhicule sur MaintenanceState ; retourne "[plate] set to maintenance" ou "Vehicle not found"
  • main.php — Incluez les fichiers RentalService et Customer. Vous recevrez trois entrées : les données de la flotte (JSON), les données du client (JSON) et les opérations (JSON).

    Format JSON de la flotte :

    [{"type": "car", "plate": "CAR-001", "brand": "Toyota", "rate": 50}, {"type": "van", "plate": "VAN-001", "brand": "Ford", "rate": 80, "mileage_rate": 0.25}]

    Format JSON du client :

    {"id": 1, "name": "Alice"}

    Format JSON des opérations :

    [{"op": "available"}, {"op": "rent", "plate": "CAR-001", "days": 3}, {"op": "complete", "plate": "CAR-001"}, {"op": "maintenance", "plate": "VAN-001"}, {"op": "customer_stats"}]

    Créez le service de location, ajoutez tous les véhicules à la flotte et créez le client. Gardez une trace des locations actives par plaque. Traitez chaque opération :

    • "available" — Affiche "Available vehicles: [count]"
    • "rent" — Loue le véhicule ; en cas de succès, stocke le Rental et affiche "Rented [plate] for [days] days" ; si c'est un Van, inclut les miles de l'opération ; sinon affiche le message d'erreur
    • "complete" — Termine la location stockée pour cette plaque ; affiche le résultat
    • "maintenance" — Affiche le résultat de setMaintenance()
    • "status" — Affiche "[plate]: [status]" pour la plaque donnée
    • "customer_stats" — Affiche "[name]: [count] rentals, $[total] spent" (2 décimales)

    Affichez chaque résultat sur une nouvelle ligne.

Ce système montre comment le patron État gère élégamment la disponibilité des véhicules sans conditions complexes, comment l'héritage crée une hiérarchie de véhicules propre avec une tarification polymorphe, et comment l'encapsulation protège l'intégrité des données de location tout au long du flux de travail.

Essayez vous-même

<?php

require_once 'RentalService.php';
require_once 'Customer.php';

// Lire les entrées
$fleetJson = trim(fgets(STDIN));
$customerJson = trim(fgets(STDIN));
$operationsJson = trim(fgets(STDIN));

// Analyser les données JSON
$fleetData = (array)json_decode($fleetJson, true);
$customerData = (array)json_decode($customerJson, true);
$operations = (array)json_decode($operationsJson, true);

// TODO: Créer une instance de RentalService

// TODO: Ajouter tous les véhicules à la flotte selon le type :
// - "car" -> new Car(plate, brand, rate)
// - "motorcycle" -> new Motorcycle(plate, brand, rate)
// - "van" -> new Van(plate, brand, rate, mileage_rate)

// TODO: Créer une instance de Customer à partir de customerData

// TODO: Créer un tableau pour suivre les locations actives par plaque
$activeRentals = [];

// TODO: Traiter chaque opération et afficher les résultats :
// - "available": Afficher "Available vehicles: [count]"
// - "rent": Louer le véhicule, stocker Rental si réussi, afficher le résultat
// - "complete": Terminer la location, afficher le résultat
// - "maintenance": Mettre en maintenance, afficher le résultat
// - "status": Afficher "[plate]: [status]"
// - "customer_stats": Afficher "[name]: [count] rentals, $[total] spent"

foreach ($operations as $op) {
    $operation = (array)$op;
    $opType = $operation['op'];
    
    // TODO: Gérer chaque type d'opération
    switch ($opType) {
        case 'available':
            // TODO: Afficher le nombre de véhicules disponibles
            break;
        case 'rent':
            // TODO: Louer le véhicule et afficher le résultat
            break;
        case 'complete':
            // TODO: Terminer la location et afficher le résultat
            break;
        case 'maintenance':
            // TODO: Mettre en maintenance et afficher le résultat
            break;
        case 'status':
            // TODO: Afficher le statut du véhicule
            break;
        case 'customer_stats':
            // TODO: Afficher les statistiques du client
            break;
    }
}

?>

Toutes les leçons de Programmation Orientée Objet