Collection et iterator pour applcation CRUD
hello !
voila je reviens avec mon frameworks lol c'est encore un petit prototype
la je m'occupe un peu de la partie DAO
Hugo tu as proposer une classe pour les collection d'objet qui m'interesse ici :
http://www.apprendre-php.com/forums/topic-109-poo-debut.html
je me suis inspirer de tous ça et par rapport à ce que j'ai fais je souhaiterais implementer l'interface Iterator ! et je sais pas trop comment je peux l'integrer par rapport à mon code que je te trasmet si dessous:
j'ai une classe User simple avec les nom, prenom etc getter setter
puis
j'ai fais une class de type CRUD si dessous
j'ai créer une interface Iterator...
puis j'ai vu dans ta proposition de collection d'objet que tu l'avais fais en abstract la class !
moi j'ai commencer par faire une interface comme suit
pour la class crud j'arrive à insere, delete etc mais je voudrais faire ma coolection d'objets et y implementer l'interface iterator et iCollection(inspirer de JAVA)
mais je bloque un peuet manque un peu d'idée lol
que penses tu du code qu e j'ai commencer ?
Réponses apportées à cette discussion
Salut Vini,
C'est plutôt pas mal comme travail même si avant de plonger vraiment dans ta demande, j'ai quelques remarques à faire.
- Quand tu catches une exception, surtout ne l'affiches pas avec un echo() ou un die() comme tu le fais. Ce n'est pas le rôle de la classe de t'imprimer une exception à l'écran. La meilleure chose à faire est de logguer l'exception dans un fichier texte grâce à une classe MyLogger::log() que tu peux te créer puis relancer l'exception juste après pour la faire remonter. Ce qui donne :
<?php
class MyClass
{
public function myMethod()
{
try
{
doSomething();
}
catch(Exception $e)
{
MyLogger::log($e);
throw $e;
}
}
}
Grâce à cela, cela te permettra d'avoir une trace de l'exception dans un fichier de log, puis de pouvoir gérer l'exception aux niveaux supérieurs. Ainsi, si tu es en environnement de développement, tu t'affiches l'exception depuis ton front controller mais si le site est en production alors ton front controller pourra t'envoyer un mail pour t'informer et afficher une page d'erreur 500 (via les bons entêtes) à ton utilisateur. Celui-ci ne verra donc pas l'exception qui a été générée mais plutôt un message perso du type : "Erreur interne, l'administrateur a été prévenu".
Personnellement je n'aime pas trop mélanger syntaxe SQL de mes objets associés. Je te recommande à chaque fois de faire deux classes. L'une pour gérer l'objet en lui même et l'autre pour tout ce qui est SQL. Par exemple :
<?php
class Article implements iCrud
{
public function delete()
{
return ArticleTable::delete($this);
}
public function save()
{
return ArticleTable::save($this);
}
}
class ArticleTable
{
const TABLE_NAME = 't_article';
public static function delete(Article $article)
{
// Une requête préparée et si possible avec une transaction
try
{
$pdo = SPDO::getInstance();
$pdo->beginTransaction();
$pdo->preparedQuery('DELETE * FROM ? WHERE id=?', array(self::TABLE_NAME, $article->getId());
$pdo->commit();
}
catch(Exception $e)
{
// La requête a échoué donc on annule la transaction
$pdo->rollback();
MyLogger::log($e);
throw $e;
}
}
}
Au moins avec ça tu peux gérer tout ce qui est purement SQL dans ta table ArticleTable et ta classe Article fait appel à cette classe ArticleTable pour aller chercher des objets dans ta BDD. De même, ton accès PDO ne sera que dans la classe ArticleTable où il a lieu d'être et pas dans la classe Article qui ne s'occupe aucunement de manipuler la base.
Tu veux implémenter Iterator pour ta classe Collection ?
Concernant ta méthode size() de ta classe de Collection, elle ne sert pas à grand chose car tu peux implémenter l'interface Countable qui te permet de redéfinir une méthode count() dans la classe qui sera appelée implicitement quand tu feras un count() de ton objet Collection.
<?php
class Collection implements Countable, Iterator
{
protected $collection = array();
public function count()
{
return count($this->collection);
}
}
$c = new Collection();
$c->add(new MyObject());
$c->add(new MyObject());
$c->add(new MyObject());
$c->add(new MyObject());
$c->add(new MyObject());
$c->add(new MyObject());
echo count($collection);
/* Appel implicite à Collection::count() qui renvoie la valeur 6 car nous avons ajouté 6 objets dans le tableau $collection */
Une classe peut implémenter plusieurs interfaces, donc rien ne t'empêche d'implémenter Countable et Iterator en même temps à partir du moment que tu redéfinis bien les méthodes des interfaces.
++
Merci pour ces conseils !
Je suis pas encore très à l'aise avec les exceptions donc ca me donne des idées en plus !
j'avais mis des echos pour visualisé mais comme tu me l'avais conseiller pour la class SPDO je comptais créer un system de log par la suite et l'adapter
je connaissais pas l'interface Countable, mais c'est interessant !
je vais tester un peu tous ça de plus c'est vrai que je peux utilisé les transactions je n'y avais pas penser !
merci !
:D
encore une petite question sur ce que tu as ecris !
l'exemple que tu m'as donné :
class Article implements iCrud
{
public function delete()
{
return ArticleTable::delete($this);
}
public function save()
{
return ArticleTable::save($this);
}
}
En faite j'insert ces methodes class article qui contiens aussile nom de l'article,id,prix etc
et quand tu ecris retur ArticleTable::save($this) ca veux dire que tu appel la requete de la class ArticleTable et le $this en paramètre est l'objet en lui meme Article ?
si c'est ça c'est intéressant je connassais pas non plus cette façon de codé !
Le $this correspond à la référence sur l'instance en cours donc l'objet que tu manipules à cet instant T. Donc quand tu passes $this en paramètre d'une méthode, tu lui passes l'objet courant (ici l'objet Article) qui contient les attributs et propriétés.
ok merci !
en effet $this est pratique dans ce cas de figure que je connaissais pas !
la POO est vraiment intéressant je ne peux plus m'en passé lol
en même temps que penses tu de ma méhode getConnection() ?
j'ai vu que dans la methode delete de ton exemple tu avais ecrit comme suit :
$pdo = SPDO::getInstance();
$pdo->beginTransaction();
$pdo->preparedQuery('DELETE * FROM ? WHERE id=?', array(self::TABLE_NAME, $article->getId());
$pdo->commit();
tu appelle directement la methode getInstance() !
je suppose que c'est plus rapide en terme d'execution ?
car je penses que getConnection() n'est pas vraiment utile qu'en penses tu ?
De plus j'ai aussi créer une méthode getAllUser() dans mon crud mais elle n'a je penses pas lieu d'être dans ma class User
mais si je veux récuperer tous les users de la table je vais pas juste faire getUser() en boucle mais plutôt faire une requête qui selectionne tous ! (niveau ressource ça serais lourd)
merci pour ton aide =[^_^]=
En effet ton getConnection() n'est pas utile. Il vaut mieux créer ta connexion SQL une bonne fois pour toute lors de l'instanciation. Avec getInstance(), au premier appel, l'objet sera créé (donc la connexion SQL ouverte).
Pour getAllUsers(), effectivement elle n'a rien à faire dans la classe User mais elle aurait sa place dans UserTable. Il faut que cette méthode te retourne une collection d'objet User hydratés.
++
encore merci !
ok donc pour ouvrir la connection faut juste que j'appelle dans mon constructeur getInstance ?
et que veux tu dire par User hydraté stp?
Tu fais l'instance de l'objet PDO dans le constructeur, pour qu'il soit crée au moment du premier appel à getInstance().
User hydraté signifie un objet issu de la class User dont les attributs ont été fixés par les valeurs issues de la BDD.
salut !
j'ai un petit souci pour récupéré l'instance de SPDO
comme j'appel les methode save depuis article par exemple !
je les appelle comme suit
public function save()
{
return ArticleTable::save($this);
}
donc il faut que ma methode de la class TableArticle soit static pour que ça marche !
et donc dans ma class Table article je fait :
private static $connection;
public function __construct() {
self::$connection = SPDO::getInstance();
}
// puis ma methode save
$statement = self::$connection($request);
$statement->execute($param);
// je te met le code un peu gros vite fais
j'obtiens le message suivant
fatalerror: Call a mumber function prepare() on a non-object in ....
en faite je crois que je ne recupère pas bien mon instance de SPDO
une idée serais la bienvenue ?
merci @+ vini