Précédent   Forum des professionnels en informatique > PHP > Langage
Langage Forum sur le langage PHP, la POO, les conventions, la sécurité, etc. Avant de poster : FAQ Langage, toutes les FAQ PHP, cours langage et sources PHP
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 14/04/2011, 17h13   #1
Invité de passage
 
Inscription : juin 2010
Messages : 5
Détails du profil
Informations forums :
Inscription : juin 2010
Messages : 5
Points : 0
Points : 0
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,
zebulon36 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/04/2011, 18h21   #2
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 984
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

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

Informations forums :
Inscription : février 2010
Messages : 2 984
Points : 5 016
Points : 5 016
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:
Citation:
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 :
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 :
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).

Citation:
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
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/04/2011, 08h46   #3
Expert Confirmé
 
Avatar de grunk
 
Homme Olivier
Développeur Web
Inscription : août 2003
Messages : 1 837
Détails du profil
Informations personnelles :
Nom : Homme Olivier
Âge : 27
Localisation : France, Côte d'Or (Bourgogne)

Informations professionnelles :
Activité : Développeur Web
Secteur : Industrie

Informations forums :
Inscription : août 2003
Messages : 1 837
Points : 3 318
Points : 3 318
Citation:
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
grunk est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/04/2011, 14h20   #4
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 984
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

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

Informations forums :
Inscription : février 2010
Messages : 2 984
Points : 5 016
Points : 5 016
Citation:
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
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 01h16.


 
 
 
 
Partenaires

Hébergement Web