-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Doctrine bridge] Support custom ID-types in EntityType / ORMQueryBuilderLoader #35165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hello @Devristo, thank you for opening this issue. There is already an extension point to provide a custom object loader, but it requires to implement a new form type extending the abstract However, note that using a pure |
Thanks, didn't think of that. Since I needed it to work with vendor-types that use the <?php
namespace App\Service;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ObjectManager;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormTypeExtensionInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
class EntityTypeExtension extends EntityType implements FormTypeExtensionInterface
{
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
// This is a nasty way to get the choiceLoader callable defined by
// the EntityType.
$myResolver = new class extends OptionsResolver {
private $choiceLoader;
public function setDefault($option, $value)
{
if ($option === 'choice_loader'){
$this->choiceLoader = $value;
}
parent::setDefault($option, $value);
}
public function getChoiceLoader()
{
return $this->choiceLoader;
}
};
// Please be warned that the options are now configured twice, here and by Symfony.
parent::configureOptions($myResolver);
// This is magic: now the callable is bound to EntityTypeExtension
// context instead of the EntityType context so we can override
// the getLoader() method-below
$choiceLoader = $myResolver->getChoiceLoader();
$resolver->setDefault('choice_loader', $choiceLoader);
}
/**
* Return the default loader object.
*
* @param QueryBuilder $queryBuilder
* @param string $class
*
* @return ORMQueryBuilderLoader
*/
public function getLoader(ObjectManager $manager, $queryBuilder, $class)
{
if (!$queryBuilder instanceof QueryBuilder) {
throw new \TypeError(sprintf('Expected an instance of %s, but got %s.', QueryBuilder::class, \is_object($queryBuilder) ? \get_class($queryBuilder) : \gettype($queryBuilder)));
}
return new MyORMQueryBuilderLoader($queryBuilder);
}
public static function getExtendedTypes()
{
return [EntityType::class];
}
/**
* @inheritDoc
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
}
/**
* @inheritDoc
*/
public function buildView(
FormView $view,
FormInterface $form,
array $options
) {
}
/**
* @inheritDoc
*/
public function finishView(
FormView $view,
FormInterface $form,
array $options
) {
}
/**
* @inheritDoc
*/
public function getExtendedType()
{
return [EntityType::class];
}
} |
Ok this is tricky :D. Maybe you could use something simpler like: <?php
namespace App\Service;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ObjectManager;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormTypeExtensionInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
class EntityTypeExtension extends EntityType implements FormTypeExtensionInterface
{
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('choice_loader', function (Options $options, $choiceLoader) {
return $choiceLoader instanceof \Closure ? \Closure::bind($choiceLoader, $this) : $choiceLoader;
});
}
// ...
} |
This unfortunately does not work as the function is already called at this point and returned a DoctrineChoiceLoader instance. Thanks for thinking with me. Will come back to this and try some different stuff when I get bored ;) |
Related issues and comments: #14583 #23853 #23808
Description
The
ORMQueryBuilderLoader
tries to guess the identifier type to perform filter out invalid values for integral or UUID types by matching a hardcoded list of Doctrine type names. However there are cases that guessing is not working properly and it causes invalid queries to be constructed.In my case I have separate UUID types for each entity, such that I have strong typing in PHP for these IDs. Lets say
BlogId
(doctrine nameblog_id
) andPostId
(doctrine namepost_id
).When using an EntityType, internally constructing a ORMQueryBuilderLoader, it fails to filter out empty strings. This creates a query Postgres chokes on with error:
ERROR: invalid input syntax for uuid
.It would be nice if there was an extension point such that this guessing logic can be altered for custom types.
Example
Maybe we could creating a factory service which can be decorated for the
ORMQueryBuilderLoader
? Such that a custom implementation can be provided?The text was updated successfully, but these errors were encountered: