-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Open
Description
Bug Report
Q | A |
---|---|
BC Break | no |
Version | 3.2.0 |
Summary
Working with enums in matching criteria for collections does not work correctly for bot lazy and eager loading.
Current behavior
When filtering collections with $collection->matching($criteria)
, if the collection is not initialized, the values from the criteria object won't be converted to database types. So \BackedEnum
s are not replaced by their scalar value.
How to reproduce
- Setup the entities and the enum below:
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
class Page
{
#[ORM\OneToMany(targetEntity: Comment::class, mappedBy: 'page')]
private Collection $comments;
public function __construct()
{
$this->comments = new ArrayCollection();
}
public function getComments(): Collection
{
return $this->comments;
}
public function getBanishedComments(): Collection
{
$criteria = Criteria::create()
->andWhere(Criteria::expr()->eq('commentStatus', CommentStatus::BANISHED));
return $this->comments->matching($criteria);
}
}
// ...
class Comment
{
#[ORM\ManyToOne(targetEntity: Page::class, inversedBy: 'comments')]
private Page $page;
#[ORM\Column(nullable: false, enumType: CommentStatus::class)]
private CommentStatus $commentStatus = CommentStatus::OK;
public function getCommentStatus(): CommentStatus
{
return $this->commentStatus;
}
}
// ...
enum CommentStatus: string
{
case OK = 'ok';
case BANISHED = 'banished';
}
- Keep the default doctrine configuration. Below the config from my symfony application:
doctrine:
dbal:
default_connection: my_db
connections:
my_db:
dbname: '%env(DB_NAME)%'
host: '%env(DB_HOST)%'
port: '%env(DB_PORT)%'
user: '%env(DB_USER)%'
password: '%env(DB_PASSWORD)%'
driver: pdo_mysql
server_version: '5.7.42'
schema_filter: ~^(?!(logs)$)~ # Exclude logs table from doctrine management
default_table_options:
collation: utf8mb4_unicode_ci
types:
tinyint: App\Doctrine\DBAL\Types\TinyintType
mediumint: App\Doctrine\DBAL\Types\MediumintType
orm:
auto_generate_proxy_classes: true
enable_lazy_ghost_objects: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
report_fields_where_declared: true
auto_mapping: true
controller_resolver:
auto_mapping: true
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
- Add some records into your database
- Test the two cases:
/** @var EntityManagerInterface $em **/
/** @var Page $page **/
$page = $em->getRepository(PageRepository::class)->find(1);
// Case 1 : without initiliazed collection
$banishedComments = $page->getBanishedComments(); // ☠️ This will throw an exception and display the message "Object of class App\CommentStatus could not be converted to string"
// Case 1 : with initiliazed collection
$comments = $page->getComments();
// This loop will initialize the collection
foreach ($comments as $comment) {
echo $comment->getCommentStatus()->value . "\n";
}
$banishedComments = $page->getBanishedComments(); // 🆗 This works
There is the stack trace:
Object of class App\CommentStatus could not be converted to string
at vendor/doctrine/dbal/src/Driver/PDO/Statement.php:48
at PDOStatement->bindValue(2, object(CommentStatus), 2)
(vendor/doctrine/dbal/src/Driver/PDO/Statement.php:48)
at Doctrine\DBAL\Driver\PDO\Statement->bindValue(2, object(CommentStatus), 2)
(vendor/doctrine/dbal/src/Driver/Middleware/AbstractStatementMiddleware.php:35)
at Doctrine\DBAL\Driver\Middleware\AbstractStatementMiddleware->bindValue(2, object(CommentStatus), 2)
(vendor/doctrine/dbal/src/Logging/Statement.php:84)
at Doctrine\DBAL\Logging\Statement->bindValue(2, object(CommentStatus), 2)
(vendor/doctrine/dbal/src/Driver/Middleware/AbstractStatementMiddleware.php:35)
at Doctrine\DBAL\Driver\Middleware\AbstractStatementMiddleware->bindValue(2, object(CommentStatus), 2)
(vendor/symfony/doctrine-bridge/Middleware/Debug/DBAL3/Statement.php:54)
at Symfony\Bridge\Doctrine\Middleware\Debug\DBAL3\Statement->bindValue(2, object(CommentStatus), 2)
(vendor/doctrine/dbal/src/Connection.php:1809)
at Doctrine\DBAL\Connection->bindParameters(object(Statement), array(1, object(CommentStatus)), array('integer', 'string'))
(vendor/doctrine/dbal/src/Connection.php:1097)
at Doctrine\DBAL\Connection->executeQuery('...')
(vendor/doctrine/orm/src/Persisters/Collection/ManyToManyPersister.php:273)
at Doctrine\ORM\Persisters\Collection\ManyToManyPersister->loadCriteria(object(PersistentCollection), object(Criteria))
(vendor/doctrine/orm/src/PersistentCollection.php:575)
at Doctrine\ORM\PersistentCollection->matching(object(Criteria))
(src/Entity/Page.php:118)
at App\Entity\Page->getBanishedComments()
(vendor/symfony/property-access/PropertyAccessor.php:388)
at Symfony\Component\PropertyAccess\PropertyAccessor->readProperty(array(object(Page)), 'banishedComments', false)
(vendor/symfony/property-access/PropertyAccessor.php:99)
at Symfony\Component\PropertyAccess\PropertyAccessor->getValue(object(Page), 'banishedComments')
(vendor/easycorp/easyadmin-bundle/src/Field/Configurator/CommonPreConfigurator.php:50)
at EasyCorp\Bundle\EasyAdminBundle\Field\Configurator\CommonPreConfigurator->configure(object(FieldDto), object(EntityDto), object(AdminContext))
(vendor/easycorp/easyadmin-bundle/src/Factory/FieldFactory.php:107)
at EasyCorp\Bundle\EasyAdminBundle\Factory\FieldFactory->processFields(object(EntityDto), object(FieldCollection))
(vendor/easycorp/easyadmin-bundle/src/Factory/EntityFactory.php:43)
Expected behavior
I expect the same behavior between the two cases.
Metadata
Metadata
Assignees
Labels
No labels