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 pattern State afin de créer une application réaliste de gestion de locations.

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. Créez ensuite trois classes qui implémentent cette interface :
    • AvailableState : renvoie "Available" et true
    • RentedState : renvoie "Rented" et false
    • MaintenanceState : renvoie "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, avec AvailableState comme valeur par défaut. Implémentez :
    • getState(): VehicleState : renvoie l'état actuel
    • setState(VehicleState $state): void : modifie l'état
    • getStatus(): string : délègue à getStatus() de l'état
    • canRent(): bool : délègue à canRent() de l'état
    • abstract calculateCost(int $days): float : chaque type de véhicule effectue le calcul différemment
    • getType(): string : renvoie le nom de la classe avec static::class
  • Vehicles.php : incluez le fichier Vehicle. Créez trois classes concrètes de véhicules :
    • Car : étend Vehicle ; calculateCost() renvoie dailyRate * days
    • Motorcycle : étend Vehicle ; calculateCost() renvoie dailyRate * days * 0.8 (remise de 20 %)
    • Van : étend Vehicle avec un paramètre supplémentaire $mileageRate (float) ; calculateCost(int $days, int $miles = 0) renvoie (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 une location à l'historique
    • getRentalCount(): int : renvoie le nombre de locations
    • getTotalSpent(): float : renvoie la somme de tous les coûts de location
  • Rental.php : incluez les fichiers Vehicle et Customer. Créez une classe Rental qui associe un client à un véhicule. Utilisez la promotion de constructeur pour customer (Customer, public readonly), vehicle (Vehicle, public readonly), days (int, private) et éventuellement miles (int, private, valeur par défaut 0). Implémentez :
    • calculateTotal(): float : si le véhicule est un Van, transmettez miles à calculateCost() ; sinon, transmettez uniquement days
    • complete(): string : calcule le total, l'ajoute à l'historique du client, définit l'état du véhicule sur AvailableState et renvoie "Rental completed: $[total]" (avec 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 plaque d'immatriculation. Implémentez :
    • addVehicle(Vehicle $vehicle): void : ajoute le véhicule à la flotte
    • findVehicle(string $plate): ?Vehicle : renvoie le véhicule ou null
    • getAvailableVehicles(): array : renvoie les véhicules pour lesquels canRent() vaut true
    • rentVehicle(Customer $customer, string $plate, int $days, int $miles = 0): string|Rental : si le véhicule est introuvable, renvoie "Vehicle not found" ; s'il n'est pas disponible, renvoie "Vehicle is not available" ; sinon, définit l'état du véhicule sur RentedState et renvoie un nouvel objet Rental
    • setMaintenance(string $plate): string : définit l'état du véhicule sur MaintenanceState ; renvoie "[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. Suivez les locations actives par plaque d'immatriculation. Traitez chaque opération :

    • "available" : affichez "Available vehicles: [count]"
    • "rent" : louez le véhicule ; en cas de succès, stockez le Rental et affichez "Rented [plate] for [days] days" ; s'il s'agit d'un Van, incluez miles depuis l'opération ; sinon, affichez le message d'erreur
    • "complete" : finalisez la location enregistrée pour cette plaque ; affichez le résultat
    • "maintenance" : affichez le résultat de setMaintenance()
    • "status" : affichez "[plate]: [status]" pour la plaque indiquée
    • "customer_stats" : affichez "[name]: [count] rentals, $[total] spent" (avec 2 décimales)

    Affichez chaque résultat sur une nouvelle ligne.

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

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 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": Print "Available vehicles: [count]"
// - "rent": Louer le véhicule, stocker Rental en cas de succès, afficher le résultat
// - "complete": Terminer la location, afficher le résultat
// - "maintenance": Définir la 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: Print available vehicle count
            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: Définir la 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

Entraînez-vous par vous-même : Compilateur PHP en ligne