DDC-1277: BasicEntityPersister::expandParameters() will check associations #1610

Closed
opened 2026-01-22 13:19:50 +01:00 by admin · 4 comments
Owner

Originally created by @doctrinebot on GitHub (Jul 14, 2011).

Originally assigned to: @guilhermeblanco on GitHub.

Jira issue originally created by user jasper@nerdsweide.nl:

When executing a EntityRepository::findBy() or EntityRepository::findOnyBy() with criteria that contain a field/value pair where the field is an association-name and the value is an array, some (for me) unexpected behavior occurs.

First an example to make my statement a bit more clear:
I have an entity User and Group where Group has many Users (User many-to-one Group).

When I call UserRepository->findBy( array( 'group' => 1 )), all goes well.
When I call UserRepository->findBy( array( 'group' => array( 1, 2, 3 ))), I get an notice and no results (Notice: Array to string conversion in /opt/local/www/doctrine2/lib/vendor/doctrine-dbal/lib/Doctrine/DBAL/Connection.php on line 613)

I've tracked the "problem" down to the BasicEntityPersister:

BasicEntityPersister::*getSelectEntitiesSQL(), which uses BasicEntityPersister::_getSelectConditionSQL(), correctly creates a query containing something like WHERE t0.group*id IN ( ? ).
But BasicEntityPersister::expandParameters() doesn't implode the array to some string that can be bound to the query. This is because it doesn't take into account that the field could be an association.

I don't know if this is intended behavior, but I would think not. I've therefor altered the BasicEntityPersister::expandParameters() a bit:

private function expandParameters($criteria)
    {
        $params = $types = array();

        foreach ($criteria AS $field => $value) {
            if ($value === null) {
                continue; // skip null values.
            }

            $type = null;
            if (isset($this->_class->fieldMappings[$field])) {
                $type = Type::getType($this->_class->fieldMappings[$field]['type'])->getBindingType();
            // BEGIN: Jasper N. Brouwer (14-07-2011)
            } else if (isset($this->_class->associationMappings[$field])) {
                if ($this->_class->associationMappings[$field]['isOwningSide']) {
                    $targetClass = $this->*em->getClassMetadata($this->*class->associationMappings[$field]['targetEntity']);
                    $targetField = $this->_class->associationMappings[$field]['joinColumns'][0]['referencedColumnName'];
                    if (isset($targetClass->fieldMappings[$targetField])) {
                        $type = Type::getType($targetClass->fieldMappings[$targetField]['type'])->getBindingType();
                    }
                }
            // END: Jasper N. Brouwer (14-07-2011)
            }
            if (is_array($value)) {
                $type += Connection::ARRAY*PARAM*OFFSET;
            }

            $params[] = $value;
            $types[] = $type;
        }
        return array($params, $types);                                                                                  
    }

I hope this bit of code also clarifies what I'm trying to explain a bit more...

Originally created by @doctrinebot on GitHub (Jul 14, 2011). Originally assigned to: @guilhermeblanco on GitHub. Jira issue originally created by user jasper@nerdsweide.nl: When executing a `EntityRepository::findBy()` or `EntityRepository::findOnyBy()` with criteria that contain a field/value pair where the field is an association-name and the value is an array, some (for me) unexpected behavior occurs. First an example to make my statement a bit more clear: I have an entity `User` and `Group` where `Group` has many `Users` (`User` many-to-one `Group`). When I call `UserRepository->findBy( array( 'group' => 1 ))`, all goes well. When I call `UserRepository->findBy( array( 'group' => array( 1, 2, 3 )))`, I get an notice and no results (Notice: Array to string conversion in /opt/local/www/doctrine2/lib/vendor/doctrine-dbal/lib/Doctrine/DBAL/Connection.php on line 613) I've tracked the "problem" down to the `BasicEntityPersister`: `BasicEntityPersister::*getSelectEntitiesSQL()`, which uses `BasicEntityPersister::_getSelectConditionSQL()`, correctly creates a query containing something like `WHERE t0.group*id IN ( ? )`. But `BasicEntityPersister::expandParameters()` doesn't implode the array to some string that can be bound to the query. This is because it doesn't take into account that the field could be an association. I don't know if this is intended behavior, but I would think not. I've therefor altered the `BasicEntityPersister::expandParameters()` a bit: ``` none private function expandParameters($criteria) { $params = $types = array(); foreach ($criteria AS $field => $value) { if ($value === null) { continue; // skip null values. } $type = null; if (isset($this->_class->fieldMappings[$field])) { $type = Type::getType($this->_class->fieldMappings[$field]['type'])->getBindingType(); // BEGIN: Jasper N. Brouwer (14-07-2011) } else if (isset($this->_class->associationMappings[$field])) { if ($this->_class->associationMappings[$field]['isOwningSide']) { $targetClass = $this->*em->getClassMetadata($this->*class->associationMappings[$field]['targetEntity']); $targetField = $this->_class->associationMappings[$field]['joinColumns'][0]['referencedColumnName']; if (isset($targetClass->fieldMappings[$targetField])) { $type = Type::getType($targetClass->fieldMappings[$targetField]['type'])->getBindingType(); } } // END: Jasper N. Brouwer (14-07-2011) } if (is_array($value)) { $type += Connection::ARRAY*PARAM*OFFSET; } $params[] = $value; $types[] = $type; } return array($params, $types); } ``` I hope this bit of code also clarifies what I'm trying to explain a bit more...
admin added the Improvement label 2026-01-22 13:19:50 +01:00
admin closed this issue 2026-01-22 13:19:51 +01:00
Author
Owner

@doctrinebot commented on GitHub (Aug 11, 2011):

Comment created by jasper@nerdsweide.nl:

I found an error in my fix :(

$this->_class->associationMappings[$field]['joinColumns'][0]['referencedColumnName']; refers to a column-name, not a field-name. I made a new patch:

private function expandParameters($criteria)                                                                            
{
    $params = $types = array();

    foreach ($criteria AS $field => $value) {
        if ($value === null) {
            continue; // skip null values.
        }

        $type = null;
        if (isset($this->_class->fieldMappings[$field])) {
            $type = Type::getType($this->_class->fieldMappings[$field]['type'])->getBindingType();
        // BEGIN: Jasper N. Brouwer (11-08-2011)
        } else if (isset($this->_class->associationMappings[$field])) {
            if ($this->_class->associationMappings[$field]['isOwningSide']) {
                $targetClass = $this->*em->getClassMetadata($this->*class->associationMappings[$field]['targetEntity']);
                $targetColumn = $this->_class->associationMappings[$field]['joinColumns'][0]['referencedColumnName'];
                if (isset($targetClass->fieldNames[$targetColumn])) {
                    $type = Type::getType($targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type'])->getBindingType();
                }
            }
        // END: Jasper N. Brouwer (11-08-2011)
        }
        if (is_array($value)) {
            $type += Connection::ARRAY*PARAM*OFFSET;
        }

        $params[] = $value;
        $types[] = $type;
    }
    return array($params, $types);
}

I'll attach a new diff to.

@doctrinebot commented on GitHub (Aug 11, 2011): Comment created by jasper@nerdsweide.nl: I found an error in my fix :( `$this->_class->associationMappings[$field]['joinColumns'][0]['referencedColumnName'];` refers to a column-name, not a field-name. I made a new patch: ``` private function expandParameters($criteria) { $params = $types = array(); foreach ($criteria AS $field => $value) { if ($value === null) { continue; // skip null values. } $type = null; if (isset($this->_class->fieldMappings[$field])) { $type = Type::getType($this->_class->fieldMappings[$field]['type'])->getBindingType(); // BEGIN: Jasper N. Brouwer (11-08-2011) } else if (isset($this->_class->associationMappings[$field])) { if ($this->_class->associationMappings[$field]['isOwningSide']) { $targetClass = $this->*em->getClassMetadata($this->*class->associationMappings[$field]['targetEntity']); $targetColumn = $this->_class->associationMappings[$field]['joinColumns'][0]['referencedColumnName']; if (isset($targetClass->fieldNames[$targetColumn])) { $type = Type::getType($targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type'])->getBindingType(); } } // END: Jasper N. Brouwer (11-08-2011) } if (is_array($value)) { $type += Connection::ARRAY*PARAM*OFFSET; } $params[] = $value; $types[] = $type; } return array($params, $types); } ``` I'll attach a new diff to.
Author
Owner

@doctrinebot commented on GitHub (Aug 14, 2011):

Comment created by @guilhermeblanco:

Hi,

Thanks a lot to report this issue and attempt to fix it.
I extracted parts of your patch to resolve this issue, thanks again for investing your time on this.

This issue is not fixed on trunk by commit 63a2f02f4d

Cheers,

@doctrinebot commented on GitHub (Aug 14, 2011): Comment created by @guilhermeblanco: Hi, Thanks a lot to report this issue and attempt to fix it. I extracted parts of your patch to resolve this issue, thanks again for investing your time on this. This issue is not fixed on trunk by commit https://github.com/doctrine/doctrine2/commit/63a2f02f4ddea1ab9191b0e4acfd1d790d2247c7 Cheers,
Author
Owner

@doctrinebot commented on GitHub (Aug 14, 2011):

Issue was closed with resolution "Fixed"

@doctrinebot commented on GitHub (Aug 14, 2011): Issue was closed with resolution "Fixed"
Author
Owner

@doctrinebot commented on GitHub (Dec 13, 2015):

Imported 2 attachments from Jira into https://gist.github.com/1c9ab72dd9bcaed57847

@doctrinebot commented on GitHub (Dec 13, 2015): Imported 2 attachments from Jira into https://gist.github.com/1c9ab72dd9bcaed57847 - [11029_BasicEntityPersister.php.diff](https://gist.github.com/1c9ab72dd9bcaed57847#file-11029_BasicEntityPersister-php-diff) - [11047_BasicEntityPersister.php-fixed.diff](https://gist.github.com/1c9ab72dd9bcaed57847#file-11047_BasicEntityPersister-php-fixed-diff)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#1610