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 :

traiter des fichiers CSV en POO : quelle conception est mieux ? [POO]


Sujet :

Langage PHP

  1. #21
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par CosmoKnacki Voir le message
    Pourquoi une classe devrait-elle absolument faire appel à ses propres méthodes? Il n'y a aucune obligation à cela.
    OK, bien sûr. Ca vient juste de mon manque d'expérience (la POO, c'est tout neuf pour moi).

    Citation Envoyé par CosmoKnacki Voir le message
    J'ai complété mon exemple
    Ca m'a bien aidé. (surtout les lignes de la fin pour utiliser la classe)

    Citation Envoyé par CosmoKnacki Voir le message
    Non pas du tout, toutes les méthodes des interfaces sont bien présentes, les unes définies au sein même de la classe, les autres apportées par le trait FileTrait
    OK, j'avais pas fait gaffe au trait.
    Il semblerait au moins que 2 des 3 propriétés de la classe CSVFileReader ($path, $handle) ne sont pas déclarées ($fieldsNumber l'est dans la classe mère).

    Peux-tu m'expliquer cette syntaxe (pas vue souvent) : protected ?string $location; (le point d'interrogation) ?

    Avec tes explications, j'y vois un peu plus clair, mais c'est pas gagné (ça fait beaucoup de nouveautés à assimiler)(interface, trait, type callable, générateur, le mécanisme des transactions en PDO)
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  2. #22
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Ça signifie que la propriété peut être de type string ou null.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  3. #23
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Grâce à tes explications Cosmo, je peux comprendre à peu près le code du post #8. Bien sûr, j'ai 3-4 questions :

    - d'abord, tu appelles le générateur ($genRow = $reader->getReader();) puis tu lances la transaction et au cours de celle-ci, tu balayes la ligne renvoyée par le générateur (foreach($genRow as $fields)). Comme on utilise un générateur, j'ai compris qu'une fois la transaction terminée pour cette ligne-là, le générateur va reprendre la main à partir de l'endroit où il s'était arrêté et donc fournir la ligne suivante. C'est bien ça ?

    - le rollBack que tu fais va remettre la bdd dans son état initial mais juste pour la ligne du CSV en cours, sachant que pour les lignes précédentes, l'écriture est déjà faite. OK ? (j'étais pas parti sur cette option, mais c'est envisageable)

    - la partie "validation" est opérationnelle, mais ne respecte pas entièrement mon cahier des charges : en effet, je compte balayer en entier le fichier CSV, donc valider l'entièreté de son contenu et de noter toutes les erreurs et les afficher à la fin. Ce dernier point n'est pas effectué par ton validateur...Je suppose qu'on peut le compléter pour qu'il fasse ça aussi.

    - dans ta transaction, tu n'envisages que des INSERT. Mon cahier des charges est plus complexe que cela : au cas où la ligne lue du CSV est déjà présente en BDD mais si certaines données ont changé, on fait plutôt un UPDATE et si aucune donnée n'a changé, on fait rien. Et on compte le nombre de INSERT et le nombre de UPDATE.
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  4. #24
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    - d'abord, tu appelles le générateur ($genRow = $reader->getReader();) puis tu lances la transaction et au cours de celle-ci, tu balayes la ligne renvoyée par le générateur (foreach($genRow as $fields)).
    Je n'appelle rien du tout, $genRow est un simple alias du générateur, cette ligne on aurait très bien pu s'en passer et écrire directement: foreach($reader->getReader() as $fields).

    Le foreach($genRow as $fields) ne boucle pas sur les champs d'une ligne, il boucle sur l'ensemble des lignes (déjà découpées en champs qui plus est). C'est pourquoi $fields est au pluriel. Autrement dit, à chaque tour de boucle, $fields est un tableau contenant tous les champs d'une ligne.

    Comme on utilise un générateur, j'ai compris qu'une fois la transaction terminée pour cette ligne-là, le générateur va reprendre la main à partir de l'endroit où il s'était arrêté et donc fournir la ligne suivante. C'est bien ça ?
    ...
    - le rollBack que tu fais va remettre la bdd dans son état initial mais juste pour la ligne du CSV en cours, sachant que pour les lignes précédentes, l'écriture est déjà faite. OK ? (j'étais pas parti sur cette option, mais c'est envisageable)
    Non pas OK, et c'est tout l'intérêt de la transaction, si un rollback est effectué, la base revient à son état initial (celui du moment où on a démarré la transaction), quelque soit le nombre d'insert ou d'update qui ont pu être effectués au cours de celle-ci.

    - la partie "validation" est opérationnelle, mais ne respecte pas entièrement mon cahier des charges : en effet, je compte balayer en entier le fichier CSV, donc valider l'entièreté de son contenu et de noter toutes les erreurs et les afficher à la fin. Ce dernier point n'est pas effectué par ton validateur...Je suppose qu'on peut le compléter pour qu'il fasse ça aussi.
    C'est faisable: rien ne t'empêche d'agrémenter chaque test de validation d'un message d'erreur particulier (à toi de modifier les classes en conséquence).
    Dans le code fourni, la boucle est interrompue à la première erreur, ce n'est pas un problème car le générateur reste à la même position, donc une fois le rollback effectué, tu peux faire une autre boucle qui partira de l'endroit où la première s'est arrêtée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $genRemainingRow = (fn($gen) => yield from $gen)($genRow);
     
    foreach($genRemainingRow as $fields) { /*****/ }
    Donc dans cette nouvelle boucle tu peux afficher directement les erreurs ou les stocker. (Elle repart précisément de la ligne de l'erreur).

    dans ta transaction, tu n'envisages que des INSERT. Mon cahier des charges est plus complexe que cela : au cas où la ligne lue du CSV est déjà présente en BDD mais si certaines données ont changé, on fait plutôt un UPDATE et si aucune donnée n'a changé, on fait rien. Et on compte le nombre de INSERT et le nombre de UPDATE.
    Tu fais ce que tu veux ce n'est pas un problème.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  5. #25
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Moi qui croyais avoir compris, j'étais complètement à côté de la plaque Ca ne me rassure pas.
    Je ferai une tentative de codage demain matin (j'ai les idées plus claires le matin).

    En attendant, j'ai du mal avec ce code :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $genRemainingRow = (fn($gen) => yield from $gen)($genRow);
     
    foreach($genRemainingRow as $fields) { /*****/ }
    Pourrais-tu l'expliciter STP ? Et la fonction fn, c'est quoi ?
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  6. #26
    Membre à l'essai
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2012
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Février 2012
    Messages : 5
    Points : 11
    Points
    11
    Par défaut
    Je répond en coup de vent car le sujet m'intéresse.
    Alors fn ça viens des fonctions fléché, qui est une écriture simplifié des fonctions anonymes.

    Yield, c'est le mot clé qui permet de faire des générateurs et yield from permet disons, d'imbriquer des yields entre eux on va dire (même si ce n'est pas exactement ça).

    Du coup, si tu n'as pas l'habitude de lire ce genre de syntaxe, c'est normale que tu galère un peu.
    Si tu la décompose, c'est plus facile à comprendre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    // la version longue de fn($gen) => yield from $gen
    $monGenerateurAnonyme = function($gen)
    {
         // récupère les valeurs de $gen pour ce générateur
         yield from $gen;
    }
     
    // On passe $genRow en paramètre de la fonction anonyme.
    // $genRemainingRow = (fn($gen) => yield from $gen)($genRow);
    $genRemainingRow = $monGenerateurAnnonyme($genRow);
     
    // Puis itération sur le générateur, donc ici on a les valeurs qui viennent de $genRow, passé par le from yield
    foreach($genRemainingRow as $fields) { /*****/ }
    Si ça peut aider

  7. #27
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Exeldo Voir le message
    Si ça peut aider
    car ça m'aide bien. Les fonctions anonymes, je connaissais un peu (je ne connaissais que le terme "closure"), mais les fonctions fléchées, que de nom...Et d'ailleurs, j'ai regardé le lien que tu donnes : rien compris.

    Et ça fait 2 notions de plus à maîtriser sur les 5 que je citais déjà au post #21

    Grâce à ton explication, je comprend un peu mieux le code, mais ne vois pas encore comment le placer dans
    Code php : 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
    <?php
    $rowValidator = new RowValidator([
        new FieldValidator([
            'is_numeric',
            fn($v) => $v > 11
        ]),
        new FieldValidator([
            fn($v) => false !== strpos($v, 'marmotte'),
            fn($v) => !preg_match('~ \[ [^]]* marmotte [^]]* ] ~x', $v)
        ]) //, ...
    ]);
     
     
    $reader = new CSVFileReader('path/to/my/file.csv');
     
    $genRow = $reader->getReader();
     
    $pdo->beginTransation();
    $query = 'INSERT INTO matable (col1, col2, ... coln) VALUES (?, ?, ... ?)';
    $stmt = $pdo->prepare($query);
     
    $valid = true;
     
    foreach($genRow as $fields) {
        if ( !$rowValidator->validate($fields) ) {
            $valid = false;
            $pdo->rollBack();
            break;
        }
        $stmt->execute($fields);
    }
     
    if ( $valid ) {
        $pdo->commit();
    }
    tout à la fin (après la ligne 35) ?

    Et cette deuxième boucle, elle va permettre de relancer la lecture du CSV au point où on a détecté une erreur, mais que va-t-il se passer quand on rencontrera une deuxième erreur ?
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  8. #28
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Petite précision/correction: $genRemainingRow = (fn($gen) => yield from $gen)($genRow); peut s'écrire plus simplement $genRemainingRow = (fn() => yield from $genRow)();.
    Car contrairement aux fonctions anonymes (ou closures), une array function a accès aux variables extérieures (par valeur) sans recourir à use.

    tout à la fin (après la ligne 35) ?
    Oui, le tout dans un else du test de $valid.

    Et cette deuxième boucle, elle va permettre de relancer la lecture du CSV au point où on a détecté une erreur, mais que va-t-il se passer quand on rencontrera une deuxième erreur ?
    Ça c'est à toi de le décider. D'ailleurs au passage, comme le générateur reprend à la même ligne où il s'était interrompu, la "première erreur" qu'il va rencontrer sera la première erreur (cette ligne est testée deux fois).
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  9. #29
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Ça c'est à toi de le décider.
    Ce que je souhaite, c'est que s'il y a N erreurs dans le CSV, on note ces N erreurs, (stockage dans un tableau), mais on parcourt en entier le fichier. Mais comment coder cela ?

    D'ailleurs au passage, comme le générateur reprend à la même ligne où il s'était interrompu, la "première erreur" qu'il va rencontrer sera la première erreur (cette ligne est testée deux fois).
    Désolé, mais pas compris...
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  10. #30
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Juste une remarque Cosmo : pour que ça passe sans erreur, j'ai du mettre toutes les méthodes que tu as déclarées dans les interfaces en public alors que tu les avais mises en protected...
    J'ai pas été loin (je n'ai codé que ce soir) :
    valid.php : copier-coller de ton code

    csv.php :
    Code php : 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
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    <?php
    abstract class CSV
    {
        protected string $separator = ',';
        protected string $protection = '"';
        protected string $escape = '\\';
     
        protected ?int $fieldsNumber = null;
     
        protected ?array $headers = null;
     
     
        abstract function checkFieldsNumber(int $fieldsNumber):bool;
     
        protected function hasHeaders():bool {
            return (bool) $this->headers;
        }
    }
     
     
     
    interface iReader
    {
        public function getReader();
    }
     
    interface iFile
    {
        public function setLocation(string $location):void;
     
        public function exists():bool;
     
        public function isReadable():bool;
     
        public function isWritable():bool;
     
    }
     
    trait FileTrait
    {
        protected ?string $location;
     
        public function setLocation(string $location):void {
            $this->location = $location;
        }
     
        public function exists():bool {
            return is_file($this->location);
        }
     
        public function isReadable():bool {
            return is_readable($this->location);
        }
     
        public function isWritable():bool {
            return is_writable($this->location);
        }
    }
     
    class CSVFileReader extends CSV implements iReader, iFile
    {
        private $path;
        private $handle;
     
        use FileTrait;
     
        public function __construct($path)
        {
            $this->path = $path;
            $this->open($this->path);
        }
     
     //méthode que j'ai rajoutée 
        public function open( $path)
        {
            $this->handle = fopen($path, 'r');
        }
     
        public function getReader() {
            while ( false !== $fields = fgetcsv($this->handle) ) {
                yield $fields;
            }
            $this->close($this->handle);
        }
     
        public function checkFieldsNumber(int $fieldsNumber):bool {
            return $this->fieldsNumber === $fieldsNumber;
        }
    }
    code qui fait rien à part importer ton code et instancier un objet et sans générer d'erreur (c'est déjà pas mal).
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <?php
    include('valid.php');
    include('csv.php');
    $reader = new CSVFileReader('C:\projets\ticket_rawsrc\csv\licences_avec_dq-test6.csv');
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  11. #31
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ?php
    include('valid.php');
    include('csv.php');
    $reader = new CSVFileReader('C:\projets\ticket_rawsrc\csv\licences_avec_dq-test6.csv');
     
    $genRow = $reader->getReader();
     
    $i=0;
    foreach($genRow as $fields)  //Autrement dit, à chaque tour de boucle, $fields est un tableau contenant tous les champs d'une ligne.
    {
        echo "ligne ".$i++;
        var_dump($fields);
        echo "<br/>";
    }
    Cosmo, je confirme ta remarque que j'ai remise en commentaire ligne 9. On avance
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  12. #32
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Très bien, c'est comme ça qu'il faut procéder en s'appropriant le code, en faisant des var_dump pour voir ce qui se passe, et effectivement oui les méthodes déclarées dans une interfaces doivent être public (je les avais copier/coller d'une classe abstraite, c'est pour ça).

    D'ailleurs plutôt que d'implémenter une interface pour que CSVFileReader puisse lire des fichiers CSV à partir d'une URL (ou d'un path), il est en fait bien plus simple de se cantonner à une classe CSVReader qui prendrait en paramètre de son constructeur une ressource vers un fichier (ou autre):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class CSVReader implements ReaderInterface
    {
        public function __construct($handle)
        {
            $this->handle = $handle;
        }
    }
    Comme ça cette classe n'aurait pas à s'occuper de tout ce qui est ouvertures, fermetures, tests d'existence des fichiers (ce qui de toute manière n'est pas son boulot).

    Et donc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if ( false === $handle = fopen('C:\projets\ticket_rawsrc\csv\licences_avec_dq-test6.csv', 'rb') ) {
        throw new Exception('impossible d\'ouvrir le fichier');
    }
     
    $reader = new CSVReader($handle);
    $genRow = $reader->getReader();
    //...
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  13. #33
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Génial
    moi qui était persuadé de jamais y arriver (mission impossible), je peux afficher le contenu du CSV !

    CSVReader.php :
    Code php : 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
    <?php
    namespace ticket_rawsrc\cosmo;
     
    interface iReader
    {
        public function getReader();
    }
     
    class CSVReader implements iReader
    {
        public function __construct($handle)
        {
            $this->handle = $handle;
        }
     
        public function getReader() {
            while ( false !== $fields = fgetcsv($this->handle) ) {
                yield $fields;
            }
        }
    }

    utiliserls.php :
    Code php : 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
    <?php
    //include('valid.php');
    include('CSVReader.php');
     
    use ticket_rawsrc\cosmo\CSVReader;
     
    if ( false === $handle = fopen('C:\projets\ticket_rawsrc\csv\licences_avec_dq-test6.csv', 'rb') ) {
        throw new Exception('impossible d\'ouvrir le fichier');
    }
     
    $reader = new CSVReader($handle);
    $genRow = $reader->getReader();
     
    $i=0;
    foreach($genRow as $fields)  //Autrement dit, à chaque tour de boucle, $fields est un tableau contenant tous les champs d'une ligne.
    {
        echo "ligne ".$i++;
        var_dump($fields);
        echo "<br/>";
    }

    Me "reste" plus qu'à rajouter la validation et l'écriture en bdd...
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  14. #34
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Rajouter les tests de validation, je dois me planter car même un test qui devrait renvoyer false, renvoit true...

    Pour simplifier les tests, j'ai créé un CSV avec seulement 3 colonnes, donc ça fait 3 champs par ligne à tester.

    Voici mon code :
    FieldValidator.php :
    Code php : 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
    <?php
    interface iValidator
    {
        public function validate($value):bool;
    }
     
    class FieldValidator implements iValidator
    {
        /* $constraints est un tableau dont les items sont de type callable
            et renvoient true ou false */
        protected $constraints;
     
        public function __construct($constraints) {
            $this->constraints = $constraints;
        }
     
        public function validate($value):bool {
            foreach ($this->constraints as $constraint) {
                if ( $constraint($value) === false ) {
                    return false;
                }
            }
            return true;
        }
    }

    RowValidator.php :
    Code php : 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
    <?php
     
    interface iValidator2 //pas 2 fois le même nom
    {
        public function validate($value):bool;
    }
     
    class RowValidator implements iValidator2
    {
        protected $validators;
     
        public function __construct(array $validators) {
            $this->validators = $validators;
        }
     
        public function validate($fields):bool {
            foreach ($fields as $k => $field) {    //foreach ($tab as $key => $value)
                if ( $this->validators[$k]->validate($field) === false ) {
                    return false;
                }
            }
            return true;
        }
    }

    CSVReader.php :
    Code php : 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
    <?php
     
    interface iReader
    {
        public function getReader();
    }
     
    class CSVReader implements iReader
    {
        public function __construct($handle)
        {
            $this->handle = $handle;
        }
     
        public function getReader() {
            while ( false !== $fields = fgetcsv($this->handle) ) {
                yield $fields;
            }
        }
    }

    le code principal (utiliserls.php) :
    Code php : 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
    <?php
     
    include('FieldValidator.php');
    include('RowValidator.php');
    include('CSVReader.php');
     
     
    if (false ===
        $handle = fopen('C:\projets\ticket_rawsrc\csv\csvcosmo.csv',
            'rb')
    )
    {
        throw new Exception('impossible d\'ouvrir le fichier');
    }
     
    $reader = new CSVReader($handle);
    $genRow = $reader->getReader();
     
    $rowValidator = new RowValidator([
        new FieldValidator([
            fn($v) => preg_match('/\ASESA[0-9]{5}\z/', $v)
            //fn($v) => (1==1)
        ]),
        new FieldValidator([
            fn($v) => (1==0) //cette fonction devrait renvoyer false
        ]),
        new FieldValidator([
            fn($v) => (1==1)
        ])
    ]); /* le tableau passé à la classe RowValidator contient 3 items qui sont 3 instances de la classe FieldValidator. A chaque instance, je passe un tableau constitué d'un seul item. Pour le premier, c'est l'évaluation d'une regexp ; pour le 2e, une fonction qui retourne toujours false et pour la 3e, une fonction qui retourne toujours true. Bien sûr, c'est que pour le test !*/
     
     
    $i = 0;
    foreach ($genRow as  $fields)
        //Autrement dit, à chaque tour de boucle, $fields est un tableau contenant tous les champs d'une ligne.
    {
        echo "ligne " . $i;
        var_dump($fields);
        echo "<br/>";
     
        if ( !$rowValidator->validate($fields) )
     
            echo "ligne".$i++." non valide";
        else
            echo "ligne".$i++." valide";
        echo "<br/><br/>";
    }
    Comme les lignes du fichier comportent 3 champs, je passe un tableau de dimension 3 à la classe RowValidator. Vu la valeur du 2e item du tableau, chaque ligne devrait être jugée non valide. Or, elles sont toutes vues valides. Où est mon erreur, STP ?
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  15. #35
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    interface iValidator2 //pas 2 fois le même nom
    {
        public function validate($value):bool;
    }
     
    class RowValidator implements iValidator2
    Il existe une interface iValidator, inutile d'en créer une autre qui fait la même chose avec un nom différent. (1 interface = 1 comportement)

    Sinon j'ai fait le test chez moi et j'obtiens le bon résultat (false pour chaque ligne).
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  16. #36
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Merci d'avoir testé.

    OK, pour l'interface avec un seul nom ; ça venait du fait que ayant créé un fichier par classe, je définissais l'interface 2 fois et évidemment, il ne voulait pas qu'on déclare 2 fois l'interface. J'ai laissé la définition une seule fois et ça roule...

    OK aussi pour le problème que je remontais hier au post #34. Ca ne le fait plus (je ne sais pas grâce à quoi).

    Par contre, la validation, pas encore au point. Comme j'ai légèrement modifié mon code, je redonne ce qui a changé :

    FieldValidator.php : inchangé

    RowValidator.php :
    Code php : 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
    <?php
     
    //interface iValidator2
    //{
    //    public function validate($value):bool;
    //}
     
    class RowValidator implements iValidator
    {
        protected $validators;
     
        public function __construct(array $validators) {
            $this->validators = $validators;
        }
     
        public function validate($fields):bool {
            $fields = explode(';',$fields[0]);
            foreach ($fields as $k => $field) {    //foreach ($tab as $key => $value)
     
                if ( $this->validators[$k]->validate($field) === false ) {
                    return false;
                }
            }
            return true;
        }
    }

    CSVReader.php : inchangé

    code principal (utiliserls.php) :
    Code php : 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
    55
    56
    57
    <?php
     
    include('FieldValidator.php');
    include('RowValidator.php');
    include('CSVReader.php');
     
    function debug($location, $var)
    {
        echo "<br/>".(is_string($location))?$location:''."<br/><pre>";
        var_dump($var);
        echo "</pre><br/>";
    }
     
    if (false ===
        $handle = fopen('C:\projets\ticket_rawsrc\csv\csvcosmo.csv',
            'rb')
    )
    {
        throw new Exception('impossible d\'ouvrir le fichier');
    }
     
    $reader = new CSVReader($handle);
    $genRow = $reader->getReader();
     
    // validation
    $rowValidator = new RowValidator([
        new FieldValidator([
            fn($v) => preg_match('/\ASESA[0-9]{5}\z/', $v)
            //fn($v) => (1==1)
        ]),
        new FieldValidator([
            fn($v) => (1==1) /*j'ai remis un test qui retourne true (je mets ça pour les champs dont on se fout) */
        ]),
        new FieldValidator([
            fn($v) => (1==1)
        ])
    ]);
    // fin validation
     
    $i = 0;
    foreach ($genRow as  $fields)
        //Autrement dit, à chaque tour de boucle, $fields est un tableau contenant tous les champs d'une ligne.
    {
        echo "ligne " . $i;
        var_dump($fields);
        echo "<br/>";
     
        $testvalid = $rowValidator->validate($fields);
    //    debug("utiliserls 51 testvalid ",$testvalid);
    //    debug("utiliserls 52 fields ",$fields);
        if ( $testvalid)
     
            echo "ligne".$i++." valide";
        else
            echo "ligne".$i++." non valide";
        echo "<br/><br/>";
    }

    Comme tu peux le voir, le premier des 3 tests consiste à vérifier une regexp. Je suis sûr de cette regexp, vu qu'on l'avait mise au point dans https://www.developpez.net/forums/d2...test-validite/
    Le format attendu est la chaîne de caractères SESA, suivie exactement de 5 chiffres.
    Je teste avec un fichier CSV où la première ligne ne remplit pas la condition et elle retourne quand même true.

    CSV :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SESAID	       ALTERNATEIDS	      PLATFORM
    SE100008	(none)	     Software Engineering
    SESA10038	(none)	     Software Engineering
    Comment ça se fait ?
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  17. #37
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    C'est quoi cette ligne $fields = explode(';',$fields[0]); dans RowValidator ? Où est passée la classe abstraite CSV, pourquoi CSVReader n'en hérite t'elle pas? Peux-tu montrer le contenu de ton fichier csv de test (brut)?
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  18. #38
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    L'explode, c'était un essai que j'avais laissé mais si je l'enlève, pareil...

    La classe abstraite CSV est bien là, mais dans le fichier inchangé CVSReader.php et l'héritage aussi : class CSVReader extends CSV implements iReader.

    Mon fichier CSV de test, le voici : non, pas moyen de le mettre en pièce jointe : fichier non valide ! (et j'ai essayé avec d'autres fichiers CSV : tous invalides).
    Ci-après son contenu :

    SESAID ALTERNATEIDS PLATFORM
    SE100008 (none) Software Engineering
    SESA10038 (none) Software Engineering
    SESA100675 (none) Software Engineering
    SESA101072 (none) Software Engineering
    SESA101549 (none) Software Engineering
    SESA101659 (none) Software Engineering
    SESA101844 (none) Software Engineering
    SESA101874 (none) Software Engineering
    SESA102556 (none) Software Engineering
    SESA103000 (none) Software Engineering
    SESA103057 (none) Software Engineering
    SESA103165 (none) Software Engineering
    SESA103184 (none) Software Engineering
    SESA103342 (none) Software Engineering
    SESA103404 (none) Software Engineering
    SESA103475 (none) Software Engineering
    SESA104175 (none) Software Engineering
    SESA104320 (none) Software Engineering
    SESA104337 (none) Software Engineering
    SESA104573 (none) Software Engineering
    SESA104591 (none) Software Engineering
    SESA10469 (none) Software Engineering
    SESA105017 (none) Software Engineering
    SESA105159 (none) Software Engineering
    SESA105186 (none) Software Engineering
    SESA105299 (none) Software Engineering
    SESA105310 (none) Software Engineering
    SESA10642 (none) Software Engineering
    SESA106614 (none) Software Engineering
    SESA106981 (none) Software Engineering
    SESA107210 (none) Software Engineering
    SESA107278 (none) Software Engineering
    SESA10735 (none) Software Engineering
    SESA10810 (none) Software Engineering
    SESA108122 (none) Software Engineering
    SESA108528 (none) Software Engineering
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  19. #39
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Ce que je voulais c'est le fichier csv (juste quelques lignes) juste pour voir quel est le délimiteur (ça n'apparaît pas dans ton extrait) et si oui ou non il y a une ligne d'entête (visiblement oui).

    L'idée est d'ajouter un setter pour le délimiteur (pour pouvoir ensuite le passer en paramètre de fgetcsv) et de pouvoir traiter la première ligne à part (pour collecter les entêtes de colonnes notamment).
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  20. #40
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 378
    Points : 5 731
    Points
    5 731
    Billets dans le blog
    1
    Par défaut
    Oui ! Le délimiteur est ;
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 3 PremièrePremière 123 DernièreDernière

Discussions similaires

  1. Réponses: 2
    Dernier message: 13/03/2007, 11h19
  2. Gestion des fichiers CSV
    Par sony351 dans le forum C++Builder
    Réponses: 5
    Dernier message: 02/11/2006, 10h11
  3. importe des fichier csv sous eclipse
    Par nael_n dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 21/08/2006, 13h57
  4. importer des fichier csv sous eclipse
    Par nael_n dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 11/08/2006, 13h00
  5. Réponses: 7
    Dernier message: 15/06/2006, 17h36

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