[DC-373] Relating to Translation table (generated by Doctrine_I18n) doesn't work correctly after resetting connection Created: 20/Dec/09 Updated: 11/Sep/12
|Affects Version/s:||1.2.1, 1.2.2, 1.2.3, 1.2.4|
|Reporter:||Kousuke Ebihara||Assignee:||Jonathan H. Wage|
PHP 5.2.11 (with Suhosin-Patch 0.9.7)
Relating to Translation table (generated by Doctrine_I18n) doesn't work correctly after resetting connection.
First, I defined the following schema.yml::
Next, I prepared the following fixture file::
Next, I run "build-all-reload" task. The table was created and data was loaded.
And I write the following code::
I try executing my code, but I got the following error::
|Comment by Arnaud Charlier [ 02/Nov/10 ]|
First, thanks a lot for your work on Doctrine. It's a real great tool we love to use.
Currently in one of our big application we have exactly the same issue.
Currently we have no solution, but we are still investigating this.
I'm available to go deep in the code with you, but any Doctrine Team help will be really nice.
Thanks to let me know as soon as possible.
|Comment by Joe Siponen [ 27/May/11 ]|
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).
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:
|Comment by Joe Siponen [ 16/Jun/11 ]|
Failing test case attached
|Comment by Kousuke Ebihara [ 08/Jun/12 ]|
Good job, Joe Siponen! Thanks for your nice patch!
I can't understand why the Doctrine team discontinued maintenance of Doctrine 1 without any fixes for some serious issues like this problem...
Joe, would you send your patch by pull-request in GitHub? They might notice this problem and try to fix in official repository by your request. If you cannnot, I will do it as your proxy. (Of course I'm going to describe your credit)
|Comment by Kousuke Ebihara [ 11/Sep/12 ]|
I've tested Joe Siponen's patch, it would be good in a situation of single connection, but it doesn't work in multiple connections.
So I modified your patch to fit my needs. I'm testing my arranged patch and I want to publish it ASAP...