0

I'm coming to you to solve a brain killer issue.

So i've a basic form to generate sub forms. I would like to pass array data to the sub form but array pass are data distorted.

I've also got an error about CSRF token which I think is linked. CSFR Error

Controller :

public function evaluatemocep($id,Request $request): Response
    {
        if ($this->getUser()) {
            $em = $this->getDoctrine()->getManager();
            $efficiency = new Efficiency();
            $problem = $em->getRepository('App:Problem')->find($id);
            $efficiency->setLinkProblem($problem);
            $form = $this->createForm(EfficiencyForm::class,$problem,['data'=>['id' => $id]]);
            $form->handleRequest($request);
            if ($form->isSubmitted() && $form->isValid()) {
                $em->persist($efficiency);
                $em->flush();
            }
                return $this->render('efficiency/efficiencyform.html.twig', [
                    'problem' => $problem,
                    'form' => $form->createView()]);
        }
        return new Response("You must be login");
    }

efficiencyform :

class EfficiencyForm extends AbstractType {

    /**
     * {@inheritDoc}
     */
    private $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {

        $problem = $this->em->getRepository(Problem::class)->find($options['data']['id']);
        $MOCrepo = $problem->getMOC();
        $EOrepo = $problem->getEO();
        $MOCA = array();
        $EOA = array();
        foreach ($EOrepo as $eo){
            array_push($EOA, $eo);
        }
        foreach ($MOCrepo as $moc){
            array_push($MOCA, $moc);
        }
                $builder->add('EffCollection', CollectionType::class, [
                    'entry_type' => EfficiencyMOCEOType::class,
                    'entry_options' => array('label' => false, 'EOA' => $EOA, 'MOCA' => $MOCA),
                    'allow_add' => true,
                    'prototype' => true,
                    'by_reference' => false,
                    'allow_delete' => true,
                    'mapped' => false,
                    'label' => 'Thinking about health'
                ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'allow_extra_fields' => true
        ]);
    }

    public function getBlockPrefix() {
        return 'RateCouple';
    }

}

EfficiencyMOCEOType :

<?php

namespace App\Form;

use App\Entity\Efficiency;
use App\Entity\EO;
use App\Entity\MOC;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class EfficiencyMOCEOType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $EOA = $options['EOA'];
        $MOCA = $options['MOCA'];

        $builder
            ->add('EO', EntityType::class, [
                'class' => EO::class,
                'label' => 'Ethical objective',
                'choices' => $EOA,
                'choice_attr' => function ($choice){return ['title' => $choice->getDescription()];},
                'required' => true])
            ->add('MOC', EntityType::class,[
                'class' => MOC::class,
                'label' => 'Model Of Care',
                'choices' => $MOCA,
                'choice_attr' => function ($choice){return ['title' => $choice->getDescription()];},
                'required' => true])
            ->add('rateRiskCurrent', ChoiceType::class,[
                'label' => 'Evaluate the risks of the selected couple : ',
                'choices' => [
                    'High Risk' => 3,
                    'Medium Risk' => 2,
                    'Low Risk' => 1
                ],
                'required' => true
            ])
            ->add('rateBenefitCurrent', ChoiceType::class,[
                'label' => 'Evaluate the benefits of the selected couple : ',
                'choices' => [
                    'High Benefit' => 3,
                    'Medium Benefit' => 2,
                    'Low Benefit' => 1
                ],
                'required' => true
            ]);
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Efficiency::class,
            'MOCA' =>[],
            'EOA' => [],
            'allow_extra_fields' => true
        ]);
    }
}

twig file :

{% extends 'base.html.twig' %}

{% block title %}New efficiency evaluation{% endblock %}

{% block body %}
{{ form(form) }}

<div>
</div>
<fieldset>
    {{ form_start(form) }}

    <ul style="display: none" class="efficiencies" data-prototype="&lt;fieldset class=&quot;form-group&quot;&gt;&lt;div id=&quot;RateCouple_linkEfficiency___name__&quot;&gt;&lt;div class=&quot;form-group&quot;&gt;&lt;label class=&quot;required&quot; for=&quot;RateCouple_linkEfficiency___name___EO&quot;&gt;Ethical objective&lt;/label&gt;&lt;select id=&quot;RateCouple_linkEfficiency___name___EO&quot; name=&quot;RateCouple[linkEfficiency][__name__][EO]&quot; class=&quot;form-control&quot;&gt;&lt;option value=&quot;3&quot; title=&quot;DESC EO 1&quot;&gt;EO 1&lt;/option&gt;&lt;/select&gt;&lt;/div&gt;&lt;div class=&quot;form-group&quot;&gt;&lt;label class=&quot;required&quot; for=&quot;RateCouple_linkEfficiency___name___MOC&quot;&gt;Model Of Care&lt;/label&gt;&lt;select id=&quot;RateCouple_linkEfficiency___name___MOC&quot; name=&quot;RateCouple[linkEfficiency][__name__][MOC]&quot; class=&quot;form-control&quot;&gt;&lt;option value=&quot;3&quot; title=&quot;DESC MOC 1&quot;&gt;MOC 1&lt;/option&gt;&lt;/select&gt;&lt;/div&gt;&lt;div class=&quot;form-group&quot;&gt;&lt;label class=&quot;required&quot; for=&quot;RateCouple_linkEfficiency___name___rateRiskCurrent&quot;&gt;Evaluate the risks of the selected couple : &lt;/label&gt;&lt;select id=&quot;RateCouple_linkEfficiency___name___rateRiskCurrent&quot; name=&quot;RateCouple[linkEfficiency][__name__][rateRiskCurrent]&quot; class=&quot;form-control&quot;&gt;&lt;option value=&quot;3&quot;&gt;High Risk&lt;/option&gt;&lt;option value=&quot;2&quot;&gt;Medium Risk&lt;/option&gt;&lt;option value=&quot;1&quot;&gt;Low Risk&lt;/option&gt;&lt;/select&gt;&lt;/div&gt;&lt;div class=&quot;form-group&quot;&gt;&lt;label class=&quot;required&quot; for=&quot;RateCouple_linkEfficiency___name___rateBenefitCurrent&quot;&gt;Evaluate the benefits of the selected couple : &lt;/label&gt;&lt;select id=&quot;RateCouple_linkEfficiency___name___rateBenefitCurrent&quot; name=&quot;RateCouple[linkEfficiency][__name__][rateBenefitCurrent]&quot; class=&quot;form-control&quot;&gt;&lt;option value=&quot;3&quot;&gt;High Benefit&lt;/option&gt;&lt;option value=&quot;2&quot;&gt;Medium Benefit&lt;/option&gt;&lt;option value=&quot;1&quot;&gt;Low Benefit&lt;/option&gt;&lt;/select&gt;&lt;/div&gt;&lt;/div&gt;&lt;/fieldset&gt;">
    </ul>
        <ul class="efficiencies">
            {% for efficiency in form.EffCollection %}
                <li>
                    {{ form_row(efficiency.EO) }}
                    </br>
                    {{ form_row(efficiency.MOC) }}
                    </br>
                    {{ form_row(efficiency.rateRiskCurrent) }}
                    </br>
                    {{ form_row(efficiency.rateBenefitCurrent) }}

                </li>
            {% endfor %}
        </ul>
    <input type="submit" value="Submit" class="btn btn-primary btn-block" />

    {{ form_end(form) }}

    <script>

        var efficiency_template = document.getElementById("efficiencies");

        function addNewEfficiency(){
            var dup_efficiency_template = efficiency_template.cloneNode(true);
            document.getElementById("list_of_efficiency").append(dup_efficiency_template);
        }

    </script>

    {% endblock %}
    {% block javascripts %}
        <script>

            var $collectionHolderEfficiency;

            var $addEfficiencyButton = $('<button type="button" class="btn btn-secondary btn-success">Add an efficiency row</button>');

            var $newEfficiencyLinkLi = $('<li></li>').append($addEfficiencyButton);


            jQuery(document).ready(function() {
                $collectionHolderEfficiency = $('ul.efficiencies');

                $collectionHolderEfficiency.find('li').each(function () {
                    addEfficiencyFormDeleteLink($(this));
                });
                $collectionHolderEfficiency.append($newEfficiencyLinkLi);
                $collectionHolderEfficiency.data('index', $collectionHolderEfficiency.find(':input').length);
                $addEfficiencyButton.on('click', function (e) {
                    addEfficiencyForm($collectionHolderEfficiency, $newEfficiencyLinkLi);
                });
            });



            function addEfficiencyForm($collectionHolderEfficiency, $newEfficiencyLinkLi) {
                var prototype = $collectionHolderEfficiency.data('prototype');
                var index = $collectionHolderEfficiency.data('index');
                var newForm = prototype;
                newForm = newForm.replace(/__name__/g, index);
                $collectionHolderEfficiency.data('index', index + 1);
                var $newFormLi = $('<li></li>').append(newForm);
                addEfficiencyFormDeleteLink($newFormLi);
                $newEfficiencyLinkLi.before($newFormLi);
            }


            function addEfficiencyFormDeleteLink($efficiencyFormLi) {
                var $removeFormButton = $('<button type="button" class="btn btn-secondary btn-danger">Delete this efficiency row</button>');
                $efficiencyFormLi.append($removeFormButton);
                $removeFormButton.on('click', function(e) {
                    $efficiencyFormLi.remove();
                });
            }

        </script>
</fieldset>
    {% endblock %}

Any help will be grateful !

Hatoo
  • 1
  • Hi, there, it would be helpful, if you would describe in more detail, what the actual problem is, because "I would like to pass array data to the sub form but array pass are data distorted." isn't particularly clear. Since your form already gets the problem entity passed to it, you should not pass its id as an option, but use a form event instead, specifically the PRE_SET_DATA form event. In general, data access should be automatic and not be done via options, if it can be helped. The form component is actually pretty smart and you *should* play to its strengths. – Jakumi Oct 27 '19 at 06:49
  • The thing is that i pass data ($EOA and $MOCA) to the second form but data that i've in the second form are not data that i get in the first. I'll try to get over the id argu to see if there is a difference ! – Hatoo Oct 27 '19 at 07:37
  • That solve the CSRF problem but i still don't get right data on my sub form – Hatoo Oct 27 '19 at 09:09
  • well, i can tell you that as far is visible, the eoa/moca arrays should be correct. how do you verify/check, that they are not? – Jakumi Oct 27 '19 at 09:17
  • I check directly from the database the $EOA and $MOCA are array base on entity related on many to many with problem entity and for example problem id 4 get 2 EO and 2 MOC but on the form i get only one with wrong label (i actually get EO and MOC of problem 1 ..) – Hatoo Oct 27 '19 at 09:24
  • it seems like your `Problem::getMOC()` and `Problem::getEO()` might not work as intended then? – Jakumi Oct 27 '19 at 09:35
  • I add on the sub-form a foreach to display variable $MOCA and $EOA and i have right variable (int(2) string(4) "MOC1" string(4) "MOC2" string(14) "EO 1 id prob 4" string(13) "EO2 id prob 4") but on the form i only get "EO 1" and "MOC 1" as choice which is not a value of $MOCA neither $EOA so i assume i've got an error on my sub-form build, i'm checking that Thanks for make me think ! – Hatoo Oct 27 '19 at 09:38

1 Answers1

0

So i figure out that the prototype link doesn't work i solve wrong data transfert but i've now got undisplay form and i can't find my error

There is my twig :


{% block title %}New efficiency evaluation{% endblock %}

{% block body %}
{{ form(form) }}
<fieldset>
    {{ form_start(form) }}

    <ul style="display: none" id="efficiencies-proto" class="efficiencies" data-prototype="{{ form_widget(form.efficiencies.vars.prototype)|e('html_attr') }}">
    </ul>
        <ul class="efficiencies">
            {% for efficiency in form.efficiencies %}
                <li>
                    {{ form_row(efficiency.EO) }}
                    </br>
                    {{ form_row(efficiency.MOC) }}
                    </br>
                    {{ form_row(efficiency.rateRiskCurrent) }}
                    </br>
                    {{ form_row(efficiency.rateBenefitCurrent) }}

                </li>
            {% endfor %}
        </ul>
    {{ form_end(form) }}
    {% endblock %}
    {% block javascripts %}
        <script>

            var $collectionHolderEfficiency;

            var $addEfficiencyButton = $('<button type="button" class="btn btn-secondary btn-success">Add an efficiency row</button>');

            var $newEfficiencyLinkLi = $('<li></li>').append($addEfficiencyButton);


            jQuery(document).ready(function() {
                $collectionHolderEfficiency = $('ul.efficiencies');

                $collectionHolderEfficiency.find('li').each(function () {
                    addEfficiencyFormDeleteLink($(this));
                });
                $collectionHolderEfficiency.append($newEfficiencyLinkLi);
                $collectionHolderEfficiency.data('index', $collectionHolderEfficiency.find(':input').length);
                $addEfficiencyButton.on('click', function (e) {
                    addEfficiencyForm($collectionHolderEfficiency, $newEfficiencyLinkLi);
                });
            });



            function addEfficiencyForm($collectionHolderEfficiency, $newEfficiencyLinkLi) {
                var prototype = $collectionHolderEfficiency.data('prototype');
                var index = $collectionHolderEfficiency.data('index');
                var newForm = prototype;
                newForm = newForm.replace(/__name__/g, index);
                $collectionHolderEfficiency.data('index', index + 1);
                var $newFormLi = $('<li></li>').append(newForm);
                addEfficiencyFormDeleteLink($newFormLi);
                $newEfficiencyLinkLi.before($newFormLi);
            }


            function addEfficiencyFormDeleteLink($efficiencyFormLi) {
                var $removeFormButton = $('<button type="button" class="btn btn-secondary btn-danger">Delete this efficiency row</button>');
                $efficiencyFormLi.append($removeFormButton);
                $removeFormButton.on('click', function(e) {
                    $efficiencyFormLi.remove();
                });
            }

        </script>
</fieldset>
    {% endblock %}

EfficiencyForm :

<?php


namespace App\Form;
use App\Entity\Efficiency;
use App\Entity\EO;
use App\Entity\MOC;
use App\Entity\Problem;
use Doctrine\ORM\EntityRepository;
use phpDocumentor\Reflection\Types\Null_;
use PhpParser\Node\Expr\Array_;
use Symfony\Component\Form\AbstractType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;


class EfficiencyForm extends AbstractType {

    /**
     * {@inheritDoc}
     */
    private $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {

        $problem = $this->em->getRepository(Problem::class)->find($options['data']['id']);
        $MOCrepo = $problem->getMOC();
        $EOrepo = $problem->getEO();
        $MOCA = array();
        $EOA = array();
        $interom = 0;
        foreach ($EOrepo as $eo){
            array_push($EOA, $eo);
            $interom ++;
        }
        foreach ($MOCrepo as $moc){
            array_push($MOCA, $moc);
        }
                $builder
                    ->add('efficiencies', CollectionType::class, [
                    'entry_type' => EfficiencyMOCEOType::class,
                    'entry_options' => array('label' => false, 'EOA' => $EOA, 'MOCA' => $MOCA),
                    'allow_add' => true,
                    'prototype' => true,
                    'by_reference' => false,
                    'allow_delete' => true,
                    'mapped' => false,
                    'label' => 'Thinking about health'
                ])
                    ->add("submit", SubmitType::class, [
                    "label" => $options["submit_button_label"],
                    "attr" => [
                        "class" => "btn btn-primary btn-bloc pull-right"
                    ]
                ])
                ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'allow_extra_fields' => true,
            "submit_button_label" => "Submit evaluation"
        ]);
    }

    public function getBlockPrefix() {
        return 'efficiencyOne';
    }

}

EfficiencyMOCEOType :

<?php

namespace App\Form;

use App\Entity\Efficiency;
use App\Entity\EO;
use App\Entity\MOC;
use phpDocumentor\Reflection\Type;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class EfficiencyMOCEOType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $EOA = $options['EOA'];
        $MOCA = $options['MOCA'];

        foreach ($MOCA as $moc) {
            var_dump($moc->getName());
        }
        foreach ($EOA as $eo) {
            var_dump($eo->getName());
        }
        var_dump(gettype($EOA));
        var_dump(gettype($MOCA));
        $builder
            ->add('EO', EntityType::class, [
                'class' => EO::class,
                'label' => 'Ethical objective',
                'choices' => $EOA,
                'choice_attr' => function ($choice){return ['title' => $choice->getDescription()];},
                'required' => true])
            ->add('MOC', EntityType::class,[
                'class' => MOC::class,
                'label' => 'Model Of Care',
                'choices' => $MOCA,
                'choice_attr' => function ($choice){return ['title' => $choice->getDescription()];},
                'required' => true])
            ->add('rateRiskCurrent', ChoiceType::class,[
                'label' => 'Evaluate the risks of the selected couple : ',
                'choices' => [
                    'High Risk' => 3,
                    'Medium Risk' => 2,
                    'Low Risk' => 1
                ],
                'required' => true
            ])
            ->add('rateBenefitCurrent', ChoiceType::class,[
                'label' => 'Evaluate the benefits of the selected couple : ',
                'choices' => [
                    'High Benefit' => 3,
                    'Medium Benefit' => 2,
                    'Low Benefit' => 1
                ],
                'required' => true
            ]);
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'MOCA' =>[],
            'EOA' => [],
            'allow_extra_fields' => true
        ]);
    }
}
Hatoo
  • 1