DDC-3400: Wrong result using php-cli #4197

Open
opened 2026-01-22 14:37:08 +01:00 by admin · 6 comments
Owner

Originally created by @doctrinebot on GitHub (Nov 19, 2014).

Originally assigned to: @Ocramius on GitHub.

Jira issue originally created by user globetrotter77a:

Same query produces different results. With apache module everything works like expected. With php-cli the join condition to i18n table is ignored and calling getCountries() returns all and not only that entity that is matched by join condition.

        $qb = $this->_em->createQueryBuilder()
                        ->select('t', 'i18n')
                        ->from($this->_entityName, 't')
                        ->innerJoin('t.countries', 'i18n')
                        ->where('i18n.locale = :localeId')
                        ->setParameter('localeId', $localeId);

Country Entity:

namespace MyApp\Model\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/****
 * Country entity
 *
 * @ORM\Entity(repositoryClass="MyApp\Model\Repository\Country")
 * @ORM\Table(name="country")
 *
 */
class Country
{
    /****
     * @var int
     * @ORM\Id
     * @ORM\Column(type="integer", name="id")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /****
     * @var string
     * @ORM\Column(type="string", name="name", length=32, unique=true)
     */
    protected $name;

    /****
     * @var int
     * @ORM\Column(type="integer", name="sort", unique=true)
     */
    protected $sort;

    /****
     * @var ArrayCollection
     * @ORM\OneToMany(targetEntity="ProductDescription\Model\Entity\CountryI18n", mappedBy="country", cascade={"all"})
     */
    protected $countries;


    /****
     * Constructor
     *
     * @return Country
     */
    public function **construct()
    {
        $this->countries = new ArrayCollection();
    }

    /****
     * Getter for $this->id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /****
     * Setter for $this->id
     *
     * @param int $id entity id
     *
     * @return void
     */
    public function setId($id)
    {
        $this->id = (int) $id;
    }

    /****
     * Getter for $this->sort
     *
     * @return int
     */
    public function getSort()
    {
        return $this->sort;
    }

    /****
     * Setter for $this->sort
     *
     * @param int $sort sort order
     *
     * @return void
     */
    public function setSort($sort)
    {
        $this->sort = (int) $sort;
    }

    /****
     * Getter for $this->name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /****
     * Setter for $this->name
     *
     * @param string $name language name in german
     *
     * @return void
     */
    public function setName($name)
    {
        $this->name = (string) $name;
    }

   /****
    * Get collection from i18n table
    *
    * @return ArrayCollection
    */
    public function getCountries()
    {
        return $this->countries;
    }

    /****
     * Proxy method. So we have working with all entities same method
     * to getting i18n data.
     *
     * @return ArrayCollection
     */
    public function getI18n()
    {
        return $this->getCountries();
    }

CountryI18nEntity:

namespace MyApp\Model\Entity;

use Doctrine\ORM\Mapping as ORM;

/****
 * CountryI18n entity
 *
 * @ORM\Entity
 * @ORM\Table(name="country*i18n", uniqueConstraints={@ORM\UniqueConstraint(name="idx_UNIQUE_country_id_locale_id", columns={"country_id", "locale*id"})})
 */
class CountryI18n
{
    /****
     * @var int
     * @ORM\Id
     * @ORM\Column(type="integer", name="id")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /****
     * @ORM\ManyToOne(targetEntity="ProductDescription\Model\Entity\Country", inversedBy="countries")
     * @ORM\JoinColumn(name="country_id", referencedColumnName="id")
     */
    protected $country;

    /****
     * @ORM\ManyToOne(targetEntity="ProductDescription\Model\Entity\Language", inversedBy="countries")
     * @ORM\JoinColumn(name="locale_id", referencedColumnName="id")
     */
    protected $locale;

    /****
     * @var string
     * @ORM\Column(type="string", name="name", length=255)
     */
    protected $name;


    /****
     * Getter for $this->id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /****
     * Setter for $this->id
     *
     * @param int $id id of row primary key
     *
     * @return void
     */
    public function setId($id)
    {
        $this->id = (int) $id;
    }

    /****
     * Getter for $this->country
     *
     * @return Country
     */
    public function getCountry()
    {
        return $this->country;
    }

    /****
     * Setter for $this->country
     *
     * @param Country $country country entity to set
     *
     * @return void
     */
    public function setCountry(Country $country)
    {
        $this->country = $country;
    }

    /****
     * Getter for $this->locale
     *
     * @return Language
     */
    public function getLocale()
    {
        return $this->locale;
    }

    /****
     * Setter for $this->locale
     *
     * @param Language $locale language entity to set as locale
     *
     * @return void
     */
    public function setLocale(Language $locale)
    {
        $this->locale = $locale;
    }

    /****
     * Getter for $this->name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /****
     * Setter for $this->name
     *
     * @param string $name translation name
     *
     * @return void
     */
    public function setName($name)
    {
        $this->name = (string) $name;
    }

}```


Originally created by @doctrinebot on GitHub (Nov 19, 2014). Originally assigned to: @Ocramius on GitHub. Jira issue originally created by user globetrotter77a: Same query produces different results. With apache module everything works like expected. With php-cli the join condition to i18n table is ignored and calling `getCountries()` returns all and not only that entity that is matched by join condition. ``` $qb = $this->_em->createQueryBuilder() ->select('t', 'i18n') ->from($this->_entityName, 't') ->innerJoin('t.countries', 'i18n') ->where('i18n.locale = :localeId') ->setParameter('localeId', $localeId); ``` Country Entity: ``` namespace MyApp\Model\Entity; use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\ArrayCollection; /**** * Country entity * * @ORM\Entity(repositoryClass="MyApp\Model\Repository\Country") * @ORM\Table(name="country") * */ class Country { /**** * @var int * @ORM\Id * @ORM\Column(type="integer", name="id") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /**** * @var string * @ORM\Column(type="string", name="name", length=32, unique=true) */ protected $name; /**** * @var int * @ORM\Column(type="integer", name="sort", unique=true) */ protected $sort; /**** * @var ArrayCollection * @ORM\OneToMany(targetEntity="ProductDescription\Model\Entity\CountryI18n", mappedBy="country", cascade={"all"}) */ protected $countries; /**** * Constructor * * @return Country */ public function **construct() { $this->countries = new ArrayCollection(); } /**** * Getter for $this->id * * @return int */ public function getId() { return $this->id; } /**** * Setter for $this->id * * @param int $id entity id * * @return void */ public function setId($id) { $this->id = (int) $id; } /**** * Getter for $this->sort * * @return int */ public function getSort() { return $this->sort; } /**** * Setter for $this->sort * * @param int $sort sort order * * @return void */ public function setSort($sort) { $this->sort = (int) $sort; } /**** * Getter for $this->name * * @return string */ public function getName() { return $this->name; } /**** * Setter for $this->name * * @param string $name language name in german * * @return void */ public function setName($name) { $this->name = (string) $name; } /**** * Get collection from i18n table * * @return ArrayCollection */ public function getCountries() { return $this->countries; } /**** * Proxy method. So we have working with all entities same method * to getting i18n data. * * @return ArrayCollection */ public function getI18n() { return $this->getCountries(); } ``` CountryI18nEntity: `````` namespace MyApp\Model\Entity; use Doctrine\ORM\Mapping as ORM; /**** * CountryI18n entity * * @ORM\Entity * @ORM\Table(name="country*i18n", uniqueConstraints={@ORM\UniqueConstraint(name="idx_UNIQUE_country_id_locale_id", columns={"country_id", "locale*id"})}) */ class CountryI18n { /**** * @var int * @ORM\Id * @ORM\Column(type="integer", name="id") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /**** * @ORM\ManyToOne(targetEntity="ProductDescription\Model\Entity\Country", inversedBy="countries") * @ORM\JoinColumn(name="country_id", referencedColumnName="id") */ protected $country; /**** * @ORM\ManyToOne(targetEntity="ProductDescription\Model\Entity\Language", inversedBy="countries") * @ORM\JoinColumn(name="locale_id", referencedColumnName="id") */ protected $locale; /**** * @var string * @ORM\Column(type="string", name="name", length=255) */ protected $name; /**** * Getter for $this->id * * @return int */ public function getId() { return $this->id; } /**** * Setter for $this->id * * @param int $id id of row primary key * * @return void */ public function setId($id) { $this->id = (int) $id; } /**** * Getter for $this->country * * @return Country */ public function getCountry() { return $this->country; } /**** * Setter for $this->country * * @param Country $country country entity to set * * @return void */ public function setCountry(Country $country) { $this->country = $country; } /**** * Getter for $this->locale * * @return Language */ public function getLocale() { return $this->locale; } /**** * Setter for $this->locale * * @param Language $locale language entity to set as locale * * @return void */ public function setLocale(Language $locale) { $this->locale = $locale; } /**** * Getter for $this->name * * @return string */ public function getName() { return $this->name; } /**** * Setter for $this->name * * @param string $name translation name * * @return void */ public function setName($name) { $this->name = (string) $name; } }``` ``````
admin added the Bug label 2026-01-22 14:37:08 +01:00
Author
Owner

@doctrinebot commented on GitHub (Nov 19, 2014):

Comment created by @ocramius:

Looks like a caching issue. The amount of information provided is insufficient as it is. I'd suggest verifying if the generated SQL is the same, and checking that all caches were cleared both in CLI and in WEB sapis.

@doctrinebot commented on GitHub (Nov 19, 2014): Comment created by @ocramius: Looks like a caching issue. The amount of information provided is insufficient as it is. I'd suggest verifying if the generated SQL is the same, and checking that all caches were cleared both in CLI and in WEB sapis.
Author
Owner

@doctrinebot commented on GitHub (Nov 20, 2014):

Comment created by globetrotter77a:

O.k. here some further information.

No caching like Xcache or APC is enabled. PHP 5.5 integrated opcache ist not enabled. All Doctrine caches are set to Array. The sql queries are in both cases exactly the same:

SELECT c0*.id AS id0, c0_.name AS name1, c0_.sort AS sort2, c1_.id AS id3, c1_.name AS name4, c1_.country_id AS country_id5, c1_.locale_id AS locale_id6 FROM country c0_ INNER JOIN country_i18n c1_ ON c0_.id = c1_.country_id WHERE c1_.locale*id = ?

/** locale_id = 2 **/

The sql result is correct

Running the console script a ZF2 Initializer runs before that performs this query builder query:


$qb = $this->_em->createQueryBuilder()
                            ->select('t', 'i18n', 'l')
                            ->from($this->_entityName, 't')
                            ->innerJoin('t.countries', 'i18n')
                            ->innerJoin('i18n.locale', 'l');

That results in following SQL:

SELECT c0*.id AS id0, c0_.name AS name1, c0_.sort AS sort2, c1_.id AS id3, c1_.name AS name4, l2_.id AS id5, l2_.name AS name6, l2_.full_name AS full_name7, l2_.locale AS locale8, c1_.country_id AS country_id9, c1_.locale_id AS locale_id10, l2_.country_id AS country_id11 FROM country c0_ INNER JOIN country_i18n c1_ ON c0_.id = c1_.country_id INNER JOIN language l2_ ON c1_.locale_id = l2*.id
@doctrinebot commented on GitHub (Nov 20, 2014): Comment created by globetrotter77a: O.k. here some further information. No caching like Xcache or APC is enabled. PHP 5.5 integrated opcache ist not enabled. All Doctrine caches are set to Array. The sql queries are in both cases exactly the same: ``` SELECT c0*.id AS id0, c0_.name AS name1, c0_.sort AS sort2, c1_.id AS id3, c1_.name AS name4, c1_.country_id AS country_id5, c1_.locale_id AS locale_id6 FROM country c0_ INNER JOIN country_i18n c1_ ON c0_.id = c1_.country_id WHERE c1_.locale*id = ? /** locale_id = 2 **/ ``` The sql result is correct Running the console script a ZF2 Initializer runs before that performs this query builder query: ``` $qb = $this->_em->createQueryBuilder() ->select('t', 'i18n', 'l') ->from($this->_entityName, 't') ->innerJoin('t.countries', 'i18n') ->innerJoin('i18n.locale', 'l'); ``` That results in following SQL: ``` SELECT c0*.id AS id0, c0_.name AS name1, c0_.sort AS sort2, c1_.id AS id3, c1_.name AS name4, l2_.id AS id5, l2_.name AS name6, l2_.full_name AS full_name7, l2_.locale AS locale8, c1_.country_id AS country_id9, c1_.locale_id AS locale_id10, l2_.country_id AS country_id11 FROM country c0_ INNER JOIN country_i18n c1_ ON c0_.id = c1_.country_id INNER JOIN language l2_ ON c1_.locale_id = l2*.id ```
Author
Owner

@doctrinebot commented on GitHub (Nov 20, 2014):

Comment created by @ocramius:

What happens if you run those SQL statements via CLI (dbal:run-sql) or WEB? Same results?

@doctrinebot commented on GitHub (Nov 20, 2014): Comment created by @ocramius: What happens if you run those SQL statements via CLI (`dbal:run-sql`) or WEB? Same results?
Author
Owner

@doctrinebot commented on GitHub (Nov 20, 2014):

Comment created by globetrotter77a:

The sql result is correct. Can I attach it to the ticket? I have exported it to csv.

@doctrinebot commented on GitHub (Nov 20, 2014): Comment created by globetrotter77a: The sql result is correct. Can I attach it to the ticket? I have exported it to csv.
Author
Owner

@doctrinebot commented on GitHub (Nov 20, 2014):

Comment created by @ocramius:

If the same results are produced on CLI and WEB APIs then I suggest trying to insulate the issue in a functional test to be run in both context. You probably have a different ORM bootstrap for CLI and WEB.

Attaching a CSV for same results makes no real difference here.

@doctrinebot commented on GitHub (Nov 20, 2014): Comment created by @ocramius: If the same results are produced on CLI and WEB APIs then I suggest trying to insulate the issue in a functional test to be run in both context. You probably have a different ORM bootstrap for CLI and WEB. Attaching a CSV for same results makes no real difference here.
Author
Owner

@doctrinebot commented on GitHub (Nov 20, 2014):

Comment created by globetrotter77a:

No, I didn't want to attach two times the same result. Wanted to attach it one time to show that those entitites that are wrong in the result doesn't appear in the sql result at all. I don't have different bootstraps. After a few short tests I think it is an error in th ArrayCache mechanism. The difference was that using Apache one initializer was not called. Calling this initializer in both cases leads now to wrong results in CLI and WEB API.

When the second query is not executed everything is fine. But when the second longer query runs and selects all i18n entities and after it the first query runs then the issue appears.

@doctrinebot commented on GitHub (Nov 20, 2014): Comment created by globetrotter77a: No, I didn't want to attach two times the same result. Wanted to attach it one time to show that those entitites that are wrong in the result doesn't appear in the sql result at all. I don't have different bootstraps. After a few short tests I think it is an error in th ArrayCache mechanism. The difference was that using Apache one initializer was not called. Calling this initializer in both cases leads now to wrong results in CLI and WEB API. When the second query is not executed everything is fine. But when the second longer query runs and selects all i18n entities and after it the first query runs then the issue appears.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#4197