Navigation

Related Articles

Back to Latest Articles

Gestion d’une galerie photo avec swfUpload dans l’admin


Olivier
Gestion d’une galerie photo avec...

Je vous propose de voir une gestion de galerie photo pour l’administration, telle que je l’ai abordée dans un de mes derniers projets.

Pour vous situer, il s’agit d’un site de vente en ligne.
Qui dit vente dit produits, et qui dit produits dit photos 😀

L’idée est de gérer les photos d’un produit directement depuis sa page d’édition de l’admin générator.

upload1

upload2

upload3

On a choisi de gérer l’upload avec swfUpload qui gére un liste d’attente pour l’upload de plusieurs fichiers. Et l’upload en background qui ne gèle pas la page, ca fait plus web2.0 :p
(http://code.google.com/p/swfupload/)

J’ai téléchargé le SWFUpload v2.2.0.1 Samples.zip et j’ai utilisé les fichiers du répertoire « simpledemo » que j’ai réparties comme suis.
(Le fichier css d’origine s’appelait default.css, je l’ai renommé pour des raisons évidentes.)

  • /web/swf/swfupload.swf
  • /web/css/swfUpload.css
  • /web/js/swfupload.js
  • /web/js/swfupload.queue.js
  • /web/js/fileprogress.js
  • /web/js/handlers.js
  • /web/images/XPButtonUploadText_61x22.png

Un coup d’oeil rapide à la partie du schema.yml qui nous intéresse. Rien de transcendant, un objet Produit avec quelques champs types et l’objet ProduitPhoto qui lui est lié. Sur l’objet ProduitPhoto, un filename et un booléen pour définir l’image par défaut du produit.

...
Produit:
  tableName:        monprojet_produit
  actAs:
    Timestampable:  ~
  columns:
    id:             { type: integer(4), unsigned: true, primary: true, autoincrement: true }
    nom:            { type: string(255), notnull: true }
    description:    { type: clob }
    prix:           { type: decimal, scale: 2 }
 
ProduitPhoto:
  tableName:        monprojet_produit_photo
  columns:
    id:             { type: integer(4), unsigned: true, primary: true, autoincrement: true }
    produit_id:     { type: integer(4), unsigned: true }
    filename:       { type: string(255), notnull: true }
    is_default:     { type: boolean, default: false }
  relations:
    Produit:
      local:        produit_id
      foreign:      id
      foreignAlias: Photos
      onDelete:     CASCADE
...

On génére l’admin-generator pour l’objet produit.

?View Code CONSOLE
./symfony doctrine:generate-admin backend Produit

Et c’est partie !

Pour rajouter cette gestion des images dans l’ecran d’édition des produits il faut rajouter un partial à la vue edit.
(On la rajoute uniquement sur l’edit, car sur l’écran create, l’objet n’est pas encore persisté en base et donc on ne peut pas lui rattacher des objets ProduitPhoto)

Le fonctionnement est le suivant. Le partial général où est inclus et configuré swfUpload (_photoUpload.php). Un parial _photoListe.php inclus dans _photoUpload.php qui servira pour raffraichir la liste en ajax (avec jQuery). Et un dernier partial _ajaxPhotoDelete.php qui ne sert qu’a retourner l’animation à faire lors de la suppression d’une photo.

On commence par positionner le partial _photoUpload.php dans le generator.yml en contexte edit.

generator:
  class: sfDoctrineGenerator
  param:
    model_class:           Produit
    theme:                 admin
    non_verbose_templates: true
    with_show:             false
    singular:              ~
    plural:                ~
    route_prefix:          produit_produit
    with_doctrine_route:     1
 
    config:
      actions: ~
      fields:
        created_at:        { label: Date de création, date_format: dd/MM/yyyy }
        updated_at:        { label: Date de modification, date_format: dd/MM/yyyy }
        nom:               { label: Nom }
        description:       { label: Déscription }
      list:
        title:             Liste des produits
        display:           [=id, =nom]
      filter: ~
      form: ~
      edit:
        title:             Modifier un produit
        display:
          "Produit":       [id, nom, description]
          "Photos":        [_photoUpload]
          "Dates":         [created_at, updated_at]
      new:
        title:             Ajouter un produit
        display:
          "Produit":       [id, nom, description]
          "Dates":         [created_at, updated_at]

Et on va se pencher plus en détail sur ce partial _photoUpload.php.

<?php use_stylesheet('swfUpload.css') ?>
 
<?php use_javascript('jquery.js') ?>
<?php use_javascript('jquery-ui.js') ?>
<?php use_javascript('swfupload.js') ?>
<?php use_javascript('swfupload.queue.js') ?>
<?php use_javascript('fileprogress.js') ?>
<?php use_javascript('handlers.js') ?>
 
<div id="pictures_list" class="sf_admin_form_row">
  <?php include_partial('produit/photoListe', array('photos' => $form->getObject()->getPhotos())) ?>
</div>
 
<div id="picture_upload" class="sf_admin_form_row">
  <div class="fieldset flash" id="fsUploadProgress"><span class="legend">File d'attente.</span></div>
  <div id="divStatus">0 fichier uploadé.</div>
  <div>
    <span id="spanButtonPlaceHolder"></span>
    <input id="btnCancel" type="button" value="Cancel All Uploads" onclick="$.swfUpload.cancelQueue();" disabled="disabled" style="margin-left: 2px; font-size: 8pt; height: 29px;" />
  </div>
</div>
 
<script type="text/javascript">
 
(function($) {
 
  $('div.actions a.default').live('click', function(event) {
    event.preventDefault();
    $.post(
      $(this).attr('href'),
      { },
      function(data) {
        $('#pictures_list').html(data);
      }
    );
  });
 
  $('div.actions a.delete').live('click', function(event) {
    event.preventDefault();
    if(confirm('Etes vous sur de vouloir supprimer cette photo ?')) {
      $.post(
        $(this).attr('href'),
        { },
        function(data) {
          eval(data);
        }
      );
    }
  });
 
  myQueueComplete = function(numFilesUploaded) {
    var status = document.getElementById("divStatus");
    status.innerHTML = numFilesUploaded + " fichier" + (numFilesUploaded === 1 ? "" : "s") + " uploadé" + (numFilesUploaded === 1 ? "" : "s") + ".";
 
    $.post(
      '<?php echo url_for('produit_ajax_photo_liste', $form->getObject()) ?>',
      { },
      function(data) {
        $('#pictures_list').html(data);
      }
    );
  };
 
  jQuery.swfUpload = new SWFUpload({
    flash_url: "/swf/swfupload.swf",
    upload_url: "<?php echo url_for('produit_photo', $form->getObject()) ?>",
    post_params: {"<?php echo ini_get('session.name') ?>" : "<?php echo session_id(); ?>"},
    file_size_limit: "100 MB",
    file_types: "*.jpg;*.gif;*.png",
    file_types_description: "Fichiers image",
    file_upload_limit: 10,
    file_queue_limit: 0,
    file_post_name: 'photo',
    custom_settings: {
      progressTarget: "fsUploadProgress",
      cancelButtonId: "btnCancel"
    },
    debug: false,
    // Button settings
    button_image_url: "/images/XPButtonUploadText_61x22.png",
    button_width: "61",
    button_height: "22",
    button_placeholder_id: "spanButtonPlaceHolder",
    // The event handler functions are defined in handlers.js
    file_queued_handler: fileQueued,
    file_queue_error_handler: fileQueueError,
    file_dialog_complete_handler: fileDialogComplete,
    upload_start_handler: uploadStart,
    upload_progress_handler: uploadProgress,
    upload_error_handler: uploadError,
    upload_success_handler: uploadSuccess,
    upload_complete_handler: uploadComplete,
    queue_complete_handler: myQueueComplete
  });
 
})(jQuery);
 
</script>

Il faut penser à inclure les différents éléments nécessaires le css et les tout les js. Je les ai inclus ici pour bien les mettre en évidence.
Après il suffit de positionner les différents éléments html nécessaires au fonctionnement de swfUpload.
Et enfin le javascript pour initialiser swfUpload. J’utilise jQuery pour gérer l’ajax, j’ai donc adapté l’initialisation de swfUpload pour la rendre « jQuery friendly » :p

L’initialisation de swfUpload est assez standard, avec toute une tripoté de paramètres pour définir : le type de fichier accepté, configurer l’apparence du bouton et configurer tous les retour d’événements qu’il est possible d’utiliser.
J’ai laissé les gestionnaires d’événements par défaut à l’exception de l’événement de fin d’upload (myQueueComplete) que j’ai redéfini pour faire un appel ajax et recharger le partial _photoListe.php.
J’attire votre attention sur le parametre post_params auquel on passe le session name et le session_id, on verra un peu plus bas le pourquoi du comment 😉

Le partial _photoListe.php, rien de spécial. Un listing des photos du produit avec 2 liens pour supprimer ou définir comme image par défaut, les 2 faisant appel à une action en ajax.
(NB: On retrouve le Helper Thumb de thomas pour les miniatures des photos)

<?php use_helper('Thumb') ?>
 
<?php if($photos->count() > 0): ?>
<?php foreach( $photos as $photo ): ?>
<div id="photo-<?php echo $photo->getId()?>" class="picture">
  <?php echo showThumb(
  $photo->getFilename(),
  'produits',
  array(
    'height' => 120,
    'width'  => 120,
    'alt'    => $photo->getProduit()->getNom(),
    'title'  => $photo->getProduit()->getNom(),
    'border' => 0
  ),
  'center',
  'produit-defaut.jpg') ?>
  <div class="actions">
    <?php if($photo->isDefault()): ?>
    <strong><img src="/images/backend/star.png" align="left" /> Par défaut</strong>
    <?php else: ?>
    <ul>
      <li><a href="<?php echo url_for('produit_photo_ajax_default', $photo) ?>" class="default"><img src="/images/backend/star.png" align="left" /> Par défaut</a></li>
      <li><a href="<?php echo url_for('produit_photo_ajax_delete', $photo) ?>" class="delete"><img src="/images/backend/cross.png" align="left" /> Supprimer</a></li>
    </ul>
    <?php endif; ?>
  </div>
</div>
<?php endforeach; ?>
<div class="clear"></div>
<?php else: ?>
<p>Aucune photo pour l'instant.</p>
<?php endif; ?>

Le partial _ajaxPhotoDelete.php, c’est juste l’effet jQuery-ui pour faire disparaitre la div de la photo qui viens d’être supprimée.

?View Code JAVASCRIPT
$('#photo-<?php echo $photo_id ?>').effect('drop');

Un petit tour sur le routing.yml pour défnir les différentes routes utilisées.

...
produit_photo:
  url:     /produit/:id/upload
  class:   sfDoctrineRoute
  options: { model: Produit, type: object }
  param:   { module: produit, action: upload }
  requirements:
    sf_method: [get, post]
 
produit_photo_ajax_default:
  url:     /produit_photo/:id/default
  class:   sfDoctrineRoute
  options: { model: ProduitPhoto, type: object }
  param:   { module: produit, action: ajaxPhotoDefault }
  requirements:
    sf_method: [post]
 
produit_photo_ajax_delete:
  url:     /produit_photo/:id/delete
  class:   sfDoctrineRoute
  options: { model: ProduitPhoto, type: object }
  param:   { module: produit, action: ajaxPhotoDelete }
  requirements:
    sf_method: [post]
 
produit_ajax_photo_liste:
  url:     /produit_photo/:id/list
  class:   sfDoctrineRoute
  options: { model: Produit, type: object }
  param:   { module: produit, action: ajaxPhotoListe }
  requirements:
    sf_method: [post]
...

On utilise la classe formulaire qui va gérer l’upload.
Il faut désactiver le csrf car l’envoie n’est pas effectué par le formulaire mais par l’animation flash.

<?php
 
class ProduitPhotoForm extends BaseProduitPhotoForm
{
  public function configure()
  {
    $this->widgetSchema['produit_id'] = new sfWidgetFormInputHidden();
    $this->widgetSchema['is_default'] = new sfWidgetFormInputHidden();
    $this->widgetSchema['filename'] = new sfWidgetFormInputFile(array());
 
    $this->validatorSchema['filename'] = new sfValidatorFile(array(
      'required'   => true,
      'path'       => sfConfig::get('sf_upload_dir').'/produits/source',
      'mime_types' => 'web_images',
      'max_size'   => 10485760
    ), array(
      'max_size' => 'Fichier trop gros (10Mo maximum).'
    ));
 
    $this->disableCSRFProtection();
  }
}

Et enfin l’action.class.php qui orchestre tout ca.
Au niveau de l’action executeUpload il faut créer « à la main » le tableau des paramètres à passer au bind.

<?php
 
require_once dirname(__FILE__).'/../lib/produitGeneratorConfiguration.class.php';
require_once dirname(__FILE__).'/../lib/produitGeneratorHelper.class.php';
 
/**
 * produit actions.
 *
 * @package    
 * @subpackage produit
 * @author     
 * @version    SVN: $Id: actions.class.php 12474 2008-10-31 10:41:27Z fabien $
 */
class produitActions extends autoProduitActions
{
 
  public function executeUpload(sfWebRequest $request)
  {
    $this->produit = $this->getRoute()->getObject();
    $this->forward404unless($this->produit);
 
    $this->form = new ProduitPhotoForm();
 
    $values = array(
      'produit_id' => $this->produit->getId(),
      'is_default' => ($this->produit->getPhotos()->count() > 0) ? false : true,
      'filename'   => $request->getFiles('photo')
    );
 
    $this->form->bind($values, $values);
 
    if ($this->form->isValid())
    {
      $photo = $this->form->save();
 
      $return = 'ok';
    }
    else
    {
      $return = 'ko';
    }
 
    return $this->renderText($return);
  }
 
 
  /**
   * ajax pour definir une photo par defaut
   *
   * @param sfWebRequest $request
   */
  public function executeAjaxPhotoDefault(sfWebRequest $request)
  {
    if($request->isXmlHttpRequest())
    {
      $photo = $this->getRoute()->getObject();
      $produit = $photo->getProduit();
 
      $old_default = $produit->getPhotoDefault();
 
      $produit->setPhotoDefaut($photo->getId());
 
      return $this->renderPartial('produit/photoListe', array('photos' => $produit->getPhotos()));
    }
    else
    {
      $this->redirect404();
    }
  }
 
 
  /**
   * ajax pour effacer une photo
   *
   * @param sfWebRequest $request
   */
  public function executeAjaxPhotoDelete(sfWebRequest $request)
  {
    if($request->isXmlHttpRequest())
    {
      $photo = $this->getRoute()->getObject();
      $photo_id = $photo->getId();
      $photo->delete();
 
      return $this->renderPartial('produit/ajaxPhotoDelete', array('photo_id' => $photo_id));
    }
    else
    {
      $this->redirect404();
    }
  }
 
 
  /**
   * ajax pour avoir la liste des photos
   *
   * @param sfWebRequest $request
   */
  public function executeAjaxPhotoListe(sfWebRequest $request)
  {
    if($request->isXmlHttpRequest())
    {
      $produit = $this->getRoute()->getObject();
 
      return $this->renderPartial('produit/photoListe', array('photos' => $produit->getPhotos()));
    }
    else
    {
      $this->redirect404();
    }
  }
 
 
}

Produit.class.php

<?php
 
class Produit extends BaseProduit
{
 
  public function setPhotoDefaut($photoId)
  {
    Doctrine_Query::create()
    ->update('ProduitPhoto p')
    ->set('p.is_default', '?', false)
    ->where('p.produit_id = ?', $this->getId())
    ->execute();
 
    Doctrine_Query::create()
    ->update('ProduitPhoto p')
    ->set('p.is_default', '?', true)
    ->andWhere('p.id = ?', $photoId)
    ->execute();
 
    return true;
  }
 
  public function getPhotoDefault()
  {
    return Doctrine::getTable('ProduitPhoto')->getDefault($this->getId());
  }
 
}

ProduitPhotoTable.class.php

<?php
 
class ProduitPhotoTable extends Doctrine_Table
{
 
  public function getDefault($produit_id)
  {
    return $this->createQuery('c')
      ->andWhere('c.produit_id = ?', $produit_id)
      ->andWhere('c.is_default = ?', true)
      ->fetchOne();
  }
 
}

ProduitPhoto.class.php

<?php
 
class ProduitPhoto extends BaseProduitPhoto
{
 
  public function isDefault()
  {
    return (bool) $this->getIsDefault();
  }
 
}

Le problème !

A ce stade, tout est fini et en place pour que ca marche. Hors ca ne marche pas… Pourquoi ? Je rapelle le contexte, on est dans l’admin donc on est identifié et c’est là le problème. En effet swfUpload est une animation flash contenu dans le page mais qui va initialiser des requêtes http parallèles à celle utilisée par le navigateur. Et donc lorsque swfUpload se pointe à l’url « produit_photo » pour initialisé son upload, il se prend une belle erreur 403…

Le problème est connu des concepteurs de swfUpload et la solutions qu’ils préconisent est de forcé l’identifiant de session dans le script d’upload en faisant un session_id($session_id). C’est pourquoi on le fait passer dans la variable « post_params » à l’initialisation de swfUpload.

Pour faire la même chose dans symfony on ne peut pas le faire dans une action, car la session est déjà initialisée à ce niveau. On est obligé d’aller modifié le factories.yml et la calsse la classe sfSessionStorage pour aller forcer l’identifiant de session dans le cas ou on fait appel à l’action upload.

C’est un tip que j’ai trouvé sur le forum symfony qui était pour la version 1.0, et qui fonctionne toujours à la différence que le contexte n’est plus passé en paramètre dans la 1.2 et donc il faut aller le charger.

factories.yml

...
all:
...
  storage:
    class: mySessionStorage
    param:
      session_name: weezobackend
...

mySessionStorage.calss.php

<?php
 
class mySessionStorage extends sfSessionStorage
{
  public function initialize($options = null)
  {
    $context = sfContext::getInstance();
 
    //Shitty work-around for swfuploader
    if( $context->getActionName() == "upload")
    {
      $sessionName = $parameters["session_name"];
 
      if($value = $context->getRequest()->getParameter($sessionName))
      {
        session_name($sessionName);
        session_id($value);
      }
    }
 
    parent::initialize($options);
  }
}

Ça y est, cette fois ça marche !
Et vous avez une gestion d’images directement dans la fiche du produit qui est assez user-friendly 😉

Merci d’avoir lu jusqu’au bout :p
Je reste à votre disposition pour toute questions ou suggestions 😉
@bientôt !

Show Comments (26)

Comments

  • thomas

    Bonjour,
    J’ai eu une petite erreur d’installation, je ne sais pas si c’est du à mes config serverus en local mais il a fallut que j’enleve ‘mime_types’ => ‘web_images’, dans la classe de mon formulaire.
    En faisant afficher les erreus il me disait invalide mime_type (‘application/octet-stream’).
    j’ai enlevé, ca marche nickel!

    de toute façon la vérification est déja faite via le JS.

    • Article Author
  • neothone

    Bonjour,

    J\’ai bien appliqué ce tuto sympatique. J\’ai rencontré des problèmes avec le generator.yml. Le parser ne comprenait pas les display dans le contexte \"edit\" et \"new\" (si on supprimait celui dans \"edit\"). J\’ai donc du les rappatrier dans le form général.

    Ensuite, je me retrouve maintenant devant ces logs :
    \"[27-Sep-2009 18:28:12] Action \"produit/1\" does not exist.
    [27-Sep-2009 18:28:12] Action \"produit_photo/1\" does not exist.\"

    Cela se produit lorsque j\’essai d\’uploadé un fichier. Evidemment erreur 500 apparait dans le swf.

    J\’ai vraiment suivi le tuto avec le mm schema, la seule différence est que j\’utilise propel plutot que doctrine. (j\’ai apporté les modifs).

    Avez-vous une idée pour ces comportement étranges ?

    Merci,
    neothone

    • Article Author
  • olivier

    Mea culpa,

    Il y avait en effet une petite coquille dans le generator.yml
    Le display n’est pas à placer dans « generator/param/config/edit/form/display » mais dans « generator/param/config/edit/display ».
    J’ai apporté la modification au post.

    Pour ce qui est de l’erreur 500. Est ce qu’elle apparait tout le temps ? ou seulement sur un nouveau produit ?

    • Article Author
  • David Maignan

    Merci beaucoup, cela fonctionne a merveille.

    • Article Author
  • Jeremy

    Bonjour!
    Merci pour ce tuto qui m\’a permis de mettre en place dans mon site un uploader pour mes galeries photos.
    Il y a cependant un bug, si je snif le réseau pour connaitre le résultat d\’execution de l\’upload, j\’ai ce message d\’erreur:

    Auriez vous une idées sur la maniere de supprimer ces erreurs ?
    Apparement cela se declenche sur le bind du form.

    Merci beaucoup

    Warning: array_keys() [function.array-keys]: The first argument should be an array in /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/form/sfForm.class.php on line 1114

    Warning: sort() expects parameter 1 to be array, null given in /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/form/sfForm.class.php on line 1115

    Warning: array_keys() [function.array-keys]: The first argument should be an array in /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/form/sfForm.class.php on line 1114

    Warning: sort() expects parameter 1 to be array, null given in /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/form/sfForm.class.php on line 1115

    Warning: array_keys() [function.array-keys]: The first argument should be an array in /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/form/sfForm.class.php on line 1114

    Warning: sort() expects parameter 1 to be array, null given in /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/form/sfForm.class.php on line 1115

    Warning: array_keys() [function.array-keys]: The first argument should be an array in /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/form/sfForm.class.php on line 1114

    Warning: sort() expects parameter 1 to be array, null given in /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/form/sfForm.class.php on line 1115

    Warning: Cannot modify header information – headers already sent by (output started at /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/form/sfForm.class.php:1114) in /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/response/sfWebResponse.class.php on line 335

    Warning: Cannot modify header information – headers already sent by (output started at /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/form/sfForm.class.php:1114) in /Users/jeremy/Sites/sfLaura/lib/vendor/symfony/lib/response/sfWebResponse.class.php on line 349
    ok

    • Article Author
  • Mathieu

    Bonjour,

    J’ai suivi toute la démarche et cela fonctionne.
    Toutefois, l’upload créé sur mon serveur des fichiers .bin inexploitable et comme toi, j’ai du retirer le mime_types dans le validateur de mon champs d’upload.

    Je ne sais pas quoi faire. J’ai vérifié que les images étaient bien dans les mime_types de sfCompat10Plugin, j’ai activé ce plugin, mais rien n’y fait.

    Une idée ? svp

    Mathieu

    • Article Author
  • Mathieu

    J’ai trouvé une issue en créant une méthode generate%nameColumn%Filename($file) dans mon Object.php qui permet de sauvegarde le fichier sous le nom que l’on souhaite.

    Pas très propre… mais ça marche.

    • Article Author
  • yanice

    j’ai une question au sujet des méthodes $photo->isDefault(), $produit->getPhotoDefault() et $produit->setPhotoDefaut().
    elles ne sont pas définies et je m’étonne que personne n’en fasse la remarque. il faut bien les ajouter aux classes ProduitPhoto.class.php et Produit.class.php n’est-ce-pas?

    • Article Author
  • olivier

    Salut yanice,

    En effet, il manquait quelques éléments qui ne concernaient pas directement l’explication du fonctionnement de swfUpload mais qui étaient succeptibles d’entraver la compréhension.
    J’ai rajouté les méthodes manquantes.

    Merci de ta participation.

    • Article Author
  • Dimitri

    Bonjour,

    J\’ai suivi le tuto à la lettre et j\’ai quelques soucis.
    Comme matthieu, j\’ai les messaged d\’erreurs en backend_dev.php mais pas en backend.php.
    Les images sont sauvegardés mas avec une extension .bin donc inexploitables.
    Quelqu\’un a t-il une idée?
    Merci

    • Article Author
  • Leny

    Salut Olivier et tout le monde,
    Merci pour ce tutoriel, c’est très sympa de faire profiter les autres de ton expérience.
    J’ai suivi ton tuto et après quelques petites erreurs de copie et quelques modifications pour coller à mon schema de données, ca marche !
    Un super effet, un grand MERCI.
    Leny

    • Article Author
  • Leny

    Salut Olivier et tout le monde,
    Merci pour ce tutoriel, c\’est très sympa de faire profiter les autres de ton expérience.
    J\’ai suivi ton tuto et après quelques petites erreurs de copie et quelques modifications pour coller à mon schema de données, ca marche !
    Un super effet, un grand MERCI.
    Leny

    • Article Author
  • Jean-Paul

    Salut!

    Merci beaucoup pour ce tuto très clair. Je rencontre néanmoins un petit souci au niveau de l’upload. Je teste en local avec Wamp.

    Dans le validateur du formulaire :
    – si je laisse ‘mime_types’ => ‘web_images’, aucune image n’est uploadée et la variable $return retourne ‘ko’
    – si je mets ‘mime_types’ => ‘image/jpeg’, je me prends une erreur 500 par swfupload
    – si je commente la ligne ‘mime_types’, l’upload marche mais l’image a une extension .bin

    Avez vous une idée pour régler ce problème? La réponse de Mathieu (7) a l’air intéressante mais il ne laisse pas sa fonction…

    De plus, lorsque je clique sur supprimer, la photo est supprimée de la base mais pas du répertoire et la page ne s’actualise pas (la photo reste jusqu’à un refresh manuel)

    Merci d’avance!

    • Article Author
  • tamer

    Thank you Olivier for the detailed tutorial.
    I did all of the tutorial but nothing happened, I run Swfupload+Symfony1.4+sfGuard4.0
    I think that the problem is with sfGuard,that it doesn’t pass the session.
    Any help, Please ASAP?????

    • Article Author
  • olivier

    Hi tamer,
    Thank you for reading us, even if we do not translate our posts.
    You said you are using sfGuard it’s looks like you are using Propel. This post was made to work with the Doctrine ORM, there must be some changes to convert it work to Propel.
    If you are not using Propel the problem is maybe that you do not use the right plugin, you should use sfDoctrineGuardPlugin.
    Plus this post is a bit old right now, it was initialy for symfony 1.2 i’ll try to re-write it soon for 1.4
    Best regards.

    • Article Author
  • tamer

    Olivier, Thank you for instant response.
    I took in mind differences between Propel and Doctrine,
    I believe that the problem is with sessions and sfGuard.because in the log file it really go to create action but there’s signout/signin sfGuard log, maybe it doesn’t pass the session of flash.
    Please if you have any idea , it’s urgent to me to solve this problem.

    • Article Author
  • Tatane

    Super tuto,

    j’ai essayé de l’implémenter en adaptant les noms à mes tables, sans succès (il y’a eu un moment ou j’arrivais à uploader, mais en .bin, puis j’ai modifié des trucs et impossible à uploader un fichier ..)

    Du coup j’ai tt recommencé en copier/coller, mêmes modèles, tout pareil et idem impossible d’uploader

    Après recherches et logs il bloque là :

    if ($this->form->isValid())
    {
    $photo = $this->form->save();

    $return = ‘ok’;
    }
    else
    {
    $return = ‘ko’;
    }

    Je ne rentre jamais dans le isValid() …
    et j’avais les mêmes erreurs ds mes logs que Jeremy au commentaire #5 …

    Une idée, là vraiment je m’en sors plus !

    (je débute sf, et je suis en version 1.4 sous wamp)

    merci d’avance pour les éventuelles pistes de debug

    • Article Author
  • netounet

    Merci d’avoir partagé ton expérience en publiant ce tuto très sympathique que j’ai implémenté sous propel.

    Du coup m’a fallut une petite heure pour créer mon plugin de gestion de galeries photos maison 😉

    Fonctionne nickel

    • Article Author
  • netounet

    Merci d\’avoir partagé ton expérience en publiant ce tuto très sympathique que j\’ai implémenté sous propel.

    Du coup m\’a fallut une petite heure pour créer mon plugin de gestion de galeries photos maison 😉

    Fonctionne nickel

    • Article Author
  • fati

    salut ,

    merci pour ce Tuto c’est très sympa et utile .

    j’ai suivi le tuto , mais j’ai rencontré un problème lorsque j’upload une image eu je clique sur save
    voila qu’est ce que donne comme message d’erreur

    « You must either specify the MIME type for file images/produit-defaut.jpg or enable mime detection  »
    Pour info j’ai mis les paramètre ci-dessous dans le fichier app.yml

    sfImageTransformPlugin:
    default_adapter: GD
    default_image:
    mime_type: image/png
    filename: Untitled.png
    mime_type:
    auto_detect: true
    library: gd_mime_type

    • Article Author
  • fati

    salut ,

    merci pour ce Tuto c’est très sympa et utile .

    j’ai suivi le tuto , mais j’ai rencontré un problème lorsque j’upload une image eu je clique sur save
    voila qu’est ce que donne comme message d’erreur

    « You must either specify the MIME type for file images/produit-defaut.jpg or enable mime detection  »
    Pour info j’ai mis les paramètre ci-dessous dans le fichier app.yml

    sfImageTransformPlugin:
    default_adapter: GD
    default_image:
    mime_type: image/png
    filename: Untitled.png
    mime_type:
    auto_detect: true
    library: gd_mime_type

    merci d’avance !!

    • Article Author
  • fati

    salut ,

    merci pour ce Tuto c\’est très sympa et utile .

    j\’ai suivi le tuto , mais j\’ai rencontré un problème lorsque j\’upload une image eu je clique sur save
    voila qu\’est ce que donne comme message d\’erreur

    \"You must either specify the MIME type for file images/produit-defaut.jpg or enable mime detection \"
    Pour info j\’ai mis les paramètre ci-dessous dans le fichier app.yml

    sfImageTransformPlugin:
    default_adapter: GD
    default_image:
    mime_type: image/png
    filename: Untitled.png
    mime_type:
    auto_detect: true
    library: gd_mime_type

    merci d\’avance !!

    • Article Author
  • Mathieu G.

    Je m’ajoute à tout le monde pour remercier Olivier pour ce code…

    Chez moi il ne fonctionne pas très bien… Je l’ai adapté à mon projet de blog afin de lier des images à un billet de blog. Sous l’interface d’admin de rédaction d’un billet j’ai donc en pied de page la petite appli d’upload d’image. Celle-ci semble fonctionner puisque puisque ça me dit « upload complete » seulement je ne vois aucun fichier créé dans le répertoire des images du dossier web…

    Je bosse en local avec symfony 1.4 + doctrine et wamp… Si quelqu’un a la solution à un problème similaire, je suis preneur !

    Merci

    • Article Author
  • Mathieu G.

    Je m\’ajoute à tout le monde pour remercier Olivier pour ce code…

    Chez moi il ne fonctionne pas très bien… Je l\’ai adapté à mon projet de blog afin de lier des images à un billet de blog. Sous l\’interface d\’admin de rédaction d\’un billet j\’ai donc en pied de page la petite appli d\’upload d\’image. Celle-ci semble fonctionner puisque puisque ça me dit \"upload complete\" seulement je ne vois aucun fichier créé dans le répertoire des images du dossier web…

    Je bosse en local avec symfony 1.4 + doctrine et wamp… Si quelqu\’un a la solution à un problème similaire, je suis preneur !

    Merci

    • Article Author
  • Leny

    Bonsoir à tous,
    J’utilisais auparavant ce plugin mais je le trouve trop compliqué à installer, il y a trop de choses à parametrer et puis je n’aime pas le flash.
    C’est pourquoi, je viens de créer un plugin en full javascript permettant de faire toutes les fonctionnalités !
    http://bit.ly/plugin_gallery_multi_ajax_upload
    Une petite façon de vous renvoyer l’ascenceur 😉
    N’hésitez pas à me poser vos questions sur le site.
    à bientôt, et bonne continuation

    • Article Author
  • ali

    où la suppression des photos

    • Article Author

Recevez nos articles