Symfony 2.8 : Formulaires imbriqués ? validation ?

ViPHP
ViPHP | 3609 Messages

08 mai 2016, 15:36

Bonjour à tous,

Je me heurte à un problème sous Symfony 2.8 auquel je ne trouve pas de réponses.
J'ai deux entités : Annonce & Image.
Annonce a une relation "manytoone" vers Image :
// Annonce.php

    /**
     * @var string $image
     *
     * @ORM\ManyToOne(targetEntity="App\MediaBundle\Entity\Image", cascade={"persist", "remove"})
     */
    private $image;
Le formulaire d'ajout d'annonce inclus celui de l'entité "Image".
$builder
// [...]
->add('image', 'App\MediaBundle\Form\ImageType', ['required' => false])
Je souhaite que "l'entité" Image ne soit pas obligatoire pour l'ajout d'une annonce, mais que si au minimum un des champs de cette dernière est rempli, alors que la validation soit effectuée.

J'ai essayé de jouer sur les deux entités (@Assert\Valid, @Assert\Type, ...), sur les formulaires de ces deux entités (required=false/true, ...), mais je ne parviens pas à mes fins...

Soit l'ajout d'image devient entièrement obligatoire, soit la validation ne se fait plus du tout...

Je suis preneur de tout vos conseils,

Cordialement,

ViPHP
ViPHP | 927 Messages

08 mai 2016, 15:59

Salut,

Pourquoi est ce une relation ManyToOne ? Car là ça veut dire qu'une même image appartient à plusieurs annonces, c'est le cas ou tu t'es trompé de sens ?

ViPHP
ViPHP | 3609 Messages

08 mai 2016, 16:47

Bonjour Genova,

Je ne suis effectivement pas sûr de cela.
En fait j'aimerais que mon entité Image soit utilisable sur plusieurs types d'entités.
Et ce de manière simple : "une seule image" ou multiple : "plusieurs images".

Donc il faudrait que je change mes relations, mais j'avoue être perdu.
Il faudrait en SQL pour que ça fonctionne avoir sur la table "Images" deux champs "entity_type" et "entity_id" pour que cette table soit utilisable par plusieurs autres.

En entité, il faudrait donc que se soit "Image" qui soit propriétaire de la relation si je ne me trompe pas. Mais je ne vois pas comment faire en sorte que la relation puisse se faire sur plusieurs types d'entité...
Sauf à dupliquer plusieurs entités Images... Mais ça n'est pas ce que je souhaite...

Sur le coup j'ai du mal à raisonner simplement avec la vision objet de Symfony... :/

ViPHP
ViPHP | 927 Messages

08 mai 2016, 17:01

Utiliser des "entity_type" et "entity_id" ça ne marchera pas avec Doctrine malheureusement, je me suis déjà confronté à ce problème. Mais effectivement je vois ce que tu veux faire, par contre une seule image pour plusieurs annonces implique que si l'image change pour une annonce, elle changera pour toutes les annonces. Donc si tu veux que ton entité image soit utilisable par d'autres entités :
- Si ton entité ne peut avoir qu'une seule image, dans ce cas tu fais un ManyToOne (comme tu l'as fait)
- Si ton entité peut avoir plusieurs images, tu fais un ManyToMany (ce qui créera une table de liaison entre l'entité et l'image).

Pour répondre à ta question initiale, en gros j'imagine que tu as créé un champ de formulaire "ImageType" qui contient lui même d'autres champs ? Vu ton besoin pour la validation, le plus propre c'est de créer une classe de validation qui répondra à tes besoins : http://symfony.com/doc/current/cookbook ... raint.html

Edit : tu peux aussi utiliser les évènements de formulaire pour faire des vérifications sur tes champs lors du "submit", je l'utilise parfois quand j'ai la flemme de faire un truc plus propre :

dans ton formulaire tu ajoutes ça :
public function buildForm(FormBuilderInterface $builder, array $options)
	{
		// ...

		$builder->addEventListener(FormEvents::POST_SUBMIT, [$this, 'validation']);
	}

	public function validation(FormEvent $event)
	{
		$form = $event->getForm();
		$data = $form->getData();

		// Ici tu vérifies si tes champs d'image sont bien remplis, si ce n'est pas le cas tu ajoutes une erreur au formulaire
		if (...) {
			$form->get('image')->addError(new FormError("Image invalide"));
		}
	}

ViPHP
ViPHP | 3609 Messages

08 mai 2016, 17:21

Merci pour tes réponses rapide ! ça décoiffe pour un dimanche :)

Donc partager une table pour plusieurs type d'entité n'est pas possible d'après toi. :(
Je ne souhaite pas qu'une image puisse appartenir à plusieurs entités (quelque soit leurs type).
je souhaitais simplement avoir une seule entité Image qui représente une seule table en bdd. Et qui soit utilisable sur différents type d'entité...

Il faudrait peut-être pour contourner cela créer une entité intermédiaire (disons "diaporama" ou "ensembledimages" :) ) qui serait du coup en OneToOne et pourrait donc être utilisé par plusieurs types d'entités ?


Pour la question initiale, je vais essayer de regarder. le problème, c'est que par exemple si je fait ça :
/**
     * @param ExecutionContextInterface $context
     * @Assert\Callback
     */
    public function validate(ExecutionContextInterface $context){

        if(
            !empty($this->getTitle()) ||
            !empty($this->getAlt()) ||
            !empty($this->getUri())
        ){
            if(empty($this->getTitle())) {
                die('ko');
                $context->buildViolation('image.title_mandatory')
                    ->atPath('title')
                    ->addViolation();
            }
        }
    }
Je vais bien avoir mon "die('ko')", mais ça n'empêchera pas la validation du formulaire si j'enlève le die dans les mêmes conditions...

ViPHP
ViPHP | 927 Messages

08 mai 2016, 20:09

Ce que tu ne peux pas faire, c'est une table avec un champ "entity_type" et "entity_id" et que Doctrine détecte tout seul avec qui il doit faire la jointure, mais tu peux t'en sortir sans.

Mais tu peux parfaitement faire en sorte que ta table image soit utilisée par différentes entités. Si ton entité n'a qu'une seule image tu fais un ManyToOne dans ton entité, et si ton entité a besoin de plusieurs images tu fais un ManyToMany.
Pour la validation de type callback je ne connaissais pas, mais visiblement tu as l'air de l'utiliser correctement, donc difficile de voir ce qui déconnes :/ En gros le "$form->isValid()" renvoie true dans ton contrôleur ?

ViPHP
ViPHP | 3609 Messages

19 mai 2016, 16:41

Hello Genova,

Je reviens un peu en retard.
Je suis donc partit sur tes conseils sur une relation manytomany (quitte à limiter le nombre d'entrées liées à 1 si besoin).
J'ai donc une entité "Image" qui peut-être liées à plusieurs entités de différents types.
C'est dans les entités hôtes que j'écris la relation manytomany.

Le problème c'est que je ne peux pas faire de relation bidirectionnelle...
Et je suis parfois embêté de ne pas savoir depuis l'image quel est l'entité hôte... :/

Je ne vois pas comment faire mieux... si ce n'est dupliquer mes entités "images"...

Petit nouveau ! | 9 Messages

07 déc. 2016, 11:06

Pourquoi tu ne peux pas faire de relation bidirectionnelle ? Tu peux le faire avec une ManyToMany comme pour les autres.
Faut juste penser que c'est une propriété de type ArrayCollection donc le mettre dans le constructeur.

Je te conseille un super tuto sur les relations ManyToMany https://knpuniversity.com/screencast/collections

G.