Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 20 sur 20
  1. #1
    Expert Confirmé Sénior
    Avatar de Benjamin Delespierre
    Profil pro Benjamin Delespierre
    Développeur Web
    Inscrit en
    février 2010
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Nom : Benjamin Delespierre
    Âge : 26
    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 932
    Points : 8 705
    Points
    8 705

    Par défaut PDOStatemnt & Iterator

    Bonjour à tous.

    Je vous propose la classe PDOStatementIterator. J'ai été amené à créer cette classe pour faciliter l'usage des Iterators avec les PDOStatement car bien que ces derniers implémentent l'interface Traversable, il n'est pas possible de l'utiliser comme un Iterator (du moins pas directement). Il est vrai que l'usage de IteratorIterator nous permet de contourner ce problème, mais on aimerai grandement pouvoir se positionner dans le PDOStatement (SeekableIterator) et compter le nombre de lignes retournées (Countable), c'est là que PDOStatement entre en scène.

    Voici le code source de la classe:
    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
     
    class PDOStatementIterator extends IteratorIterator implements SeekableIterator, Countable {
     
        protected $_statement;
     
        protected $_count;
     
        public function __construct (PDOStatement $statement) {
            parent::__construct($this->_statement = $statement);
        }
     
        public function seek ($position) {
            if ($position > $this->count() || $position < $this->key())
                throw new OutOfBoundsException("Cannot seek to $position");
     
            for ($i = $this->key(); $i < $position; $i++)
                $this->next();
        }
     
        public function count () {
            if (!isset($this->_count))
    		    return $this->_count = $this->_statement->rowCount();
    	    return $this->_count;
        }
    }
    Cette classe est ni plus ni moins qu'un IteratorIterator seekable et coutable... On conserve une référence sur le PDOStatement à cet effet.
    L'usage de cette classe est indépendant du fetch_mode choisi dans le PDOStatement, ce qui la rends bien pratique pour récupérer des collections en LazyLoading.
    Exemple:
    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
     
    class User { 
      protected $_data;
     
      public function __get ($key) {
        return isset($this->_data[$key]) ? $this->_data[$key] : null;
      }
     
      public function __set ($key, $value) {
    	$this->_data[$key] = $value;
      }
    }
     
    // ...
     
    $user = new User;
     
    $stmt = $pdo->prepare('SELECT * FROM `users`');
    $stmt->setFetchMode(PDO::FETCH_INTO, $user);
    $stmt->execute();
     
    $it = new PDOStatementIterator($stmt);
    $itit = new LimitIterator($it, 10, 20);
    foreach ($itit as $user) {
      var_dump($user);
    }
    Une amélioration possible serait d'étendre NoRewindIterator au lieu de IteratorIterator, mais je n'ai pas encore réussi à la faire marcher dans ce sens...

    Voir également la discussion d'origine: http://www.developpez.net/forums/d10...oo-orm-entite/

    Vos commentaires sont les bienvenus.

  2. #2
    Rédacteur
    Avatar de doctorrock
    Homme Profil pro Julien Pauli
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    603
    Détails du profil
    Informations personnelles :
    Nom : Homme Julien Pauli
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 603
    Points : 2 991
    Points
    2 991

    Par défaut

    A vue de nez, je dirai nikel.

    Traversable est compliquée, elle déclare un itérateur interne, donc on peut utiliser foreach() (ça appel fetch()), mais l'itérateur n'est pas visible depuis PHP, pour personnaliser le comportement, faut l'encapsuler dans IteratorIterator, comme tu l'as fait.

    NoRewind ne fonctionne pas ?
    .: Expert contributeur certifié PHP/ZF :.
    Mes articles - Twitter - GitHub

  3. #3
    Expert Confirmé Sénior
    Avatar de Benjamin Delespierre
    Profil pro Benjamin Delespierre
    Développeur Web
    Inscrit en
    février 2010
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Nom : Benjamin Delespierre
    Âge : 26
    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 932
    Points : 8 705
    Points
    8 705

    Par défaut

    Cette implémentation ne fonctionne pas correctement:

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    class PDOStatementIterator extends NoRewindIteratro implements SeekableIterator, Countable {
     
        protected $_statement;
     
        protected $_count;
     
        public function __construct (PDOStatement $statement) {
            parent::__construct(new IteratorIterator($this->_statement = $statement));
        }
     
        // ...

  4. #4
    Rédacteur
    Avatar de doctorrock
    Homme Profil pro Julien Pauli
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    603
    Détails du profil
    Informations personnelles :
    Nom : Homme Julien Pauli
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 603
    Points : 2 991
    Points
    2 991

    Par défaut

    Code :
    parent::__construct($this->_statement = $statement);
    .: Expert contributeur certifié PHP/ZF :.
    Mes articles - Twitter - GitHub

  5. #5
    Expert Confirmé Sénior
    Avatar de Benjamin Delespierre
    Profil pro Benjamin Delespierre
    Développeur Web
    Inscrit en
    février 2010
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Nom : Benjamin Delespierre
    Âge : 26
    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 932
    Points : 8 705
    Points
    8 705

    Par défaut

    Non car le constructeur de NoRewindIterator attends un Iterator. La solution consiste à wrapper le PDOStatement dans un IteratorIterator avant de le wrapper à son tour par un NoRewindIterator, mais pour une raison qui m'échappe, ça ne fonctionne pas dans le contexte du constructeur... L'objet construit ne se traverse plus.

  6. #6
    Rédacteur
    Avatar de doctorrock
    Homme Profil pro Julien Pauli
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    603
    Détails du profil
    Informations personnelles :
    Nom : Homme Julien Pauli
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 603
    Points : 2 991
    Points
    2 991

    Par défaut

    NoRewindIterator extends IteratorIterator
    .: Expert contributeur certifié PHP/ZF :.
    Mes articles - Twitter - GitHub

  7. #7
    Expert Confirmé Sénior
    Avatar de Benjamin Delespierre
    Profil pro Benjamin Delespierre
    Développeur Web
    Inscrit en
    février 2010
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Nom : Benjamin Delespierre
    Âge : 26
    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 932
    Points : 8 705
    Points
    8 705

    Par défaut

    La signature de leurs constructeurs est différentes. Essaie tu verras.

  8. #8
    Rédacteur
    Avatar de doctorrock
    Homme Profil pro Julien Pauli
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    603
    Détails du profil
    Informations personnelles :
    Nom : Homme Julien Pauli
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 603
    Points : 2 991
    Points
    2 991

    Par défaut

    Ahh oui les vilains,ils ont typés sur Iterator et non pas Traversable.

    Pas bien ça

    Du coup je sais pas, j'ai pas testé le IteratorIterator , mais ça devrait fonctionner.
    Bug possible ?
    .: Expert contributeur certifié PHP/ZF :.
    Mes articles - Twitter - GitHub

  9. #9
    Expert Confirmé Sénior
    Avatar de Benjamin Delespierre
    Profil pro Benjamin Delespierre
    Développeur Web
    Inscrit en
    février 2010
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Nom : Benjamin Delespierre
    Âge : 26
    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 932
    Points : 8 705
    Points
    8 705

    Par défaut

    J'ai testé à la main avec ça:
    Code :
    1
    2
    3
    4
     
    $stmt = $pdo->prepare('machin truc');
    $it = new IteratorIterator($stmt); // traverser cet objet fonctionne
    $itit = new NoRewindIterator($it); // ne se traverse pas...

  10. #10
    Rédacteur
    Avatar de doctorrock
    Homme Profil pro Julien Pauli
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    603
    Détails du profil
    Informations personnelles :
    Nom : Homme Julien Pauli
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 603
    Points : 2 991
    Points
    2 991

    Par défaut

    C'est plutot louche
    .: Expert contributeur certifié PHP/ZF :.
    Mes articles - Twitter - GitHub

  11. #11
    Modérateur

    Inscrit en
    septembre 2010
    Messages
    7 957
    Détails du profil
    Informations forums :
    Inscription : septembre 2010
    Messages : 7 957
    Points : 9 507
    Points
    9 507

    Par défaut

    malheureusement on ne pas pas utiliser ce genre de classe direct dans PDO::ATTR_STATEMENT_CLASS sans passer par un pont

  12. #12
    Expert Confirmé Sénior
    Avatar de Benjamin Delespierre
    Profil pro Benjamin Delespierre
    Développeur Web
    Inscrit en
    février 2010
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Nom : Benjamin Delespierre
    Âge : 26
    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 932
    Points : 8 705
    Points
    8 705

    Par défaut

    Non en effet, à moins de réécrire un iterateur en partant de Iterator.

  13. #13
    Rédacteur
    Avatar de doctorrock
    Homme Profil pro Julien Pauli
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    603
    Détails du profil
    Informations personnelles :
    Nom : Homme Julien Pauli
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 603
    Points : 2 991
    Points
    2 991

    Par défaut

    Citation Envoyé par stealth35 Voir le message
    malheureusement on ne pas pas utiliser ce genre de classe direct dans PDO::ATTR_STATEMENT_CLASS sans passer par un pont
    Yes, il type sur PDOStatement. C'est une limite interne
    .: Expert contributeur certifié PHP/ZF :.
    Mes articles - Twitter - GitHub

  14. #14
    Rédacteur
    Avatar de doctorrock
    Homme Profil pro Julien Pauli
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    603
    Détails du profil
    Informations personnelles :
    Nom : Homme Julien Pauli
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 603
    Points : 2 991
    Points
    2 991

    Par défaut

    Citation Envoyé par Benjamin Delespierre Voir le message
    Non en effet, à moins de réécrire un iterateur en partant de Iterator.
    Ouai ?

    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
     
    class MySt extends PDOStatement implements IteratorAggregate
    {
        public function getIterator() {
            return new ArrayIterator($this->fetchAll());
    }
    }
     
    $p = new PDO('sqlite::memory:');
    $p->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('MySt'));
    $p->exec('CREATE TABLE foo (txt TEXT);');
    $p->exec("INSERT INTO foo VALUES ('foobar');");
     
    var_dump(iterator_to_array($p->query("SELECT * FROM foo")));
     
    /*
    array(1) {
      [0]=>
      array(2) {
        ["txt"]=>
        string(6) "foobar"
        [0]=>
        string(6) "foobar"
      }
    }*/
    Ecrit en 2min, utilise fetchAll() à l'arrache. En implémentant Iterator, on peut appeler seulement fetch() à chaque tour.
    .: Expert contributeur certifié PHP/ZF :.
    Mes articles - Twitter - GitHub

  15. #15
    Modérateur

    Inscrit en
    septembre 2010
    Messages
    7 957
    Détails du profil
    Informations forums :
    Inscription : septembre 2010
    Messages : 7 957
    Points : 9 507
    Points
    9 507

    Par défaut

    Ça perd de beaucoup de son intérêt la, je vois pas comment tu peux implémenter Iterator puisque c'est pas possible de le faire :

    Code :
    1
    2
    class Bug38592 extends PDOStatement implements Iterator {}
    //Fatal error: Class Bug38592 could not implement interface Iterator in Unknown on line 0

  16. #16
    Rédacteur
    Avatar de doctorrock
    Homme Profil pro Julien Pauli
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    603
    Détails du profil
    Informations personnelles :
    Nom : Homme Julien Pauli
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 603
    Points : 2 991
    Points
    2 991

    Par défaut

    Yes, c'est parcequ'il implémente Traversable en interne et ne peut pas implémenter Iterator.

    Bloqué !
    .: Expert contributeur certifié PHP/ZF :.
    Mes articles - Twitter - GitHub

  17. #17
    Expert Confirmé Sénior
    Avatar de Benjamin Delespierre
    Profil pro Benjamin Delespierre
    Développeur Web
    Inscrit en
    février 2010
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Nom : Benjamin Delespierre
    Âge : 26
    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 932
    Points : 8 705
    Points
    8 705

    Par défaut

    On revient donc sur notre wrapper de départ... Aucune piste en ce qui concerne le NoRewindIterator.
    Pour rappel les tests de wrap d'un PDOStatement dans un IteratorIterator ne posent aucun problème, or lorsqu'on met cet IteratorIterator dans un NoRewindIterator, plus rien ne marche...

    Voici un exemple:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    $db = "backoffice";
    $db_type = "mysql";
    $db_user = "root";
    $db_password = "";
    $db_host = "localhost";
     
    $pdo = new PDO("$db_type:dbname=$db;host=$db_host", $db_user, $db_password);
    $query = "SELECT * FROM users";
    $stmt = $pdo->query($query);
     
    $it = new IteratorIterator($stmt);
    $itit = new NoRewindIterator($it);
    foreach ($itit as $row) {
     var_dump($row);
    }
     
    var_dump("done");

  18. #18
    Rédacteur
    Avatar de doctorrock
    Homme Profil pro Julien Pauli
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    603
    Détails du profil
    Informations personnelles :
    Nom : Homme Julien Pauli
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 603
    Points : 2 991
    Points
    2 991

    Par défaut

    Faut regarder si ya pas un rapport de bug à ce sujet.

    A tout hasard, tester avec un NoRewindIterator(IteratorIterator) sur autre chose que PDOStatement, pour prouver que le bug supposé vient bien de PDOStatement (pas sûr)
    .: Expert contributeur certifié PHP/ZF :.
    Mes articles - Twitter - GitHub

  19. #19
    Expert Confirmé Sénior
    Avatar de Benjamin Delespierre
    Profil pro Benjamin Delespierre
    Développeur Web
    Inscrit en
    février 2010
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Nom : Benjamin Delespierre
    Âge : 26
    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 932
    Points : 8 705
    Points
    8 705

    Par défaut

    Chose étrange, il semble que NoRewindIterator nécéssite un iterateur rembobiné pour fonctionner correctement... Je vais voir la doc à ce sujet.

    Voici un exemple:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    $a = new ArrayObject(array(1,2,3,4,5));
     
    $it = new IteratorIterator($a);
    $it->rewind(); // Si on commente cette ligne, le NoRewindIterator ne se traverse plus...
     
    $itit = new NoRewindIterator($it);
    foreach ($itit as $val)
      echo $val;
    A noter que cette forme fonctionne parfaitement:
    Code :
    1
    2
    3
    4
    5
    6
     
    $a = new ArrayIterator(array(1,2,3,4,5));
     
    $itit = new NoRewindIterator($a); // On a besoin d'un Iterator ici
    foreach ($itit as $val)
      echo $val;

  20. #20
    Rédacteur
    Avatar de doctorrock
    Homme Profil pro Julien Pauli
    Architecte de système d'information
    Inscrit en
    mai 2006
    Messages
    603
    Détails du profil
    Informations personnelles :
    Nom : Homme Julien Pauli
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2006
    Messages : 603
    Points : 2 991
    Points
    2 991

    Par défaut

    Idem sur le Caching ; ça , c'est un bug ! (déja vu, relevé, mais pas corrigé il me semble)
    .: Expert contributeur certifié PHP/ZF :.
    Mes articles - Twitter - GitHub

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •