IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

[POO] Exécuter un traitement métier sur un nombre important d'objet


Sujet :

Langage PHP

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2010
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2010
    Messages : 33
    Points : 30
    Points
    30
    Par défaut [POO] Exécuter un traitement métier sur un nombre important d'objet
    Bonjour,

    J’ai une classe MANIFESTATION qui représente une manifestation culturelle (festival, concert … etc)

    Chaque instance de ma classe représente donc UNE manifestation.
    Les caractéristiques de l’ensemble des manifestations (date, lieu, description, … etc) sont stockées dans une DB

    Comment faire pour supprimer de manière élégante TOUTES les manifestations dont la date est dans le passé.

    * Méthode 1 : Passer un SQL DELETE sur ma DB en sélectionnant les dates antérieures à la date du jour.

    C’est très efficace mais cela me semble être du travail de cochon : Aucun objet MANIFESTATION n’est instancié et la logique métier de suppression n’est pas exécutée dans les objets eux-mêmes. (Par ailleurs, si je dois effectuer des traitements particuliers complémentaires pour chaque manifestation supprimée, je ne peux pas le faire avec cette méthode)

    * Méthode 2 : Instancier un objet pour chaque manifestation présente dans ma DB, parcourir l’ensemble de ces instances ; et pour chacune d’elle, exécuter un méthode qui va supprimer l’objet (… dans la DB) si la date de la manifestation est dans le passé.

    Cela me semble parfait du point de vue des principes de la POO : Cela encapsule bien la logique et le traitement métier de suppression dans l’objet lui-même. Mais à l’inverse, cela me semble très couteux en ressources : nombre d’instanciations d’objets, nombre de requêtes SQL …).

    Quelle est la bonne méthode ? Y a-t-il un pattern de conception ? Faut il introduire une classe CONTENEUR_DE_MANIFESTATIONS dans lequel on déporterait une partie de la logique métier de la classe MANIFESTATION, afin de traiter les manifestation en masse ?


    D’une manière générale, j’ai l’impression que la POO est très efficace et très élégante pour traiter des objets dont le nombre d’instance est peu nombreux ; mais les applications gèrent souvent des milliers d’objet de même type (clients, commandes, produits … etc). Dans ce cas, comment appliquer un traitement métier sur un sous ensemble défini de ces objets de meme type, sans avoir à passer par une instanciation et un parcour de tous les objets ?

    Merci pour vos lumières,

  2. #2
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Salut

    Comme tu l'as mentionné avec tes deux méthodes, la problématique est que les objets Manifestation ont un comportement particulier lors du delete, alors voici ce que je propose:
    Quelle est la bonne méthode ? Y a-t-il un pattern de conception ? Faut il introduire une classe CONTENEUR_DE_MANIFESTATIONS dans lequel on déporterait une partie de la logique métier de la classe MANIFESTATION, afin de traiter les manifestation en masse ?
    Oui et on va se servir du pattern Iterator, en optimisant les accès base.
    Comme dit précédemment, exécuter 1000x la requête de select pour chaque manifestation est complètement absurde. En revanche, exécuter 1x la requête de sélection qui correspond à tous les tuples matché par la condition (à savoir date < une_date) et construire les objets à la main avec ces tuples est déjà plus faisable.

    Je te propose de te servir de la classe PDOStatementIterator (disponible ici) et de procéder comme suit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
     
    <?php
     
    class ManifestationManager {
     
      // on garde en mémoire l'objet PDO de travail
      public static $_pdo;
     
      public static function getManifestations ($params = array()) {
    	 // on va vérifier avant tout qu'on a un objet pdo dispo
    	 if (!(isset(self::$_pod) || self::$_pdo instanceof PDO))
    		throw new RuntimeException(__CLASS__ . " needs a valid PDO instance");
     
         // on prépare la requête de séléction
    	 $query = "SELECT * FROM `manifestations`";
     
    	 // on ajoute les paramètres supplémentaires
    	 if (!empty($params)) {
    	    $pieces = array();
    		foreach ($params as $q_param) {
    			list($attr, $glue, $val) = $q_param;
    			$pieces[] = "`{$attr}`{$glue}'{$val}'";
    		}
    		$query .= implode(' AND ', $pieces);
    	 }
     
    	 // on prépare le statement
    	 $stmt = self::$_pdo->prepare($query);
     
    	 // on tente d'executer la requête
    	 if ($stmt->execute()) {
    		// on créé une manifestation vide
    		// qui nous servira lors de l'iteration
    		$manifestation = new Manifestation();
    		$stmt->setFetchMode(PDO::FETCH_INTO, $manifestation);
    		return new PDOStatementIterator($stmt);
    	 }
    	 else
    	    throw new RuntimeException("Query failed: $query");
      }
     
      public static function deleteManifestations ($params = array()) {
         // on récupère la liste
    	 $list = self::getManifestations($params);
     
    	 $res = array();
    	 foreach ($list as $manifestation) {
    		$res[] = $manifestation->delete();
    	 }
     
    	 // on renvoie les résultats
    	 return $res;
      }
    }
    Il y a deux prérequis:
    - le constructeur de la classe Manifestation doit être capable de créer des instances vides qui seront remplies par PDOStatement::fetch à la mode PDO::FETCH_INTO
    - la classe Manifestation doit soit avoir des propriété publiques qui correspondent aux attributs de la table MySQL soit implémenter __get et __set pour que PDOStatement::fetch puisse remplir l'instance à chaque itération.

    Voici un exemple d'utilisation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    ManifestationManager::$_pdo = $pdo; // ton instance PDO
    ManifestationManager::deleteManifestations(array(
    	array('date', '>', time() - 24 * 3600), 
    ));
    Tu peux ajouter autant de clauses que tu le souhaite en ajoutant des array supplémentaires.

    L'avantage de l'itérateur dans notre cas est qu'on ne consomme que les ressources nécessaires, un seul objet est instancié et on se sert de lui pour traverser une collection.
    Un autre avantage est de pouvoir coller un iterateur par dessus cet iterateur pour implémenter un comportement particulier (par exemple aller de 0 à 10 avec LimitIterator).

    D’une manière générale, j’ai l’impression que la POO est très efficace et très élégante pour traiter des objets dont le nombre d’instance est peu nombreux
    Les collections et les iterateurs sont là pour te prouver le contraire

  3. #3
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 693
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 693
    Points : 20 246
    Points
    20 246
    Par défaut
    Par ailleurs, si je dois effectuer des traitements particuliers complémentaires pour chaque manifestation supprimée, je ne peux pas le faire avec cette méthode
    Je pense que tu as ta réponse. Si aucun autre traitement n'est nécessaire et que les performances sont une composante importante, faire un (petit) écart à la logique objet est une chose à envisager.

    En revanche si tu risque d'avoir besoin d'agir sur tes objets à supprimer , la solution de Benjamin semble tout à fait adaptée.

    Perso je suis pas partisan de rajouter une chié de code parce que ça fait joli. Si une solution simple et efficace répond au besoin sans remettre en cause la structure de l'application , je prend

  4. #4
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Perso je suis pas partisan de rajouter une chié de code parce que ça fait joli. Si une solution simple et efficace répond au besoin sans remettre en cause la structure de l'application , je prend
    Oui, à condition de ne pas le faire trop souvent, ça pollue le code plus vite qu'on ne le pense

Discussions similaires

  1. Réponses: 7
    Dernier message: 25/05/2009, 13h29
  2. [MySQL] exécuter un traitement sur une table tous les lundi
    Par nicocaine dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 07/06/2007, 11h19
  3. Réponses: 1
    Dernier message: 19/04/2007, 03h37
  4. Réponses: 3
    Dernier message: 08/09/2003, 16h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo