[DC-262] Doctrine_Manager::resetInstance() is not restting all properties Created: 19/Nov/09  Updated: 19/Nov/09  Resolved: 19/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.2.0-BETA3
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Juozas Kaziukenas Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

Calling Doctrine_Manager::resetInstance() resets the instance, however opening a new instance (and new connections) produces an error in the line 221 of Doctrine_Connection:

$this->getAttribute(Doctrine_Core::ATTR_LISTENER)->onOpen($this);

Which is because Doctrine_Manager::setDefaultAttributes() has a static variable $init in that function, hence reset instance is not resetting it and new manager instance looses default attributes.

Proposed fix: move $init variable to the object level.



 Comments   
Comment by Jonathan H. Wage [ 19/Nov/09 ]

This is already fixed in 1.2.0-BETA3





[DC-236] Doctrine_Collection->toHierarchy() : __children field doesn't contain correct children Created: 16/Nov/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Nested Set
Affects Version/s: 1.2.0-BETA1, 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Critical
Reporter: Nate Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

PHP 5.2.9 on Windows Server 2003 with MySQL



 Description   

This bug was discovered while using getDescendants with the new toHierarchy function. Rather than containing the correct child elements in the __children field, it contains whatever the next record is. Each record only has a single child, which is the record with the next-highest lft value. You can see this in the following pastebin. Notice that the very bottom element is placed around level 15 in the tree, yet it should be level 4 according to the "level" field.

The line that was used to produce the above pastebin was:
print_r($children = $file->getNode()>getDescendants(null, false)>toHierarchy()->toArray());
The class used for $file is: http://pastebin.ca/1673706



 Comments   
Comment by Jonathan H. Wage [ 16/Nov/09 ]

Thanks for reporting the issue, it is fixed now.





[DC-235] wrong strpos() check in Doctrine_Cache_Driver::deleteByPrefix() Created: 16/Nov/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Caching
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Christian Schaefer Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

In Doctrine_Cache_Driver::::deleteByPrefix() on line 216 you can read:

if (strpos($key, $prefix) == 0) ...

to check whether the prefix starts on the first position.
As strpos() returns false if the prefix is not found at all and 0 evaluates to false this results to the deletion of unnecessary cache keys.

correct would be:

if (strpos($key, $prefix) === 0) ... // triple '='






[DC-232] Add Doctrine_Record#hasMappedValue() Created: 14/Nov/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Record
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Improvement Priority: Minor
Reporter: Adam Huttler Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File diff.txt    

 Description   

Need a simple method for determining if a mapped value has been defined. The attached diff is against an earlier revision of Doctrine_Record, but it's just a couple of lines of code so it can easily be inserted manually.



 Comments   
Comment by Jonathan H. Wage [ 16/Nov/09 ]

Thanks for reminding us of the needed function.





[DC-230] CLONE [DC-197] default model orderBy option breaks data-load task Created: 13/Nov/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Data Fixtures
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Miloslav "adrive" Kmet Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

currently the default orderBy clause one can specify for models gets added to all queries, including DELETE and UPDATE.
This breaks data-load because it includes in the orderBy the table alias but currently only SELECT queries support aliases.

For example if I have the following schema:

Mytable:
options:

{ orderBy: name ASC }

columns:
name:

{ type: string(100), notnull: true }

The data-load task does a Doctrine::getTable('Mytable')>delete()>execute(); to clear the table before loading the fixtures which results in the following SQL:
DELETE FROM mytable ORDER BY m.name ASC

which errors out as the m alias was not defined.

Attached is the patch that makes only SELECT queries get the default orderBy clause from the option.



 Comments   
Comment by Miloslav "adrive" Kmet [ 13/Nov/09 ]

Sorry, if I did something wrong, but I do not found, how to reopen an issue in JIRA (stil not familiar with it.)

I am using the latest 6725 revision of doctrine with sfDoctrinePlugin, but this issue still exists at least in posgresql:

I have the following error:

{{
kmet@toox /www/dev/mis $ s doctrine:data-load

>> doctrine Loading data fixtures from "/www/dev/mis/data/fixtures"

SQLSTATE[42601]: Syntax error: 7 CHYBA: syntaktická chyba pri alebo v blízkosti "ORDER"

LINE 1: DELETE FROM st_i18n_culture ORDER BY name ASC

^. Failing Query: "DELETE FROM st_i18n_culture ORDER BY name ASC"

}}

I am not using the orderBy: functionality in my models, but my model have the field "name".





[DC-225] Class prefix is not prepended to model subclasses Created: 12/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export, Inheritance
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Nate Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

PHP 5.2.9 on Windows 2003



 Description   

If class prefixes are being used with inheritance, the items in the setSubClasses array do not include the class prefix. I only tested this with column aggregation. Assuming that the prefix is "Default_Model_", the below example generates a "Default_Model_User" and "Default_Model_UserAdmin" class.

Inside the Default_Model_User class, this is generated:
$this->setSubClasses(array('UserAdmin' => array('coursetype' => 1)));

but it should be:
$this->setSubClasses(array('Default_Model_UserAdmin' => array('coursetype' => 1)));

Example schema:

User:
columns:
id:
primary: true
type: integer(4)
unsigned: 1
autoincrement: true
name:
type: string(255)
notnull: true
type:
type: integer(4)
unsigned: 1

UserAdmin:
inheritance:
extends: User
type: column_aggregation
keyField: type
keyValue: 1
columns:
test:
type: integer(1)
unsigned: 1
default: 128






[DC-224] Pear style class generation causes underscores in models_path to be replaced with slashes Created: 12/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Cli, Import/Export
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Minor
Reporter: Nate Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Windows Server 2003



 Description   

In Doctrine/Import/Builder.php, if pear style generation is enabled, underscores are replaced with slashes to create the Pear style directory layout. The code that builder.php uses is below.

if ($this->_pearStyle) {
$writePath = str_replace('_', '/', $writePath);
}

If the models_path contains an underscore, for example "D:\Inetpub_EXT\app\models", the underscore also gets converted to a slash. All of the models end up being created in the "D:\Inetpub\EXT\app\models" directory.






[DC-223] Cloning a query object re-creates hydrator object and loses hydration mode in the process. Created: 12/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Critical
Reporter: Reko Tiira Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File Doctrine_Query.patch    

 Description   

This is obviously wrong since cloning should result in identical object, but why this is such a critical bug is because it breaks setting array hydration for nested set base query, because the query object gets cloned during the fetching of tree. This bug was introduced in revsion 6691 in attempt to fix DC-204. Included is a patch that correctly clones the hydrator instead of resetting its information completely.






[DC-222] Found a reference to deprecated Doctrine class in Doctrine_Sequence_Db2 Created: 12/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: None
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Minor
Reporter: Hendri Smit Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File Doctrine_Sequence_Db2.patch    

 Description   

Should be changed to Doctrine_Core. See attached patch file.






[DC-221] Doctrine_Migration fail when used two times Created: 11/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Migrations
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: thibault duplessis Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

daily symfony 1.3 svn, doctrine 1.2.0-BETA2



 Description   

The second Doctrine_Migration instance is unusable.

It is very easy to reproduce the bug :

// first instance
$migration = new Doctrine_Migration('/path/to/migration/classes');
print_r($migration->getMigrationClasses()); // will work, and show the migration classes as expected

// same code, second instance
$migration = new Doctrine_Migration('/path/to/migration/classes');
print_r($migration->getMigrationClasses()); // will not work. No more migration classes displayed.

This is due to the fact that Doctrine_Migration->loadMigrationClassesFromDirectory only registers classes that are not already loaded :

Doctrine_Migration->loadMigrationClassesFromDirectory
$array = array_diff(get_declared_classes(), $classes);
$className = end($array);

If a migration class is already declared ( ie the second time we use Doctrine_Migration ), it will not be recognized.

Thank you for your great work.



 Comments   
Comment by Jonathan H. Wage [ 12/Nov/09 ]

I fixed Doctrine_Migration but this will still exist if you had previously loaded the class manually.

$array = array_diff(get_declared_classes(), $classes);
$className = end($array);

This is the only way we have to know what class is in a file, since the class name and file name aren't the same thing.





[DC-216] import camelize table names Created: 11/Nov/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: None
Fix Version/s: 1.0.14, 1.1.6, 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Oded Bahar Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

linux / windows


Attachments: File Import.php     File Import.php    

 Description   

after upgrade of doctrine version ( as a part of symfony upgrade) now creates new "camelcase" names insted of the existing classes (e.g. "Tbl_My_Table" replaced to "TblMyTable"), the problematic function is "importSchema" in the attched "Import.php" file. i have added remarks to the lines that creates the the error.



 Comments   
Comment by Oded Bahar [ 11/Nov/09 ]

attached a resolution for this bug. please check and approve if possiable

Comment by Jonathan H. Wage [ 12/Nov/09 ]

This is not a bug, this is how the behavior should be. The className is set to the classified version of the table name. The table is set to what it is in the database. So a table named "table_name" would become a class named "TableName"

Comment by Oded Bahar [ 12/Nov/09 ]

please check previous versions of this file, where classes named "ENT_Table_Names" could be created, if you would change the classes names then you would break the consistency for earlier versions where this was possible,

Comment by Jonathan H. Wage [ 12/Nov/09 ]

What version of Symfony are you using? This behavior has been this way for quite a while. "table_name" becomes a class named "TableName" with the tableName set to "table_name".

Comment by Oded Bahar [ 15/Nov/09 ]

the symfony version was 1.2.2 and we have upgraded to 1.2.9
doctrine current version 1.0.12, upgraded from 1.0.6

The database table name we are using is "ENT_Table_Name".

In the original ImportSchema function, line 385:
$classTable = Doctrine_Inflector::tableize($table);
line 396-397
$relClassTable = Doctrine_Inflector::tableize($table);
$class = Doctrine_Inflector::classify($relClassTable);

tablize would create e_n_t_table_name
and classifiy would rename it to ENT_Table_Name

in the current version importschema line 384:
$definition['tableName'] = $table;
$definition['className'] = Doctrine_Inflector::classify($table);

so the name is replaced to ENTTableName which breaks consistency. i.e. we had ENT_Table_Name (ver 1.06) and now we have ENTTableName (version 1.0.12)

Comment by Jonathan H. Wage [ 16/Nov/09 ]

Ok I see what the issue was. I removed the line of code that first tableizes it.





[DC-215] Invalid fix for DC-204, the clone should take over the hydration mode Created: 11/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Resolved
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Dennis Verspuij Assignee: Guilherme Blanco
Resolution: Duplicate Votes: 0
Labels: None


 Description   

The fix for DC-204 in changeset [6691] is incorrect. I have a model using the nested set plugin. When I set hydration mode HYDRATE_ARRAY on its base query and perform a query objects are returned instead of arrays. I think this is due to the fact that clones of the query should take over the selected hydration mode. Please have a look.



 Comments   
Comment by Dennis Verspuij [ 12/Nov/09 ]

Duplicate of DC-223, now fixed





[DC-213] Doctrine_Import_Schema::parseSchema(): handling of global options in schema definition Created: 11/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Schema Files
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Raphael Schumacher Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

(independent from specific env)



 Description   

Doctrine allows schema files (schema.yml in my case as symfony user) to define global settings that shall be valid for each class (within the same schema file) to be taken as default unless specified otherwise within the class.
However, once an individual class does specify (even only) one single option, none of the global options are being used anymore at all. This is the current implementation as of in Doctrine_Import_Schema::parseSchema(), line 330.
IMHO this implementation makes the feature of rather little benefit for users, particularly because 'options' is an array, even a nested one since symfony 1.3 did introduce their own options therein ('forms' and 'filters').

Following example:

schema.yml
# global settings, as default for all classes
detect_relations:                   false
options:
    type:                           innodb
    collate:                        utf8_unicode_ci
    charset:                        utf8
    symfony:
        form:                       true
        filter:                     true

DocumentSource:
    tableName:                      dk_doc_source
    abstract:                       'Possible sources for documents (code set)'
    options:
        symfony:                    { filter: false }
    actAs:
        Timestampable:              ~
    columns:
        name:                       { type: string(63), notnull: true }
        description:                { type: string(255) }

DocumentType:
    tableName:                      dk_doc_type
    abstract:                       'Allowed types for documents'
    options:
        symfony:                    { form: false, filter: false }
    actAs:
        Timestampable:              ~
    columns:
        name:                       { type: string(63), notnull: true }
        description:                { type: string(255) }

DocumentTag:
    tableName:                      dk_doc_tag
    abstract:                       'Tags for documents'
    actAs:
        Timestampable:              ~
    columns:
        name:                       { type: string(63), notnull: true }
        description:                { type: string(255) }

After an import with the current implementation, the classes end up having the following options:

  • DocumentSource:
        options:                             # taken from the specific class, no global setting was taken over
            symfony:                    { filter: false }
    
  • DocumentType:
        options:                            # taken from the specific class , again no global setting was taken over
            symfony:                    { form: false, filter: false }
    
  • DocumentTag:
    options:                            # taken from the globals
        type:                           innodb
        collate:                        utf8_unicode_ci
        charset:                        utf8
        symfony:
            form:                       true
            filter:                     true
    

As a developer I originally understood the feature in that DocumentSource and DocumentType would still get the global option settings like collate, charset etc without having to repeat them again and again.

  • Like e.g. for DocumentSource:
    options:                            # global and class specific options brought together
        type:                           innodb
        collate:                        utf8_unicode_ci
        charset:                        utf8
        symfony:
            form:                       true
            filter:                     false
    

--> is the effect of the current implementation is intentional?
I.e. I wish to raise the question: shall globals...

  1. only be applicable to an individual class if the latter doesn't specifiy any option at all? (principle of XOR), or
  2. complement the class' individual options, i.e. the developer defines the desired default options as globals, and specifies any difference from that in the individual class? (principle of inheritance).

IMHO as a user of Doctrine & Symfony, I cleary prefer the inheritance principle (2).

A thinkable solution is to use array_replace_recursive() or a similar function instead of a simple assignment:

Doctrine_Import_Schema::parseSchema(); lines 326 - 333
CURRENT:
        // Apply the globals to each table if it does not have a custom value set already
        foreach ($array as $className => $table) {
            foreach ($globals as $key => $value) {
                if ( !isset($array[$className][$key])) {
                    $array[$className][$key] = $value;
                }
            }
        }
PATCH:
        // Apply the globals to each table if it does not have a custom value set already
        foreach ($array as $className => $table) {
            foreach ($globals as $key => $value) {
                   $array[$className][$key] = array_replace_recursive($value, $array[$className][$key]);    // do inherit the global settings
            }
        }

I haven't yet tried out this patch nor even tested it, since anything first depends from a clarification on the common expectations from the feature of globals in schema files.

Cheers, RAPHAEL

PS. update: I created a corresponding issue in Symfony trac.






[DC-212] Doctrine_Node_NestedSet::hasParent() returns true on non-leaf objects. Created: 11/Nov/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Nested Set
Affects Version/s: 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Minor
Reporter: PhazeonPhoenix Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

The code for Doctrine_Node_NestedSet::hasParent() will return true if a Doctrine_Record is not yet a valid node. The code for hasParent() returns the inverse of Doctrine_Node_NestedSet::isRoot() which returns false for both non-root nodes and non-valid nodes. I believe a call to Doctrine_Node_NestedSet::isValidNode() should be included in this function to prevent this issue.






[DC-211] Generated phpdoc relations comments doesn't include classPrefix Created: 11/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Minor
Reporter: Juozas Kaziukenas Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

When generating models like this:

'pearStyle' => true,
'generateTableClasses' => true,
'classPrefix' => 'Model_',
'baseClassPrefix' => 'Base_',
'baseClassesDirectory' => null,
'classPrefixFiles' => false,
'generateAccessors' => false,

Or any other similar style which includes models prefix, comments generated are like this:

/**
* Model_Base_Class
*
* This class has been auto-generated by the Doctrine ORM Framework
*
* @property integer $id
* @property Operators $Operators
*
* @package -
* @subpackage -
* @author -
* @version SVN: $Id: Builder.php 6698 2009-11-10 17:58:02Z jwage $
*/

Problem is with line "@property Operators $Operators" which is incorrect (even though reference is correct in code: "Model_Operators as Operators").

After digging in builder it seems that in lines 628-633 of Doctrine_Import_Builder

if (isset($definition['relations']) && ! empty($definition['relations'])) {
foreach ($definition['relations'] as $relation) {
$type = (isset($relation['type']) && $relation['type'] == Doctrine_Relation::MANY) ? 'Doctrine_Collection':$relation['class'];
$ret[] = '@property ' . $type . ' $' . $relation['alias'];
}
}

Here the $relation['class'] doesn't have full name, even though same key is used in lines 384-395:

$class = isset($relation['class']) ? $relation['class']:$name;
$alias = (isset($relation['alias']) && $relation['alias'] !== $this->_classPrefix . $relation['class']) ? ' as ' . $relation['alias'] : '';

if ( ! isset($relation['type'])) {
$relation['type'] = Doctrine_Relation::ONE;
}

if ($relation['type'] === Doctrine_Relation::ONE)\

Unknown macro: { $ret[$i] = " ".'$this->hasOne('' . $class . $alias . ''';\}

else {
$ret[$i] = " ".'$this->hasMany(\'' . $class . $alias . '\'';
}






[DC-210] PEAR style models generation produces unusable table classes Created: 11/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Import/Export
Affects Version/s: 1.2.0-BETA2
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Blocker
Reporter: Juozas Kaziukenas Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None


 Description   

When generating models like:

'pearStyle' => true,
'generateTableClasses' => true,
'classPrefix' => 'Model_',
'baseClassPrefix' => 'Base_',
'baseClassesDirectory' => 'Base',
'classPrefixFiles' => true

or

'pearStyle' => true,
'generateTableClasses' => true,
'classPrefix' => 'Model_',
'baseClassPrefix' => 'Base_',
'baseClassesDirectory' => 'Base',
'classPrefixFiles' => false

Produced files are like this:

Model_ModelName extends Base_ModelName
Base_ModelName extends Doctrine_Record
ModelNameTable extends Doctrine_Table

Problem is ModelNameTable class is not prefixed with "Model_" and thus cannot be autoloaded.






[DC-209] Compiler includes unnecessary files Created: 10/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Compiler
Affects Version/s: 1.1.5
Fix Version/s: 1.2.0-BETA3

Type: Improvement Priority: Minor
Reporter: Jan Dudek Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None

Attachments: Text File compiler-path.patch    

 Description   

Doctrine Compiler recursively includes all the files it finds under Doctrine::getPath() location, which is the directory that contains Doctrine.php. In some cases it is convenient to put other libraries in the same directory, especially if they also use Zend Framework-like naming scheme. If including any of those files fails, for example because of parse error or not satisified dependency, to whole compilation fails.

The fix changes the directory traversed recursively to Doctrine::getPath().'/Doctrine', so the compiler does not try to include anything unrelated.






[DC-194] Oracle dropDatabase does not work Created: 06/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Connection
Affects Version/s: 1.1.4, 1.1.5
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Igor D'Astolfo Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

Oracle 10 or higher



 Description   

Doctrine_Export_Oracle::dropDatabase does not work, it contains some SQL errors. Here is the patch:

--- Doctrine-1.1.5/lib/Doctrine/Export/Oracle.php	2009-11-03 19:33:04.000000000 +0100
+++ doctrine/Doctrine/Export/Oracle.php	2009-11-06 14:40:46.000000000 +0100
@@ -76,17 +76,19 @@
         $sql[] = "BEGIN
 FOR I IN (select table_name from user_tables)
 LOOP 
-EXECUTE IMMEDIATE 'DROP TABLE '||I.table_name||' CASCADE CONSTRAINTS';
+EXECUTE IMMEDIATE 'DROP TABLE \"'||I.table_name||'\" CASCADE CONSTRAINTS';
 END LOOP;
 END;";
 
         $sql[] = "BEGIN
 FOR I IN (SELECT SEQUENCE_NAME, SEQUENCE_OWNER FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER <> 'SYS')
 LOOP 
-EXECUTE IMMEDIATE 'DROP SEQUENCE '||I.SEQUENCE_OWNER||'.'||I.SEQUENCE_NAME;
+EXECUTE IMMEDIATE 'DROP SEQUENCE \"'||I.SEQUENCE_OWNER||'\".\"'||I.SEQUENCE_NAME||'\"';
 END LOOP;
 END;";





[DC-187] The Unique does not work correctly when using "SoftDelete" Created: 04/Nov/09  Updated: 12/Nov/09  Resolved: 12/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Behaviors
Affects Version/s: 1.1.4, 1.1.5
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Fabian Brussa Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

WindowsXP, WAMP 2.0



 Description   

Scenario:

class User extends Doctrine_Record
{
public function setTableDefinition()

{ $this->hasColumn('username', 'string', 255); $this->hasColumn('email', 'string', 255); $this->unique('username', 'email'); }

public function setUp()

{ $this->actAs('SoftDelete'); }

}

Test:

//create User
$user = new User();
$user->username = 'Fabian';
$user->email = 'fabian@test.com';
$user->save();

...
...
// delete user
$user = Doctrine_Query::create()
->select('*')
->from('User')
->where("id=1")
->fetchOne();
$user->delete(); //this mark as deleted the user (delete_at field)

....
....

//create User with same data
$user = new User();
$user->username = 'Fabian';
$user->email = 'fabian@test.com';
$user->save();

// This throw error by the "unique"



 Comments   
Comment by Jonathan H. Wage [ 10/Nov/09 ]

I think you should add deleted_at to the array of fields to be unique by.

Comment by Fabian Brussa [ 10/Nov/09 ]

Jonathan, but deleted_at is null, therefore can not be part of the array of fields .

I tried adding it does not work, take all the data as different

Comment by Jonathan H. Wage [ 10/Nov/09 ]

I see. If that is the case, I don't see of any way to resolve this. Do you?

Comment by Fabian Brussa [ 10/Nov/09 ]

mmm, if it is possible to know whether the class acts as SoftDelete at the time of validating the unique, could skip if is marked as deleted (deleted_at not null)

Comment by Jonathan H. Wage [ 10/Nov/09 ]

It is not Doctrine, it is the database that throws the error due to the unique index.

Comment by Fabian Brussa [ 11/Nov/09 ]

Jonathan, in the database is not created the unique index, only in definition of the class users with ($this->unique('username', 'email'); )

I'm seeing if is possible to consider the "deleted_at" in then Validate Method in Doctrine_Validator_Unique

Comment by Fabian Brussa [ 11/Nov/09 ]

Adding these lines in the method "validate", class "Doctrine_Validator_Unique", just before a

$stmt  = $table->getConnection()->getDbh()->prepare($sql);

works fine
.

 
$arr = $table->getTemplates();
if ( array_key_exists("Doctrine_Template_SoftDelete",$arr))
{
	$fieldNameDeleteAt = $arr["Doctrine_Template_SoftDelete"]->getOption("name"); 
	$sql .= " AND $fieldNameDeleteAt IS NULL";
}

Be okay to do this here?

Prerequisite: not defined unique index in the database.

Comment by Jonathan H. Wage [ 11/Nov/09 ]

I am not sure, because the unique index is always created in the database. Can you even disable it? So adding this code is useless since the index is created by default and will throw the exception.

Comment by Jonathan H. Wage [ 11/Nov/09 ]

This code:

$this->unique('username', 'email');

Does two things, it adds a unique validator for the columns, but it also adds a unique index in the mapping information which gets created in the database if it supports unique indexes.

Comment by Fabian Brussa [ 11/Nov/09 ]

Hi Jonathan,

Thanks for your swift response!

I understand that the indexes are created automatically in the database and that is what I think should (or could) work differently.

When creating an index for multiple fields in combination with the softdelete I would like to propose to not create the indexes in the database and depend on the doctrine Unique class to handle this. In this case the doctrine Unique class should take into account that softdelete is activated and thus only query the not deleted records to check if they are unique.

I hope you see this as a solution for a common problem and are willing to take it into consideration.

Comment by Jonathan H. Wage [ 12/Nov/09 ]

I would rather not implement specific hacks for individual behaviors. Instead I think we need more generic solutions.

To get around this you can do the following now:

        $this->unique(
            array('username', 'email'),
            array('where' => "deleted_at IS NULL"),
            false
        );

The 2nd argument is an array of options for the unique validator. It already accepted a "where" key so you can add deleted_at IS NULL to the where condition. The 3rd argument "false" is so that it does not create the unique index in the database.





[DC-183] Undefined constant Doctrine_Core::ATTR_DEFAULT_TEXTFLD_LENGTH Created: 04/Nov/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Native SQL
Affects Version/s: 1.2.0-BETA1
Fix Version/s: 1.2.0-BETA3

Type: Bug Priority: Blocker
Reporter: Juozas Kaziukenas Assignee: Jonathan H. Wage
Resolution: Fixed Votes: 0
Labels: None
Environment:

All



 Description   

File http://trac.doctrine-project.org/browser/branches/1.2/lib/Doctrine/DataDict/Sqlite.php

Contains undefined constant Doctrine_Core::ATTR_DEFAULT_TEXTFLD_LENGTH which breaks generation of sql for sqlite

Proposed fix: use $this->conn->options['default_text_field_length'] ?



 Comments   
Comment by Juozas Kaziukenas [ 13/Nov/09 ]

I've tested it again and now it seems to be broken in that same line.

Now in 76 line of Doctrine_DataDict_Sqlite I need to use:

return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$this->conn->varchar_max_length.')')

Which I found in Mysql datadict, even though Mssql uses:

return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$this->conn->options['default_text_field_length'].')')

Which won't work because there is no options in conn.

Using rev6721

Comment by Juozas Kaziukenas [ 13/Nov/09 ]

It is caused by the fact that $options in connection are (now?) protected, hence cannot be accessed like that. There is way to access them by:

return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$this->conn->getOption('default_text_field_length').')')

But key doesn't exist and return value is null.





[DC-145] Invalid parameter number: number of bound variables does not match number of tokens Created: 27/Oct/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Query
Affects Version/s: 1.0.13, 1.1.4
Fix Version/s: 1.0.14, 1.1.6, 1.2.0-BETA3

Type: Bug Priority: Critical
Reporter: Amir W Assignee: Guilherme Blanco
Resolution: Fixed Votes: 8
Labels: None

Attachments: GIF File ScreenHunter_01 Nov. 16 17.50.gif    

 Description   

Please see description posted on Doctrine's group:
http://groups.google.com/group/doctrine-user/browse_thread/thread/6cc308526e5ab075



 Comments   
Comment by Jonathan H. Wage [ 27/Oct/09 ]

Possible to give some more information? Code you're using to produce the error. We need to be able to produce the issue with some code in order to fix it. If you could make a test case that will help us. Otherwise it is very difficult to fix an issue blindly Thanks. Something that also helps is singling out the revision that caused the problem.

Comment by Bill Hunt [ 27/Oct/09 ]

I've discovered the same issue, with the symfony doctrine plugin Revision 23394. I just updated to the latest version and a "andWhereNotIn" clause which worked perfectly before is now failing -

$q->andWhereNotIn('hr.providerid', $ignoreProviderIds);

where $ignoreProviderIds = array('51', '31');

The stack trace is making it look like it's repeating the parameters somehow? Note the "'51', '31', '51', '31'" line below...

  1. at ()
    in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Connection.php line 1086 ...

1083.
1084. $name = 'Doctrine_Connection_' . $this->driverName . '_Exception';
1085.
1086. $exc = new $name($e->getMessage(), (int) $e->getCode());
1087. if ( ! isset($e->errorInfo) || ! is_array($e->errorInfo))

{ 1088. $e->errorInfo = array(null, null, null, null); 1089. }
  1. at Doctrine_Connection->rethrowException(object('PDOException'), object('Doctrine_Connection_Statement'))
    in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Connection/Statement.php line 253 ...

250. } catch (Doctrine_Adapter_Exception $e)

{ 251. }

252.
253. $this->_conn->rethrowException($e, $this);
254.
255. return false;
256. }

  1. at Doctrine_Connection_Statement->execute(array('51', '31', '51', '31'))
    in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Connection.php line 1014 ...

1011. try {
1012. if ( ! empty($params))

{ 1013. $stmt = $this->prepare($query); 1014. $stmt->execute($params); 1015. 1016. return $stmt; 1017. }

else

{ # at Doctrine_Connection->execute('SELECT DISTINCT h6.hotelid, COUNT(h10.hotelid) AS h10__0 FROM hotel h6 LEFT JOIN hotelDetails h7 ON h6.hotelid = h7.hotelid LEFT JOIN hotelProvider h8 ON h6.hotelid = h8.hotelid LEFT JOIN hotelPriceDetails h9 ON h6.hotelid = h9.hotelid LEFT JOIN location l4 ON h6.locationid = l4.locationid LEFT JOIN location l5 ON h6.locationid = l5.locationid LEFT JOIN locationAdmin1Code l6 ON l5.admin1codeid = l6.locationadmin1codeid LEFT JOIN hotelRating h10 ON h6.hotelid = h10.hotelid WHERE h6.hotelrating >= 3.0 AND h6.hotelrating < 5 AND h6.hotellatitude IS NOT NULL AND h6.hotellatitude != 0 AND h6.hotellongitude IS NOT NULL AND h6.hotellongitude != 0 AND h9.hotelavgminprice < 500 AND h6.hotelstars >= 2 AND h6.locationid = 33033 AND h10.providerid NOT IN (?, ?) GROUP BY h6.hotelid HAVING h10__0 > 0 ORDER BY h6.hotelrating desc LIMIT 3', array('51', '31', '51', '31')) in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Query.php line 1155 ... 1152. $this->useQueryCache(false); 1153. 1154. // mysql doesn't support LIMIT in subqueries 1155. $list = $this->_conn->execute($subquery, $this->getParams($params))->fetchAll(Doctrine::FETCH_COLUMN); 1156. $subquery = implode(', ', array_map(array($this->_conn, 'quote'), $list)); 1157. 1158. break; # at Doctrine_Query->getSqlQuery(array('51', '31')) in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Query/Abstract.php line 977 ... 974. }

975. }
976. } else

{ 977. $query = $this->getSqlQuery($params); 978. }

979. } else

{ 980. $query = $this->_view->getSelectSql(); # at Doctrine_Query_Abstract->_execute(array('51', '31')) in SF_ROOT_DIR/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Query/Abstract.php line 1036 ... 1033. $result = $this->_constructQueryFromCache($cached); 1034. }

1035. } else {
1036. $stmt = $this->_execute($params);
1037.
1038. if (is_integer($stmt)) {
1039. $result = $stmt;

  1. at Doctrine_Query_Abstract->execute()
    in SF_ROOT_DIR/apps/frontend/modules/common/actions/components.class.php line 1129 ...
Comment by Bill Hunt [ 27/Oct/09 ]

Here's a diff of the changes that seem to be problematic:

sfDoctrinePlugin/lib/doctrine/Doctrine/Query.php

< * $Id: Query.php 6564 2009-10-23 18:21:16Z jwage $

> * $Id: Query.php 6407 2009-09-24 21:38:36Z guilhermeblanco $
329,330d328
< } else if ( ! ($this->_conn->getAttribute(Doctrine::ATTR_PORTABILITY) & Doctrine::PORTABILITY_EXPR)){
< return $dqlAlias;
1155c1153
< $list = $this->_conn->execute($subquery, $this->getParams($params))->fetchAll(Doctrine::FETCH_COLUMN);

> $list = $this->_conn->execute($subquery, $params)->fetchAll(Doctrine::FETCH_COLUMN);

Comment by Aurélien Appéré [ 04/Nov/09 ]

The problem comes from what Bill Hunt says.
Tha fact is that parameters ($params) are duplicated by function getParams($params).

Comment by Oncle Tom [ 05/Nov/09 ]

I also encouter it and it's really blocking (as exception is thrown, failing page to display).

The most "funny" things it does not always happen (even though I have it through sfDoctrinePager).
But clearly, I encountered it on parts of code I have not changed since months.

Comment by Eugeniy Belyaev [ 05/Nov/09 ]

For me it happens when I'm trying to 'limit' the query. Query is complicated and contains joins, 'where' conditions, grouping and 'havings'.
And now it fails with duplicating bound params. Right after last subversion update and only when 'limiting'.

Comment by Eugeniy Belyaev [ 05/Nov/09 ]

Oh. Forgot to say - I'm using 1.0 version (which comes with symfony 1.2)

Comment by Bill Hunt [ 05/Nov/09 ]

As a temporary fix, I've downgraded the file in question on my site until the bug is patched. This may help some of you:

svn update -r 6407 symfony/plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Query.php

You may need to modify your path to suit your own needs, of course.

Comment by François Hucliez [ 06/Nov/09 ]

same problems since I have updated, yesterday (11/05).
I observe in the stack trace a parameters duplication, with a special effect when parameter value is zero (see "array(0, )") :

at Doctrine_Connection->execute('SELECT DISTINCT c3.id FROM contact c3 LEFT JOIN adresse_contact a2 ON c3.id = a2.contact_id LEFT JOIN etablissement e3 ON a2.etablissement_id = e3.id LEFT JOIN centre c4 ON a2.centre_id = c4.id LEFT JOIN email_contact e4 ON c3.id = e4.contact_id WHERE c3.non_valide = ? ORDER BY c3.nom, c3.prenom, c3.id LIMIT 16', array(0, ))
in SF_ROOT_DIR\lib\vendor\symfony\lib\plugins\sfDoctrinePlugin\lib\vendor\doctrine\Doctrine\Query.php line 1155

I just add this comment to say - like Eugeniy- I'm using 1.0.13 version (Revision: 6645) wich comes with symfony 1.2.9DEV

Comment by Simon Gow [ 09/Nov/09 ]

I've got the same problem, which seems to only affect the query when a limit is applied. (same reasons as above).

I'd probably revert the revision, but specifically you can fix it with

in Query.php 1155 removing $this->getParams($params) to $params

$list = $this->_conn->execute($subquery, $params)->fetchAll(Doctrine::FETCH_COLUMN);

and moving $q = $this->getCountQuery();

from 1930 to 1937 after $params = $this->_conn->convertBooleans($params);

Comment by Eugeniy Belyaev [ 10/Nov/09 ]

I think it's critical, isn't it?

Comment by Eugeniy Belyaev [ 12/Nov/09 ]

This bug affects sympal too

Comment by Etienne VOILLIOT [ 16/Nov/09 ]

Some informations to solve the problem : $this->getParams($params) merge arrays, and values are duplicated

Comment by Jonathan H. Wage [ 16/Nov/09 ]

This was already fixed in all versions in SVN. The fix will be in the next scheduled releases.





[DC-36] Pager brakes joins with "with" keyword Created: 17/Sep/09  Updated: 16/Nov/09  Resolved: 16/Nov/09

Status: Closed
Project: Doctrine 1
Component/s: Pager, Query
Affects Version/s: None
Fix Version/s: 1.1.6, 1.2.0-BETA3

Type: Bug Priority: Major
Reporter: Ivo Võsa Assignee: Guilherme Blanco
Resolution: Fixed Votes: 1
Labels: None

Attachments: File debug.yml     File schema.yml     File test.php    

 Description   

Extra join condition get applied multiple times so i get error: 'SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens'

Problem seems to be related to change http://trac.doctrine-project.org/changeset/5550

What happens now is Doctrine_Query::_buildSqlFromPart() gets executed 3 times.
First time correctly with $ignorePending == false, second time correctly with $ignorePending == true and third time wrongly with $ignorePending == false.



 Comments   
Comment by Jonathan H. Wage [ 17/Sep/09 ]

What version of 1.1 are you using?

Comment by Ivo Võsa [ 18/Sep/09 ]

Sandbox 1.1.3 and I also did 'svn co http://svn.doctrine-project.org/branches/1.1/'

Comment by Ivo Võsa [ 18/Sep/09 ]

As i did some debuging yesterday i'll post results:

debug_print_backtace(); done at Doctrine_query::_buildSqlFromPart()

#0  Doctrine_Query->_buildSqlFromPart() called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Query.php:1233]
#1  Doctrine_Query->getSqlQuery() called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Query.php:1959]
#2  Doctrine_Query->getCountQuery() called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Query.php:2055]
#3  Doctrine_Query->count(Array ()) called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Pager.php:109]
#4  Doctrine_Pager->_initialize(Array ()) called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Pager.php:571]
#5  Doctrine_Pager->execute() called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/test.php:23]

#0  Doctrine_Query->_buildSqlFromPart(1) called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Query.php:1973]
#1  Doctrine_Query->getCountQuery() called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Query.php:2055]
#2  Doctrine_Query->count(Array ()) called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Pager.php:109]
#3  Doctrine_Pager->_initialize(Array ()) called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Pager.php:571]
#4  Doctrine_Pager->execute() called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/test.php:23]

#0  Doctrine_Query->_buildSqlFromPart() called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Query.php:1233]
#1  Doctrine_Query->getSqlQuery(Array ()) called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Query/Abstract.php:1076]
#2  Doctrine_Query_Abstract->_execute(Array ()) called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Query/Abstract.php:1142]
#3  Doctrine_Query_Abstract->execute(Array (), ) called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/lib/Doctrine/Pager.php:574]
#4  Doctrine_Pager->execute() called at [/home/iff/Desktop/Doctrine-1.1.3-Sandbox/test.php:23]

That lead me to following interesting parts in the code.

Doctrine_Query.php line 1959

    public function getCountQuery()
    {
        // triggers dql parsing/processing
        $this->getSqlQuery(); // this is ugly

Doctrine_Query.php line 1126

    protected function _processPendingJoinConditions($alias)
    {
        $parts = array();

        if ($alias !== null && isset($this->_pendingJoinConditions[$alias])) {
            $parser = new Doctrine_Query_JoinCondition($this, $this->_tokenizer);

            foreach ($this->_pendingJoinConditions[$alias] as $joinCondition) {
                $parts[] = $parser->parse($joinCondition);
            }

            // FIX #1860 and #1876: Cannot unset them, otherwise query cannot be reused later
            //unset($this->_pendingJoinConditions[$alias]);
        }

Doctrine_Query.php line 1033

    protected function _buildSqlFromPart($ignorePending = false)

So the problem should be obvious now. But what is the solution? Adding bunch of $ignorePending parameters to functions or object properties, so that pager can set it, when it executes does not seem right.

Comment by Ivo Võsa [ 18/Sep/09 ]

P.S. And in case someone is having same problem. Quick "solution" to get it working is changing

$q->from('User u')
    ->leftJoin('u.UserGroup g WITH g.status = ?', $status);

to

$q->from('User u')
    ->leftJoin('u.UserGroup g WITH g.status = ' . (int)$status);

it still produces query like "AND (u2.status = 0) AND (u2.status = 0)" but you won't get exception this way.

Comment by Nicholas Kasyanov [ 22/Sep/09 ]

http://www.doctrine-project.org/jira/browse/DC-48 I think it is same problem

Comment by Jonathan H. Wage [ 24/Sep/09 ]

This is fixed by http://trac.doctrine-project.org/changeset/6400





Generated at Thu Apr 24 10:14:17 UTC 2014 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.