Development

#7689 (Doctrine model not using correct connection with multiple databases)

You must first sign up to be able to contribute.

Ticket #7689 (closed defect: duplicate)

Opened 5 years ago

Last modified 2 years ago

Doctrine model not using correct connection with multiple databases

Reported by: JamesWhitt Assigned to: Jonathan.Wage
Priority: major Milestone:
Component: sfDoctrinePlugin Version: 1.4.x DEV
Keywords: multiple databases Cc:
Qualification: Unreviewed

Description

The issue seems to be that no matter what connection is specified, once the model is used, it will always try to use the last connection in the list. Here's what I did.

I created two databases quickly: CREATE DATABASE test1; CREATE TABLE IF NOT EXISTS Rebel (

RebelID int(11) NOT NULL auto_increment, RebelName varchar(32) NOT NULL, BallOrChain tinyint(4) NOT NULL, PRIMARY KEY (RebelID)

) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE DATABASE test2; CREATE TABLE IF NOT EXISTS Song (

Sacred int(11) NOT NULL, Heart varchar(32) NOT NULL, UNIQUE KEY Sacred (Sacred)

) ENGINE=InnoDB DEFAULT CHARSET=latin1;

I then configured the databases in sf: ./symfony configure:database --name=test1 --class=sfDoctrineDatabase "mysql:host=localhost;dbname=test1" test1 test1 ./symfony configure:database --name=test2 --class=sfDoctrineDatabase "mysql:host=localhost;dbname=test2" test2 test2

$ cat config/databases.yml all:

test1:

class: sfDoctrineDatabase param:

dsn: 'mysql:host=localhost;dbname=test1' username: test1 password: test1

test2:

class: sfDoctrineDatabase param:

dsn: 'mysql:host=localhost;dbname=test2' username: test2 password: test2

Then I ran all the normal things: ./symfony doctrine:build-schema ./symfony doctrine:build-model ./symfony doctrine:build-form ./symfony doctrine:build-filters

./symfony doctrine:generate-module --with-show --non-verbose-templates frontend rebel rebel ./symfony doctrine:generate-module --with-show --non-verbose-templates frontend song song

Verified that the model created correctly with the connection specified in base: $ head lib/model/doctrine/base/BaseRebel.class.php <?php // Connection Component Binding Doctrine_Manager::getInstance()->bindComponent('Rebel', 'test1');

Now if I go to http://test.localhost/frontend_dev.php/rebel, I get an error: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test2.Rebel' doesn't exist. Failing Query: "SELECT r.rebelid AS rrebelid, r.rebelname AS rrebelname, r.ballorchain AS rballorchain FROM Rebel r"

From this I see that it's still trying to use the test2 connection even though everything is telling it to go to db test1.

If I go to http://test.localhost/frontend_dev.php/song it uses the correct connection (test2).

Attachments

test.tar.bz2 (6.6 kB) - added by JamesWhitt on 11/24/09 17:18:21.
Bzip2 tar of the main project files of the test system
doctrine_core.r7492.patch (0.7 kB) - added by pluk77 on 10/08/10 14:00:10.
patch to core.php used in sf 1.4.6
doctrine_core.r7687.patch (0.7 kB) - added by pluk77 on 10/08/10 14:00:38.
patch to core.php used in sf 1.4.8
doctrine_manager.r7657.patch (1.5 kB) - added by pluk77 on 10/08/10 14:01:14.
patch to manager.php used in sf 1.4.6 & sf 1.4.8

Change History

11/24/09 17:18:21 changed by JamesWhitt

  • attachment test.tar.bz2 added.

Bzip2 tar of the main project files of the test system

11/24/09 17:23:56 changed by FabianLange

  • status changed from new to closed.
  • resolution set to duplicate.

duplicate of #7676

11/24/09 19:51:10 changed by Jonathan.Wage

Can you give us the full stacktrace so we can see what code issued the query which resulted in the exception? Thanks.

(follow-up: ↓ 4 ) 12/04/09 15:31:04 changed by kimnorgaard

  • status changed from closed to reopened.
  • resolution deleted.

I am experiencing a similar problem.

We are running the latest 1.4 SVN with doctrine.

databases:yml contains:

all:

db_1:

class: sfDoctrineDatabase param:

dsn: 'mysql:host=127.0.0.1;dbname=db1' username: checklist password: pass

db_2:

class: sfDoctrineDatabase param:

dsn: 'mysql:host=127.0.0.1;dbname=db2' username: checklist password: pass

testmodel exists on db_1 and *not* on db_2.

I generate an admin interface with:

$ symfony doctrine:generate-admin backend testmodel

Then I try to create a new entity with "add" on:

http://localhost/backend_dev.php/testmodel/new

The entity it created in db_1, but when it tries to redirect to:

http://localhost/backend_dev.php/testmodel/1/edit

... it uses the db_2 connection and gives me an exception, correctly stating that it can't select from the tables on that database.

When I call the index action, it selects from the db_1 database just fine.

If I reverse the two databases in databases.yml the problem goes away.

I suspect that $this->getRoute()->getObject() is the sinner.

Backtrace:

500 | Internal Server Error | Doctrine_Connection_Mysql_Exception
SQLSTATE[42000]: Syntax error or access violation: 1142 SELECT command denied to user 'checklist'@'localhost' for table 'testmodel'

stack trace
at ()
in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection.php line 1082 ...
            $message .= sprintf('. Failing Query: "%s"', $query);

        }


        $exc  = new $name($message, (int) $e->getCode());

        if ( ! isset($e->errorInfo) || ! is_array($e->errorInfo)) {

            $e->errorInfo = array(null, null, null, null);

        }
at Doctrine_Connection->rethrowException(object('PDOException'), object('Doctrine_Connection_Statement'))
in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection/Statement.php line 269 ...
        } catch (Doctrine_Adapter_Exception $e) {

        }


        $this->_conn->rethrowException($e, $this);


        return false;

    }
at Doctrine_Connection_Statement->execute(array('2'))
in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection.php line 1006 ...
        try {

            if ( ! empty($params)) {

                $stmt = $this->prepare($query);

                $stmt->execute($params);


                return $stmt;

            } else {
at Doctrine_Connection->execute('SELECT t.id AS t__id, t.name AS t__name, t.description AS t__description, t.created_at AS t__created_at, t.updated_at AS t__updated_at, t.version AS t__version FROM testmodel t WHERE (t.id = ?)', array('1'))
in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Query/Abstract.php line 976 ...
            return $this->_conn->exec($query, $params);

        }


        $stmt = $this->_conn->execute($query, $params);


        $this->_params['exec'] = array();

at Doctrine_Query_Abstract->_execute(array())
in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Query/Abstract.php line 1026 ...
                $result = $this->_constructQueryFromCache($cached);

            }

        } else {

            $stmt = $this->_execute($params);


            if (is_integer($stmt)) {

                $result = $stmt;
at Doctrine_Query_Abstract->execute()
in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/routing/sfDoctrineRoute.class.php line 99 ...
      }

      else

      {

        $results = $q->execute();

      }

    }

    else
at sfDoctrineRoute->getObjectsForParameters(array('module' => 'testmodel', 'action' => 'edit', 'sf_format' => 'html', 'id' => '1'))
in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/routing/sfDoctrineRoute.class.php line 40 ...

  protected function getObjectForParameters($parameters)

  {

    $results = $this->getObjectsForParameters($parameters);


    // If query returned Doctrine_Collection with results inside then we

    // need to return the first Doctrine_Record
at sfDoctrineRoute->getObjectForParameters(array('module' => 'testmodel', 'action' => 'edit', 'sf_format' => 'html', 'id' => '1'))
in SF_ROOT_DIR/lib/vendor/symfony/lib/routing/sfObjectRoute.class.php line 109 ...
    }


    // check the related object

    if (!($this->object = $this->getObjectForParameters($this->parameters)) && (!isset($this->options['allow_empty']) || !$this->options['allow_empty']))

    {

      throw new sfError404Exception(sprintf('Unable to find the %s object with the following parameters "%s").', $this->options['model'], str_replace("\n", '', var_export($this->filterParameters($this->parameters), true))));

    }
at sfObjectRoute->getObject()
in SF_ROOT_DIR/cache/backend/dev/modules/autoTemplate/actions/actions.class.php line 93 ...

  public function executeEdit(sfWebRequest $request)

  {

    $this->template = $this->getRoute()->getObject();

    $this->form = $this->configuration->getForm($this->template);

  }

at autoTemplateActions->executeEdit(object('sfWebRequest'))
in SF_ROOT_DIR/lib/vendor/symfony/lib/action/sfActions.class.php line 60 ...
    }


    // run action

    return $this->$actionToRun($request);

  }

}


[...]

(in reply to: ↑ 3 ) 12/04/09 15:37:20 changed by kimnorgaard

at sfObjectRoute->getObject() in SF_ROOT_DIR/cache/backend/dev/modules/autoTemplate/actions/actions.class.php line 93 ... public function executeEdit(sfWebRequest $request) { $this->template = $this->getRoute()->getObject(); $this->form = $this->configuration->getForm($this->template); }

template = testmodel in this part - I searched and replaced the model name in the strack trace.

01/15/10 11:23:40 changed by tkoomzaaskz

Yep, I agree - there is a bug somewhere.

I am using symfony 1.4 with Doctrine. I have 4 connections set:

all:

  master:
    class: sfDoctrineDatabase
    param:
      dsn:      mysql:host=localhost;dbname=x_database
      username: x_admin
      password: -XN31w"^5_D1-N_9

  aaa:
    class: sfDoctrineDatabase
    param:
      dsn:      mysql:host=localhost;dbname=aaa
      username: abc_user
      password: abc

  bbb:
    class: sfDoctrineDatabase
    param:
      dsn:      mysql:host=localhost;dbname=bbb
      username: abc_user
      password: abc

  ccc:
    class: sfDoctrineDatabase
    param:
      dsn:      mysql:host=localhost;dbname=ccc
      username: abc_user
      password: abc

I have a main product table and specific aaa bbb and ccc products (with connections set).

When I execute admin generator list for main object (master connection) - it works. When I execute admin generator new - it works. When I execute admin generator edit - it doesn't work. It breaks with the following stack trace:

500 | Internal Server Error | Doctrine_Connection_Mysql_Exception
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'ccc.product' doesn't exist
stack trace

    * at ()
      in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection.php line 1082 ...
            1079.             $message .= sprintf('. Failing Query: "%s"', $query);
            1080.         }
            1081.
            1082.         $exc  = new $name($message, (int) $e->getCode());
            1083.         if ( ! isset($e->errorInfo) || ! is_array($e->errorInfo)) {
            1084.             $e->errorInfo = array(null, null, null, null);
            1085.         }
    * at Doctrine_Connection->rethrowException(object('PDOException'), object('Doctrine_Connection_Statement'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection/Statement.php line 269 ...
             266.         } catch (Doctrine_Adapter_Exception $e) {
             267.         }
             268.
             269.         $this->_conn->rethrowException($e, $this);
             270.
             271.         return false;
             272.     }
    * at Doctrine_Connection_Statement->execute(array('5'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection.php line 1006 ...
            1003.         try {
            1004.             if ( ! empty($params)) {
            1005.                 $stmt = $this->prepare($query);
            1006.                 $stmt->execute($params);
            1007.
            1008.                 return $stmt;
            1009.             } else {
    * at Doctrine_Connection->execute('SELECT p.id AS p__id, p.aaa_object_id AS p__aaa_object_id, p.bbb_object_id AS p__bbb_object_id, p.ccc_object_id AS p__ccc_object_id, p.quantity AS p__quantity, p.weight_shown AS p__weight_shown, p.weight_post AS p__weight_post, p.created_at AS p__created_at, p.updated_at AS p__updated_at FROM product p WHERE (p.id = ?)', array('5'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Query/Abstract.php line 976 ...
             973.             return $this->_conn->exec($query, $params);
             974.         }
             975.
             976.         $stmt = $this->_conn->execute($query, $params);
             977.
             978.         $this->_params['exec'] = array();
 979.
    * at Doctrine_Query_Abstract->_execute(array())
      in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Query/Abstract.php line 1026 ...
            1023.                 $result = $this->_constructQueryFromCache($cached);
            1024.             }
            1025.         } else {
            1026.             $stmt = $this->_execute($params);
            1027.
            1028.             if (is_integer($stmt)) {
            1029.                 $result = $stmt;
    * at Doctrine_Query_Abstract->execute()
      in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/routing/sfDoctrineRoute.class.php line 99 ...
              96.       }
              97.       else
              98.       {
              99.         $results = $q->execute();
             100.       }
             101.     }
             102.     else
    * at sfDoctrineRoute->getObjectsForParameters(array('module' => 'product', 'action' => 'edit', 'sf_format' => 'html', 'id' => '5'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/routing/sfDoctrineRoute.class.php line 40 ...
              37.
              38.   protected function getObjectForParameters($parameters)
              39.   {
              40.     $results = $this->getObjectsForParameters($parameters);
              41.
              42.     // If query returned Doctrine_Collection with results inside then we
              43.     // need to return the first Doctrine_Record
    * at sfDoctrineRoute->getObjectForParameters(array('module' => 'product', 'action' => 'edit', 'sf_format' => 'html', 'id' => '5'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/routing/sfObjectRoute.class.php line 109 ...
             106.     }
             107.
             108.     // check the related object
             109.     if (!($this->object = $this->getObjectForParameters($this->parameters)) && (!isset($this->options['allow_empty']) || !$this->options['allow_empty']))
             110.     {
             111.       throw new sfError404Exception(sprintf('Unable to find the %s object with the following parameters "%s").', $this->options['model'], str_replace("\n", '', var_export($this->filterParameters($this->parameters), true))));
             112.     }
    * at sfObjectRoute->getObject()
      in SF_ROOT_DIR/cache/admin/dev/modules/autoProduct/actions/actions.class.php line 93 ...
              90.
              91.   public function executeEdit(sfWebRequest $request)
              92.   {
              93.     $this->product = $this->getRoute()->getObject();
              94.     $this->form = $this->configuration->getForm($this->product);
              95.   }
  96.
    * at autoProductActions->executeEdit(object('sfWebRequest'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/action/sfActions.class.php line 60 ...
              57.     }
              58.
              59.     // run action
              60.     return $this->$actionToRun($request);
              61.   }
              62. }
  63.
    * at sfActions->execute(object('sfWebRequest'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/filter/sfExecutionFilter.class.php line 92 ...
              89.   {
              90.     // execute the action
              91.     $actionInstance->preExecute();
              92.     $viewName = $actionInstance->execute($this->context->getRequest());
              93.     $actionInstance->postExecute();
              94.
              95.     return null === $viewName ? sfView::SUCCESS : $viewName;
    * at sfExecutionFilter->executeAction(object('productActions'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/filter/sfExecutionFilter.class.php line 78 ...
              75.       }
              76.     }
              77.
              78.     return $this->executeAction($actionInstance);
              79.   }
              80.
              81.   /**
    * at sfExecutionFilter->handleAction(object('sfFilterChain'), object('productActions'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/filter/sfExecutionFilter.class.php line 42 ...
              39.     {
              40.       $timer = sfTimerManager::getTimer(sprintf('Action "%s/%s"', $actionInstance->getModuleName(), $actionInstance->getActionName()));
              41.
              42.       $viewName = $this->handleAction($filterChain, $actionInstance);
              43.
              44.       $timer->addTime();
              45.       $timer = sfTimerManager::getTimer(sprintf('View "%s" for "%s/%s"', $viewName, $actionInstance->getModuleName(), $actionInstance->getActionName()));
    * at sfExecutionFilter->execute(object('sfFilterChain'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/filter/sfFilterChain.class.php line 53 ...
              50.       }
              51.
              52.       // execute the next filter
              53.       $this->chain[$this->index]->execute($this);
              54.     }
              55.   }
  56.
    * at sfFilterChain->execute()
      in SF_ROOT_DIR/lib/vendor/symfony/lib/filter/sfBasicSecurityFilter.class.php line 72 ...
              69.     }
              70.
              71.     // the user has access, continue
              72.     $filterChain->execute();
              73.   }
              74.
              75.   /**
    * at sfBasicSecurityFilter->execute(object('sfFilterChain'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/filter/sfFilterChain.class.php line 53 ...
              50.       }
              51.
              52.       // execute the next filter
              53.       $this->chain[$this->index]->execute($this);
              54.     }
              55.   }
  56.
    * at sfFilterChain->execute()
      in SF_ROOT_DIR/lib/vendor/symfony/lib/filter/sfRenderingFilter.class.php line 33 ...
              30.   public function execute($filterChain)
              31.   {
              32.     // execute next filter
              33.     $filterChain->execute();
              34.
              35.     // get response object
              36.     $response = $this->context->getResponse();
    * at sfRenderingFilter->execute(object('sfFilterChain'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/filter/sfFilterChain.class.php line 53 ...
              50.       }
              51.
              52.       // execute the next filter
              53.       $this->chain[$this->index]->execute($this);
              54.     }
              55.   }
  56.
    * at sfFilterChain->execute()
      in SF_ROOT_DIR/plugins/sfDoctrineGuardPlugin/lib/sfGuardRememberMeFilter.class.php line 56 ...
              53.       }
              54.     }
              55.
              56.     $filterChain->execute();
              57.   }
              58. }
  59.
    * at sfGuardRememberMeFilter->execute(object('sfFilterChain'))
      in SF_ROOT_DIR/lib/vendor/symfony/lib/filter/sfFilterChain.class.php line 53 ...
              50.       }
              51.
              52.       // execute the next filter
              53.       $this->chain[$this->index]->execute($this);
              54.     }
              55.   }
  56.
    * at sfFilterChain->execute()
      in SF_ROOT_DIR/lib/vendor/symfony/lib/controller/sfController.class.php line 229 ...
             226.       }
             227.
             228.       // process the filter chain
             229.       $filterChain->execute();
             230.     }
             231.     else
             232.     {
    * at sfController->forward('product', 'edit')
      in SF_ROOT_DIR/lib/vendor/symfony/lib/controller/sfFrontWebController.class.php line 48 ...
              45.       }
              46.
              47.       // make the first request
              48.       $this->forward($moduleName, $actionName);
              49.     }
              50.     catch (sfException $e)
              51.     {
    * at sfFrontWebController->dispatch()
      in SF_ROOT_DIR/lib/vendor/symfony/lib/util/sfContext.class.php line 170 ...
             167.    */
             168.   public function dispatch()
             169.   {
             170.     $this->getController()->dispatch();
             171.   }
             172.
             173.   /**
    * at sfContext->dispatch()
      in SF_ROOT_DIR/web/admin_dev.php line 13 ...

It seems that the only action that is wrong is edit.

03/12/10 10:07:16 changed by drashid

Going back to the problem with multiple connections.

I am using symfony 1.4.3 (doctrine 1.2). I have two databases

all:
  db1:
    class: sfDoctrineDatabase
    param:
      dsn: mysql:dbname=db1;host=localhost
      username: root
      password: null

  db2:
    class: sfDoctrineDatabase
    param:
      dsn: mysql:dbname=db2;host=localhost
      username: root
      password: null

But as said in first message “it will always try to use the last connection in the list”.

db1 has a table “table1” now If I use (in Table1Table class)

var_dum($this->getConnection()->getName());

The connection is always db2 (it should not be). The connection should be db1 for table1. And the “baseTable1.class.php” also confirms.

Doctrine_Manager::getInstance()->bindComponent(Table1', 'db1);

Now If I force to use a specific connection it works which is not the right way to it (but this is the only way how it worked),

$conn = Doctrine_Manager::getInstance();
$conn->closeConnection($this->getConnection());
$this->setConnection($conn->getConnection('db1'));

03/12/10 15:56:47 changed by drashid

I think that I have found the problem. The problem is not with multiple connections but with generation of schema.yml using

symfony doctrine:build-schema

for a table “students” this command generates,

Students:
  connection: db1
  tableName: students

Now see the difference in class name that will be “Students” while table name is “students”. And if you see the class baseStudent.class.php it contains,

Doctrine_Manager::getInstance()->bindComponent('Students', 'db1');

So, the doctrine manager binds the component “Students” with “db1”.

Now when we try to access the table “students” the doctrine manager checks the component “students” for a connection using the function "getConnectionForComponent($componentName)" in Manager.php

As doctrine manager never finds a connection for “students” it tries to use the default connection which is the last connection in database.yml and that’s it.

I hope it will help to solve the problem.

03/26/10 20:02:46 changed by Jonathan.Wage

I don't think that is the issue. The $componentName is the Model name, not the table name. So it is passing Students.

04/25/10 01:19:09 changed by Anthonyjs

The model name seems to come from the class name, in PHP this is case insensitive, in Doctrine I am guessing it is case sensitive because table names can be case sensitive?

I had the same problem, eg code generated in actions was lowercase, but generated class's were upper case.

In the doctrine core class the getTable() function calls Doctrine_Manager::getInstance()->getConnectionForComponent() with whatever is passed from the action.

But the Generated Base class calls Doctrine_Manager::getInstance()->bindComponent() with the upper case generated values.

The storage mechanism is an Array(), which will treat the strings "Object" and "object" differently.

I have had similar weird connection issues with fixtures as well, so I put this to the test by making sure all my manual code match case with generated base classes and see if it resolves my connection issues.

05/04/10 16:53:52 changed by Xantos

I'm experiencing (i think) the same problem.

My databases.yml contains two databases (database1 and database2).

My user table looks like:

User:
  connection: database1
  tableName: User
  actAs:
    SoftDelete:
    Versionable:
  columns:
    name:
      type: string(255)
      notnull: true
    email:
      type: string(255)      
      notnull: true

When inserting a record doctrine tries to update the version table. The following error occurs: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'database2.user_version' doesn't exist

06/17/10 17:46:30 changed by menno

Hi, can anybody tell me when this defect is likely to be fixed?

I have an application with multiple db's running on my local machine, mac osx. Works like a charm. But when I upload it to my server (linux) it fails horribly. So could it have something to do with case sensitivity?

Anyway, hope this will be fixed soon, because I'm kind of stuck now...

Keep up the good work!

06/18/10 10:10:28 changed by menno

Correction. After updating symfony 1.4 branche on my mac, it also failed. Reverting back to the stable 1.4.5 tag fixed the problem on both servers.

07/04/10 18:08:51 changed by pluk77

  • milestone set to 1.4.6.

I found that using custom methods in the table classes work like they should and the correct database / connection is chosen.

When the magic functions of doctrine are used, the last connection is used instead of the correct one.

Doctrine::getTable('Patient')->find(1) would use the last one, and therefore not always the correct one.

Doctrine::getTable('Patient')->customFind(1) uses the correct connection.

Because of this, the sfDoctrineGuard plugin does not work like expected as it makes use of magic functions in its code and therefore depending on which connection was used before works or breaks.

All and all, this bug makes using 2 databases completely unusable in combination with sfDoctrineGuard.

(Changing back to 1.4.5 did not work for me.)

07/17/10 14:28:55 changed by Pkamer

Hi all, The patch provided in the following Doctrine ticket fixes this issue: http://www.doctrine-project.org/jira/browse/DC-421

07/18/10 12:32:33 changed by pluk77

Will need to test this as a doubt this patch solves all the problems as the problem seems to be related to the the autoloader failing, resulting in no bound connection.

see http://www.doctrine-project.org/jira/browse/DC-740

07/26/10 20:31:41 changed by pluk77

Sorry, but unfortunately that patch does not work on the latest SVN version of Doctrine. The patch is for version 7038 and the current version is 7668

In the current version, the $conn that was missing in "return Doctrine_Query::create($conn, $class)" has already been replaced by "return Doctrine_Query::create($this->_conn, $class)" and the connection is managed on an object level.

The connection should be set during loading of the class, which is not always happening due to the autoloader failing (see my previos post).

08/25/10 17:37:38 changed by trevor.lanyon

I have been dealing with the same issue. In order to work around it I would revert lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine to a revision before 7667 and it would work without error, or, at least select the right database.

After doing a svn update I received my usual error with Doctrine not being able to select the appropriate connection but when I reverted:

I know get an error:

Fatal error: Class 'Doctrine' not found in ....

I realize that reverting to an such an old version of the Doctrine plugin was probably going to break eventually but I also thought that this issue would be resolved.

Is there any chance of there being an update for this?

08/26/10 13:04:57 changed by pluk77

I had the same issue on our Linux machine. Not sure where the problem is, but it seems the doctrine class is not auto loaded for some reason. Since that class is purely there for backwards compatibility I created a dummy class under the project lib folder that extends the Doctrine_core class. This Doctrine_core class is auto-loaded, so that fixes all problems.

09/23/10 15:13:30 changed by neuromancer

Hi pluk77, please can you give more informations about your workaround.
Thanks and good Symfony developing to all.

09/23/10 21:18:08 changed by pluk77

@neuromacer: Sure I can, although it is a bit off-topic for this specific issue. I created the following file: \lib\model\doctrine\Doctrine.php with the following content:

<?php
class Doctrine extends Doctrine_Core
{
}

This works because the autoloader only loads classes once and the original doctrine_core class is loaded without problems.

09/26/10 13:29:40 changed by heiko

I can confrim this bug for the latest dev branch. It is impossible for me to use more than one database connection. All the suggested patches abvove didn't work for me. The only thing that helped is to change the first letter of the mdule name in the generated doctrine base classes:

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

should be:

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

this is really a blocker and I wonder if anybody is using this nice software in a productive environment, because such bug is open for nearly a year now.

09/27/10 09:09:02 changed by pluk77

@heiko: we are using it in a prod environment and after applying my 2 patches, all works like it should. have a look at this doctrine issue: http://www.doctrine-project.org/jira/browse/DC-740

the doctrine_core patch is to ensure that the the Symfony autoloader is used to load the classes, and the doctrine_manager patch is to ensure the classes are loaded lower case.

This should fix all multiple database related issues, although I have not tested if Migration is actually affected.

09/28/10 00:55:24 changed by heiko

Thanks for your reply. I've applied your doctrine_core patch, but it didn't fixed the issue. But I haven't found anything about a doctrine_manager patch. What I really don't understand is, why aren't these patches integrated into the dev version after such a long time.

09/28/10 08:39:58 changed by pluk77

@heiko: I can only assume that this is because the patches are true hacks. They make the Doctrine plugin dependant on Symfony which is generally a bad idea if you want to use the plugin outside of Symfony.

email me privately and I will assist you with the patches: pluk77 a t gmail d o t com

10/08/10 07:25:51 changed by danielh

Thought I'd throw my 2 cents in here. I have a project which has been running fine on symfony 1.4.6. Tried upgrading to 1.4.8 and i get the table not found error.

So to be clear, I have 2 connections/databases: blog and site. I have symfony 1.4.6 in /lib/vendor/symfony. If i access it via my browser, it all works fine, and has done for a while on a fairly active production site. If i switch lib/vendor/symfony to 1.4.8, i get the table not found error.

I've also tried rebuilding the models and everything, it doesn't work. It appears that in the latest version of doctrine or the doctrine plugin, that the autoloading or loading order has changed somehow. The change means the model (in this case "Region") doesn't get loaded on a Doctrine::getTable('Region') call like it did previously. Because BaseRegion? isn't loaded before the query, the Region model is never bound to the right connection. I can fix it with the following hack:

// forces autoloading of Region model files
new Region();
$regions = Doctrine::getTable('Region')->findAll();

This code works fine under 1.4.8, when i remove the "new Region()" i get the table not found error. BTW the symfony versions I'm using are the SVN tagged versions for 1.4.6 and 1.4.8

10/08/10 14:00:10 changed by pluk77

  • attachment doctrine_core.r7492.patch added.

patch to core.php used in sf 1.4.6

10/08/10 14:00:38 changed by pluk77

  • attachment doctrine_core.r7687.patch added.

patch to core.php used in sf 1.4.8

10/08/10 14:01:14 changed by pluk77

  • attachment doctrine_manager.r7657.patch added.

patch to manager.php used in sf 1.4.6 & sf 1.4.8

10/08/10 14:05:37 changed by pluk77

apply the attached patches to core.php and manager.php, clear the cache, regenerate models and all should be working.

These patches fix the case sensitivity and the autoloading.

We are using it successfully and Heiko can confirm the patches are working as it solved his problems as well.

10/15/10 10:11:52 changed by heiko

Yes. Patches are working perfectly.

But I found another bug which maybe related to this. If you make a join in a dql query over two databases (connections) it will fail, because doctrine doesn't inject the databse prefix to the sql statement.

The only solution seems to be, to use raw-sql queries with the correct db-prefixes.

10/20/10 03:15:52 changed by roylaurie

The patches work fine if you're just using the Symfony plugin for Doctrine.

However, here's a condition that I've ran into twice with two different clients recently:

* Client is using a vanilla (PEAR) installation of Doctrine for many of their command-line apps.

* Client is attempting to use newer Symfony models with older Doctrine models in command-line apps.

* Multiple connections associated with models.

In this situation, vanilla Doctrine's Doctrine_Core class is loaded instead of Symfony's plugin version of it. Patching vanilla Doctrine in the same manner is messy and probably unwanted.

This works, but I don't like doing it:

    public static function modelsAutoload($className)
    {
        if (class_exists($className, false) || interface_exists($className, false)) {
            return false;
        }

        // http://trac.symfony-project.org/ticket/7689
        if (class_exists('sfContext') && sfContext::hasInstance()) {
            sfAutoload::getInstance()->autoload($className);
        }

        if ( ! self::$_modelsDirectory) {

Does anyone have a more elegant solution? This is disgustingly hacky.

11/04/10 17:59:03 changed by scod

hi all, so, to be clear, we need to apply the patches given?

12/04/10 18:20:57 changed by Kris.Wallsmith

  • status changed from reopened to closed.
  • resolution set to duplicate.
  • milestone deleted.

This is a duplicate of #9092.