Comportement différent selon l'environnement

Champ requis en prod, alors que pas en dev'

a marqué ce sujet comme résolu.

Bonjour à tous !

J’ai un comportement que je n’arrive pas à cerner, et qui me paraît presque être un vrai bug de Symfony que de l’ICC.

J’ai un formulaire avec un champ de type choice, dont je rends chaque option séparément en utilisant form_widget(form.choiceField.0), form_widget(form.choiceField.1), etc.
Entre les options ainsi rendues, j’ai d’autres champs qui viennent. Le code est ci-dessous. L’idée étant de choisir un type de média et de renseigner le ou les champ(s) relatifs à ce type.

Maintenant, il se trouve que si les options de mon choiceField sont forcément requises, il n’en est pas de même pour les champs "intercalaires". Avec l’environnement de dev, pas de problème. Mais avec l’environnement de production, ces champs intercalaires, même s’ils sont bien spécifiés comme non requis dans le FormType, l’attribut required est ajouté. Du coup, on doit renseigner les informations pour tous les types de média alors qu’on n’enregistrera que les données d’un seul.

Il paraît que c’est quelque chose de connu, mais je n’ai pas réussi à en trouver trace sur le repository officiel, et n’ai pas de solution pour l’instant.
Est-ce que quelqu’un aurait déjà observé un tel comportement et aurait un workaround à me proposer ?

Je précise que je parle des environnements Symfony. Ce souci a été constaté sur trois machines différentes en comparant le code HTML généré en passant par app.php et app_dev.php sur la même machine, tous caches purgés.

Merci d’avance

<?php

namespace MyWonderfulBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;

/**
 * Media
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="media")
 * @ORM\Entity
 */
class Media
{
    const UPLOAD_DIR = 'uploads/medias';

    const VIDEO = 'video';
    const IMAGE = 'image';

    const YOUTUBE_EMBED_BASE = '//www.youtube.com/embed/';
    const VIMEO_EMBED_BASE = '//player.vimeo.com/video/';

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="type", type="string", length=255, nullable=false)
     */
    private $type;

    /**
     * The name of the media.
     * It can be the name of the image or the identifier of the video
     *
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=true)
     */
    private $name;

    /**
     * The path of the media.
     * This can be the base URL for a distant media, mostly the base embed URL
     * for videos
     *
     * @var string
     *
     * @ORM\Column(name="path", type="string", length=255, nullable=true)
     */
    private $path;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="updatedAt", type="datetime", nullable=true)
     */
    private $updatedAt;

    public function __toString() {
        return $this->getName();
    }

    public static function getTypeMedia() {
        return array(self::IMAGE => self::IMAGE, self::VIDEO => self::VIDEO);
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set type
     *
     * @param string $type
     * @return Media
     */
    public function setType($type)
    {
        $this->type = $type;

        return $this;
    }

    /**
     * Get type
     *
     * @return string
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * Set path
     *
     * @param string $path
     * @return Media
     */
    public function setPath($path)
    {
        $this->path = $path;

        return $this;
    }

    /**
     * Get path
     *
     * @return string
     */
    public function getPath()
    {
        return $this->path;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Media
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set updatedAt
     *
     * @param string $updatedAt
     * @return Media
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt
     *
     * @return string
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }

    /*************************************************************/

     /**
     * @Assert\Image(
     *     minWidth = 600,
     *     minWidthMessage="L'image doit avoir une largeur minimale de 660 pixels",
     *     minHeight = 400,
     *     minHeightMessage="L'image doit avoir une hauteur minimale de 412 pixels",
     * )
     */
    public $file;

    // Getters et setters comme à l'accoutumée
}
Mon entité Media
<?php

namespace MyWonderfulBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

use MyWonderfulBundle\Entity\Media;

class MediaType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('type', 'choice', array(
                'choices'  => Media::getTypeMedia(),
                'expanded' => true,
                'multiple' => false,
                'attr'     => array(
                    'class' => 'radio'
                )
            ))
            ->add('video_url', 'text', array(
                'required' => false,
            ))
            ->add('file', 'file', array(
                'required' => false,
                'label'    => 'Image',
                'attr'     => array(
                    'accept' => 'image/*',
                    'class'  => 'filestyle'
                )
            ))
            ->add('name', 'hidden')
            ->add('path', 'hidden')
            ->add('updatedAt', 'datetime', array(
                'data'  => new \DateTime(),
                'attr'  => array('class' => 'hidden'),
                'label' => false
            ))
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'MyWonderfulBundle\Entity\Media'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'my_wonderful_bundle_media';
    }
}
Le FormType associé
<div class="well">

    {% if form.vars.value is not empty -%}

        {% if form.type.vars.value == constant('MyWonderfulBundle\\Entity\\Media::IMAGE') -%}
            {{ form.vars.value|media({'class':'img-thumbnail ' ~ form.parent.vars.name|slice(0, -1)}) }}
        {% elseif form.type.vars.value == constant('MyWonderfulBundle\\Entity\\Media::VIDEO') -%}
            {{ form.vars.value|media({'width':'150','height':'150'}) }}
        {%- endif %}
    {%- endif %}

    <div class="form-group clearfix">
      {{ form_widget(form.type.0, (displayVideo ? {} : {'attr': {'checked': true}, 'label_attr': {'class': 'hidden'}})) }}
    </div>
    <div class="form-group clearfix">
        {{ form_widget(form.file) }}
    </div>
    {% if displayVideo %}
    <div class="form-group clearfix">
        {{ form_widget(form.type.1) }}
    </div>
    <div class="form-group clearfix">
      {{ form_widget(form.video_url) }}
    </div>
    {% endif %}
    {{ form_widget(form.name) }}
    {{ form_widget(form.updatedAt) }}
</div>
Le template pour le formulaire de l’entité

Edit 9 octobre 2015

Il n’est pas impossible que ce soit dû à l’utilisation d’une macro plutôt que le système de templating. La piste me vient de cette discussion, plus précisement la réponse de stof qui précise un souci avec la gestion de required du fait des macros existantes.

Edit 9 octobre 2015 2

Fausse joie : avec le templating, c’est pareil… Voici le HTML généré par la même machine et le même code, en haut en dev' et en bas en prod' :

<input id="my_wonderfulbundle_product_galleryMedias_1_file" name="my_wonderfulbundle_product[galleryMedias][1][file]" accept="image/*" class="filestyle ajaxUpload" data-uri="/app_dev.php/media/_upload" data-target="uploads/medias" type="file">

<input id="my_wonderfulbundle_product_galleryMedias_1_file" name="my_wonderfulbundle_product[galleryMedias][1][file]" required="required" class="ajaxUpload" data-uri="/app.php/media/_upload" data-target="uploads/medias" type="file">

Temporairement, j’ai rendu mon champ "à l’ancienne". Mais si quelqu’un avait un comportement similaire, qu’il comprenait la raison et qu’il avait la bonne solution au sens Symfony, je serais très intéressé.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte