Не удается получить родительский элемент в валидаторе класса вложенной коллекции при добавлении нового элемента коллекции (Symfony 3.4) - PullRequest
0 голосов
/ 25 января 2019

Что я хочу сделать

В форме у меня есть вложенная коллекция OneToMany ProspektDates с DateField во вложенной коллекции OneToMany Prospektlaendervarianten объекта Prospekt, которую я хочу проверитьс валидатором класса для свойств Entity Prospekt, зависящих от свойства в родительской коллекции Prospektaendervarianten.

Проблема

Когда я редактирую существующее свойство date из ProspektDate, все в порядке.Проблема в том, что когда вызывается валидатор класса и я добавил новый date в форму, свойство laendervarianten в коллекции ProspektDates не установлено, и у меня нет доступа к родителю ине может проверить их свойства.

Добавление даты в ProspektDate очень похоже на описанное здесь: https://symfony.com/doc/current/form/form_collections.html

Решения, которые я думал о

Я, наверное,Я мог бы добавить скрытое поле сущности в форму ProspektDates, но для меня это звучит как обходной путь, так как Doctrine в какой-то момент устанавливает свойство laendervarianten, слишком поздно для меня, и мне интересно, есть ли лучшая возможность бездобавление поля в форму.

Я также подумал о Class Validator для ProspektLaendervarianten, в котором у меня есть доступ ко всему, но это также звучит как обходной путь для чего-то, что я пропустил.Кроме того, мне всегда нужно проверять всю коллекцию, которую я хочу, чтобы иметь возможность проверить одну date из ProspektDates.

Настройка

Entity Prospekt

/**
 * Prospekt
 *
 * @ORM\Table(name="prospekt")
 * @ORM\Entity()
 */
class Prospekt
{
    /**
     * @var \DateTime
     *
     * @ORM\Column(name="du", type="datetime", nullable=true)
     */
    private $du;


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


    /**
     *
     * @Assert\Valid
     * @ORM\OneToMany(targetEntity="ProspektLaendervarianten", mappedBy="prospekt", orphanRemoval=true, cascade={"all"}, fetch="EAGER")
     */
    private $laendervarianten;

}

Entity ProspektLaendervarianten

/**
 * ProspektLaendervarianten
 *
 * @ORM\Table(name="prospekt_laendervarianten")
 * @ORM\Entity()

 */
class ProspektLaendervarianten
{
    /**
     * @ORM\ManyToOne(targetEntity="Prospekt", inversedBy="laendervarianten")
     * @ORM\JoinColumn(name="prospekt_id", referencedColumnName="id", nullable=true)
     */
    private $prospekt;

    /**
     * @ORM\ManyToOne(targetEntity="BaseCountries")
     * @ORM\JoinColumn(name="base_country_id", referencedColumnName="id", nullable=true)
     */
    private $baseCountry;

    /**
     *
     * @Assert\Valid()
     * @ORM\OneToMany(targetEntity="ProspektDates", mappedBy="laendervarianten", orphanRemoval=true, cascade={"all"}, fetch="EAGER")
     * @ORM\OrderBy({"date" = "ASC"})
     */
    protected $prospektDates;
}

Entity ProspektDates

/**
 * ProspektDates
 *
 * @CustomAssert\EtGermany
 *
 * @ORM\Table(name="prospekt_date)
 * @ORM\Entity()
 */


class ProspektDates
{
    /**
     * @var \DateTime|null
     * @Assert\Valid()
     * @ORM\Column(name="date", type="datetime", nullable=true)
     */
    private $date;

    /**
     * @var ProspektLaendervarianten
     *
     * @ORM\ManytoOne(targetEntity="ProspektLaendervarianten", inversedBy="prospektDates")
     * @ORM\JoinColumn(name="prospekt_laender_varianten_id", referencedColumnName="id", nullable=false)
     */
    private $laendervarianten;
}

Часть формы

{% for land in form.laendervarianten %}

    <div class="row">
        <div class="col-md-4">
            <div class="row">
                <div class="col-md-6 aktiv">
                        {{ land.vars.data.baseCountry.title }}
                </div>
            </div>
        </div>
        <div class="col-md-8 without-padding">
            <div class="row">

                <div class="col-md-4">
                    <div class="row prospekt-dates"
                         data-prototype="{{ form_widget(land.prospektDates.vars.prototype)|e('html_attr') }}"
                         data-index="{{ land.prospektDates|length }}">

                        {{ form_widget(land.prospektDates) }}


                        <div class="form-group">
                            <a href="#" class="prospekt-date-add">
                                <span class="fa fa-plus-circle"></span>
                            </a>
                        </div>


                    </div>
                </div>
            </div>
        </div>
    </div>
{% endfor %}

Класс валидатора для Entity ProspektDates

    class EtGermanyValidator extends ConstraintValidator
    {
        public function validate($protocol, Constraint $constraint)
        {

            /* @var $protocol ProspektDates */
            if (!$constraint instanceof EtGermany) {
                throw new UnexpectedTypeException($constraint, EtGermany::class);
            }


            if (null === $protocol->getDate() || '' === $protocol->getDate()) {
                return;
            }
            //when saving new date laendervarianten is null. Here's my problem!
            if (empty($protocol->getLaendervarianten())) {
                return;
            }

            // only validate if BaseCountry of parent Collection is Germany
            if (BaseCountries::DE !== $protocol->getLaendervarianten()->getBaseCountry()->getId()) {
                return;
            }

            // check if property Date (DateTime) of ProspektDates is later than property Du (DateTime) of Entity Prospekt
            $du = $protocol->getLaendervarianten()->getProspekt()->getDu();
            $et = $protocol->getDate();
            if ($et < $du) {
                $this->context->buildViolation($constraint->message)
                    ->atPath('date')
                    ->addViolation();
            }
    /*
            if (!is_string($value)) {
                throw new UnexpectedTypeException($value, 'string');
            }
    */

        }
    } 

FormType для коллекционных проспектовDates

class ProspektDateType extends AbstractType
{

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('date',
                DateType::class,
                array(

                    'attr' => [
                        'class' => 'form-control input-inline date_custom input-sm date_et',
                        'html5' => false,
                        'readonly' => true

                    ],
                    'required' => false,
                    'widget'        => 'single_text',
                    'format'        => 'ccc, dd.MM.y',
                    'label' => 'ET',
                    'model_timezone' => 'Europe/Berlin',

                )
            );
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => ProspektDates::class,
            'error_bubbling'=>false
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'prospektDates';
    }
}

FormType для коллекционных проспектов Laendervarianten

class ProspektLaendervariantenType extends AbstractType

{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('prospektDates', CollectionType::class, [
            'label'         => 'ETs',
            'entry_type'    => ProspektDateType::class,
            'entry_options' => [
                'label' => false,
                'attr' => [
                    'class' => 'date-item', 
                ],
            ],
            'allow_add'     => true,
            'allow_delete'  => true,
            'prototype'     => true,
            'required'      => false,
           'by_reference'  => false,
            'delete_empty'  => true,
           'prototype_name' => '__prospektDates-collection__',

           'attr'          => [
                'class' => 'prospektDates-collection',
            ],
           'block_name' => 'prospektDates',

       ]);

    }



    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'ProspektLaendervarianten::class',
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'laendervarianten';
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...