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

Symfony PHP Discussion :

backend d'admin photo


Sujet :

Symfony PHP

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2012
    Messages : 44
    Points : 32
    Points
    32
    Par défaut backend d'admin photo
    Bonjour,

    Ne trouvant pas où poster mon sujet, je viens ici pour chercher conseil, avis, retour d'expérience par rapport à ma situation.

    Je travail sur un projet de site internet pour un photographe. J'ai choisi pour ce site d'utiliser le framework Symfony2.

    Je souhaite faire une partie administration pour gérer les photos. Je vois qu'il existe différents bundles qui pourrait m'aider. Mais je n'arrive pas à m'y retrouver. De quel façon dois je m'y prendre???

    - Mon idée: Je souhaiterais que mon client est juste un bouton à cliquer (Mise à jour des photos) pour qu'automatiquement il y ai:

    une comparaison de dossier pour identifier les changements entre le dossier local du photographe et ce qui est déjà en ligne,
    upload (avec redimensionnement, vignette, classement dans des répertoires),
    récupération des données (noms, chemins, tags, mots clés...les données exifs) et mise à jour de la base de données,
    possibilité d'interruption sans perte et reprise là où ça en était,
    information du temps de mise à jour (+ barre de progression),
    exécution en arrière plan pour ne pas bloquer la navigation,
    un avertissement (sonore, mail, cloche de pont, claque sur la tête...)
    et... c'est déjà pas mal!

    Parmi les bundles proposés, j'ai beaucoup de mal à m'y retrouver à cause de ma maîtrise de la langue anglaise, Je ne saisi pas toujours bien qu'est ce que fait quoi comment les bundles qui me sont proposés! :/

    Mon idée n'est peut-être pas la meilleurs façon de procéder!? Auriez vous des pistes, des suggestions, une méthode?

    Merci de votre attention!

    Mirfak

  2. #2
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    voir du coté de ce bundle : PunkAveFileUploaderBundle

    ou d'autres bundles d'upload d'iamge.

    ensuite il faudra personnaliser le bundle(heritage) pour integrer tes fonctionnalités particulières.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2012
    Messages : 44
    Points : 32
    Points
    32
    Par défaut
    Merci,

    Je vais aller jetter un oeil sur cette piste

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2012
    Messages : 44
    Points : 32
    Points
    32
    Par défaut
    Bon, finalement, je choisi d'essayer de coder moi même...
    C'est pas gagné! :/

    Voici la suite plus spécifique de mon questionnement: composant process

  5. #5
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Je me demande bien comment php pourrait accéder à un dossier sur l'ordinateur du visiteur... non seulement c'est pas gagné mais j'ai bien peur que cela soit impossible.

  6. #6
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    en effet, impossible d’accéder au dossier des visiteurs sinon imagine la brèche pour les hackeurs...
    peut être le seul moyen serait de créer un plug-in à intégrer aux navigateurs....

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2012
    Messages : 44
    Points : 32
    Points
    32
    Par défaut
    oui, c pas une bonne idée ça! pour la question sécurité! donc je reviens à une version téléchargement en ftp! :/ et l'automatisation démarrera ensuite sur le serveur.

    Merci de votre attention

  8. #8
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    alors dans ce cas le bundle PunkAveFileUploaderBundle

    il permet l'upload et le traitement d'image.

    ensuite à toi d'ajouter tes fonctionnalités...

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2012
    Messages : 44
    Points : 32
    Points
    32
    Par défaut
    Bon, ben finalement, j'ai mis la main dans le moteur et j'ai écris mon propre ptit code! (en partant du fait que les images seront uploader en ftp)
    J'ai bien conscience qu'il y a encore du boulot, mais je suis bien content d'avoir réussi à coder un truc qui fonctionne...

    Mon script de mise à jour se lance grâce à la fonction Process, en arrière plan et n'empêche donc pas de continuer à naviguer sur le web, ni même d'éteindre son ordi.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // Depuis mon controler
            $logger=$this->get('logger');
            $logger->info('lancement du process depuis le controller');
            $cmd='php ../app/console photo:maj';
            $process=new Process($cmd);
            $process->start();
            $logger->info('le process a été lancée depuis le controller');
    Ma commande récupère les photos enregistrées en BDD et les photos contenues dans le répertoire de stockage.
    J'ai pas réussi à faire une comparaison sur les objets
    Je passe donc tout en tableau (array) et je crée 2 autres tableaux (un pour les photos modifiées et un pour les nouvelles photos) qui me servent à mettre à jour la BDD.
    Pour chacun des tableaux obtenus, je crée une entrée dans un fichier de logs.
    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
    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
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    <?php
     
    namespace Gg\SiteBundle\Command;
     
    use Gg\SiteBundle\Entity\Photo;
    use Gg\SiteBundle\Form\PhotoType;
    use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
    use Symfony\Component\Console\Input\InputArgument;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Input\InputOption;
    use Symfony\Component\Console\Output\OutputInterface;
    use Symfony\Component\Finder\Finder;
    use \DateTime;
     
    Class MajCommand extends ContainerAwareCommand{
     
        protected function configure()
        {
            $this
                ->setName('photo:maj')
                ->setDescription('Mise à jour de la base de données de photos');
        }
     
        protected function execute(InputInterface $input, OutputInterface $output)
        {
    // Variables
            $chemin=dirname(dirname(dirname(dirname(__DIR__)))).'/web/img/galerie/';
            $logger=$this->getContainer()->get('logger');
            $log=dirname($chemin).'/logs/LOG_'.date("Y_m_d_G_i_s").'.txt';
    // Fonctions
            function log_iptc($array){
                if (array_key_exists('iptc', $array)){
                    $log_iptc='IPTC :'."\n";
                    foreach ($array['iptc'] as $cle=>$index) {
                        if (is_array($index)){
                            $log_iptc.="\t\t".$cle.' =>'."\n";
                            foreach ($index as $key=>$valeur) {
                                $log_iptc.="\t\t\tIndex: ".$key.'='.$valeur."\n";
                            }
                        }
                    }
                    return $log_iptc;
                }
            }
            function log($log, $element){
                $log_iptc = log_iptc($element);
                file_put_contents($log,
                    '=> '.$element['nom']."\n".
                    "\t".'dernière modification: '.$element['date']->format('Y-m-d H:i:s')."\n".
                    "\t".'taille (octets) :'.$element['taille']."\n".
                    "\t".'chemin :'.$element['chemin']."\n".
                    "\t".$log_iptc."\n"
                    , FILE_APPEND);
            }
     
    // Log (app/logs)
            $logger->info('début de l execution de  la commande');
     
    // LOG (web/img/logs)
            file_put_contents($log,
                'Mise à jour du '.date("j F Y G:i:s ")."\n\n"
                , FILE_APPEND);
     
    // Liste des photos en BDD
            $array_photos=array();
            $repository = $this ->getContainer()->get('doctrine')
                                ->getManager()
                                ->getRepository('GgSiteBundle:Photo');
            $liste_photos = $repository->findAll();
            foreach ($liste_photos as $element){
                $array_photos[]=array(
                    'nom'=>$element->getNom(),
                    'taille'=>$element->getTaille(),
                    'date'=>$element->getDate(),
                    'chemin'=>$element->getChemin(),
                    'iptc'=>$element->getIptc()
                    );
            }
            // LOG photos BDD (web/img/logs)
            file_put_contents($log,
                count($array_photos).' photos en BDD : '."\n"
                , FILE_APPEND);
            foreach ($array_photos as $element){
                log($log, $element);
            }
     
    // Liste des photos dans le répertoire
            $finder = new Finder();
            $finder ->files()
                    ->in($chemin)
                    ->name('*.JPG')
                    ->name('*.JPEG')
                    ->name('*.jpg')
                    ->name('*.jpeg');
            foreach ($finder as $element){
                $photos[]=get_object_vars($element);
                $file=$element->getRealpath();
                $date=$element->getCTime();
                $date=DateTime::__set_state(array(
                    'date' => date('Y-m-d H:i:s',$date),
                    'timezone_type' => 3,
                    'timezone' => 'Europe/Paris'));
                GetImageSize ($file,$info);
                $iptc = array(
                    'mots_cles'=> 'vide',
                    'date_creation'=> 'vide',
                    'heure_creation'=> 'vide',
                    'copyright'=> 'vide'
                );
                $iptc_index = array(
                    'mots_cles'=> '2#025',
                    'date_creation'=> '2#055',
                    'heure_creation'=> '2#060',
                    'copyright'=> '2#116'
                );
                if (isset($info["APP13"])){
                    $iptc_origine = iptcparse ($info["APP13"]);
                    foreach($iptc_index as $index=>$code){
                        if (is_array($iptc_origine)){
                            if (array_key_exists($code, $iptc_origine)) {
                                $iptc[$index] = $iptc_origine[$code];
                            }
                        }
                    };
                }
                $array_finder[]=array(
                    'nom'=>$element->getfilename(),
                    'taille'=>$element->getSize(),
                    'date'=>$date,
                    'chemin'=>$file,
                    'iptc'=>$iptc
                    );
            }
            // LOG photos Répertoire (web/img/logs)
            file_put_contents($log,
                "\n".count($array_finder).' fichiers dans le répertoire ('.$chemin.'):'."\n"
                , FILE_APPEND);
            foreach ($array_finder as $element) {
                log($log, $element);
            }
     
    // nouvelle liste de photos à enregistrer en BDD
            $nvlle_liste=array();
            $modif_liste=array();
            foreach ($array_finder as $photo){
                // Modif Liste
                foreach ($array_photos as $element){
                    if (in_array($photo['nom'], $element)){
                        if ($photo != $element){
                            $modif_liste[]=$photo;
                        }
                    }
                }
                // Nvlle Liste
                if (!in_array($photo, $array_photos) && !in_array($photo, $modif_liste)){
                    $nvlle_liste[]=$photo;
                }
            }
            // LOG photos à enregistrer (BDD)
            // LOG Modifs
            file_put_contents($log,
                "\n".count($modif_liste).' photos modifiées à mettre à jour en BDD: '."\n"
                , FILE_APPEND);
            foreach ($modif_liste as $element){
                log($log, $element);
            }
            // LOG Nvlles
            file_put_contents($log,
                "\n".count($nvlle_liste).' nouvelles photos à enregistrer en BDD: '."\n"
                , FILE_APPEND);
            foreach ($nvlle_liste as $element){
                log($log, $element);
            }
     
    // Enregistrement en BDD
            // Les Modifs
            foreach ($modif_liste as $element){
                $nom=$element['nom'];
                $em = $this ->getContainer()->get('doctrine')
                            ->getManager();
                $photo= $em->getRepository('GgSiteBundle:Photo')
                            ->getModif($nom);
                $photo  ->setTaille($element['taille'])
                        ->setChemin($element['chemin'])
                        ->setIptc($element['iptc'])
                        ->setDate($element['date']);
                $em-> flush();
            }
            // Les Nouveautés
            foreach ($nvlle_liste as $element){
                $photo = new Photo();
                $photo  ->setNom($element['nom'])
                        ->setTaille($element['taille'])
                        ->setChemin($element['chemin'])
                        ->setIptc($element['iptc'])
                        ->setDate($element['date']);
                $repository = $this ->getContainer()->get('doctrine')
                                    ->getManager();
                $repository ->persist($photo);
                $repository ->flush();
            }
     
    // LOG Fin et fermeture (web/img/logs)
            file_put_contents($log, 'FIN', FILE_APPEND);
     
    // Log Fin  (app/logs)
            sleep(10);
            $logger->info($log);
            $logger->info('fin de l execution de  la commande');
     
        }
    }
    La prochaine chose que je vois à faire, c'est la création d'une entitée IPTC que je relierais en many-to-many avec l'entitée photo...

    Mais y a sûrement plein d'autre truc qui pourrait être mieux gérée dans mon code!
    Commentaires bienvenus!

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Septembre 2012
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2012
    Messages : 44
    Points : 32
    Points
    32
    Par défaut
    Bon, après quelques galères pour gérer ma relation many to many avec mes motsclef en arraycollection, j'ai tout repris presqu'à zéro!

    J'ai réussi à faire ma comparaison d'objet et j'ai retiré les logs. J'ai également mis de côté (pour l'instant) l'idée d'un update.

    Voici le nouveau code
    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
    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
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    <?php
     
    namespace Gg\SiteBundle\Command;
     
    use Gg\SiteBundle\Entity\Photo;
    use Gg\SiteBundle\Entity\Motclef;
    use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
    use Symfony\Component\Console\Input\InputArgument;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Input\InputOption;
    use Symfony\Component\Console\Output\OutputInterface;
    use Symfony\Component\Finder\Finder;
    use \DateTime;
     
    Class MajCommand extends ContainerAwareCommand{
     
        protected function configure()
        {
            $this
                ->setName('photo:maj')
                ->setDescription('Mise à jour de la base de données de photos');
        }
     
        protected function execute(InputInterface $input, OutputInterface $output)
        {
            // Variables
            $chemin=dirname(dirname(dirname(dirname(__DIR__)))).'/web/img/galerie/';
            $repository = $this ->getContainer()
                                ->get('doctrine')
                                ->getManager();
     
            // Fonctions
            // Vérifier en BDD si les mots cles existent
            function motclef($array,$repository){
                if (is_array($array)){
                    // nettoyage du motclef
                    foreach ($array as $value){
                        $indexof = strpos($value, '-');
                        $nom =  substr($value,$indexof+1);
                        // recherche du motclef en BDD
                        $motclef_rechercher = $repository   ->getRepository('GgSiteBundle:Motclef')
                                                            ->findOneBy(array('nom' => $nom));
                        // Si il existe, on attribut l'objet
                        if($motclef_rechercher !== null){
                            $motclef = $motclef_rechercher;
                        }
                        // Si non, on le crée
                        else{
                            $motclef = new Motclef();
                            $motclef -> setNom($nom);
                            $repository ->persist($motclef);
                        }
                        $motclefs[] = $motclef;
                    }
                    return $motclefs;
                }
            }
     
            // Tableau d'objet photo en BDD
            $photos_bdd = $repository   ->getRepository('GgSiteBundle:Photo')
                                        ->findAll();
     
            // Tableau d'objet photo dans le répertoire
            $finder = new Finder();
            $finder ->files()
                    ->in($chemin)
                    ->name('*.JPG')
                    ->name('*.JPEG')
                    ->name('*.jpg')
                    ->name('*.jpeg');
            foreach ($finder as $element){
                $photo=new photo();
     
                // Titre & soutitre
                $titre_photo_original=$element->getfilename();
                $titre=explode('.',$titre_photo_original);
                $titre_photo=$titre[0];
                $titre_soutitre=explode('(',$titre[0]);
                if (isset($titre_soutitre[1])){
                    $soutitre_photo=explode(')',$titre_soutitre[1]);
                    $titre_photo=$titre_soutitre[0].$soutitre_photo[1];
                    $soutitre_photo=$soutitre_photo[0];
                }
                $photo->setTitre($titre_photo);
                $photo->setSoutitre($soutitre_photo);
     
                // Chemin
                $chemin=$element->getRealpath();
                $photo->setChemin(strstr($chemin, 'img/galerie/'));
     
                // Iptc (date de prise de vue & Mots Clef)
                GetImageSize ($chemin,$info);
                $iptc = array(
                    'mots_cles'=> '',
                    'date_creation'=> '',
                    'heure_creation'=> ''
                );
                $iptc_index = array(
                    'mots_cles'=> '2#025',
                    'date_creation'=> '2#055',
                    'heure_creation'=> '2#060'
                );
                if (isset($info["APP13"])){
                    $iptc_origine = iptcparse ($info["APP13"]);
                    foreach($iptc_index as $index=>$code){
                        if (is_array($iptc_origine)){
                            if (array_key_exists($code, $iptc_origine)) {
                                $iptc[$index] = $iptc_origine[$code];
                            }
                        }
                    };
                }
                // Date Prise de vue
                if (!empty ($iptc['date_creation'])){
                    $d = str_split($iptc['date_creation'][0],2);
                    $t = str_split($iptc['heure_creation'][0],2);
                    $date_pv = new DateTime();
                    $date_pv->setDate($d[0].$d[1], $d[2], $d[3])
                            ->setTime($t[0], $t[1], $t[2]);
                }
                $photo->setDate_pv($date_pv);
     
                // Motclefs
                $motclefs=motclef($iptc['mots_cles'],$repository);
                foreach($motclefs as $motclef){
                    $photo ->addMotclef($motclef);
                }
     
                // On vérifie qu'une photo du même nom n'existe pas en BDD et on enregistre
                $photo_bdd = $repository    -> getRepository('GgSiteBundle:Photo')
                                            -> findOneBy(array('titre' => $titre_photo));
                if($photo_bdd === null){
                    $repository -> persist($photo);
                }
                $repository -> flush();
            }
        }
    }
    Commentaires et idées d'amélioration bienvenues...

    Pour l'instant, j'enregistre chaque photo en même temps que les nouveaux mots clé dans ma boucle foreach... Est ce une bonne chose?
    Ne serait ce pas mieux de sortir mon flush de la boucle et d'utiliser un tableau d'objets photo que je flush en fin de script...

    Pour un update j'aurais besoin de pouvoir comparer les photos du repertoire (finder) avec celle enregistrée en BDD. Mais je sais pas encore quoi comparer!? Les motclefs sont pour l'instant les seules à pouvoir changer.
    Je pourrais comparer sur le nom (qui doit rester unique), puis si le nom existe comme attribut d'une photo en bdd, comparer les motclefs!!! Jsuis pas sur que ce sois la bonne manière de s'y prendre!!! :/
    Ou alors je fais une comparaison d'objet, mais mon objet créer d'après les photos trouver dans le répertoire n'ont pas encore d'Id. Et ça m'oblige à créer un objet sur toutes les photos alors que j'ai besoin que des nouvelles où celles qui ont été modifiées...
    Je réfléchi au fur et à mesure que je tapes! lol
    Je pourrais aussi comparer la date d'enregistrement ou la taille du fichier si je trouve le nom en BDD....

    Affaires à creuser...

Discussions similaires

  1. [1.x] surcharge template backend admin generator
    Par mantex dans le forum Symfony
    Réponses: 1
    Dernier message: 25/01/2011, 08h21
  2. Réponses: 0
    Dernier message: 19/05/2010, 11h17
  3. [Joomla!] Galerie photo et attente de validation des photos par l'admin
    Par filiplarlibe dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 2
    Dernier message: 03/08/2009, 13h05
  4. Réponses: 14
    Dernier message: 01/02/2008, 16h03
  5. [Galerie] Cherche script de Galerie photos multi-admin
    Par djew13 dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 3
    Dernier message: 23/10/2006, 15h15

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