Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
doctrine-dbal
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tomáš Trávníček
doctrine-dbal
Commits
827755af
Commit
827755af
authored
May 16, 2007
by
zYne
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
--no commit message
--no commit message
parent
82ba74e2
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
54 additions
and
2609 deletions
+54
-2609
Collection.php
draft/new-core/Collection.php
+0
-632
Hydrate.php
draft/new-core/Hydrate.php
+0
-633
Query.php
draft/new-core/Query.php
+0
-1294
Collection.php
lib/Doctrine/Collection.php
+9
-1
Connection.php
lib/Doctrine/Connection.php
+0
-2
UnitOfWork.php
lib/Doctrine/Connection/UnitOfWork.php
+20
-9
Query.php
lib/Doctrine/Query.php
+4
-4
Check.php
lib/Doctrine/Query/Check.php
+2
-2
Association.php
lib/Doctrine/Relation/Association.php
+4
-0
HydrateTestCase.php
tests/HydrateTestCase.php
+0
-8
RecordTestCase.php
tests/RecordTestCase.php
+11
-20
UnitTestCase.php
tests/UnitTestCase.php
+4
-4
No files found.
draft/new-core/Collection.php
deleted
100644 → 0
View file @
82ba74e2
<?php
/*
* $Id: Collection.php 1207 2007-03-31 19:49:23Z zYne $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
Doctrine
::
autoload
(
'Doctrine_Access'
);
/**
* Doctrine_Collection
* Collection of Doctrine_Record objects.
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision: 1207 $
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class
Doctrine_Collection2
extends
Doctrine_Collection
implements
Countable
,
IteratorAggregate
,
Serializable
{
/**
* @var array $data an array containing the records of this collection
*/
protected
$data
=
array
();
/**
* @var Doctrine_Table $table each collection has only records of specified table
*/
protected
$_table
;
/**
* @var array $_snapshot a snapshot of the fetched data
*/
protected
$_snapshot
=
array
();
/**
* @var Doctrine_Record $reference collection can belong to a record
*/
protected
$reference
;
/**
* @var string $referenceField the reference field of the collection
*/
protected
$referenceField
;
/**
* @var Doctrine_Relation the record this collection is related to, if any
*/
protected
$relation
;
/**
* @var string $keyColumn the name of the column that is used for collection key mapping
*/
protected
$keyColumn
;
/**
* @var Doctrine_Null $null used for extremely fast null value testing
*/
protected
static
$null
;
/**
* constructor
*
* @param Doctrine_Table|string $table
*/
public
function
__construct
(
$table
)
{
if
(
!
(
$table
instanceof
Doctrine_Table
))
{
$table
=
Doctrine_Manager
::
getInstance
()
->
getTable
(
$table
);
}
$this
->
_table
=
$table
;
$name
=
$table
->
getAttribute
(
Doctrine
::
ATTR_COLL_KEY
);
if
(
$name
!==
null
)
{
$this
->
keyColumn
=
$name
;
}
}
/**
* initNullObject
* initializes the null object for this collection
*
* @return void
*/
public
static
function
initNullObject
(
Doctrine_Null
$null
)
{
self
::
$null
=
$null
;
}
/**
* getTable
* returns the table this collection belongs to
*
* @return Doctrine_Table
*/
public
function
getTable
()
{
return
$this
->
_table
;
}
/**
* this method is automatically called when this Doctrine_Collection is serialized
*
* @return array
*/
public
function
serialize
()
{
$vars
=
get_object_vars
(
$this
);
unset
(
$vars
[
'reference'
]);
unset
(
$vars
[
'reference_field'
]);
unset
(
$vars
[
'relation'
]);
unset
(
$vars
[
'expandable'
]);
unset
(
$vars
[
'expanded'
]);
unset
(
$vars
[
'generator'
]);
$vars
[
'table'
]
=
$vars
[
'table'
]
->
getComponentName
();
return
serialize
(
$vars
);
}
/**
* unseralize
* this method is automatically called everytime a Doctrine_Collection object is unserialized
*
* @return void
*/
public
function
unserialize
(
$serialized
)
{
$manager
=
Doctrine_Manager
::
getInstance
();
$connection
=
$manager
->
getCurrentConnection
();
$array
=
unserialize
(
$serialized
);
foreach
(
$array
as
$name
=>
$values
)
{
$this
->
$name
=
$values
;
}
$this
->
_table
=
$connection
->
getTable
(
$this
->
_table
);
$this
->
expanded
=
array
();
$this
->
expandable
=
true
;
$name
=
$this
->
_table
->
getAttribute
(
Doctrine
::
ATTR_COLL_KEY
);
if
(
$name
!==
null
)
{
$this
->
keyColumn
=
$name
;
}
}
/**
* setKeyColumn
* sets the key column for this collection
*
* @param string $column
* @return Doctrine_Collection
*/
public
function
setKeyColumn
(
$column
)
{
$this
->
keyColumn
=
$column
;
return
$this
;
}
/**
* getKeyColumn
* returns the name of the key column
*
* @return string
*/
public
function
getKeyColumn
()
{
return
$this
->
column
;
}
/**
* getData
* returns all the records as an array
*
* @return array
*/
public
function
getData
()
{
return
$this
->
data
;
}
/**
* getFirst
* returns the first record in the collection
*
* @return mixed
*/
public
function
getFirst
()
{
return
reset
(
$this
->
data
);
}
/**
* getLast
* returns the last record in the collection
*
* @return mixed
*/
public
function
getLast
()
{
return
end
(
$this
->
data
);
}
/**
* setReference
* sets a reference pointer
*
* @return void
*/
public
function
setReference
(
Doctrine_Record
$record
,
Doctrine_Relation
$relation
)
{
$this
->
reference
=
$record
;
$this
->
relation
=
$relation
;
if
(
$relation
instanceof
Doctrine_Relation_ForeignKey
||
$relation
instanceof
Doctrine_Relation_LocalKey
)
{
$this
->
referenceField
=
$relation
->
getForeign
();
$value
=
$record
->
get
(
$relation
->
getLocal
());
foreach
(
$this
->
getNormalIterator
()
as
$record
)
{
if
(
$value
!==
null
)
{
$record
->
set
(
$this
->
referenceField
,
$value
,
false
);
}
else
{
$record
->
set
(
$this
->
referenceField
,
$this
->
reference
,
false
);
}
}
}
elseif
(
$relation
instanceof
Doctrine_Relation_Association
)
{
}
}
/**
* getReference
*
* @return mixed
*/
public
function
getReference
()
{
return
$this
->
reference
;
}
/**
* remove
* removes a specified collection element
*
* @param mixed $key
* @return boolean
*/
public
function
remove
(
$key
)
{
if
(
!
isset
(
$this
->
data
[
$key
]))
{
$this
->
expand
(
$key
);
throw
new
Doctrine_Collection_Exception
(
'Unknown key '
.
$key
);
}
$removed
=
$this
->
data
[
$key
];
unset
(
$this
->
data
[
$key
]);
return
$removed
;
}
/**
* contains
* whether or not this collection contains a specified element
*
* @param mixed $key the key of the element
* @return boolean
*/
public
function
contains
(
$key
)
{
return
isset
(
$this
->
data
[
$key
]);
}
/**
* get
* returns a record for given key
*
* There are two special cases:
*
* 1. if null is given as a key a new record is created and attached
* at the end of the collection
*
* 2. if given key does not exist, then a new record is create and attached
* to the given key
*
* Collection also maps referential information to newly created records
*
* @param mixed $key the key of the element
* @return Doctrine_Record return a specified record
*/
public
function
get
(
$key
)
{
if
(
$key
===
null
||
!
isset
(
$this
->
data
[
$key
]))
{
$record
=
$this
->
_table
->
create
();
if
(
isset
(
$this
->
referenceField
))
{
$record
->
set
(
$this
->
referenceField
,
$this
->
reference
,
false
);
}
$this
->
data
[]
=
$record
;
return
$record
;
}
return
$this
->
data
[
$key
];
}
/**
* @return array an array containing all primary keys
*/
public
function
getPrimaryKeys
()
{
$list
=
array
();
$name
=
$this
->
_table
->
getIdentifier
();
foreach
(
$this
->
data
as
$record
)
{
if
(
is_array
(
$record
)
&&
isset
(
$record
[
$name
]))
{
$list
[]
=
$record
[
$name
];
}
else
{
$list
[]
=
$record
->
getIncremented
();
}
}
return
$list
;
}
/**
* returns all keys
* @return array
*/
public
function
getKeys
()
{
return
array_keys
(
$this
->
data
);
}
/**
* count
* this class implements interface countable
* returns the number of records in this collection
*
* @return integer
*/
public
function
count
()
{
return
count
(
$this
->
data
);
}
/**
* set
* @param integer $key
* @param Doctrine_Record $record
* @return void
*/
public
function
set
(
$key
,
Doctrine_Record
$record
)
{
if
(
isset
(
$this
->
referenceField
))
{
$record
->
set
(
$this
->
referenceField
,
$this
->
reference
,
false
);
}
$this
->
data
[
$key
]
=
$record
;
}
/**
* adds a record to collection
* @param Doctrine_Record $record record to be added
* @param string $key optional key for the record
* @return boolean
*/
public
function
add
(
Doctrine_Record
$record
,
$key
=
null
)
{
if
(
isset
(
$this
->
referenceField
))
{
$record
->
set
(
$this
->
referenceField
,
$this
->
reference
,
false
);
}
/**
* for some weird reason in_array cannot be used here (php bug ?)
*
* if used it results in fatal error : [ nesting level too deep ]
*/
foreach
(
$this
->
data
as
$val
)
{
if
(
$val
===
$record
)
{
return
false
;
}
}
if
(
isset
(
$key
))
{
if
(
isset
(
$this
->
data
[
$key
]))
{
return
false
;
}
$this
->
data
[
$key
]
=
$record
;
return
true
;
}
if
(
isset
(
$this
->
keyColumn
))
{
$value
=
$record
->
get
(
$this
->
keyColumn
);
if
(
$value
===
null
)
{
throw
new
Doctrine_Collection_Exception
(
"Couldn't create collection index. Record field '"
.
$this
->
keyColumn
.
"' was null."
);
}
$this
->
data
[
$value
]
=
$record
;
}
else
{
$this
->
data
[]
=
$record
;
}
return
true
;
}
/**
* loadRelated
*
* @param mixed $name
* @return boolean
*/
public
function
loadRelated
(
$name
=
null
)
{
$list
=
array
();
$query
=
new
Doctrine_Query
(
$this
->
_table
->
getConnection
());
if
(
!
isset
(
$name
))
{
foreach
(
$this
->
data
as
$record
)
{
$value
=
$record
->
getIncremented
();
if
(
$value
!==
null
)
{
$list
[]
=
$value
;
}
};
$query
->
from
(
$this
->
_table
->
getComponentName
()
.
'('
.
implode
(
", "
,
$this
->
_table
->
getPrimaryKeys
())
.
')'
);
$query
->
where
(
$this
->
_table
->
getComponentName
()
.
'.id IN ('
.
substr
(
str_repeat
(
"?, "
,
count
(
$list
)),
0
,
-
2
)
.
')'
);
return
$query
;
}
$rel
=
$this
->
_table
->
getRelation
(
$name
);
if
(
$rel
instanceof
Doctrine_Relation_LocalKey
||
$rel
instanceof
Doctrine_Relation_ForeignKey
)
{
foreach
(
$this
->
data
as
$record
)
{
$list
[]
=
$record
[
$rel
->
getLocal
()];
}
}
else
{
foreach
(
$this
->
data
as
$record
)
{
$value
=
$record
->
getIncremented
();
if
(
$value
!==
null
)
{
$list
[]
=
$value
;
}
}
}
$dql
=
$rel
->
getRelationDql
(
count
(
$list
),
'collection'
);
$coll
=
$query
->
query
(
$dql
,
$list
);
$this
->
populateRelated
(
$name
,
$coll
);
}
/**
* populateRelated
*
* @param string $name
* @param Doctrine_Collection $coll
* @return void
*/
public
function
populateRelated
(
$name
,
Doctrine_Collection
$coll
)
{
$rel
=
$this
->
_table
->
getRelation
(
$name
);
$table
=
$rel
->
getTable
();
$foreign
=
$rel
->
getForeign
();
$local
=
$rel
->
getLocal
();
if
(
$rel
instanceof
Doctrine_Relation_LocalKey
)
{
foreach
(
$this
->
data
as
$key
=>
$record
)
{
foreach
(
$coll
as
$k
=>
$related
)
{
if
(
$related
[
$foreign
]
==
$record
[
$local
])
{
$this
->
data
[
$key
]
->
setRelated
(
$name
,
$related
);
}
}
}
}
elseif
(
$rel
instanceof
Doctrine_Relation_ForeignKey
)
{
foreach
(
$this
->
data
as
$key
=>
$record
)
{
if
(
!
$record
->
exists
())
{
continue
;
}
$sub
=
new
Doctrine_Collection
(
$table
);
foreach
(
$coll
as
$k
=>
$related
)
{
if
(
$related
[
$foreign
]
==
$record
[
$local
])
{
$sub
->
add
(
$related
);
$coll
->
remove
(
$k
);
}
}
$this
->
data
[
$key
]
->
setRelated
(
$name
,
$sub
);
}
}
elseif
(
$rel
instanceof
Doctrine_Relation_Association
)
{
$identifier
=
$this
->
_table
->
getIdentifier
();
$asf
=
$rel
->
getAssociationFactory
();
$name
=
$table
->
getComponentName
();
foreach
(
$this
->
data
as
$key
=>
$record
)
{
if
(
!
$record
->
exists
())
{
continue
;
}
$sub
=
new
Doctrine_Collection
(
$table
);
foreach
(
$coll
as
$k
=>
$related
)
{
if
(
$related
->
get
(
$local
)
==
$record
[
$identifier
])
{
$sub
->
add
(
$related
->
get
(
$name
));
}
}
$this
->
data
[
$key
]
->
setRelated
(
$name
,
$sub
);
}
}
}
/**
* getNormalIterator
* returns normal iterator - an iterator that will not expand this collection
*
* @return Doctrine_Iterator_Normal
*/
public
function
getNormalIterator
()
{
return
new
Doctrine_Collection_Iterator_Normal
(
$this
);
}
/**
* takeSnapshot
* takes a snapshot from this collection
*
* snapshots are used for diff processing, for example
* when a fetched collection has three elements, then two of those
* are being removed the diff would contain one element
*
* Doctrine_Collection::save() attaches the diff with the help of last
* snapshot.
*
* @return Doctrine_Collection
*/
public
function
takeSnapshot
()
{
$this
->
_snapshot
=
$this
->
data
;
return
$this
;
}
/**
* getSnapshot
* returns the data of the last snapshot
*
* @return array returns the data in last snapshot
*/
public
function
getSnapshot
()
{
return
$this
->
_snapshot
;
}
/**
* processDiff
* processes the difference of the last snapshot and the current data
*
* an example:
* Snapshot with the objects 1, 2 and 4
* Current data with objects 2, 3 and 5
*
* The process would:
* 1. remove object 4
* 2. add objects 3 and 5
*
* @return Doctrine_Collection
*/
public
function
processDiff
()
{
foreach
(
array_diff
(
$this
->
snapshot
,
$this
->
data
)
as
$record
)
{
$record
->
delete
();
}
foreach
(
array_diff
(
$this
->
data
,
$this
->
snapshot
)
as
$record
)
{
$record
->
save
();
}
return
$this
;
}
/**
* save
* saves all records of this collection
*
* @return Doctrine_Collection
*/
public
function
save
(
Doctrine_Connection
$conn
=
null
)
{
if
(
$conn
==
null
)
{
$conn
=
$this
->
_table
->
getConnection
();
}
$conn
->
beginTransaction
();
foreach
(
$this
as
$key
=>
$record
)
{
$record
->
save
(
$conn
);
}
$conn
->
commit
();
return
$this
;
}
/**
* delete
* single shot delete
* deletes all records from this collection
* and uses only one database query to perform this operation
*
* @return Doctrine_Collection
*/
public
function
delete
(
Doctrine_Connection
$conn
=
null
)
{
if
(
$conn
==
null
)
{
$conn
=
$this
->
_table
->
getConnection
();
}
$conn
->
beginTransaction
();
foreach
(
$this
as
$key
=>
$record
)
{
$record
->
delete
(
$conn
);
}
$conn
->
commit
();
$this
->
data
=
array
();
return
$this
;
}
/**
* getIterator
* @return object ArrayIterator
*/
public
function
getIterator
()
{
$data
=
$this
->
data
;
return
new
ArrayIterator
(
$data
);
}
/**
* returns a string representation of this object
*/
public
function
__toString
()
{
return
Doctrine_Lib
::
getCollectionAsString
(
$this
);
}
}
draft/new-core/Hydrate.php
deleted
100644 → 0
View file @
82ba74e2
<?php
/*
* $Id: Hydrate.php 1255 2007-04-16 14:43:12Z pookey $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_Hydrate is a base class for Doctrine_RawSql and Doctrine_Query.
* Its purpose is to populate object graphs.
*
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision: 1255 $
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class
Doctrine_Hydrate2
{
/**
* QUERY TYPE CONSTANTS
*/
/**
* constant for SELECT queries
*/
const
SELECT
=
0
;
/**
* constant for DELETE queries
*/
const
DELETE
=
1
;
/**
* constant for UPDATE queries
*/
const
UPDATE
=
2
;
/**
* constant for INSERT queries
*/
const
INSERT
=
3
;
/**
* constant for CREATE queries
*/
const
CREATE
=
4
;
/**
* @var array $params query input parameters
*/
protected
$params
=
array
();
/**
* @var Doctrine_Connection $conn Doctrine_Connection object
*/
protected
$conn
;
/**
* @var Doctrine_View $view Doctrine_View object
*/
protected
$view
;
/**
* @var array $_aliasMap two dimensional array containing the map for query aliases
* Main keys are component aliases
*
* table table object associated with given alias
*
* relation the relation object owned by the parent
*
* parent the alias of the parent
*/
protected
$_aliasMap
=
array
();
/**
* @var array $tableAliases
*/
protected
$tableAliases
=
array
();
/**
*
*/
protected
$pendingAggregates
=
array
();
/**
*
*/
protected
$subqueryAggregates
=
array
();
/**
* @var array $aggregateMap an array containing all aggregate aliases, keys as dql aliases
* and values as sql aliases
*/
protected
$aggregateMap
=
array
();
/**
* @var Doctrine_Hydrate_Alias $aliasHandler
*/
protected
$aliasHandler
;
/**
* @var array $parts SQL query string parts
*/
protected
$parts
=
array
(
'select'
=>
array
(),
'from'
=>
array
(),
'set'
=>
array
(),
'join'
=>
array
(),
'where'
=>
array
(),
'groupby'
=>
array
(),
'having'
=>
array
(),
'orderby'
=>
array
(),
'limit'
=>
false
,
'offset'
=>
false
,
);
/**
* @var integer $type the query type
*
* @see Doctrine_Query::* constants
*/
protected
$type
=
self
::
SELECT
;
/**
* constructor
*
* @param Doctrine_Connection|null $connection
*/
public
function
__construct
(
$connection
=
null
)
{
if
(
!
(
$connection
instanceof
Doctrine_Connection
))
{
$connection
=
Doctrine_Manager
::
getInstance
()
->
getCurrentConnection
();
}
$this
->
conn
=
$connection
;
$this
->
aliasHandler
=
new
Doctrine_Hydrate_Alias
();
}
/**
* getTableAliases
*
* @return array
*/
public
function
getTableAliases
()
{
return
$this
->
tableAliases
;
}
public
function
setTableAliases
(
array
$aliases
)
{
$this
->
tableAliases
=
$aliases
;
}
public
function
getTableAlias
(
$componentAlias
)
{
return
$this
->
aliasHandler
->
getShortAlias
(
$componentAlias
);
}
public
function
addQueryPart
(
$name
,
$part
)
{
if
(
!
isset
(
$this
->
parts
[
$name
]))
{
throw
new
Doctrine_Hydrate_Exception
(
'Unknown query part '
.
$name
);
}
$this
->
parts
[
$name
][]
=
$part
;
}
public
function
getDeclaration
(
$name
)
{
if
(
!
isset
(
$this
->
_aliasMap
[
$name
]))
{
throw
new
Doctrine_Hydrate_Exception
(
'Unknown component alias '
.
$name
);
}
return
$this
->
_aliasMap
[
$name
];
}
public
function
setQueryPart
(
$name
,
$part
)
{
if
(
!
isset
(
$this
->
parts
[
$name
]))
{
throw
new
Doctrine_Hydrate_Exception
(
'Unknown query part '
.
$name
);
}
if
(
$name
!==
'limit'
&&
$name
!==
'offset'
)
{
$this
->
parts
[
$name
]
=
array
(
$part
);
}
else
{
$this
->
parts
[
$name
]
=
$part
;
}
}
/**
* copyAliases
*
* @return void
*/
public
function
copyAliases
(
$query
)
{
$this
->
aliasHandler
=
$query
->
aliasHandler
;
return
$this
;
}
/**
* createSubquery
*
* @return Doctrine_Hydrate
*/
public
function
createSubquery
()
{
$class
=
get_class
(
$this
);
$obj
=
new
$class
();
// copy the aliases to the subquery
$obj
->
copyAliases
(
$this
);
// this prevents the 'id' being selected, re ticket #307
$obj
->
isSubquery
(
true
);
return
$obj
;
}
/**
* limitSubqueryUsed
*
* @return boolean
*/
public
function
isLimitSubqueryUsed
()
{
return
false
;
}
public
function
getQueryPart
(
$part
)
{
if
(
!
isset
(
$this
->
parts
[
$part
]))
{
throw
new
Doctrine_Hydrate_Exception
(
'Unknown query part '
.
$part
);
}
return
$this
->
parts
[
$part
];
}
/**
* remove
*
* @param $name
*/
public
function
remove
(
$name
)
{
if
(
isset
(
$this
->
parts
[
$name
]))
{
if
(
$name
==
"limit"
||
$name
==
"offset"
)
{
$this
->
parts
[
$name
]
=
false
;
}
else
{
$this
->
parts
[
$name
]
=
array
();
}
}
return
$this
;
}
/**
* clear
* resets all the variables
*
* @return void
*/
protected
function
clear
()
{
$this
->
tables
=
array
();
$this
->
parts
=
array
(
'select'
=>
array
(),
'from'
=>
array
(),
'set'
=>
array
(),
'join'
=>
array
(),
'where'
=>
array
(),
'groupby'
=>
array
(),
'having'
=>
array
(),
'orderby'
=>
array
(),
'limit'
=>
false
,
'offset'
=>
false
,
);
$this
->
inheritanceApplied
=
false
;
$this
->
tableAliases
=
array
();
$this
->
aliasHandler
->
clear
();
}
/**
* getConnection
*
* @return Doctrine_Connection
*/
public
function
getConnection
()
{
return
$this
->
conn
;
}
/**
* setView
* sets a database view this query object uses
* this method should only be called internally by doctrine
*
* @param Doctrine_View $view database view
* @return void
*/
public
function
setView
(
Doctrine_View
$view
)
{
$this
->
view
=
$view
;
}
/**
* getView
* returns the view associated with this query object (if any)
*
* @return Doctrine_View the view associated with this query object
*/
public
function
getView
()
{
return
$this
->
view
;
}
/**
* getParams
*
* @return array
*/
public
function
getParams
()
{
return
$this
->
params
;
}
/**
* setParams
*
* @param array $params
*/
public
function
setParams
(
array
$params
=
array
())
{
$this
->
params
=
$params
;
}
/**
* _fetch
*
* @param array $params prepared statement parameters
* @param integer $fetchMode the fetchmode
* @see Doctrine::FETCH_* constants
*/
public
function
_fetch
(
$params
=
array
(),
$fetchMode
=
Doctrine
::
FETCH_RECORD
)
{
$params
=
$this
->
conn
->
convertBooleans
(
array_merge
(
$this
->
params
,
$params
));
if
(
!
$this
->
view
)
{
$query
=
$this
->
getQuery
(
$params
);
}
else
{
$query
=
$this
->
view
->
getSelectSql
();
}
if
(
$this
->
isLimitSubqueryUsed
()
&&
$this
->
conn
->
getDBH
()
->
getAttribute
(
Doctrine
::
ATTR_DRIVER_NAME
)
!==
'mysql'
)
{
$params
=
array_merge
(
$params
,
$params
);
}
$stmt
=
$this
->
conn
->
execute
(
$query
,
$params
);
return
$this
->
parseData
(
$stmt
);
}
public
function
setAliasMap
(
$map
)
{
$this
->
_aliasMap
=
$map
;
}
public
function
getAliasMap
()
{
return
$this
->
_aliasMap
;
}
/**
* mapAggregateValues
* map the aggregate values of given dataset row to a given record
*
* @param Doctrine_Record $record
* @param array $row
* @return Doctrine_Record
*/
public
function
mapAggregateValues
(
$record
,
array
$row
,
$alias
)
{
$found
=
false
;
// aggregate values have numeric keys
if
(
isset
(
$row
[
0
]))
{
// map each aggregate value
foreach
(
$row
as
$index
=>
$value
)
{
$agg
=
false
;
if
(
isset
(
$this
->
pendingAggregates
[
$alias
][
$index
]))
{
$agg
=
$this
->
pendingAggregates
[
$alias
][
$index
][
3
];
}
elseif
(
isset
(
$this
->
subqueryAggregates
[
$alias
][
$index
]))
{
$agg
=
$this
->
subqueryAggregates
[
$alias
][
$index
];
}
$record
->
mapValue
(
$agg
,
$value
);
$found
=
true
;
}
}
return
$found
;
}
/**
* execute
* executes the dql query and populates all collections
*
* @param string $params
* @return Doctrine_Collection the root collection
*/
public
function
execute
(
$params
=
array
(),
$return
=
Doctrine
::
FETCH_RECORD
)
{
$array
=
(
array
)
$this
->
_fetch
(
$params
,
$return
=
Doctrine
::
FETCH_RECORD
);
if
(
empty
(
$this
->
_aliasMap
))
{
throw
new
Doctrine_Hydrate_Exception
(
"Couldn't execute query. Component alias map was empty."
);
}
// initialize some variables used within the main loop
reset
(
$this
->
_aliasMap
);
$rootMap
=
current
(
$this
->
_aliasMap
);
$rootAlias
=
key
(
$this
->
_aliasMap
);
$coll
=
new
Doctrine_Collection2
(
$rootMap
[
'table'
]);
$prev
[
$rootAlias
]
=
$coll
;
$prevRow
=
array
();
/**
* iterate over the fetched data
* here $data is a two dimensional array
*/
foreach
(
$array
as
$data
)
{
/**
* remove duplicated data rows and map data into objects
*/
foreach
(
$data
as
$tableAlias
=>
$row
)
{
// skip empty rows (not mappable)
if
(
empty
(
$row
))
{
continue
;
}
$alias
=
$this
->
aliasHandler
->
getComponentAlias
(
$tableAlias
);
$map
=
$this
->
_aliasMap
[
$alias
];
// initialize previous row array if not set
if
(
!
isset
(
$prevRow
[
$tableAlias
]))
{
$prevRow
[
$tableAlias
]
=
array
();
}
// don't map duplicate rows
if
(
$prevRow
[
$tableAlias
]
!==
$row
)
{
$identifiable
=
$this
->
isIdentifiable
(
$row
,
$map
[
'table'
]
->
getIdentifier
());
if
(
$identifiable
)
{
// set internal data
$map
[
'table'
]
->
setData
(
$row
);
}
// initialize a new record
$record
=
$map
[
'table'
]
->
getRecord
();
// map aggregate values (if any)
if
(
$this
->
mapAggregateValues
(
$record
,
$row
,
$alias
))
{
$identifiable
=
true
;
}
if
(
$alias
==
$rootAlias
)
{
// add record into root collection
if
(
$identifiable
)
{
$coll
->
add
(
$record
);
unset
(
$prevRow
);
}
}
else
{
$relation
=
$map
[
'relation'
];
$parentAlias
=
$map
[
'parent'
];
$parentMap
=
$this
->
_aliasMap
[
$parentAlias
];
$parent
=
$prev
[
$parentAlias
]
->
getLast
();
// check the type of the relation
if
(
$relation
->
isOneToOne
())
{
if
(
!
$identifiable
)
{
continue
;
}
$prev
[
$alias
]
=
$record
;
}
else
{
// one-to-many relation or many-to-many relation
if
(
!
$prev
[
$parentAlias
]
->
getLast
()
->
hasReference
(
$relation
->
getAlias
()))
{
// initialize a new collection
$prev
[
$alias
]
=
new
Doctrine_Collection2
(
$map
[
'table'
]);
$prev
[
$alias
]
->
setReference
(
$parent
,
$relation
);
}
else
{
// previous entry found from memory
$prev
[
$alias
]
=
$prev
[
$parentAlias
]
->
getLast
()
->
get
(
$relation
->
getAlias
());
}
// add record to the current collection
if
(
$identifiable
)
{
$prev
[
$alias
]
->
add
(
$record
);
}
}
// initialize the relation from parent to the current collection/record
$parent
->
set
(
$relation
->
getAlias
(),
$prev
[
$alias
]);
}
// following statement is needed to ensure that mappings
// are being done properly when the result set doesn't
// contain the rows in 'right order'
if
(
$prev
[
$alias
]
!==
$record
)
{
$prev
[
$alias
]
=
$record
;
}
}
$prevRow
[
$tableAlias
]
=
$row
;
}
}
return
$coll
;
}
/**
* isIdentifiable
* returns whether or not a given data row is identifiable (it contains
* all primary key fields specified in the second argument)
*
* @param array $row
* @param mixed $primaryKeys
* @return boolean
*/
public
function
isIdentifiable
(
array
$row
,
$primaryKeys
)
{
if
(
is_array
(
$primaryKeys
))
{
foreach
(
$primaryKeys
as
$id
)
{
if
(
$row
[
$id
]
==
null
)
{
return
false
;
}
}
}
else
{
if
(
!
isset
(
$row
[
$primaryKeys
]))
{
return
false
;
}
}
return
true
;
}
/**
* getType
*
* returns the type of this query object
* by default the type is Doctrine_Hydrate::SELECT but if update() or delete()
* are being called the type is Doctrine_Hydrate::UPDATE and Doctrine_Hydrate::DELETE,
* respectively
*
* @see Doctrine_Hydrate::SELECT
* @see Doctrine_Hydrate::UPDATE
* @see Doctrine_Hydrate::DELETE
*
* @return integer return the query type
*/
public
function
getType
()
{
return
$this
->
type
;
}
/**
* applyInheritance
* applies column aggregation inheritance to DQL / SQL query
*
* @return string
*/
public
function
applyInheritance
()
{
// get the inheritance maps
$array
=
array
();
foreach
(
$this
->
_aliasMap
as
$componentAlias
=>
$data
)
{
$tableAlias
=
$this
->
getTableAlias
(
$componentAlias
);
$array
[
$tableAlias
][]
=
$data
[
'table'
]
->
inheritanceMap
;
}
// apply inheritance maps
$str
=
''
;
$c
=
array
();
$index
=
0
;
foreach
(
$array
as
$tableAlias
=>
$maps
)
{
$a
=
array
();
// don't use table aliases if the query isn't a select query
if
(
$this
->
type
!==
Doctrine_Query
::
SELECT
)
{
$tableAlias
=
''
;
}
else
{
$tableAlias
.=
'.'
;
}
foreach
(
$maps
as
$map
)
{
$b
=
array
();
foreach
(
$map
as
$field
=>
$value
)
{
if
(
$index
>
0
)
{
$b
[]
=
'('
.
$tableAlias
.
$field
.
' = '
.
$value
.
' OR '
.
$tableAlias
.
$field
.
' IS NULL)'
;
}
else
{
$b
[]
=
$tableAlias
.
$field
.
' = '
.
$value
;
}
}
if
(
!
empty
(
$b
))
{
$a
[]
=
implode
(
' AND '
,
$b
);
}
}
if
(
!
empty
(
$a
))
{
$c
[]
=
implode
(
' AND '
,
$a
);
}
$index
++
;
}
$str
.=
implode
(
' AND '
,
$c
);
return
$str
;
}
/**
* parseData
* parses the data returned by statement object
*
* @param mixed $stmt
* @return array
*/
public
function
parseData
(
$stmt
)
{
$array
=
array
();
while
(
$data
=
$stmt
->
fetch
(
PDO
::
FETCH_ASSOC
))
{
/**
* parse the data into two-dimensional array
*/
foreach
(
$data
as
$key
=>
$value
)
{
$e
=
explode
(
'__'
,
$key
);
$field
=
strtolower
(
array_pop
(
$e
));
$tableAlias
=
strtolower
(
implode
(
'__'
,
$e
));
$data
[
$tableAlias
][
$field
]
=
$value
;
unset
(
$data
[
$key
]);
}
$array
[]
=
$data
;
}
$stmt
->
closeCursor
();
return
$array
;
}
/**
* @return string returns a string representation of this object
*/
public
function
__toString
()
{
return
Doctrine_Lib
::
formatSql
(
$this
->
getQuery
());
}
}
draft/new-core/Query.php
deleted
100644 → 0
View file @
82ba74e2
<?php
/*
* $Id: Query.php 1296 2007-04-26 17:42:03Z zYne $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
Doctrine
::
autoload
(
'Doctrine_Hydrate'
);
/**
* Doctrine_Query
*
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision: 1296 $
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class
Doctrine_Query
extends
Doctrine_Hydrate2
implements
Countable
{
/**
* @param array $subqueryAliases the table aliases needed in some LIMIT subqueries
*/
private
$subqueryAliases
=
array
();
/**
* @param boolean $needsSubquery
*/
private
$needsSubquery
=
false
;
/**
* @param boolean $limitSubqueryUsed
*/
private
$limitSubqueryUsed
=
false
;
protected
$_status
=
array
(
'needsSubquery'
=>
true
);
/**
* @param boolean $isSubquery whether or not this query object is a subquery of another
* query object
*/
private
$isSubquery
;
private
$isDistinct
=
false
;
private
$neededTables
=
array
();
/**
* @var array $pendingFields
*/
private
$pendingFields
=
array
();
/**
* @var array $pendingSubqueries SELECT part subqueries, these are called pending subqueries since
* they cannot be parsed directly (some queries might be correlated)
*/
private
$pendingSubqueries
=
array
();
/**
* @var boolean $subqueriesProcessed Whether or not pending subqueries have already been processed.
* Consequent calls to getQuery would result badly constructed queries
* without this variable
*
* Since subqueries can be correlated, they can only be processed when
* the main query is fully constructed
*/
private
$subqueriesProcessed
=
false
;
/**
* @var array $_parsers an array of parser objects
*/
protected
$_parsers
=
array
();
/**
* create
* returns a new Doctrine_Query object
*
* @return Doctrine_Query
*/
public
static
function
create
()
{
return
new
Doctrine_Query
();
}
/**
* isSubquery
* if $bool parameter is set this method sets the value of
* Doctrine_Query::$isSubquery. If this value is set to true
* the query object will not load the primary key fields of the selected
* components.
*
* If null is given as the first parameter this method retrieves the current
* value of Doctrine_Query::$isSubquery.
*
* @param boolean $bool whether or not this query acts as a subquery
* @return Doctrine_Query|bool
*/
public
function
isSubquery
(
$bool
=
null
)
{
if
(
$bool
===
null
)
{
return
$this
->
isSubquery
;
}
$this
->
isSubquery
=
(
bool
)
$bool
;
return
$this
;
}
/**
* getAggregateAlias
*
* @return string
*/
public
function
getAggregateAlias
(
$dqlAlias
)
{
if
(
isset
(
$this
->
aggregateMap
[
$dqlAlias
]))
{
return
$this
->
aggregateMap
[
$dqlAlias
];
}
return
null
;
}
public
function
isDistinct
(
$distinct
=
null
)
{
if
(
isset
(
$distinct
))
$this
->
isDistinct
=
(
bool
)
$distinct
;
return
$this
->
isDistinct
;
}
/**
* getParser
* parser lazy-loader
*
* @throws Doctrine_Query_Exception if unknown parser name given
* @return Doctrine_Query_Part
*/
public
function
getParser
(
$name
)
{
if
(
!
isset
(
$this
->
_parsers
[
$name
]))
{
$class
=
'Doctrine_Query_'
.
ucwords
(
strtolower
(
$name
));
Doctrine
::
autoload
(
$class
);
if
(
!
class_exists
(
$class
))
{
throw
new
Doctrine_Query_Exception
(
'Unknown parser '
.
$name
);
}
$this
->
_parsers
[
$name
]
=
new
$class
(
$this
);
}
return
$this
->
_parsers
[
$name
];
}
/**
* processPendingFields
* the fields in SELECT clause cannot be parsed until the components
* in FROM clause are parsed, hence this method is called everytime a
* specific component is being parsed.
*
* @throws Doctrine_Query_Exception if unknown component alias has been given
* @param string $componentAlias the alias of the component
* @return void
*/
public
function
processPendingFields
(
$componentAlias
)
{
$tableAlias
=
$this
->
getTableAlias
(
$componentAlias
);
$table
=
$this
->
_aliasMap
[
$componentAlias
][
'table'
];
if
(
isset
(
$this
->
pendingFields
[
$componentAlias
]))
{
$fields
=
$this
->
pendingFields
[
$componentAlias
];
// check for wildcards
if
(
in_array
(
'*'
,
$fields
))
{
$fields
=
$table
->
getColumnNames
();
}
else
{
// only auto-add the primary key fields if this query object is not
// a subquery of another query object
if
(
!
$this
->
isSubquery
)
{
$fields
=
array_unique
(
array_merge
(
$table
->
getPrimaryKeys
(),
$fields
));
}
}
}
foreach
(
$fields
as
$name
)
{
$name
=
$table
->
getColumnName
(
$name
);
$this
->
parts
[
'select'
][]
=
$tableAlias
.
'.'
.
$name
.
' AS '
.
$tableAlias
.
'__'
.
$name
;
}
$this
->
neededTables
[]
=
$tableAlias
;
}
/**
* parseSelect
* parses the query select part and
* adds selected fields to pendingFields array
*
* @param string $dql
*/
public
function
parseSelect
(
$dql
)
{
$refs
=
Doctrine_Tokenizer
::
bracketExplode
(
$dql
,
','
);
foreach
(
$refs
as
$reference
)
{
if
(
strpos
(
$reference
,
'('
)
!==
false
)
{
if
(
substr
(
$reference
,
0
,
1
)
===
'('
)
{
// subselect found in SELECT part
$this
->
parseSubselect
(
$reference
);
}
else
{
$this
->
parseAggregateFunction2
(
$reference
);
}
}
else
{
$e
=
explode
(
'.'
,
$reference
);
if
(
count
(
$e
)
>
2
)
{
$this
->
pendingFields
[]
=
$reference
;
}
else
{
$this
->
pendingFields
[
$e
[
0
]][]
=
$e
[
1
];
}
}
}
}
/**
* parseSubselect
*
* parses the subquery found in DQL SELECT part and adds the
* parsed form into $pendingSubqueries stack
*
* @param string $reference
* @return void
*/
public
function
parseSubselect
(
$reference
)
{
$e
=
Doctrine_Tokenizer
::
bracketExplode
(
$reference
,
' '
);
$alias
=
$e
[
1
];
if
(
count
(
$e
)
>
2
)
{
if
(
strtoupper
(
$e
[
1
])
!==
'AS'
)
{
throw
new
Doctrine_Query_Exception
(
'Syntax error near: '
.
$reference
);
}
$alias
=
$e
[
2
];
}
$subquery
=
substr
(
$e
[
0
],
1
,
-
1
);
$this
->
pendingSubqueries
[]
=
array
(
$subquery
,
$alias
);
}
public
function
parseAggregateFunction2
(
$func
)
{
$e
=
Doctrine_Tokenizer
::
bracketExplode
(
$func
,
' '
);
$func
=
$e
[
0
];
$pos
=
strpos
(
$func
,
'('
);
$name
=
substr
(
$func
,
0
,
$pos
);
try
{
$argStr
=
substr
(
$func
,
(
$pos
+
1
),
-
1
);
$args
=
explode
(
','
,
$argStr
);
$func
=
call_user_func_array
(
array
(
$this
->
conn
->
expression
,
$name
),
$args
);
if
(
substr
(
$func
,
0
,
1
)
!==
'('
)
{
$pos
=
strpos
(
$func
,
'('
);
$name
=
substr
(
$func
,
0
,
$pos
);
}
else
{
$name
=
$func
;
}
$e2
=
explode
(
' '
,
$args
[
0
]);
$distinct
=
''
;
if
(
count
(
$e2
)
>
1
)
{
if
(
strtoupper
(
$e2
[
0
])
==
'DISTINCT'
)
{
$distinct
=
'DISTINCT '
;
}
$args
[
0
]
=
$e2
[
1
];
}
$parts
=
explode
(
'.'
,
$args
[
0
]);
$owner
=
$parts
[
0
];
$alias
=
(
isset
(
$e
[
1
]))
?
$e
[
1
]
:
$name
;
$e3
=
explode
(
'.'
,
$alias
);
if
(
count
(
$e3
)
>
1
)
{
$alias
=
$e3
[
1
];
$owner
=
$e3
[
0
];
}
// a function without parameters eg. RANDOM()
if
(
$owner
===
''
)
{
$owner
=
0
;
}
$this
->
pendingAggregates
[
$owner
][]
=
array
(
$name
,
$args
,
$distinct
,
$alias
);
}
catch
(
Doctrine_Expression_Exception
$e
)
{
throw
new
Doctrine_Query_Exception
(
'Unknown function '
.
$func
.
'.'
);
}
}
public
function
processPendingSubqueries
()
{
if
(
$this
->
subqueriesProcessed
===
true
)
{
return
false
;
}
foreach
(
$this
->
pendingSubqueries
as
$value
)
{
list
(
$dql
,
$alias
)
=
$value
;
$sql
=
$this
->
createSubquery
()
->
parseQuery
(
$dql
,
false
)
->
getQuery
();
reset
(
$this
->
_aliasMap
);
$componentAlias
=
key
(
$this
->
_aliasMap
);
$tableAlias
=
$this
->
getTableAlias
(
$componentAlias
);
$sqlAlias
=
$tableAlias
.
'__'
.
count
(
$this
->
aggregateMap
);
$this
->
parts
[
'select'
][]
=
'('
.
$sql
.
') AS '
.
$sqlAlias
;
$this
->
aggregateMap
[
$alias
]
=
$sqlAlias
;
$this
->
subqueryAggregates
[
$componentAlias
][]
=
$alias
;
}
$this
->
subqueriesProcessed
=
true
;
return
true
;
}
public
function
processPendingAggregates
(
$componentAlias
)
{
$tableAlias
=
$this
->
getTableAlias
(
$componentAlias
);
$map
=
reset
(
$this
->
_aliasMap
);
$root
=
$map
[
'table'
];
$table
=
$this
->
_aliasMap
[
$componentAlias
][
'table'
];
$aggregates
=
array
();
if
(
isset
(
$this
->
pendingAggregates
[
$componentAlias
]))
{
$aggregates
=
$this
->
pendingAggregates
[
$componentAlias
];
}
if
(
$root
===
$table
)
{
if
(
isset
(
$this
->
pendingAggregates
[
0
]))
{
$aggregates
+=
$this
->
pendingAggregates
[
0
];
}
}
foreach
(
$aggregates
as
$parts
)
{
list
(
$name
,
$args
,
$distinct
,
$alias
)
=
$parts
;
$arglist
=
array
();
foreach
(
$args
as
$arg
)
{
$e
=
explode
(
'.'
,
$arg
);
if
(
is_numeric
(
$arg
))
{
$arglist
[]
=
$arg
;
}
elseif
(
count
(
$e
)
>
1
)
{
$map
=
$this
->
_aliasMap
[
$e
[
0
]];
$table
=
$map
[
'table'
];
$e
[
1
]
=
$table
->
getColumnName
(
$e
[
1
]);
if
(
!
$table
->
hasColumn
(
$e
[
1
]))
{
throw
new
Doctrine_Query_Exception
(
'Unknown column '
.
$e
[
1
]);
}
$arglist
[]
=
$tableAlias
.
'.'
.
$e
[
1
];
}
else
{
$arglist
[]
=
$e
[
0
];
}
}
$sqlAlias
=
$tableAlias
.
'__'
.
count
(
$this
->
aggregateMap
);
if
(
substr
(
$name
,
0
,
1
)
!==
'('
)
{
$this
->
parts
[
'select'
][]
=
$name
.
'('
.
$distinct
.
implode
(
', '
,
$arglist
)
.
') AS '
.
$sqlAlias
;
}
else
{
$this
->
parts
[
'select'
][]
=
$name
.
' AS '
.
$sqlAlias
;
}
$this
->
aggregateMap
[
$alias
]
=
$sqlAlias
;
$this
->
neededTables
[]
=
$tableAlias
;
}
}
/**
* getQueryBase
* returns the base of the generated sql query
* On mysql driver special strategy has to be used for DELETE statements
*
* @return string the base of the generated sql query
*/
public
function
getQueryBase
()
{
switch
(
$this
->
type
)
{
case
self
::
DELETE
:
$q
=
'DELETE FROM '
;
break
;
case
self
::
UPDATE
:
$q
=
'UPDATE '
;
break
;
case
self
::
SELECT
:
$distinct
=
(
$this
->
isDistinct
())
?
'DISTINCT '
:
''
;
$q
=
'SELECT '
.
$distinct
.
implode
(
', '
,
$this
->
parts
[
'select'
])
.
' FROM '
;
break
;
}
return
$q
;
}
/**
* buildFromPart
*
* @return string
*/
public
function
buildFromPart
()
{
$q
=
''
;
foreach
(
$this
->
parts
[
'from'
]
as
$k
=>
$part
)
{
if
(
$k
===
0
)
{
$q
.=
$part
;
continue
;
}
// preserve LEFT JOINs only if needed
if
(
substr
(
$part
,
0
,
9
)
===
'LEFT JOIN'
)
{
$e
=
explode
(
' '
,
$part
);
$aliases
=
array_merge
(
$this
->
subqueryAliases
,
array_keys
(
$this
->
neededTables
));
if
(
!
in_array
(
$e
[
3
],
$aliases
)
&&
!
in_array
(
$e
[
2
],
$aliases
)
&&
!
empty
(
$this
->
pendingFields
))
{
continue
;
}
}
$e
=
explode
(
' ON '
,
$part
);
// we can always be sure that the first join condition exists
$e2
=
explode
(
' AND '
,
$e
[
1
]);
$part
=
$e
[
0
]
.
' ON '
.
array_shift
(
$e2
);
if
(
!
empty
(
$e2
))
{
$parser
=
new
Doctrine_Query_JoinCondition
(
$this
);
$part
.=
' AND '
.
$parser
->
_parse
(
implode
(
' AND '
,
$e2
));
}
$q
.=
' '
.
$part
;
}
return
$q
;
}
/**
* builds the sql query from the given parameters and applies things such as
* column aggregation inheritance and limit subqueries if needed
*
* @param array $params an array of prepared statement params (needed only in mysql driver
* when limit subquery algorithm is used)
* @return string the built sql query
*/
public
function
getQuery
(
$params
=
array
())
{
if
(
empty
(
$this
->
parts
[
'select'
])
||
empty
(
$this
->
parts
[
'from'
]))
{
return
false
;
}
$needsSubQuery
=
false
;
$subquery
=
''
;
$map
=
reset
(
$this
->
_aliasMap
);
$table
=
$map
[
'table'
];
$rootAlias
=
key
(
$this
->
_aliasMap
);
if
(
!
empty
(
$this
->
parts
[
'limit'
])
&&
$this
->
needsSubquery
&&
$table
->
getAttribute
(
Doctrine
::
ATTR_QUERY_LIMIT
)
==
Doctrine
::
LIMIT_RECORDS
)
{
$needsSubQuery
=
true
;
$this
->
limitSubqueryUsed
=
true
;
}
// process all pending SELECT part subqueries
$this
->
processPendingSubqueries
();
// build the basic query
$str
=
''
;
if
(
$this
->
isDistinct
())
{
$str
=
'DISTINCT '
;
}
$q
=
$this
->
getQueryBase
();
$q
.=
$this
->
buildFromPart
();
if
(
!
empty
(
$this
->
parts
[
'set'
]))
{
$q
.=
' SET '
.
implode
(
', '
,
$this
->
parts
[
'set'
]);
}
$string
=
$this
->
applyInheritance
();
if
(
!
empty
(
$string
))
{
$this
->
parts
[
'where'
][]
=
'('
.
$string
.
')'
;
}
$modifyLimit
=
true
;
if
(
!
empty
(
$this
->
parts
[
"limit"
])
||
!
empty
(
$this
->
parts
[
"offset"
]))
{
if
(
$needsSubQuery
)
{
$subquery
=
$this
->
getLimitSubquery
();
switch
(
strtolower
(
$this
->
conn
->
getName
()))
{
case
'mysql'
:
// mysql doesn't support LIMIT in subqueries
$list
=
$this
->
conn
->
execute
(
$subquery
,
$params
)
->
fetchAll
(
PDO
::
FETCH_COLUMN
);
$subquery
=
implode
(
', '
,
$list
);
break
;
case
'pgsql'
:
// pgsql needs special nested LIMIT subquery
$subquery
=
'SELECT doctrine_subquery_alias.'
.
$table
->
getIdentifier
()
.
' FROM ('
.
$subquery
.
') AS doctrine_subquery_alias'
;
break
;
}
$field
=
$this
->
aliasHandler
->
getShortAlias
(
$rootAlias
)
.
'.'
.
$table
->
getIdentifier
();
// only append the subquery if it actually contains something
if
(
$subquery
!==
''
)
{
array_unshift
(
$this
->
parts
[
'where'
],
$field
.
' IN ('
.
$subquery
.
')'
);
}
$modifyLimit
=
false
;
}
}
$q
.=
(
!
empty
(
$this
->
parts
[
'where'
]))
?
' WHERE '
.
implode
(
' AND '
,
$this
->
parts
[
'where'
])
:
''
;
$q
.=
(
!
empty
(
$this
->
parts
[
'groupby'
]))
?
' GROUP BY '
.
implode
(
', '
,
$this
->
parts
[
'groupby'
])
:
''
;
$q
.=
(
!
empty
(
$this
->
parts
[
'having'
]))
?
' HAVING '
.
implode
(
' AND '
,
$this
->
parts
[
'having'
])
:
''
;
$q
.=
(
!
empty
(
$this
->
parts
[
'orderby'
]))
?
' ORDER BY '
.
implode
(
', '
,
$this
->
parts
[
'orderby'
])
:
''
;
if
(
$modifyLimit
)
{
$q
=
$this
->
conn
->
modifyLimitQuery
(
$q
,
$this
->
parts
[
'limit'
],
$this
->
parts
[
'offset'
]);
}
// return to the previous state
if
(
!
empty
(
$string
))
{
array_pop
(
$this
->
parts
[
'where'
]);
}
if
(
$needsSubQuery
)
{
array_shift
(
$this
->
parts
[
'where'
]);
}
return
$q
;
}
/**
* getLimitSubquery
* this is method is used by the record limit algorithm
*
* when fetching one-to-many, many-to-many associated data with LIMIT clause
* an additional subquery is needed for limiting the number of returned records instead
* of limiting the number of sql result set rows
*
* @return string the limit subquery
*/
public
function
getLimitSubquery
()
{
$map
=
reset
(
$this
->
_aliasMap
);
$table
=
$map
[
'table'
];
$componentAlias
=
key
(
$this
->
_aliasMap
);
// get short alias
$alias
=
$this
->
aliasHandler
->
getShortAlias
(
$componentAlias
);
$primaryKey
=
$alias
.
'.'
.
$table
->
getIdentifier
();
// initialize the base of the subquery
$subquery
=
'SELECT DISTINCT '
.
$primaryKey
;
if
(
$this
->
conn
->
getDBH
()
->
getAttribute
(
PDO
::
ATTR_DRIVER_NAME
)
==
'pgsql'
)
{
// pgsql needs the order by fields to be preserved in select clause
foreach
(
$this
->
parts
[
'orderby'
]
as
$part
)
{
$e
=
explode
(
' '
,
$part
);
// don't add primarykey column (its already in the select clause)
if
(
$e
[
0
]
!==
$primaryKey
)
{
$subquery
.=
', '
.
$e
[
0
];
}
}
}
$subquery
.=
' FROM'
;
foreach
(
$this
->
parts
[
'from'
]
as
$part
)
{
// preserve LEFT JOINs only if needed
if
(
substr
(
$part
,
0
,
9
)
===
'LEFT JOIN'
)
{
$e
=
explode
(
' '
,
$part
);
if
(
!
in_array
(
$e
[
3
],
$this
->
subqueryAliases
)
&&
!
in_array
(
$e
[
2
],
$this
->
subqueryAliases
))
{
continue
;
}
}
$subquery
.=
' '
.
$part
;
}
// all conditions must be preserved in subquery
$subquery
.=
(
!
empty
(
$this
->
parts
[
'where'
]))
?
' WHERE '
.
implode
(
' AND '
,
$this
->
parts
[
'where'
])
:
''
;
$subquery
.=
(
!
empty
(
$this
->
parts
[
'groupby'
]))
?
' GROUP BY '
.
implode
(
', '
,
$this
->
parts
[
'groupby'
])
:
''
;
$subquery
.=
(
!
empty
(
$this
->
parts
[
'having'
]))
?
' HAVING '
.
implode
(
' AND '
,
$this
->
parts
[
'having'
])
:
''
;
$subquery
.=
(
!
empty
(
$this
->
parts
[
'orderby'
]))
?
' ORDER BY '
.
implode
(
', '
,
$this
->
parts
[
'orderby'
])
:
''
;
// add driver specific limit clause
$subquery
=
$this
->
conn
->
modifyLimitQuery
(
$subquery
,
$this
->
parts
[
'limit'
],
$this
->
parts
[
'offset'
]);
$parts
=
Doctrine_Tokenizer
::
quoteExplode
(
$subquery
,
' '
,
"'"
,
"'"
);
foreach
(
$parts
as
$k
=>
$part
)
{
if
(
strpos
(
$part
,
"'"
)
!==
false
)
{
continue
;
}
if
(
$this
->
aliasHandler
->
hasAliasFor
(
$part
))
{
$parts
[
$k
]
=
$this
->
aliasHandler
->
generateNewAlias
(
$part
);
}
if
(
strpos
(
$part
,
'.'
)
!==
false
)
{
$e
=
explode
(
'.'
,
$part
);
$trimmed
=
ltrim
(
$e
[
0
],
'( '
);
$pos
=
strpos
(
$e
[
0
],
$trimmed
);
$e
[
0
]
=
substr
(
$e
[
0
],
0
,
$pos
)
.
$this
->
aliasHandler
->
generateNewAlias
(
$trimmed
);
$parts
[
$k
]
=
implode
(
'.'
,
$e
);
}
}
$subquery
=
implode
(
' '
,
$parts
);
return
$subquery
;
}
/**
* tokenizeQuery
* splits the given dql query into an array where keys
* represent different query part names and values are
* arrays splitted using sqlExplode method
*
* example:
*
* parameter:
* $query = "SELECT u.* FROM User u WHERE u.name LIKE ?"
* returns:
* array('select' => array('u.*'),
* 'from' => array('User', 'u'),
* 'where' => array('u.name', 'LIKE', '?'))
*
* @param string $query DQL query
* @throws Doctrine_Query_Exception if some generic parsing error occurs
* @return array an array containing the query string parts
*/
public
function
tokenizeQuery
(
$query
)
{
$e
=
Doctrine_Tokenizer
::
sqlExplode
(
$query
,
' '
);
foreach
(
$e
as
$k
=>
$part
)
{
$part
=
trim
(
$part
);
switch
(
strtolower
(
$part
))
{
case
'delete'
:
case
'update'
:
case
'select'
:
case
'set'
:
case
'from'
:
case
'where'
:
case
'limit'
:
case
'offset'
:
case
'having'
:
$p
=
$part
;
$parts
[
$part
]
=
array
();
break
;
case
'order'
:
case
'group'
:
$i
=
(
$k
+
1
);
if
(
isset
(
$e
[
$i
])
&&
strtolower
(
$e
[
$i
])
===
"by"
)
{
$p
=
$part
;
$parts
[
$part
]
=
array
();
}
else
$parts
[
$p
][]
=
$part
;
break
;
case
"by"
:
continue
;
default
:
if
(
!
isset
(
$p
))
throw
new
Doctrine_Query_Exception
(
"Couldn't parse query."
);
$parts
[
$p
][]
=
$part
;
}
}
return
$parts
;
}
/**
* DQL PARSER
* parses a DQL query
* first splits the query in parts and then uses individual
* parsers for each part
*
* @param string $query DQL query
* @param boolean $clear whether or not to clear the aliases
* @throws Doctrine_Query_Exception if some generic parsing error occurs
* @return Doctrine_Query
*/
public
function
parseQuery
(
$query
,
$clear
=
true
)
{
if
(
$clear
)
{
$this
->
clear
();
}
$query
=
trim
(
$query
);
$query
=
str_replace
(
"
\n
"
,
' '
,
$query
);
$query
=
str_replace
(
"
\r
"
,
' '
,
$query
);
$parts
=
$this
->
tokenizeQuery
(
$query
);
foreach
(
$parts
as
$k
=>
$part
)
{
$part
=
implode
(
' '
,
$part
);
switch
(
strtolower
(
$k
))
{
case
'create'
:
$this
->
type
=
self
::
CREATE
;
break
;
case
'insert'
:
$this
->
type
=
self
::
INSERT
;
break
;
case
'delete'
:
$this
->
type
=
self
::
DELETE
;
break
;
case
'select'
:
$this
->
type
=
self
::
SELECT
;
$this
->
parseSelect
(
$part
);
break
;
case
'update'
:
$this
->
type
=
self
::
UPDATE
;
$k
=
'FROM'
;
case
'from'
:
$class
=
'Doctrine_Query_'
.
ucwords
(
strtolower
(
$k
));
$parser
=
new
$class
(
$this
);
$parser
->
parse
(
$part
);
break
;
case
'set'
:
$class
=
'Doctrine_Query_'
.
ucwords
(
strtolower
(
$k
));
$parser
=
new
$class
(
$this
);
$parser
->
parse
(
$part
);
break
;
case
'group'
:
case
'order'
:
$k
.=
'by'
;
case
'where'
:
case
'having'
:
$class
=
'Doctrine_Query_'
.
ucwords
(
strtolower
(
$k
));
$parser
=
new
$class
(
$this
);
$name
=
strtolower
(
$k
);
$parser
->
parse
(
$part
);
break
;
case
'limit'
:
$this
->
parts
[
'limit'
]
=
trim
(
$part
);
break
;
case
'offset'
:
$this
->
parts
[
'offset'
]
=
trim
(
$part
);
break
;
}
}
return
$this
;
}
public
function
load
(
$path
,
$loadFields
=
true
)
{
// parse custom join conditions
$e
=
explode
(
' ON '
,
$path
);
$joinCondition
=
''
;
if
(
count
(
$e
)
>
1
)
{
$joinCondition
=
' AND '
.
$e
[
1
];
$path
=
$e
[
0
];
}
$tmp
=
explode
(
' '
,
$path
);
$originalAlias
=
(
count
(
$tmp
)
>
1
)
?
end
(
$tmp
)
:
null
;
$e
=
preg_split
(
"/[.:]/"
,
$tmp
[
0
],
-
1
);
$fullPath
=
$tmp
[
0
];
$prevPath
=
''
;
$fullLength
=
strlen
(
$fullPath
);
if
(
isset
(
$this
->
_aliasMap
[
$e
[
0
]]))
{
$table
=
$this
->
_aliasMap
[
$e
[
0
]][
'table'
];
$prevPath
=
$parent
=
array_shift
(
$e
);
}
foreach
(
$e
as
$key
=>
$name
)
{
// get length of the previous path
$length
=
strlen
(
$prevPath
);
// build the current component path
$prevPath
=
(
$prevPath
)
?
$prevPath
.
'.'
.
$name
:
$name
;
$delimeter
=
substr
(
$fullPath
,
$length
,
1
);
// if an alias is not given use the current path as an alias identifier
if
(
strlen
(
$prevPath
)
===
$fullLength
&&
isset
(
$originalAlias
))
{
$componentAlias
=
$originalAlias
;
}
else
{
$componentAlias
=
$prevPath
;
}
if
(
!
isset
(
$table
))
{
// process the root of the path
$table
=
$this
->
loadRoot
(
$name
,
$componentAlias
);
}
else
{
$join
=
(
$delimeter
==
':'
)
?
'INNER JOIN '
:
'LEFT JOIN '
;
$relation
=
$table
->
getRelation
(
$name
);
$this
->
_aliasMap
[
$componentAlias
]
=
array
(
'table'
=>
$relation
->
getTable
(),
'parent'
=>
$parent
,
'relation'
=>
$relation
);
if
(
!
$relation
->
isOneToOne
())
{
$this
->
needsSubquery
=
true
;
}
$localAlias
=
$this
->
getShortAlias
(
$parent
,
$table
->
getTableName
());
$foreignAlias
=
$this
->
getShortAlias
(
$componentAlias
,
$relation
->
getTable
()
->
getTableName
());
$localSql
=
$this
->
conn
->
quoteIdentifier
(
$table
->
getTableName
())
.
' '
.
$localAlias
;
$foreignSql
=
$this
->
conn
->
quoteIdentifier
(
$relation
->
getTable
()
->
getTableName
())
.
' '
.
$foreignAlias
;
$map
=
$relation
->
getTable
()
->
inheritanceMap
;
if
(
!
$loadFields
||
!
empty
(
$map
)
||
$joinCondition
)
{
$this
->
subqueryAliases
[]
=
$foreignAlias
;
}
if
(
$relation
instanceof
Doctrine_Relation_Association
)
{
$asf
=
$relation
->
getAssociationFactory
();
$assocTableName
=
$asf
->
getTableName
();
if
(
!
$loadFields
||
!
empty
(
$map
)
||
$joinCondition
)
{
$this
->
subqueryAliases
[]
=
$assocTableName
;
}
$assocPath
=
$prevPath
.
'.'
.
$asf
->
getComponentName
();
$assocAlias
=
$this
->
getShortAlias
(
$assocPath
,
$asf
->
getTableName
());
$queryPart
=
$join
.
$assocTableName
.
' '
.
$assocAlias
.
' ON '
.
$localAlias
.
'.'
.
$table
->
getIdentifier
()
.
' = '
.
$assocAlias
.
'.'
.
$relation
->
getLocal
();
if
(
$relation
instanceof
Doctrine_Relation_Association_Self
)
{
$queryPart
.=
' OR '
.
$localAlias
.
'.'
.
$table
->
getIdentifier
()
.
' = '
.
$assocAlias
.
'.'
.
$relation
->
getForeign
();
}
$this
->
parts
[
'from'
][]
=
$queryPart
;
$queryPart
=
$join
.
$foreignSql
.
' ON '
.
$foreignAlias
.
'.'
.
$relation
->
getTable
()
->
getIdentifier
()
.
' = '
.
$assocAlias
.
'.'
.
$relation
->
getForeign
()
.
$joinCondition
;
if
(
$relation
instanceof
Doctrine_Relation_Association_Self
)
{
$queryPart
.=
' OR '
.
$foreignAlias
.
'.'
.
$table
->
getIdentifier
()
.
' = '
.
$assocAlias
.
'.'
.
$relation
->
getLocal
();
}
}
else
{
$queryPart
=
$join
.
$foreignSql
.
' ON '
.
$localAlias
.
'.'
.
$relation
->
getLocal
()
.
' = '
.
$foreignAlias
.
'.'
.
$relation
->
getForeign
()
.
$joinCondition
;
}
$this
->
parts
[
'from'
][]
=
$queryPart
;
}
if
(
$loadFields
)
{
$restoreState
=
false
;
// load fields if necessary
if
(
$loadFields
&&
empty
(
$this
->
pendingFields
)
&&
empty
(
$this
->
pendingAggregates
)
&&
empty
(
$this
->
pendingSubqueries
))
{
$this
->
pendingFields
[
$componentAlias
]
=
array
(
'*'
);
$restoreState
=
true
;
}
if
(
isset
(
$this
->
pendingFields
[
$componentAlias
]))
{
$this
->
processPendingFields
(
$componentAlias
);
}
if
(
isset
(
$this
->
pendingAggregates
[
$componentAlias
])
||
isset
(
$this
->
pendingAggregates
[
0
]))
{
$this
->
processPendingAggregates
(
$componentAlias
);
}
if
(
$restoreState
)
{
$this
->
pendingFields
=
array
();
$this
->
pendingAggregates
=
array
();
}
}
$parent
=
$prevPath
;
}
return
end
(
$this
->
_aliasMap
);
}
/**
* loadRoot
*
* @param string $name
* @param string $componentAlias
*/
public
function
loadRoot
(
$name
,
$componentAlias
)
{
// get the connection for the component
$this
->
conn
=
Doctrine_Manager
::
getInstance
()
->
getConnectionForComponent
(
$name
);
$table
=
$this
->
conn
->
getTable
(
$name
);
$tableName
=
$table
->
getTableName
();
// get the short alias for this table
$tableAlias
=
$this
->
aliasHandler
->
getShortAlias
(
$componentAlias
,
$tableName
);
// quote table name
$queryPart
=
$this
->
conn
->
quoteIdentifier
(
$tableName
);
if
(
$this
->
type
===
self
::
SELECT
)
{
$queryPart
.=
' '
.
$tableAlias
;
}
$this
->
parts
[
'from'
][]
=
$queryPart
;
$this
->
tableAliases
[
$tableAlias
]
=
$componentAlias
;
$this
->
_aliasMap
[
$componentAlias
]
=
array
(
'table'
=>
$table
);
return
$table
;
}
/**
* count
* fetches the count of the query
*
* This method executes the main query without all the
* selected fields, ORDER BY part, LIMIT part and OFFSET part.
*
* Example:
* Main query:
* SELECT u.*, p.phonenumber FROM User u
* LEFT JOIN u.Phonenumber p
* WHERE p.phonenumber = '123 123' LIMIT 10
*
* The query this method executes:
* SELECT COUNT(DISTINCT u.id) FROM User u
* LEFT JOIN u.Phonenumber p
* WHERE p.phonenumber = '123 123'
*
* @param array $params an array of prepared statement parameters
* @return integer the count of this query
*/
public
function
count
(
$params
=
array
())
{
// initialize temporary variables
$where
=
$this
->
parts
[
'where'
];
$having
=
$this
->
parts
[
'having'
];
$map
=
reset
(
$this
->
_aliasMap
);
$componentAlias
=
key
(
$this
->
_aliasMap
);
$table
=
$map
[
'table'
];
// build the query base
$q
=
'SELECT COUNT(DISTINCT '
.
$this
->
aliasHandler
->
getShortAlias
(
$table
->
getTableName
())
.
'.'
.
$table
->
getIdentifier
()
.
') FROM '
.
$this
->
buildFromPart
();
// append column aggregation inheritance (if needed)
$string
=
$this
->
applyInheritance
();
if
(
!
empty
(
$string
))
{
$where
[]
=
$string
;
}
// append conditions
$q
.=
(
!
empty
(
$where
))
?
' WHERE '
.
implode
(
' AND '
,
$where
)
:
''
;
$q
.=
(
!
empty
(
$having
))
?
' HAVING '
.
implode
(
' AND '
,
$having
)
:
''
;
if
(
!
is_array
(
$params
))
{
$params
=
array
(
$params
);
}
// append parameters
$params
=
array_merge
(
$this
->
params
,
$params
);
return
(
int
)
$this
->
getConnection
()
->
fetchOne
(
$q
,
$params
);
}
/**
* isLimitSubqueryUsed
* whether or not limit subquery algorithm is used
*
* @return boolean
*/
public
function
isLimitSubqueryUsed
()
{
return
$this
->
limitSubqueryUsed
;
}
/**
* query
* query the database with DQL (Doctrine Query Language)
*
* @param string $query DQL query
* @param array $params prepared statement parameters
* @see Doctrine::FETCH_* constants
* @return mixed
*/
public
function
query
(
$query
,
$params
=
array
())
{
$this
->
parseQuery
(
$query
);
return
$this
->
execute
(
$params
);
}
/**
* getShortAlias
* some database such as Oracle need the identifier lengths to be < ~30 chars
* hence Doctrine creates as short identifier aliases as possible
*
* this method is used for the creation of short table aliases, its also
* smart enough to check if an alias already exists for given component (componentAlias)
*
* @param string $componentAlias the alias for the query component to search table alias for
* @param string $tableName the table name from which the table alias is being created
* @return string the generated / fetched short alias
*/
public
function
getShortAlias
(
$componentAlias
,
$tableName
)
{
return
$this
->
aliasHandler
->
getShortAlias
(
$componentAlias
,
$tableName
);
}
/**
* addSelect
* adds fields to the SELECT part of the query
*
* @param string $select DQL SELECT part
* @return Doctrine_Query
*/
public
function
addSelect
(
$select
)
{
return
$this
->
getParser
(
'select'
)
->
parse
(
$select
,
true
);
}
/**
* addWhere
* adds conditions to the WHERE part of the query
*
* @param string $where DQL WHERE part
* @param mixed $params an array of parameters or a simple scalar
* @return Doctrine_Query
*/
public
function
addWhere
(
$where
,
$params
=
array
())
{
if
(
is_array
(
$params
))
{
$this
->
params
=
array_merge
(
$this
->
params
,
$params
);
}
else
{
$this
->
params
[]
=
$params
;
}
return
$this
->
getParser
(
'where'
)
->
parse
(
$where
,
true
);
}
/**
* addGroupBy
* adds fields to the GROUP BY part of the query
*
* @param string $groupby DQL GROUP BY part
* @return Doctrine_Query
*/
public
function
addGroupBy
(
$groupby
)
{
return
$this
->
getParser
(
'groupby'
)
->
parse
(
$groupby
,
true
);
}
/**
* addHaving
* adds conditions to the HAVING part of the query
*
* @param string $having DQL HAVING part
* @param mixed $params an array of parameters or a simple scalar
* @return Doctrine_Query
*/
public
function
addHaving
(
$having
,
$params
=
array
())
{
if
(
is_array
(
$params
))
{
$this
->
params
=
array_merge
(
$this
->
params
,
$params
);
}
else
{
$this
->
params
[]
=
$params
;
}
return
$this
->
getParser
(
'having'
)
->
parse
(
$having
,
true
);
}
/**
* addOrderBy
* adds fields to the ORDER BY part of the query
*
* @param string $orderby DQL ORDER BY part
* @return Doctrine_Query
*/
public
function
addOrderBy
(
$orderby
)
{
return
$this
->
getParser
(
'orderby'
)
->
parse
(
$orderby
,
true
);
}
/**
* select
* sets the SELECT part of the query
*
* @param string $select DQL SELECT part
* @return Doctrine_Query
*/
public
function
select
(
$select
)
{
return
$this
->
getParser
(
'select'
)
->
parse
(
$select
);
}
/**
* distinct
* Makes the query SELECT DISTINCT.
*
* @param bool $flag Whether or not the SELECT is DISTINCT (default true).
* @return Doctrine_Query
*/
public
function
distinct
(
$flag
=
true
)
{
$this
->
_parts
[
'distinct'
]
=
(
bool
)
$flag
;
return
$this
;
}
/**
* forUpdate
* Makes the query SELECT FOR UPDATE.
*
* @param bool $flag Whether or not the SELECT is FOR UPDATE (default true).
* @return Doctrine_Query
*/
public
function
forUpdate
(
$flag
=
true
)
{
$this
->
_parts
[
self
::
FOR_UPDATE
]
=
(
bool
)
$flag
;
return
$this
;
}
/**
* delete
* sets the query type to DELETE
*
* @return Doctrine_Query
*/
public
function
delete
()
{
$this
->
type
=
self
::
DELETE
;
return
$this
;
}
/**
* update
* sets the UPDATE part of the query
*
* @param string $update DQL UPDATE part
* @return Doctrine_Query
*/
public
function
update
(
$update
)
{
$this
->
type
=
self
::
UPDATE
;
return
$this
->
getParser
(
'from'
)
->
parse
(
$update
);
}
/**
* set
* sets the SET part of the query
*
* @param string $update DQL UPDATE part
* @return Doctrine_Query
*/
public
function
set
(
$key
,
$value
)
{
return
$this
->
getParser
(
'set'
)
->
parse
(
$key
.
' = '
.
$value
);
}
/**
* from
* sets the FROM part of the query
*
* @param string $from DQL FROM part
* @return Doctrine_Query
*/
public
function
from
(
$from
)
{
return
$this
->
getParser
(
'from'
)
->
parse
(
$from
);
}
/**
* innerJoin
* appends an INNER JOIN to the FROM part of the query
*
* @param string $join DQL INNER JOIN
* @return Doctrine_Query
*/
public
function
innerJoin
(
$join
)
{
return
$this
->
getParser
(
'from'
)
->
parse
(
'INNER JOIN '
.
$join
);
}
/**
* leftJoin
* appends a LEFT JOIN to the FROM part of the query
*
* @param string $join DQL LEFT JOIN
* @return Doctrine_Query
*/
public
function
leftJoin
(
$join
)
{
return
$this
->
getParser
(
'from'
)
->
parse
(
'LEFT JOIN '
.
$join
);
}
/**
* groupBy
* sets the GROUP BY part of the query
*
* @param string $groupby DQL GROUP BY part
* @return Doctrine_Query
*/
public
function
groupBy
(
$groupby
)
{
return
$this
->
getParser
(
'groupby'
)
->
parse
(
$groupby
);
}
/**
* where
* sets the WHERE part of the query
*
* @param string $join DQL WHERE part
* @param mixed $params an array of parameters or a simple scalar
* @return Doctrine_Query
*/
public
function
where
(
$where
,
$params
=
array
())
{
$this
->
params
=
(
array
)
$params
;
return
$this
->
getParser
(
'where'
)
->
parse
(
$where
);
}
/**
* having
* sets the HAVING part of the query
*
* @param string $having DQL HAVING part
* @param mixed $params an array of parameters or a simple scalar
* @return Doctrine_Query
*/
public
function
having
(
$having
,
$params
)
{
$this
->
params
=
(
array
)
$params
;
return
$this
->
getParser
(
'having'
)
->
parse
(
$having
);
}
/**
* orderBy
* sets the ORDER BY part of the query
*
* @param string $orderby DQL ORDER BY part
* @return Doctrine_Query
*/
public
function
orderBy
(
$orderby
)
{
return
$this
->
getParser
(
'orderby'
)
->
parse
(
$orderby
);
}
/**
* limit
* sets the DQL query limit
*
* @param integer $limit limit to be used for limiting the query results
* @return Doctrine_Query
*/
public
function
limit
(
$limit
)
{
return
$this
->
getParser
(
'limit'
)
->
parse
(
$limit
);
}
/**
* offset
* sets the DQL query offset
*
* @param integer $offset offset to be used for paginating the query
* @return Doctrine_Query
*/
public
function
offset
(
$offset
)
{
return
$this
->
getParser
(
'offset'
)
->
parse
(
$offset
);
}
}
lib/Doctrine/Collection.php
View file @
827755af
...
...
@@ -561,6 +561,14 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
return
$this
;
}
public
function
getDeleteDiff
()
{
return
array_diff
(
$this
->
_snapshot
,
$this
->
data
);
}
public
function
getInsertDiff
()
{
return
array_diff
(
$this
->
data
,
$this
->
_snapshot
);
}
/**
* save
* saves all records of this collection and processes the
...
...
lib/Doctrine/Connection.php
View file @
827755af
...
...
@@ -785,8 +785,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
}
$tableObject
->
getRelations
();
//$this->getTable('RelationTestChild')->getRelation('Children');
}
$next
=
count
(
$this
->
tables
);
}
...
...
lib/Doctrine/Connection/UnitOfWork.php
View file @
827755af
...
...
@@ -30,7 +30,7 @@ Doctrine::autoload('Doctrine_Connection_Module');
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class
Doctrine_Connection_UnitOfWork
extends
Doctrine_Connection_Module
implements
IteratorAggregate
,
Countable
class
Doctrine_Connection_UnitOfWork
extends
Doctrine_Connection_Module
{
/**
* buildFlushTree
...
...
@@ -163,6 +163,20 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module implemen
}
}
elseif
(
$fk
instanceof
Doctrine_Relation_Association
)
{
$assocTable
=
$fk
->
getAssociationTable
();
foreach
(
$v
->
getDeleteDiff
()
as
$r
)
{
$query
=
'DELETE FROM '
.
$assocTable
->
getTableName
()
.
' WHERE '
.
$fk
->
getForeign
()
.
' = ?'
.
' AND '
.
$fk
->
getLocal
()
.
' = ?'
;
$this
->
query
(
$r
->
getIncremented
(),
$record
->
getIncremented
());
}
foreach
(
$v
->
getInsertDiff
as
$r
)
{
$assocRecord
=
$assocTable
->
create
();
$assocRecord
->
set
(
$fk
->
getForeign
(),
$r
);
$assocRecord
->
set
(
$fk
->
getLocal
(),
$record
);
$assocRecord
->
save
(
$this
->
conn
);
}
$v
->
save
(
$this
->
conn
);
}
}
...
...
@@ -188,6 +202,8 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module implemen
foreach
(
$record
->
getTable
()
->
getRelations
()
as
$rel
)
{
$table
=
$rel
->
getTable
();
$alias
=
$rel
->
getAlias
();
}
}
/**
...
...
@@ -206,7 +222,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module implemen
$obj
=
$record
->
get
(
$fk
->
getAlias
());
$obj
->
delete
(
$this
->
conn
);
break
;
}
;
}
}
}
/**
...
...
@@ -347,9 +363,4 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module implemen
return
true
;
}
public
function
getIterator
()
{
}
public
function
count
()
{
}
}
lib/Doctrine/Query.php
View file @
827755af
...
...
@@ -205,7 +205,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable
*/
public
function
parseSelect
(
$dql
)
{
$refs
=
Doctrine_
Query
::
bracketExplode
(
$dql
,
','
);
$refs
=
Doctrine_
Tokenizer
::
bracketExplode
(
$dql
,
','
);
foreach
(
$refs
as
$reference
)
{
if
(
strpos
(
$reference
,
'('
)
!==
false
)
{
...
...
@@ -237,7 +237,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable
*/
public
function
parseSubselect
(
$reference
)
{
$e
=
Doctrine_
Query
::
bracketExplode
(
$reference
,
' '
);
$e
=
Doctrine_
Tokenizer
::
bracketExplode
(
$reference
,
' '
);
$alias
=
$e
[
1
];
if
(
count
(
$e
)
>
2
)
{
...
...
@@ -253,7 +253,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable
}
public
function
parseAggregateFunction2
(
$func
)
{
$e
=
Doctrine_
Query
::
bracketExplode
(
$func
,
' '
);
$e
=
Doctrine_
Tokenizer
::
bracketExplode
(
$func
,
' '
);
$func
=
$e
[
0
];
$pos
=
strpos
(
$func
,
'('
);
...
...
lib/Doctrine/Query/Check.php
View file @
827755af
...
...
@@ -83,7 +83,7 @@ class Doctrine_Query_Check
*/
public
function
parseClause
(
$dql
)
{
$parts
=
Doctrine_
Query
::
sqlExplode
(
$dql
,
' AND '
);
$parts
=
Doctrine_
Tokenizer
::
sqlExplode
(
$dql
,
' AND '
);
if
(
count
(
$parts
)
>
1
)
{
$ret
=
array
();
...
...
@@ -93,7 +93,7 @@ class Doctrine_Query_Check
$r
=
implode
(
' AND '
,
$ret
);
}
else
{
$parts
=
Doctrine_
Query
::
quoteExplode
(
$dql
,
' OR '
);
$parts
=
Doctrine_
Tokenizer
::
quoteExplode
(
$dql
,
' OR '
);
if
(
count
(
$parts
)
>
1
)
{
$ret
=
array
();
foreach
(
$parts
as
$part
)
{
...
...
lib/Doctrine/Relation/Association.php
View file @
827755af
...
...
@@ -42,6 +42,10 @@ class Doctrine_Relation_Association extends Doctrine_Relation
{
return
$this
->
definition
[
'assocTable'
];
}
public
function
getAssociationTable
()
{
return
$this
->
definition
[
'assocTable'
];
}
/**
* processDiff
*
...
...
tests/HydrateTestCase.php
View file @
827755af
...
...
@@ -19,12 +19,6 @@
* <http://www.phpdoctrine.com>.
*/
require_once
(
'../draft/new-core/Record.php'
);
require_once
(
'../draft/new-core/Hydrate.php'
);
require_once
(
'../draft/new-core/Query.php'
);
require_once
(
'../draft/new-core/Collection.php'
);
/**
* Doctrine_Hydrate_TestCase
*
...
...
@@ -36,8 +30,6 @@ require_once('../draft/new-core/Collection.php');
* @since 1.0
* @version $Revision$
*/
class
Doctrine_Hydrate_TestCase
extends
Doctrine_UnitTestCase
{
protected
$testData1
=
array
(
...
...
tests/RecordTestCase.php
View file @
827755af
...
...
@@ -31,14 +31,14 @@
* @version $Revision$
*/
class
Doctrine_Record_TestCase
extends
Doctrine_UnitTestCase
{
/**
public
function
prepareTables
()
{
$this
->
tables
[]
=
"enumTest"
;
$this
->
tables
[]
=
"fieldNameTest"
;
$this
->
tables
[]
=
"GzipTest"
;
parent
::
prepareTables
();
}
*/
public
function
testIssetForPrimaryKey
()
{
$this
->
assertTrue
(
isset
(
$this
->
users
[
0
]
->
id
));
$this
->
assertTrue
(
isset
(
$this
->
users
[
0
][
'id'
]));
...
...
@@ -50,7 +50,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase {
$this
->
assertFalse
(
isset
(
$user
[
'id'
]));
$this
->
assertFalse
(
$user
->
contains
(
'id'
));
}
/**
public
function
testUnknownColumn
()
{
}
...
...
@@ -299,14 +299,6 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase {
$this
->
assertEqual
(
$user
->
name
,
null
);
}
public function testDateTimeType() {
$date = new DateTest();
}
public
function
testSerialize
()
{
$user
=
$this
->
connection
->
getTable
(
"User"
)
->
find
(
4
);
$str
=
serialize
(
$user
);
...
...
@@ -324,9 +316,6 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase {
$user
->
call
(
'substr'
,
'name'
,
0
,
1
);
$this
->
assertEqual
(
$user
->
name
,
'z'
);
}
public
function
testCompositePK
()
{
$record
=
new
EntityReference
();
$this
->
assertEqual
(
$record
->
getTable
()
->
getIdentifier
(),
array
(
"entity1"
,
"entity2"
));
...
...
@@ -711,8 +700,8 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase {
$this
->
assertEqual
(
$new
->
loginname
,
'jackd'
);
}
public function testReferences()
{
public
function
testReferences
()
{
$user
=
$this
->
objTable
->
find
(
5
);
$pf
=
$this
->
connection
->
getTable
(
"Phonenumber"
);
...
...
@@ -946,13 +935,15 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase {
}
public function testCount() {
public
function
testCount
()
{
$user
=
$this
->
connection
->
getTable
(
"User"
)
->
find
(
4
);
$this
->
assertTrue
(
is_integer
(
$user
->
count
()));
}
public function testGetReference() {
public
function
testGetReference
()
{
$user
=
$this
->
connection
->
getTable
(
"User"
)
->
find
(
4
);
$this
->
assertTrue
(
$user
->
Email
instanceof
Doctrine_Record
);
...
...
@@ -961,10 +952,10 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase {
$this
->
assertTrue
(
$user
->
Phonenumber
->
count
()
==
1
);
}
public function testGetIterator() {
public
function
testGetIterator
()
{
$user
=
$this
->
connection
->
getTable
(
"User"
)
->
find
(
4
);
$this
->
assertTrue
(
$user
->
getIterator
()
instanceof
ArrayIterator
);
}
*/
}
?>
tests/UnitTestCase.php
View file @
827755af
...
...
@@ -228,9 +228,9 @@ class Doctrine_UnitTestCase extends UnitTestCase {
}
}
public
function
setUp
()
{
if
(
!
$this
->
init
)
$this
->
init
();
if
(
isset
(
$this
->
objTable
))
if
(
!
$this
->
init
)
{
$this
->
init
();
}
$this
->
objTable
->
clear
();
$this
->
init
=
true
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment