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
7b711ae7
Commit
7b711ae7
authored
May 24, 2008
by
romanb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactorings. merged hydration bugfix from 0.11.
parent
74ce82bd
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
51 additions
and
1419 deletions
+51
-1419
ClassMetadata.php
lib/Doctrine/ClassMetadata.php
+1
-1
Entity.php
lib/Doctrine/Entity.php
+24
-20
EntityRepository.php
lib/Doctrine/EntityRepository.php
+4
-5
HydratorNew.php
lib/Doctrine/HydratorNew.php
+6
-40
Mapper.php
lib/Doctrine/Mapper.php
+0
-747
DefaultStrategy.php
lib/Doctrine/Mapper/DefaultStrategy.php
+0
-120
Exception.php
lib/Doctrine/Mapper/Exception.php
+0
-3
JoinedStrategy.php
lib/Doctrine/Mapper/JoinedStrategy.php
+0
-318
Strategy.php
lib/Doctrine/Mapper/Strategy.php
+0
-156
Null.php
lib/Doctrine/Null.php
+11
-4
ForumUser.php
tests/models/forum/ForumUser.php
+5
-5
No files found.
lib/Doctrine/ClassMetadata.php
View file @
7b711ae7
lib/Doctrine/Entity.php
View file @
7b711ae7
...
...
@@ -994,26 +994,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Countable, Ite
*/
public
function
get
(
$fieldName
,
$load
=
false
)
{
/*// check for custom accessor, if not done yet.
if ( ! isset(self::$_accessorCache[$this->_entityName][$fieldName])) {
if (self::$_useAutoAccessorOverride) {
$getterMethod = 'get' . Doctrine::classify($fieldName);
if (method_exists($this, $getterMethod)) {
self::$_accessorCache[$this->_entityName][$fieldName] = $getterMethod;
} else {
self::$_accessorCache[$this->_entityName][$fieldName] = false;
}
}
if ($getter = $this->_class->getCustomAccessor($fieldName)) {
self::$_accessorCache[$this->_entityName][$fieldName] = $getter;
} else if ( ! isset(self::$_accessorCache[$this->_entityName][$fieldName])) {
self::$_accessorCache[$this->_entityName][$fieldName] = false;
}
}
// invoke custom accessor, if it exists.
if ($getter = self::$_accessorCache[$this->_entityName][$fieldName]) {
return $this->$getter();
}*/
$this
->
_invokeCustomAccessor
(
$fieldName
);
// Use built-in accessor functionality
$nullObj
=
Doctrine_Null
::
$INSTANCE
;
...
...
@@ -1046,6 +1027,29 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Countable, Ite
}
}
private
function
_invokeCustomAccessor
(
$fieldName
)
{
if
(
!
isset
(
self
::
$_accessorCache
[
$this
->
_entityName
][
$fieldName
]))
{
if
(
self
::
$_useAutoAccessorOverride
)
{
$getterMethod
=
'get'
.
Doctrine
::
classify
(
$fieldName
);
if
(
method_exists
(
$this
,
$getterMethod
))
{
self
::
$_accessorCache
[
$this
->
_entityName
][
$fieldName
]
=
$getterMethod
;
}
else
{
self
::
$_accessorCache
[
$this
->
_entityName
][
$fieldName
]
=
false
;
}
}
if
(
$getter
=
$this
->
_class
->
getCustomAccessor
(
$fieldName
))
{
self
::
$_accessorCache
[
$this
->
_entityName
][
$fieldName
]
=
$getter
;
}
else
if
(
!
isset
(
self
::
$_accessorCache
[
$this
->
_entityName
][
$fieldName
]))
{
self
::
$_accessorCache
[
$this
->
_entityName
][
$fieldName
]
=
false
;
}
}
// invoke custom accessor, if it exists.
if
(
$getter
=
self
::
$_accessorCache
[
$this
->
_entityName
][
$fieldName
])
{
return
$this
->
$getter
();
}
}
public
function
getClassName
()
{
return
$this
->
_entityName
;
...
...
lib/Doctrine/EntityRepository.php
View file @
7b711ae7
...
...
@@ -59,7 +59,7 @@ class Doctrine_EntityRepository
if
(
!
empty
(
$alias
))
{
$alias
=
' '
.
trim
(
$alias
);
}
return
Doctrine_Query
::
create
(
$this
->
_em
)
->
from
(
$this
->
_entityName
.
$alias
);
return
$this
->
_em
->
createQuery
(
)
->
from
(
$this
->
_entityName
.
$alias
);
}
/**
...
...
@@ -101,11 +101,10 @@ class Doctrine_EntityRepository
}
/**
* Finds all entities of the mapper's class.
* Use with care.
* Finds all entities in the repository.
*
* @param int $hydrationMode
Doctrine::HYDRATE_ARRAY or Doctrine::HYDRATE_RECORD
* @return
Doctrine_Collection
* @param int $hydrationMode
* @return
mixed
*/
public
function
findAll
(
$hydrationMode
=
null
)
{
...
...
lib/Doctrine/HydratorNew.php
View file @
7b711ae7
...
...
@@ -102,8 +102,6 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
$driver
=
new
Doctrine_Hydrator_RecordDriver
(
$this
->
_em
);
}
$event
=
new
Doctrine_Event
(
null
,
Doctrine_Event
::
HYDRATE
,
null
);
$s
=
microtime
(
true
);
// Used variables during hydration
...
...
@@ -112,8 +110,6 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
$rootComponentName
=
$this
->
_queryComponents
[
$rootAlias
][
'table'
]
->
getClassName
();
// if only one class is involved we can make our lives easier
$isSimpleQuery
=
count
(
$this
->
_queryComponents
)
<=
1
;
// Holds hydration listeners that get called during hydration
$listeners
=
array
();
// Lookup map to quickly discover/lookup existing records in the result
// It's the identifier "memory"
$identifierMap
=
array
();
...
...
@@ -142,13 +138,11 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
// disable lazy-loading of related elements during hydration
$component
[
'table'
]
->
setAttribute
(
Doctrine
::
ATTR_LOAD_REFERENCES
,
false
);
$componentName
=
$component
[
'table'
]
->
getClassName
();
//$listeners[$componentName] = $component['table']->getRecordListener();
$identifierMap
[
$dqlAlias
]
=
array
();
$resultPointers
[
$dqlAlias
]
=
array
();
$idTemplate
[
$dqlAlias
]
=
''
;
}
$cache
=
array
();
// Evaluate HYDRATE_SINGLE_SCALAR
if
(
$hydrationMode
==
Doctrine
::
HYDRATE_SINGLE_SCALAR
)
{
...
...
@@ -177,21 +171,11 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
$class
=
$this
->
_queryComponents
[
$rootAlias
][
'table'
];
$componentName
=
$class
->
getComponentName
();
// just event stuff
//$event->set('data', $rowData[$rootAlias]);
//$listeners[$componentName]->preHydrate($event);
//--
// Check for an existing element
$index
=
false
;
if
(
$isSimpleQuery
||
!
isset
(
$identifierMap
[
$rootAlias
][
$id
[
$rootAlias
]]))
{
$element
=
$driver
->
getElement
(
$rowData
[
$rootAlias
],
$componentName
);
// just event stuff
//$event->set('data', $element);
//$listeners[$componentName]->postHydrate($event);
//--
// do we need to index by a custom field?
if
(
$field
=
$this
->
_getCustomIndexField
(
$rootAlias
))
{
// TODO: must be checked in the parser. fields used in INDEXBY
...
...
@@ -230,17 +214,11 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
}
// now hydrate the rest of the data found in the current row, that belongs to other
// (related) c
omponent
s.
// (related) c
lasse
s.
foreach
(
$rowData
as
$dqlAlias
=>
$data
)
{
$index
=
false
;
$map
=
$this
->
_queryComponents
[
$dqlAlias
];
$componentName
=
$map
[
'table'
]
->
getComponentName
();
// just event stuff
//$event->set('data', $data);
//$listeners[$componentName]->preHydrate($event);
//--
$componentName
=
$map
[
'table'
]
->
getClassName
();
$parent
=
$map
[
'parent'
];
$relation
=
$map
[
'relation'
];
$relationAlias
=
$relation
->
getAlias
();
...
...
@@ -263,30 +241,18 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
$oneToOne
=
false
;
if
(
isset
(
$nonemptyComponents
[
$dqlAlias
]))
{
$driver
->
initRelatedCollection
(
$baseElement
,
$relationAlias
);
if
(
!
isset
(
$identifierMap
[
$path
][
$id
[
$parent
]][
$id
[
$dqlAlias
]]))
{
$indexExists
=
isset
(
$identifierMap
[
$path
][
$id
[
$parent
]][
$id
[
$dqlAlias
]]);
$index
=
$indexExists
?
$identifierMap
[
$path
][
$id
[
$parent
]][
$id
[
$dqlAlias
]]
:
false
;
$indexIsValid
=
$index
!==
false
?
isset
(
$baseElement
[
$relationAlias
][
$index
])
:
false
;
if
(
!
$indexExists
||
!
$indexIsValid
)
{
$element
=
$driver
->
getElement
(
$data
,
$componentName
);
// just event stuff
//$event->set('data', $element);
//$listeners[$componentName]->postHydrate($event);
//--
if
(
$field
=
$this
->
_getCustomIndexField
(
$dqlAlias
))
{
// TODO: must be checked in the parser. fields used in INDEXBY
// must be a) the primary key or b) unique & notnull
/*if ($driver->isIndexKeyInUse($baseElement, $relationAlias, $field)) {
throw Doctrine_Hydrator_Exception::nonUniqueKeyMapping();
} else if ( ! $driver->isFieldSet($element, $field)) {
throw Doctrine_Hydrator_Exception::nonExistantFieldUsedAsIndex($field);
}*/
$driver
->
addRelatedIndexedElement
(
$baseElement
,
$relationAlias
,
$element
,
$field
);
}
else
{
$driver
->
addRelatedElement
(
$baseElement
,
$relationAlias
,
$element
);
}
$identifierMap
[
$path
][
$id
[
$parent
]][
$id
[
$dqlAlias
]]
=
$driver
->
getLastKey
(
$driver
->
getReferenceValue
(
$baseElement
,
$relationAlias
));
}
else
{
$index
=
$identifierMap
[
$path
][
$id
[
$parent
]][
$id
[
$dqlAlias
]];
}
}
else
if
(
!
isset
(
$baseElement
[
$relationAlias
]))
{
$driver
->
setRelatedElement
(
$baseElement
,
$relationAlias
,
...
...
lib/Doctrine/Mapper.php
deleted
100644 → 0
View file @
74ce82bd
<?php
/*
* $Id$
*
* 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.org>.
*/
/**
* A Mapper is responsible for mapping between the domain model and the database
* back and forth. Each entity in the domain model has a corresponding mapper.
*
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision: 3406 $
* @link www.phpdoctrine.org
* @since 2.0
* @todo Rename to "EntityPersister" or similar.
*/
class
Doctrine_Mapper
{
/**
* Metadata object that descibes the mapping of the mapped entity class.
*
* @var Doctrine_ClassMetadata
*/
protected
$_classMetadata
;
/**
* The name of the domain class this mapper is used for.
*/
protected
$_domainClassName
;
/**
* The Doctrine_Connection object that the database connection of this mapper.
*
* @var Doctrine_Connection $conn
*/
protected
$_conn
;
/**
* The concrete mapping strategy that is used.
*/
protected
$_mappingStrategy
;
/**
* Null object.
*/
private
$_nullObject
;
/**
* A list of registered entity listeners.
*/
private
$_entityListeners
=
array
();
/**
* Enter description here...
*
* @var unknown_type
* @todo To EntityManager.
*/
private
$_dataTemplate
=
array
();
/**
* Constructs a new mapper.
*
* @param string $name The name of the domain class this mapper is used for.
* @param Doctrine_Table $table The table object used for the mapping procedure.
* @throws Doctrine_Connection_Exception if there are no opened connections
*/
public
function
__construct
(
$name
,
Doctrine_ClassMetadata
$classMetadata
)
{
$this
->
_domainClassName
=
$name
;
$this
->
_conn
=
$classMetadata
->
getConnection
();
$this
->
_classMetadata
=
$classMetadata
;
$this
->
_nullObject
=
Doctrine_Null
::
$INSTANCE
;
if
(
$classMetadata
->
getInheritanceType
()
==
Doctrine
::
INHERITANCE_TYPE_JOINED
)
{
$this
->
_mappingStrategy
=
new
Doctrine_Mapper_JoinedStrategy
(
$this
);
}
else
{
$this
->
_mappingStrategy
=
new
Doctrine_Mapper_DefaultStrategy
(
$this
);
}
}
/**
* sets the connection for this class
*
* @params Doctrine_Connection a connection object
* @return Doctrine_Table this object
* @todo refactor
*/
public
function
setConnection
(
Doctrine_Connection
$conn
)
{
$this
->
_conn
=
$conn
;
return
$this
;
}
/**
* Returns the connection the mapper is currently using.
*
* @return Doctrine_Connection|null The connection object.
*/
public
function
getConnection
()
{
return
$this
->
_conn
;
}
/**
* creates a new record
*
* @param $array an array where keys are field names and
* values representing field values
* @return Doctrine_Entity the created record object
* @todo To EntityManager.
*/
public
function
create
(
array
$array
=
array
())
{
$record
=
new
$this
->
_domainClassName
();
$record
->
fromArray
(
$array
);
return
$record
;
}
public
function
addEntityListener
(
Doctrine_Record_Listener
$listener
)
{
if
(
!
in_array
(
$listener
,
$this
->
_entityListeners
))
{
$this
->
_entityListeners
[]
=
$listener
;
return
true
;
}
return
false
;
}
public
function
removeEntityListener
(
Doctrine_Record_Listener
$listener
)
{
if
(
$key
=
array_search
(
$listener
,
$this
->
_entityListeners
,
true
))
{
unset
(
$this
->
_entityListeners
[
$key
]);
return
true
;
}
return
false
;
}
public
function
notifyEntityListeners
(
Doctrine_Entity
$entity
,
$callback
,
$eventType
)
{
if
(
$this
->
_entityListeners
)
{
$event
=
new
Doctrine_Event
(
$entity
,
$eventType
);
foreach
(
$this
->
_entityListeners
as
$listener
)
{
$listener
->
$callback
(
$event
);
}
}
}
/**
* Enter description here...
*
* @param Doctrine_Entity $entity
* @return unknown
* @todo To EntityManager
*/
public
function
detach
(
Doctrine_Entity
$entity
)
{
return
$this
->
_conn
->
unitOfWork
->
detach
(
$entity
);
}
/**
* clear
* clears the first level cache (identityMap)
*
* @return void
* @todo what about a more descriptive name? clearIdentityMap?
* @todo To EntityManager
*/
public
function
clear
()
{
$this
->
_conn
->
unitOfWork
->
clearIdentitiesForEntity
(
$this
->
_classMetadata
->
getRootClassName
());
}
/**
* addRecord
* adds a record to identity map
*
* @param Doctrine_Entity $record record to be added
* @return boolean
* @todo Better name? registerRecord? Move elsewhere to the new location of the identity maps.
* @todo Remove.
*/
public
function
addRecord
(
Doctrine_Entity
$record
)
{
if
(
$this
->
_conn
->
unitOfWork
->
contains
(
$record
))
{
return
false
;
}
$this
->
_conn
->
unitOfWork
->
registerIdentity
(
$record
);
return
true
;
}
/**
* Tells the mapper to manage the entity if it's not already managed.
*
* @return boolean TRUE if the entity was previously not managed and is now managed,
* FALSE otherwise (the entity is already managed).
* @todo Remove.
*/
public
function
manage
(
Doctrine_Entity
$record
)
{
return
$this
->
_conn
->
unitOfWork
->
manage
(
$record
);
}
/**
* removeRecord
* removes a record from the identity map, returning true if the record
* was found and removed and false if the record wasn't found.
*
* @param Doctrine_Entity $record record to be removed
* @return boolean
* @todo Move elsewhere to the new location of the identity maps.
*/
public
function
removeRecord
(
Doctrine_Entity
$record
)
{
if
(
$this
->
_conn
->
unitOfWork
->
contains
(
$record
))
{
$this
->
_conn
->
unitOfWork
->
unregisterIdentity
(
$record
);
return
true
;
}
return
false
;
}
/**
* getRecord
* First checks if record exists in identityMap, if not
* returns a new record.
*
* @return Doctrine_Entity
* @todo To EntityManager.
*/
public
function
getRecord
(
array
$data
)
{
if
(
!
empty
(
$data
))
{
$identifierFieldNames
=
$this
->
_classMetadata
->
getIdentifier
();
$found
=
false
;
foreach
(
$identifierFieldNames
as
$fieldName
)
{
if
(
!
isset
(
$data
[
$fieldName
]))
{
// primary key column not found return new record
$found
=
true
;
break
;
}
$id
[]
=
$data
[
$fieldName
];
}
if
(
$found
)
{
return
new
$this
->
_domainClassName
(
true
,
$data
);
}
$idHash
=
$this
->
_conn
->
unitOfWork
->
getIdentifierHash
(
$id
);
if
(
$record
=
$this
->
_conn
->
unitOfWork
->
tryGetByIdHash
(
$idHash
,
$this
->
_classMetadata
->
getRootClassName
()))
{
$record
->
hydrate
(
$data
);
}
else
{
$record
=
new
$this
->
_domainClassName
(
false
,
$data
);
$this
->
_conn
->
unitOfWork
->
registerIdentity
(
$record
);
}
$data
=
array
();
}
else
{
$record
=
new
$this
->
_domainClassName
(
true
,
$data
);
}
return
$record
;
}
/**
* @param $id database row id
* @todo Looks broken. Figure out an implementation and decide whether its needed.
*/
final
public
function
getProxy
(
$id
=
null
)
{
if
(
$id
!==
null
)
{
$identifierColumnNames
=
$this
->
_classMetadata
->
getIdentifierColumnNames
();
$query
=
'SELECT '
.
implode
(
', '
,
$identifierColumnNames
)
.
' FROM '
.
$this
->
_classMetadata
->
getTableName
()
.
' WHERE '
.
implode
(
' = ? && '
,
$identifierColumnNames
)
.
' = ?'
;
$query
=
$this
->
applyInheritance
(
$query
);
$params
=
array_merge
(
array
(
$id
),
array
());
$data
=
$this
->
_conn
->
execute
(
$query
,
$params
)
->
fetch
(
PDO
::
FETCH_ASSOC
);
if
(
$data
===
false
)
{
return
false
;
}
}
return
$this
->
getRecord
(
$data
);
}
/**
* applyInheritance
* @param $where query where part to be modified
* @return string query where part with column aggregation inheritance added
* @todo What to do with this? Remove if possible.
*/
final
public
function
applyInheritance
(
$where
)
{
$discCol
=
$this
->
_classMetadata
->
getInheritanceOption
(
'discriminatorColumn'
);
if
(
!
$discCol
)
{
return
$where
;
}
$discMap
=
$this
->
_classMetadata
->
getInheritanceOption
(
'discriminatorMap'
);
$inheritanceMap
=
array
(
$discCol
=>
array_search
(
$this
->
_domainClassName
,
$discMap
));
if
(
!
empty
(
$inheritanceMap
))
{
$a
=
array
();
foreach
(
$inheritanceMap
as
$column
=>
$value
)
{
$a
[]
=
$column
.
' = ?'
;
}
$i
=
implode
(
' AND '
,
$a
);
$where
.=
' AND '
.
$i
;
}
return
$where
;
}
/**
* prepareValue
* this method performs special data preparation depending on
* the type of the given column
*
* 1. It unserializes array and object typed columns
* 2. Uncompresses gzip typed columns
* 3. Gets the appropriate enum values for enum typed columns
* 4. Initializes special null object pointer for null values (for fast column existence checking purposes)
*
* example:
* <code type='php'>
* $field = 'name';
* $value = null;
* $table->prepareValue($field, $value); // Doctrine_Null
* </code>
*
* @throws Doctrine_Table_Exception if unserialization of array/object typed column fails or
* @throws Doctrine_Table_Exception if uncompression of gzip typed column fails *
* @param string $field the name of the field
* @param string $value field value
* @param string $typeHint A hint on the type of the value. If provided, the type lookup
* for the field can be skipped. Used i.e. during hydration to
* improve performance on large and/or complex results.
* @return mixed prepared value
* @todo To EntityManager. Make private and use in createEntity().
* .. Or, maybe better: Move to hydrator for performance reasons.
*/
public
function
prepareValue
(
$fieldName
,
$value
,
$typeHint
=
null
)
{
if
(
$value
===
$this
->
_nullObject
)
{
return
$this
->
_nullObject
;
}
else
if
(
$value
===
null
)
{
return
null
;
}
else
{
$type
=
is_null
(
$typeHint
)
?
$this
->
_classMetadata
->
getTypeOf
(
$fieldName
)
:
$typeHint
;
switch
(
$type
)
{
case
'integer'
:
case
'string'
;
// don't do any casting here PHP INT_MAX is smaller than what the databases support
break
;
case
'enum'
:
return
$this
->
_classMetadata
->
enumValue
(
$fieldName
,
$value
);
break
;
case
'boolean'
:
return
(
boolean
)
$value
;
break
;
case
'array'
:
case
'object'
:
if
(
is_string
(
$value
))
{
$value
=
unserialize
(
$value
);
if
(
$value
===
false
)
{
throw
new
Doctrine_Mapper_Exception
(
'Unserialization of '
.
$fieldName
.
' failed.'
);
}
return
$value
;
}
break
;
case
'gzip'
:
$value
=
gzuncompress
(
$value
);
if
(
$value
===
false
)
{
throw
new
Doctrine_Mapper_Exception
(
'Uncompressing of '
.
$fieldName
.
' failed.'
);
}
return
$value
;
break
;
}
}
return
$value
;
}
/**
* getComponentName
*
* @return void
* @deprecated Use getMappedClassName()
*/
public
function
getComponentName
()
{
return
$this
->
_domainClassName
;
}
/**
* Gets the name of the class the mapper is used for.
*/
public
function
getMappedClassName
()
{
return
$this
->
_domainClassName
;
}
/**
* Saves an entity and all it's related entities.
*
* @param Doctrine_Entity $record The entity to save.
* @param Doctrine_Connection $conn The connection to use. Will default to the mapper's
* connection.
* @throws Doctrine_Mapper_Exception If the mapper is unable to save the given entity.
*/
public
function
save
(
Doctrine_Entity
$record
,
Doctrine_Connection
$conn
=
null
)
{
if
(
!
(
$record
instanceof
$this
->
_domainClassName
))
{
throw
new
Doctrine_Mapper_Exception
(
"Mapper of type "
.
$this
->
_domainClassName
.
"
can't save instances of type"
.
get_class
(
$record
)
.
"."
);
}
if
(
$conn
===
null
)
{
$conn
=
$this
->
_conn
;
}
$state
=
$record
->
state
();
if
(
$state
===
Doctrine_Entity
::
STATE_LOCKED
)
{
return
false
;
}
$record
->
state
(
Doctrine_Entity
::
STATE_LOCKED
);
try
{
$conn
->
beginInternalTransaction
();
$saveLater
=
$this
->
_saveRelated
(
$record
);
$record
->
state
(
$state
);
if
(
$record
->
isValid
())
{
$this
->
_insertOrUpdate
(
$record
);
}
else
{
$conn
->
transaction
->
addInvalid
(
$record
);
}
$state
=
$record
->
state
();
$record
->
state
(
Doctrine_Entity
::
STATE_LOCKED
);
foreach
(
$saveLater
as
$fk
)
{
$alias
=
$fk
->
getAlias
();
if
(
$record
->
hasReference
(
$alias
))
{
$obj
=
$record
->
$alias
;
// check that the related object is not an instance of Doctrine_Null
if
(
!
(
$obj
instanceof
Doctrine_Null
))
{
$obj
->
save
(
$conn
);
}
}
}
// save the MANY-TO-MANY associations
$this
->
saveAssociations
(
$record
);
// reset state
$record
->
state
(
$state
);
$conn
->
commit
();
}
catch
(
Exception
$e
)
{
$conn
->
rollback
();
throw
$e
;
}
return
true
;
}
/**
* Inserts or updates an entity, depending on it's state.
*
* @param Doctrine_Entity $record The entity to insert/update.
*/
protected
function
_insertOrUpdate
(
Doctrine_Entity
$record
)
{
$record
->
preSave
();
$this
->
notifyEntityListeners
(
$record
,
'preSave'
,
Doctrine_Event
::
RECORD_SAVE
);
switch
(
$record
->
state
())
{
case
Doctrine_Entity
::
STATE_TDIRTY
:
$this
->
_insert
(
$record
);
break
;
case
Doctrine_Entity
::
STATE_DIRTY
:
case
Doctrine_Entity
::
STATE_PROXY
:
$this
->
_update
(
$record
);
break
;
case
Doctrine_Entity
::
STATE_CLEAN
:
case
Doctrine_Entity
::
STATE_TCLEAN
:
// do nothing
break
;
}
$record
->
postSave
();
$this
->
notifyEntityListeners
(
$record
,
'postSave'
,
Doctrine_Event
::
RECORD_SAVE
);
}
/**
* saves the given record
*
* @param Doctrine_Entity $record
* @return void
*/
public
function
saveSingleRecord
(
Doctrine_Entity
$record
)
{
$this
->
_insertOrUpdate
(
$record
);
}
/**
* _saveRelated
* saves all related records to $record
*
* @throws PDOException if something went wrong at database level
* @param Doctrine_Entity $record
*/
protected
function
_saveRelated
(
Doctrine_Entity
$record
)
{
$saveLater
=
array
();
foreach
(
$record
->
getReferences
()
as
$k
=>
$v
)
{
$rel
=
$record
->
getTable
()
->
getRelation
(
$k
);
$local
=
$rel
->
getLocal
();
$foreign
=
$rel
->
getForeign
();
if
(
$rel
instanceof
Doctrine_Relation_ForeignKey
)
{
$saveLater
[
$k
]
=
$rel
;
}
else
if
(
$rel
instanceof
Doctrine_Relation_LocalKey
)
{
// ONE-TO-ONE relationship
$obj
=
$record
->
get
(
$rel
->
getAlias
());
// Protection against infinite function recursion before attempting to save
if
(
$obj
instanceof
Doctrine_Entity
&&
$obj
->
isModified
())
{
$obj
->
save
(
$this
->
_conn
);
/** Can this be removed?
$id = array_values($obj->identifier());
foreach ((array) $rel->getLocal() as $k => $field) {
$record->set($field, $id[$k]);
}
*/
}
}
}
return
$saveLater
;
}
/**
* saveAssociations
*
* this method takes a diff of one-to-many / many-to-many original and
* current collections and applies the changes
*
* for example if original many-to-many related collection has records with
* primary keys 1,2 and 3 and the new collection has records with primary keys
* 3, 4 and 5, this method would first destroy the associations to 1 and 2 and then
* save new associations to 4 and 5
*
* @throws Doctrine_Connection_Exception if something went wrong at database level
* @param Doctrine_Entity $record
* @return void
*/
public
function
saveAssociations
(
Doctrine_Entity
$record
)
{
foreach
(
$record
->
getReferences
()
as
$relationName
=>
$relatedObject
)
{
if
(
$relatedObject
===
Doctrine_Null
::
$INSTANCE
)
{
continue
;
}
$rel
=
$record
->
getTable
()
->
getRelation
(
$relationName
);
if
(
$rel
instanceof
Doctrine_Relation_Association
)
{
$relatedObject
->
save
(
$this
->
_conn
);
$assocTable
=
$rel
->
getAssociationTable
();
foreach
(
$relatedObject
->
getDeleteDiff
()
as
$r
)
{
$query
=
'DELETE FROM '
.
$assocTable
->
getTableName
()
.
' WHERE '
.
$rel
->
getForeign
()
.
' = ?'
.
' AND '
.
$rel
->
getLocal
()
.
' = ?'
;
// FIXME: composite key support
$ids1
=
$r
->
identifier
();
$id1
=
count
(
$ids1
)
>
0
?
array_pop
(
$ids1
)
:
null
;
$ids2
=
$record
->
identifier
();
$id2
=
count
(
$ids2
)
>
0
?
array_pop
(
$ids2
)
:
null
;
$this
->
_conn
->
execute
(
$query
,
array
(
$id1
,
$id2
));
}
$assocMapper
=
$this
->
_conn
->
getMapper
(
$assocTable
->
getComponentName
());
foreach
(
$relatedObject
->
getInsertDiff
()
as
$r
)
{
$assocRecord
=
$assocMapper
->
create
();
$assocRecord
->
set
(
$assocTable
->
getFieldName
(
$rel
->
getForeign
()),
$r
);
$assocRecord
->
set
(
$assocTable
->
getFieldName
(
$rel
->
getLocal
()),
$record
);
$assocMapper
->
save
(
$assocRecord
);
}
}
}
}
/**
* Updates an entity.
*
* @param Doctrine_Entity $record record to be updated
* @return boolean whether or not the update was successful
* @todo Move to Doctrine_Table (which will become Doctrine_Mapper).
*/
protected
function
_update
(
Doctrine_Entity
$record
)
{
$record
->
preUpdate
();
$this
->
notifyEntityListeners
(
$record
,
'preUpdate'
,
Doctrine_Event
::
RECORD_UPDATE
);
$table
=
$this
->
_classMetadata
;
$this
->
_mappingStrategy
->
doUpdate
(
$record
);
$record
->
postUpdate
();
$this
->
notifyEntityListeners
(
$record
,
'postUpdate'
,
Doctrine_Event
::
RECORD_UPDATE
);
return
true
;
}
/**
* Inserts an entity.
*
* @param Doctrine_Entity $record record to be inserted
* @return boolean
*/
protected
function
_insert
(
Doctrine_Entity
$record
)
{
$record
->
preInsert
();
$this
->
notifyEntityListeners
(
$record
,
'preInsert'
,
Doctrine_Event
::
RECORD_INSERT
);
$this
->
_mappingStrategy
->
doInsert
(
$record
);
$this
->
addRecord
(
$record
);
$record
->
postInsert
();
$this
->
notifyEntityListeners
(
$record
,
'postInsert'
,
Doctrine_Event
::
RECORD_INSERT
);
return
true
;
}
/**
* Deletes given entity and all it's related entities.
*
* Triggered Events: onPreDelete, onDelete.
*
* @return boolean true on success, false on failure
* @throws Doctrine_Mapper_Exception
*/
public
function
delete
(
Doctrine_Entity
$record
,
Doctrine_Connection
$conn
=
null
)
{
if
(
!
$record
->
exists
())
{
return
false
;
}
if
(
!
(
$record
instanceof
$this
->
_domainClassName
))
{
throw
new
Doctrine_Mapper_Exception
(
"Mapper of type "
.
$this
->
_domainClassName
.
"
can't save instances of type"
.
get_class
(
$record
)
.
"."
);
}
if
(
$conn
==
null
)
{
$conn
=
$this
->
_conn
;
}
$record
->
preDelete
();
$this
->
notifyEntityListeners
(
$record
,
'preDelete'
,
Doctrine_Event
::
RECORD_DELETE
);
$table
=
$this
->
_classMetadata
;
$state
=
$record
->
state
();
$record
->
state
(
Doctrine_Entity
::
STATE_LOCKED
);
$this
->
_mappingStrategy
->
doDelete
(
$record
);
$record
->
postDelete
();
$this
->
notifyEntityListeners
(
$record
,
'postDelete'
,
Doctrine_Event
::
RECORD_DELETE
);
return
true
;
}
public
function
getClassMetadata
()
{
return
$this
->
_classMetadata
;
}
public
function
free
()
{
$this
->
_mappingStrategy
=
null
;
}
public
function
getMapping
()
{
return
$this
->
_mappingStrategy
;
}
public
function
getFieldName
(
$columnName
)
{
return
$this
->
_mappingStrategy
->
getFieldName
(
$columnName
);
}
public
function
getFieldNames
()
{
return
$this
->
_mappingStrategy
->
getFieldNames
();
}
public
function
getOwningClass
(
$fieldName
)
{
return
$this
->
_mappingStrategy
->
getOwningClass
(
$fieldName
);
}
/* Hooks used during SQL query construction to manipulate the query. */
/**
* Callback that is invoked during the SQL construction process.
*/
public
function
getCustomJoins
()
{
return
$this
->
_mappingStrategy
->
getCustomJoins
();
}
/**
* Callback that is invoked during the SQL construction process.
*/
public
function
getCustomFields
()
{
return
$this
->
_mappingStrategy
->
getCustomFields
();
}
}
lib/Doctrine/Mapper/DefaultStrategy.php
deleted
100644 → 0
View file @
74ce82bd
<?php
/*
* $Id$
*
* 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.org>.
*/
/**
* The default mapping strategy maps a single entity instance to a single database table,
* as is the case in Single Table Inheritance & Concrete Table Inheritance.
*
* @author Roman Borschel <roman@code-factory.org>
* @package Doctrine
* @subpackage DefaultStrategy
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision$
* @link www.phpdoctrine.org
* @since 1.0
*/
class
Doctrine_Mapper_DefaultStrategy
extends
Doctrine_Mapper_Strategy
{
/**
* Deletes an entity.
*/
public
function
doDelete
(
Doctrine_Entity
$record
)
{
$conn
=
$this
->
_mapper
->
getConnection
();
$metadata
=
$this
->
_mapper
->
getClassMetadata
();
try
{
$conn
->
beginInternalTransaction
();
$this
->
_deleteComposites
(
$record
);
$record
->
state
(
Doctrine_Entity
::
STATE_TDIRTY
);
$identifier
=
$this
->
_convertFieldToColumnNames
(
$record
->
identifier
(),
$metadata
);
$this
->
_deleteRow
(
$metadata
->
getTableName
(),
$identifier
);
$record
->
state
(
Doctrine_Entity
::
STATE_TCLEAN
);
$this
->
_mapper
->
removeRecord
(
$record
);
$conn
->
commit
();
}
catch
(
Exception
$e
)
{
$conn
->
rollback
();
throw
$e
;
}
}
/**
* Inserts a single entity into the database, without any related entities.
*
* @param Doctrine_Entity $record The entity to insert.
*/
public
function
doInsert
(
Doctrine_Entity
$record
)
{
$conn
=
$this
->
_mapper
->
getConnection
();
$fields
=
$record
->
getPrepared
();
if
(
empty
(
$fields
))
{
return
false
;
}
//$class = $record->getClassMetadata();
$class
=
$this
->
_mapper
->
getClassMetadata
();
$identifier
=
(
array
)
$class
->
getIdentifier
();
$fields
=
$this
->
_convertFieldToColumnNames
(
$fields
,
$class
);
$seq
=
$class
->
getTableOption
(
'sequenceName'
);
if
(
!
empty
(
$seq
))
{
$id
=
$conn
->
sequence
->
nextId
(
$seq
);
$seqName
=
$identifier
[
0
];
$fields
[
$seqName
]
=
$id
;
$record
->
assignIdentifier
(
$id
);
}
$this
->
_insertRow
(
$class
->
getTableName
(),
$fields
);
if
(
empty
(
$seq
)
&&
count
(
$identifier
)
==
1
&&
$class
->
getIdentifierType
()
!=
Doctrine
::
IDENTIFIER_NATURAL
)
{
if
(
strtolower
(
$conn
->
getName
())
==
'pgsql'
)
{
$seq
=
$class
->
getTableName
()
.
'_'
.
$identifier
[
0
];
}
$id
=
$conn
->
sequence
->
lastInsertId
(
$seq
);
if
(
!
$id
)
{
throw
new
Doctrine_Mapper_Exception
(
"Couldn't get last insert identifier."
);
}
$record
->
assignIdentifier
(
$id
);
}
else
{
$record
->
assignIdentifier
(
true
);
}
}
/**
* Updates an entity.
*/
public
function
doUpdate
(
Doctrine_Entity
$record
)
{
$conn
=
$this
->
_mapper
->
getConnection
();
$classMetadata
=
$this
->
_mapper
->
getClassMetadata
();
$identifier
=
$this
->
_convertFieldToColumnNames
(
$record
->
identifier
(),
$classMetadata
);
$data
=
$this
->
_convertFieldToColumnNames
(
$record
->
getPrepared
(),
$classMetadata
);
$this
->
_updateRow
(
$classMetadata
->
getTableName
(),
$data
,
$identifier
);
$record
->
assignIdentifier
(
true
);
}
}
\ No newline at end of file
lib/Doctrine/Mapper/Exception.php
deleted
100644 → 0
View file @
74ce82bd
<?php
class
Doctrine_Mapper_Exception
extends
Doctrine_Exception
{}
\ No newline at end of file
lib/Doctrine/Mapper/JoinedStrategy.php
deleted
100644 → 0
View file @
74ce82bd
<?php
/*
* $Id$
*
* 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.org>.
*/
/**
* The joined mapping strategy maps a single entity instance to several tables in the
* database as it is defined by <tt>Class Table Inheritance</tt>.
*
* @author Roman Borschel <roman@code-factory.org>
* @package Doctrine
* @subpackage DefaultStrategy
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision$
* @link www.phpdoctrine.org
* @since 1.0
*/
class
Doctrine_Mapper_JoinedStrategy
extends
Doctrine_Mapper_Strategy
{
protected
$_columnNameFieldNameMap
=
array
();
/**
* Inserts an entity that is part of a Class Table Inheritance hierarchy.
*
* @param Doctrine_Entity $record record to be inserted
* @return boolean
*/
public
function
doInsert
(
Doctrine_Entity
$record
)
{
$class
=
$this
->
_mapper
->
getClassMetadata
();
$conn
=
$this
->
_mapper
->
getConnection
();
$dataSet
=
$this
->
_groupFieldsByDefiningClass
(
$record
);
$component
=
$class
->
getClassName
();
$classes
=
$class
->
getParentClasses
();
array_unshift
(
$classes
,
$component
);
try
{
$conn
->
beginInternalTransaction
();
$identifier
=
null
;
foreach
(
array_reverse
(
$classes
)
as
$k
=>
$parent
)
{
$parentClass
=
$conn
->
getClassMetadata
(
$parent
);
if
(
$k
==
0
)
{
$identifierType
=
$parentClass
->
getIdentifierType
();
if
(
$identifierType
==
Doctrine
::
IDENTIFIER_AUTOINC
)
{
$this
->
_insertRow
(
$parentClass
->
getTableName
(),
$dataSet
[
$parent
]);
$identifier
=
$conn
->
sequence
->
lastInsertId
();
}
else
if
(
$identifierType
==
Doctrine
::
IDENTIFIER_SEQUENCE
)
{
$seq
=
$record
->
getClassMetadata
()
->
getTableOption
(
'sequenceName'
);
if
(
!
empty
(
$seq
))
{
$id
=
$conn
->
sequence
->
nextId
(
$seq
);
$identifierFields
=
(
array
)
$parentClass
->
getIdentifier
();
$dataSet
[
$parent
][
$identifierFields
[
0
]]
=
$id
;
$this
->
_insertRow
(
$parentClass
->
getTableName
(),
$dataSet
[
$parent
]);
}
}
else
{
throw
new
Doctrine_Mapper_Exception
(
"Unsupported identifier type '
$identifierType
'."
);
}
$record
->
assignIdentifier
(
$identifier
);
}
else
{
foreach
((
array
)
$record
->
identifier
()
as
$id
=>
$value
)
{
$dataSet
[
$parent
][
$parentClass
->
getColumnName
(
$id
)]
=
$value
;
}
$this
->
_insertRow
(
$parentClass
->
getTableName
(),
$dataSet
[
$parent
]);
}
}
$conn
->
commit
();
}
catch
(
Exception
$e
)
{
$conn
->
rollback
();
throw
$e
;
}
return
true
;
}
/**
* Updates an entity that is part of a Class Table Inheritance hierarchy.
*
* @param Doctrine_Entity $record record to be updated
* @return boolean whether or not the update was successful
* @todo Move to Doctrine_Table (which will become Doctrine_Mapper).
*/
public
function
doUpdate
(
Doctrine_Entity
$record
)
{
$conn
=
$this
->
_mapper
->
getConnection
();
$classMetadata
=
$this
->
_mapper
->
getClassMetadata
();
$identifier
=
$this
->
_convertFieldToColumnNames
(
$record
->
identifier
(),
$classMetadata
);
$dataSet
=
$this
->
_groupFieldsByDefiningClass
(
$record
);
$component
=
$classMetadata
->
getClassName
();
$classes
=
$classMetadata
->
getParentClasses
();
array_unshift
(
$classes
,
$component
);
foreach
(
$record
as
$field
=>
$value
)
{
if
(
$value
instanceof
Doctrine_Entity
)
{
if
(
!
$value
->
exists
())
{
$value
->
save
();
}
$idValues
=
$value
->
identifier
();
$record
->
set
(
$field
,
$idValues
[
0
]);
}
}
foreach
(
array_reverse
(
$classes
)
as
$class
)
{
$parentTable
=
$conn
->
getClassMetadata
(
$class
);
$this
->
_updateRow
(
$parentTable
->
getTableName
(),
$dataSet
[
$class
],
$identifier
);
}
$record
->
assignIdentifier
(
true
);
return
true
;
}
/**
* Deletes an entity that is part of a Class Table Inheritance hierarchy.
*
*/
public
function
doDelete
(
Doctrine_Entity
$record
)
{
$conn
=
$this
->
_mapper
->
getConnection
();
try
{
$class
=
$this
->
_mapper
->
getClassMetadata
();
$conn
->
beginInternalTransaction
();
$this
->
_deleteComposites
(
$record
);
$record
->
state
(
Doctrine_Entity
::
STATE_TDIRTY
);
$identifier
=
$this
->
_convertFieldToColumnNames
(
$record
->
identifier
(),
$class
);
// run deletions, starting from the class, upwards the hierarchy
$conn
->
delete
(
$class
->
getTableName
(),
$identifier
);
foreach
(
$class
->
getParentClasses
()
as
$parent
)
{
$parentClass
=
$conn
->
getClassMetadata
(
$parent
);
$this
->
_deleteRow
(
$parentClass
->
getTableName
(),
$identifier
);
}
$record
->
state
(
Doctrine_Entity
::
STATE_TCLEAN
);
$this
->
_mapper
->
removeRecord
(
$record
);
$conn
->
commit
();
}
catch
(
Exception
$e
)
{
$conn
->
rollback
();
throw
$e
;
}
return
true
;
}
/**
* Adds all parent classes as INNER JOINs and subclasses as OUTER JOINs
* to the query.
*
* Callback that is invoked during the SQL construction process.
*
* @return array The custom joins in the format <className> => <joinType>
*/
public
function
getCustomJoins
()
{
$customJoins
=
array
();
$classMetadata
=
$this
->
_mapper
->
getClassMetadata
();
foreach
(
$classMetadata
->
getParentClasses
()
as
$parentClass
)
{
$customJoins
[
$parentClass
]
=
'INNER'
;
}
foreach
(
$classMetadata
->
getSubclasses
()
as
$subClass
)
{
if
(
$subClass
!=
$this
->
_mapper
->
getComponentName
())
{
$customJoins
[
$subClass
]
=
'LEFT'
;
}
}
return
$customJoins
;
}
/**
* Adds the discriminator column to the selected fields in a query as well as
* all fields of subclasses. In Class Table Inheritance the default behavior is that
* all subclasses are joined in through OUTER JOINs when querying a base class.
*
* Callback that is invoked during the SQL construction process.
*
* @return array An array with the field names that will get added to the query.
*/
public
function
getCustomFields
()
{
$classMetadata
=
$this
->
_mapper
->
getClassMetadata
();
$conn
=
$this
->
_mapper
->
getConnection
();
$fields
=
array
(
$classMetadata
->
getInheritanceOption
(
'discriminatorColumn'
));
if
(
$classMetadata
->
getSubclasses
())
{
foreach
(
$classMetadata
->
getSubclasses
()
as
$subClass
)
{
$fields
=
array_merge
(
$conn
->
getClassMetadata
(
$subClass
)
->
getFieldNames
(),
$fields
);
}
}
return
array_unique
(
$fields
);
}
/**
*
*/
public
function
getFieldNames
()
{
if
(
$this
->
_fieldNames
)
{
return
$this
->
_fieldNames
;
}
$fieldNames
=
$this
->
_mapper
->
getClassMetadata
()
->
getFieldNames
();
$this
->
_fieldNames
=
array_unique
(
$fieldNames
);
return
$fieldNames
;
}
/**
*
*/
public
function
getFieldName
(
$columnName
)
{
if
(
isset
(
$this
->
_columnNameFieldNameMap
[
$columnName
]))
{
return
$this
->
_columnNameFieldNameMap
[
$columnName
];
}
$classMetadata
=
$this
->
_mapper
->
getClassMetadata
();
$conn
=
$this
->
_mapper
->
getConnection
();
if
(
$classMetadata
->
hasColumn
(
$columnName
))
{
$this
->
_columnNameFieldNameMap
[
$columnName
]
=
$classMetadata
->
getFieldName
(
$columnName
);
return
$this
->
_columnNameFieldNameMap
[
$columnName
];
}
foreach
(
$classMetadata
->
getSubclasses
()
as
$subClass
)
{
$subTable
=
$conn
->
getClassMetadata
(
$subClass
);
if
(
$subTable
->
hasColumn
(
$columnName
))
{
$this
->
_columnNameFieldNameMap
[
$columnName
]
=
$subTable
->
getFieldName
(
$columnName
);
return
$this
->
_columnNameFieldNameMap
[
$columnName
];
}
}
throw
new
Doctrine_Mapper_Exception
(
"No field name found for column name '
$columnName
'."
);
}
/**
*
* @todo Looks like this better belongs into the ClassMetadata class.
*/
public
function
getOwningClass
(
$fieldName
)
{
$conn
=
$this
->
_mapper
->
getConnection
();
$classMetadata
=
$this
->
_mapper
->
getClassMetadata
();
if
(
$classMetadata
->
hasField
(
$fieldName
)
&&
!
$classMetadata
->
isInheritedField
(
$fieldName
))
{
return
$classMetadata
;
}
foreach
(
$classMetadata
->
getParentClasses
()
as
$parentClass
)
{
$parentTable
=
$conn
->
getClassMetadata
(
$parentClass
);
if
(
$parentTable
->
hasField
(
$fieldName
)
&&
!
$parentTable
->
isInheritedField
(
$fieldName
))
{
return
$parentTable
;
}
}
foreach
((
array
)
$classMetadata
->
getSubclasses
()
as
$subClass
)
{
$subTable
=
$conn
->
getClassMetadata
(
$subClass
);
if
(
$subTable
->
hasField
(
$fieldName
)
&&
!
$subTable
->
isInheritedField
(
$fieldName
))
{
return
$subTable
;
}
}
throw
new
Doctrine_Mapper_Exception
(
"Unable to find defining class of field '
$fieldName
'."
);
}
/**
* Analyzes the fields of the entity and creates a map in which the field names
* are grouped by the class names they belong to.
*
* @return array
*/
protected
function
_groupFieldsByDefiningClass
(
Doctrine_Entity
$record
)
{
$conn
=
$this
->
_mapper
->
getConnection
();
$classMetadata
=
$this
->
_mapper
->
getClassMetadata
();
$dataSet
=
array
();
$component
=
$classMetadata
->
getClassName
();
$array
=
$record
->
getPrepared
();
$classes
=
array_merge
(
array
(
$component
),
$classMetadata
->
getParentClasses
());
foreach
(
$classes
as
$class
)
{
$dataSet
[
$class
]
=
array
();
$parentClassMetadata
=
$conn
->
getClassMetadata
(
$class
);
foreach
(
$parentClassMetadata
->
getColumns
()
as
$columnName
=>
$definition
)
{
if
((
isset
(
$definition
[
'primary'
])
&&
$definition
[
'primary'
]
===
true
)
||
(
isset
(
$definition
[
'inherited'
])
&&
$definition
[
'inherited'
]
===
true
))
{
continue
;
}
$fieldName
=
$classMetadata
->
getFieldName
(
$columnName
);
if
(
!
array_key_exists
(
$fieldName
,
$array
))
{
continue
;
}
$dataSet
[
$class
][
$columnName
]
=
$array
[
$fieldName
];
}
}
return
$dataSet
;
}
}
lib/Doctrine/Mapper/Strategy.php
deleted
100644 → 0
View file @
74ce82bd
<?php
/*
* $Id$
*
* 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.org>.
*/
/**
* Base class for all mapping strategies used by mappers.
*
* @author Roman Borschel <roman@code-factory.org>
* @package Doctrine
* @subpackage Strategy
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision$
* @link www.phpdoctrine.org
* @since 1.0
*/
abstract
class
Doctrine_Mapper_Strategy
{
protected
$_mapper
;
/**
* The names of all the fields that are available on entities created by this mapper.
*/
protected
$_fieldNames
=
array
();
public
function
__construct
(
Doctrine_Mapper
$mapper
)
{
$this
->
_mapper
=
$mapper
;
}
/**
* Assumes that the keys of the given field array are field names and converts
* them to column names.
*
* @return array
*/
protected
function
_convertFieldToColumnNames
(
array
$fields
,
Doctrine_ClassMetadata
$class
)
{
$converted
=
array
();
foreach
(
$fields
as
$fieldName
=>
$value
)
{
$converted
[
$class
->
getColumnName
(
$fieldName
)]
=
$value
;
}
return
$converted
;
}
/**
* deletes all related composites
* this method is always called internally when a record is deleted
*
* @throws PDOException if something went wrong at database level
* @return void
*/
protected
function
_deleteComposites
(
Doctrine_Entity
$record
)
{
$classMetadata
=
$this
->
_mapper
->
getClassMetadata
();
foreach
(
$classMetadata
->
getRelations
()
as
$fk
)
{
if
(
$fk
->
isComposite
())
{
$obj
=
$record
->
get
(
$fk
->
getAlias
());
if
(
$obj
instanceof
Doctrine_Entity
&&
$obj
->
state
()
!=
Doctrine_Entity
::
STATE_LOCKED
)
{
$obj
->
delete
(
$this
->
_mapper
->
getConnection
());
}
}
}
}
/**
* Callback that is invoked during the SQL construction process.
*/
public
function
getCustomJoins
()
{
return
array
();
}
/**
* Callback that is invoked during the SQL construction process.
*/
public
function
getCustomFields
()
{
return
array
();
}
public
function
getFieldName
(
$columnName
)
{
return
$this
->
_mapper
->
getClassMetadata
()
->
getFieldName
(
$columnName
);
}
public
function
getFieldNames
()
{
if
(
$this
->
_fieldNames
)
{
return
$this
->
_fieldNames
;
}
$this
->
_fieldNames
=
$this
->
_mapper
->
getClassMetadata
()
->
getFieldNames
();
return
$this
->
_fieldNames
;
}
public
function
getOwningClass
(
$fieldName
)
{
return
$this
->
_mapper
->
getClassMetadata
();
}
abstract
public
function
doDelete
(
Doctrine_Entity
$record
);
abstract
public
function
doInsert
(
Doctrine_Entity
$record
);
abstract
public
function
doUpdate
(
Doctrine_Entity
$record
);
/**
* Inserts a row into a table.
*
* @todo This method could be used to allow mapping to secondary table(s).
* @see http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SecondaryTable
*/
protected
function
_insertRow
(
$tableName
,
array
$data
)
{
$this
->
_mapper
->
getConnection
()
->
insert
(
$tableName
,
$data
);
}
/**
* Deletes rows of a table.
*
* @todo This method could be used to allow mapping to secondary table(s).
* @see http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SecondaryTable
*/
protected
function
_deleteRow
(
$tableName
,
array
$identifierToMatch
)
{
$this
->
_mapper
->
getConnection
()
->
delete
(
$tableName
,
$identifierToMatch
);
}
/**
* Deletes rows of a table.
*
* @todo This method could be used to allow mapping to secondary table(s).
* @see http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SecondaryTable
*/
protected
function
_updateRow
(
$tableName
,
array
$data
,
array
$identifierToMatch
)
{
$this
->
_mapper
->
getConnection
()
->
update
(
$tableName
,
$data
,
$identifierToMatch
);
}
}
\ No newline at end of file
lib/Doctrine/Null.php
View file @
7b711ae7
...
...
@@ -20,10 +20,17 @@
*/
/**
* Doctrine_Null
* Null class representing a null value that has been fetched from
* the database or a fetched, empty association. This is for internal use only.
* User code should never deal with this null object.
*
* Simple empty class representing a null value.
* Used for extra fast null value testing with isset() rather than array_key_exists().
* Semantics are as follows:
*
* Regular PHP null : Value is undefined. When a field with that value is accessed
* and lazy loading is used the database is queried.
*
* Null object: Null valued of a field or empty association that has already been loaded.
* On access, the database is not queried.
*
* @package Doctrine
* @subpackage Null
...
...
tests/models/forum/ForumUser.php
View file @
7b711ae7
...
...
@@ -20,13 +20,13 @@ class ForumUser extends Doctrine_Entity
$class
->
mapColumn
(
'id'
,
'integer'
,
4
,
array
(
'primary'
=>
true
,
'autoincrement'
=>
true
));
$class
->
mapColumn
(
'username'
,
'string'
,
50
);
$class
->
mapColumn
(
'username'
,
'string'
,
50
,
array
(
'accessor'
=>
'getUsernameCustom'
)
);
}
/*
public function getUsername()
public
function
getUsername
Custom
()
{
return $this->rawGet('username') . "!";
return
$this
->
rawGet
Field
(
'username'
)
.
"!"
;
}
*/
}
\ No newline at end of file
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