Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Blocker Blocker
    • Resolution: Fixed
    • Affects Version/s: 1.0.14, 1.2.2, 1.2.3
    • Fix Version/s: 1.2.3
    • Component/s: Connection, I18n
    • Labels:
      None
    • Environment:
      MySQL 5.1.37
      PHP 5.2.11
      symfony 1.2.11 DEV

      symfony 1.4.13
      PHP 5.3.6
      Postgres 8.4.8

      Description

      I used to work with a single database named "doctrine". The query was working properly.

      I then decided to use 2 databases so I got my schema like this:

      connection: doctrine

      Category:
      actAs:
      I18n:
      actAs:
      Sluggable:
      fields: [name]
      Timestampable: ~
      fields: [name, description]
      columns:
      id: ~
      name:
      type: string(255)
      notnull: true
      description: string

      User:
      connection: second
      columns:
      id: ~
      name:
      type: string(255)
      notnull: true

      I did setup my connections in config/databases.yml this way:

      all:
      doctrine:
      // ....
      second:
      // ....

      build-model, build-forms, build-filters and cc got ran. But now, I got an exception saying the "Translation" relation doesn't exist. The Base Models include correctly the bindComponent line:

      Doctrine_Manager::getInstance()->bindComponent('Category', 'doctrine');

      For now, I managed to kind of fixing it with simply swapping the databases order in my config/databases.yml and it's now working again perfectly.

      I forgot to mention that in the CategoryTable when i call $this->getConnection()->getName(), it outputs "second"

        Activity

        Hide
        Colin Darie added a comment -

        I'm experiencing the same issue with 4 connections. The I18n behavior is almost unusable for models whose connection is not the last one defined. I searched for an acceptable solution but I haven't found one (IMHO the setting to the right connection before each query is not acceptable in large projects). I tried to do like in Search behavior, but it didn't work, I doesn't know enough doctrine internals to understand why.

        Show
        Colin Darie added a comment - I'm experiencing the same issue with 4 connections. The I18n behavior is almost unusable for models whose connection is not the last one defined. I searched for an acceptable solution but I haven't found one (IMHO the setting to the right connection before each query is not acceptable in large projects). I tried to do like in Search behavior, but it didn't work, I doesn't know enough doctrine internals to understand why.
        Hide
        Jonathan H. Wage added a comment -

        Can you test this in Doctrine 1.2? I believe it is fixed.

        Show
        Jonathan H. Wage added a comment - Can you test this in Doctrine 1.2? I believe it is fixed.
        Hide
        Georg added a comment - - edited

        I am using the latest symfony 1.4 which is doctrine 1.2.3 afaik, and this bug still exists.
        Try

        actAs:
        I18n:
        fields: [name]
        generateFiles: true
        generatePath: /project/lib/model/doctrine/i18n

        and the resulting model base class is not bound to the correct connection.

        Show
        Georg added a comment - - edited I am using the latest symfony 1.4 which is doctrine 1.2.3 afaik, and this bug still exists. Try actAs: I18n: fields: [name] generateFiles: true generatePath: /project/lib/model/doctrine/i18n and the resulting model base class is not bound to the correct connection.
        Hide
        Joe Siponen added a comment - - edited

        I've just now battled with the very same problem in Doctrine 1.2 (the version bundled with symfony 1.4) and the problem seems to be caused by the fact that Doctrine_Record_Generator simply isn't written such that it is able to reinitialize generators for unloaded table instances after a connection is closed. This problem also manifests itself after a table has been loaded in a connection and one tries retrieve a table again after Doctrine_Connection->evictTables() has been called. This makes it impossible to to open more than one connection at a time in a request/script when using behaviors that dynamically modify table instances (such as the i18n behavior). The issue states that this has been fixed but I looked at the latest code and the problem still seems to be very much the same.

        Doctrine_Record_Generator determines if it needs to run its initialization methods simply by checking if the to-be generated class, as defined by the className option, exists using a class_exists call. This means that the first time this method is called the initialization happens but for every subsequent call no initialization is made. Now, in the i18m behavior, the important initialization happens in its setTableDefinition method in which it removes any of the translated fields from the table instance that is been setup and redefines them as relations on the to-be-created Translation class. It then finishes off by dynamically declaring the new class for the translation record using its generateClassFromTable method.

        Thus, the first time everything goes smoothly and the i18n generator's setTableDefinition is called and the table instance is properly initialized. Everything will now work as expected while the current connection is open since the connection instance keeps the i18n modified table instances alive and well for callers.

        But, when the current connection is closed the i18n modified table instances it holds are also removed (goes out of scope). Then, when a new connection is opened, this new connection will start without having any table instances. This means that the next time one asks the new connection for a table instance of the same class with the i18n behavior the i18n behaviors will fail to initialize because the generator at this time believes its class has actually been initialized which, in turn, means that the table using the i18n behavior isn't properly initialized. No initialization means that this table will now include the non-existant i18n fields in the select part of its queries (those are in the translation table) causing those queries to fail miserably.

        I believe this could be fixed by adding a static attribute to Doctrine_Record_Generator that tracks the spl_object_hash of the underlying dbh instance variable of the doctrine connection of the table parameter. If the hash is the same the next time that the initialize method is called the generator can decide not to reinitialize itself but if it detects that the hash of the current connection is different then that is definitely a clue to the generator that it needs to reinitialize itself (i.e. run all of the initialization methods but generateClassFromTable which should't be called more than once).

        Maybe do it like this perhaps:

         
        abstract class Doctrine_Record_Generator extends Doctrine_Record_Abstract
        {
          public function initialize(Doctrine_Table $table)
          {
            /* ... */ 
          
            $currentConnectionHash = spl_object_hash($table->getConnection()->getDbh());
            
            //Next part is called if this is the first connection made or if this is a new open connection with new table instances
            if ($currentConnectionHash != self::$lastConnectionHash)
            {
              self::$lastConnectionHash = $currentConnectionHash;
              
              $this->buildTable();
        
              $fk = $this->buildForeignKeys($this->_options['table']);
        
              $this->_table->setColumns($fk);
        
              $this->buildRelation();
        
              $this->setTableDefinition();
              $this->setUp();
              
              if ($this->_options['generateFiles'] === false && class_exists($this->_options['className'])) {
                $this->generateClassFromTable($this->_table); //Don't generate the class more than once ever
              }
              
              $this->buildChildDefinitions();
        
              $this->_table->initIdentifier();
            }
          }
        }
        
        Show
        Joe Siponen added a comment - - edited I've just now battled with the very same problem in Doctrine 1.2 (the version bundled with symfony 1.4) and the problem seems to be caused by the fact that Doctrine_Record_Generator simply isn't written such that it is able to reinitialize generators for unloaded table instances after a connection is closed. This problem also manifests itself after a table has been loaded in a connection and one tries retrieve a table again after Doctrine_Connection->evictTables() has been called. This makes it impossible to to open more than one connection at a time in a request/script when using behaviors that dynamically modify table instances (such as the i18n behavior). The issue states that this has been fixed but I looked at the latest code and the problem still seems to be very much the same. Doctrine_Record_Generator determines if it needs to run its initialization methods simply by checking if the to-be generated class, as defined by the className option, exists using a class_exists call. This means that the first time this method is called the initialization happens but for every subsequent call no initialization is made. Now, in the i18m behavior, the important initialization happens in its setTableDefinition method in which it removes any of the translated fields from the table instance that is been setup and redefines them as relations on the to-be-created Translation class. It then finishes off by dynamically declaring the new class for the translation record using its generateClassFromTable method. Thus, the first time everything goes smoothly and the i18n generator's setTableDefinition is called and the table instance is properly initialized. Everything will now work as expected while the current connection is open since the connection instance keeps the i18n modified table instances alive and well for callers. But, when the current connection is closed the i18n modified table instances it holds are also removed (goes out of scope). Then, when a new connection is opened, this new connection will start without having any table instances. This means that the next time one asks the new connection for a table instance of the same class with the i18n behavior the i18n behaviors will fail to initialize because the generator at this time believes its class has actually been initialized which, in turn, means that the table using the i18n behavior isn't properly initialized. No initialization means that this table will now include the non-existant i18n fields in the select part of its queries (those are in the translation table) causing those queries to fail miserably. I believe this could be fixed by adding a static attribute to Doctrine_Record_Generator that tracks the spl_object_hash of the underlying dbh instance variable of the doctrine connection of the table parameter. If the hash is the same the next time that the initialize method is called the generator can decide not to reinitialize itself but if it detects that the hash of the current connection is different then that is definitely a clue to the generator that it needs to reinitialize itself (i.e. run all of the initialization methods but generateClassFromTable which should't be called more than once). Maybe do it like this perhaps: abstract class Doctrine_Record_Generator extends Doctrine_Record_Abstract { public function initialize(Doctrine_Table $table) { /* ... */ $currentConnectionHash = spl_object_hash($table->getConnection()->getDbh()); //Next part is called if this is the first connection made or if this is a new open connection with new table instances if ($currentConnectionHash != self::$lastConnectionHash) { self::$lastConnectionHash = $currentConnectionHash; $this->buildTable(); $fk = $this->buildForeignKeys($this->_options['table']); $this->_table->setColumns($fk); $this->buildRelation(); $this->setTableDefinition(); $this->setUp(); if ($this->_options['generateFiles'] === false && class_exists($this->_options['className'])) { $this->generateClassFromTable($this->_table); //Don't generate the class more than once ever } $this->buildChildDefinitions(); $this->_table->initIdentifier(); } } }
        Hide
        James Bell added a comment -

        I'm also experiencing this issue, using the stable version of Symfony 1.4.13. If I define multiple database connections, the i18n Translation relations fail with this call: Doctrine_Relation_Parser->getRelation('Translation', )

        'Unknown relation alias Translation'

        dev:
        mysql1:
        class: sfDoctrineDatabase
        param:
        dsn: 'mysql:host=localhost;dbname=microscooters'
        username: microuser_uk
        password: sailing

        mysql2:
        class: sfDoctrineDatabase
        param:
        dsn: 'mysql:host=localhost;dbname=microscooters_ie'
        username: microuser_ie
        password: windy

        postgresql:
        class: sfDoctrineDatabase
        param:
        dsn: 'pgsql:host=localhost;dbname=mses6'
        username: postgres
        password: postgres

        In this case, the primary connection is the postgresql one, and that is where the i18n behaviour is defined:

        Category:
        actAs:
        Timestampable: ~
        Auditable: ~
        NestedSet: ~
        I18n:
        fields: [picture_id, sort_type, name, handle, subheading, breadcrumb, description, enabled, meta_title, meta_keywords, meta_description]
        i18nField: culture
        length: 5
        actAs:
        Timestampable: ~
        Auditable: ~
        ...

        I tried to implement the suggest above (ie adding a static hash of the database handle to the Doctrine_Record_Generator class file, which does clear out the connections. However, I then have difficulty with Doctrine recognizing CategoryTranslation as a class:

        "( ! ) Fatal error: Class 'CategoryTranslation' not found in /sitename/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Table.php on line 545"

        Is there anything else I can to do test/fix this?

        Show
        James Bell added a comment - I'm also experiencing this issue, using the stable version of Symfony 1.4.13. If I define multiple database connections, the i18n Translation relations fail with this call: Doctrine_Relation_Parser->getRelation('Translation', ) 'Unknown relation alias Translation' dev: mysql1: class: sfDoctrineDatabase param: dsn: 'mysql:host=localhost;dbname=microscooters' username: microuser_uk password: sailing mysql2: class: sfDoctrineDatabase param: dsn: 'mysql:host=localhost;dbname=microscooters_ie' username: microuser_ie password: windy postgresql: class: sfDoctrineDatabase param: dsn: 'pgsql:host=localhost;dbname=mses6' username: postgres password: postgres In this case, the primary connection is the postgresql one, and that is where the i18n behaviour is defined: Category: actAs: Timestampable: ~ Auditable: ~ NestedSet: ~ I18n: fields: [picture_id, sort_type, name, handle, subheading, breadcrumb, description, enabled, meta_title, meta_keywords, meta_description] i18nField: culture length: 5 actAs: Timestampable: ~ Auditable: ~ ... I tried to implement the suggest above (ie adding a static hash of the database handle to the Doctrine_Record_Generator class file, which does clear out the connections. However, I then have difficulty with Doctrine recognizing CategoryTranslation as a class: "( ! ) Fatal error: Class 'CategoryTranslation' not found in /sitename/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Table.php on line 545" Is there anything else I can to do test/fix this?
        Hide
        Joe Siponen added a comment -

        This is a duplicate of http://www.doctrine-project.org/jira/browse/DC-373. I've also added a failing test case to that issue that should reproduce the issue as described here.

        Show
        Joe Siponen added a comment - This is a duplicate of http://www.doctrine-project.org/jira/browse/DC-373 . I've also added a failing test case to that issue that should reproduce the issue as described here.
        Hide
        Andy.L added a comment -

        still exists in 1.2.4

        Show
        Andy.L added a comment - still exists in 1.2.4

          People

          • Assignee:
            Jonathan H. Wage
            Reporter:
            Xav.
          • Votes:
            1 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: