PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Monday, March 7, 2022

[FIXED] Symfony 5.4 Form: Issue with EntityType custom query_builder orderBy('rand') and setMaxResult

 March 07, 2022     doctrine, php, symfony5     No comments   

Issue

I'm struggling with a 'strange' behavior. When I use setMaxResult() + Rand() on my query_builder. I got randomly the message that my value is not valid.

Symfony\Component\Validator\ConstraintViolation {#1320 ▼ -message: "Cette valeur n'est pas valide." -messageTemplate: "This value is not valid." -parameters: [▶] -plural: null -root: Symfony\Component\Form\Form {#911 ▶} -propertyPath: "children[press]" -invalidValue: "8" -constraint: Symfony\Component\Form\Extension\Validator\Constraints\Form {#987 …} -code: "1dafa156-89e1-4736-b832-419c2e501fca" -cause: Symfony\Component\Form\Exception\TransformationFailedException {#916 …} }

If I remove setMaxResult(10) it works fine, if I remove Rand() It works too but not both

Could you please help me... I don't get it and I don't know what I can do

Here is my code:

GridType:


namespace App\Form;

use App\Entity\Press;
use App\Model\GridModel;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class GridType extends AbstractType
{
    /**
     * @var EntityManagerInterface
     */
    private $entityManager;

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

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('press', EntityType::class, [
                'class' => Press::class,
                'query_builder' => $this->entityManager->getRepository(Press::class)->getIncluded($options['grid']),
                'choice_label' => 'number',
                'placeholder' => 'Sélectionner une presse',
            ]);
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'grid' => null,
            'data_class' => GridModel::class,
            'csrf_protection' => false,
        ]);
    }
}

PressRepository:

<?php

namespace App\Repository;

use App\Constant\GlobalConstant;
use App\Entity\Grid;
use App\Entity\Press;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @method Press|null find($id, $lockMode = null, $lockVersion = null)
 * @method Press|null findOneBy(array $criteria, array $orderBy = null)
 * @method Press[]    findAll()
 * @method Press[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class PressRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Press::class);
    }

    /**
     * @param Grid|null $grid
     * @return QueryBuilder|null
     */
    public function getIncluded(Grid $grid = null): ?QueryBuilder
    {
        $result = $this->createQueryBuilder('i')
            ->andWhere('i.status = :status')
            ->andWhere('i.include = :include')
            ->setParameters([
                'status' => GlobalConstant::STATUS_VALID,
                'include' => true,
            ]);

        if ($grid) {
            $result->andWhere('i NOT IN (:grid)')
                ->setParameter(
                    'grid', $grid->getPress()
                );
        }

        return $result->orderBy('i.number', 'ASC')
            ->setMaxResults(5)
            ->orderBy('RAND()');
    }

Solution

The way Forms work, the query is executed every time the type is instanced, that means that the result of the initial query when loading the empty form is different than the one when submitting it (because of the random ordering). Since the submitted value is not anymore in the valid 'choices', you see that TransformationFailedException.

One way to solve this would be to use ChoiceType instead of EntityType, and persist the query result in the session, for example.

public function __construct(
    PressRepository $repository,
    // This is deprecated in 5.3
    // see https://symfony.com/blog/new-in-symfony-5-3-session-service-deprecation
    SessionInterface $session
)
{
    $this->repository = $repository;
    $this->session = $session;
}

public function buildForm(FormBuilderInterface $builder, array $options): void
{
    if (!$session->has('press_form_choices')) {
        $session->set(
            'press_form_choices',
            $this->repository->getIncluded($options['grid'])
        );
    }
    $choices = $session->get('press_form_choices');
    $builder
    ->add('press', ChoiceType::class, [
        'choices' => $choices,
        'choice_label' => 'number',
        'choice_value' => 'id',
        'placeholder' => 'Sélectionner une presse',
    ]);
}   

Upon sucessfull submission, clean up your session in your controller: $session->remove('press_form_choices');.



Answered By - msg
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home
View mobile version

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing