1
0
mirror of synced 2025-01-29 19:41:45 +03:00

Merge remote-tracking branch 'doctrine/master' into SupportCustomIdGenerators

This commit is contained in:
Vitali Yakavenka 2011-12-19 16:47:47 -08:00
commit 4879c50c5d
326 changed files with 5470 additions and 2857 deletions

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
build.properties
build/
logs/
reports/

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[submodule "lib/vendor/Symfony/Component/Yaml"]
path = lib/vendor/Symfony/Component/Yaml
url = git://github.com/symfony/Yaml.git
[submodule "lib/vendor/doctrine-build-common"]
path = lib/vendor/doctrine-build-common
url = https://github.com/doctrine/doctrine-build-common.git

View File

@ -1,6 +1,6 @@
# ResultCache implementation rewritten
The result cache is completly rewritten and now works on the database result level, not inside the ORM AbstractQuery
The result cache is completely rewritten and now works on the database result level, not inside the ORM AbstractQuery
anymore. This means that for result cached queries the hydration will now always be performed again, regardless of
the hydration mode. Affected areas are:
@ -12,20 +12,24 @@ The API is backwards compatible however most of the getter methods on the `Abstr
deprecated in favor of calling AbstractQuery#getQueryCacheProfile(). This method returns a `Doctrine\DBAL\Cache\QueryCacheProfile`
instance with access to result cache driver, lifetime and cache key.
# EntityManager#getPartialReference() creates read-only entity
Entities returned from EntityManager#getPartialReference() are now marked as read-only if they
haven't been in the identity map before. This means objects of this kind never lead to changes
in the UnitOfWork.
# Fields omitted in a partial DQL query or a native query are never updated
Fields of an entity that are not returned from a partial DQL Query or native SQL query
will never be updated through an UPDATE statement.
# Removed support for onUpdate in @JoinColumn
The onUpdate foreign key handling makes absolutly no sense in an ORM. Additionally Oracle doesn't even support it. Support for it is removed.
The onUpdate foreign key handling makes absolutely no sense in an ORM. Additionally Oracle doesn't even support it. Support for it is removed.
# Changes in Annotation Handling
@ -41,4 +45,32 @@ from 2.0 have to configure the annotation driver if they don't use `Configuratio
$driver = new AnnotationDriver($reader, (array)$paths);
$config->setMetadataDriverImpl($driver);
$config->setMetadataDriverImpl($driver);
# Scalar mappings can now be ommitted from DQL result
You are now allowed to mark scalar SELECT expressions as HIDDEN an they are not hydrated anymore.
Example:
SELECT u, SUM(a.id) AS HIDDEN numArticles FROM User u LEFT JOIN u.Articles a ORDER BY numArticles DESC HAVING numArticles > 10
Your result will be a collection of Users, and not an array with key 0 as User object instance and "numArticles" as the number of articles per user
# Map entities as scalars in DQL result
When hydrating to array or even a mixed result in object hydrator, previously you had the 0 index holding you entity instance.
You are now allowed to alias this, providing more flexibility for you code.
Example:
SELECT u AS user FROM User u
Will now return a collection of arrays with index "user" pointing to the User object instance.
# Performance optimizations
Thousands of lines were completely reviewed and optimized for best performance.
Removed redundancy and improved code readability made now internal Doctrine code easier to understand.
Also, Doctrine 2.2 now is around 10-15% faster than 2.1.

11
build.properties Normal file
View File

@ -0,0 +1,11 @@
# Project Name
project.name=DoctrineORM
# Dependency minimum versions
dependencies.common=2.1.0
dependencies.dbal=2.1.0
dependencies.sfconsole=2.0.0
# Version class and file
project.version_class = Doctrine\ORM\Version
project.version_file = lib/Doctrine/ORM/Version.php

222
build.xml
View File

@ -1,11 +1,7 @@
<?xml version="1.0"?>
<!--
Doctrine 2 build file.
-->
<project name="Doctrine2" default="build" basedir=".">
<project name="DoctrineORM" default="build" basedir=".">
<taskdef classname="phing.tasks.ext.d51PearPkg2Task" name="d51pearpkg2" />
<import file="${project.basedir}/lib/vendor/doctrine-build-common/packaging.xml" />
<property file="build.properties" />
@ -14,6 +10,8 @@
-->
<fileset id="shared-artifacts" dir=".">
<include name="LICENSE"/>
<include name="UPGRADE*" />
<include name="doctrine-mapping.xsd" />
</fileset>
<!--
@ -51,118 +49,34 @@
-->
<fileset id="symfony-sources" dir="./lib/vendor">
<include name="Symfony/Component/**"/>
<exclude name="**/.git/**" />
</fileset>
<!--
Clean the directory for the next build.
-->
<target name="clean">
<available file="./build.properties" property="build_properties_exist" value="true"/>
<fail unless="build_properties_exist" message="The build.properties file is missing." />
<delete dir="${build.dir}" includeemptydirs="true" />
<delete dir="${dist.dir}" includeemptydirs="true" />
<delete dir="${report.dir}" includeemptydirs="true" />
</target>
<!--
Prepare the new build directories after cleaning
-->
<target name="prepare" depends="clean">
<echo msg="Creating build directory: ${build.dir}" />
<mkdir dir="${build.dir}" />
<echo msg="Creating distribution directory: ${dist.dir}" />
<mkdir dir="${dist.dir}" />
<echo msg="Creating report directory: ${report.dir}" />
<mkdir dir="${report.dir}" />
<mkdir dir="${build.dir}/logs"/>
<mkdir dir="${report.dir}/tests"/>
</target>
<!--
Builds ORM package, preparing it for distribution.
-->
<target name="build-orm" depends="prepare">
<exec command="grep '${version}' ${project.basedir}/lib/Doctrine/ORM/Version.php" checkreturn="true"/>
<copy todir="${build.dir}/doctrine-orm">
<target name="copy-files" depends="prepare">
<copy todir="${build.dir}/${project.name}-${version}">
<fileset refid="shared-artifacts"/>
</copy>
<copy todir="${build.dir}/doctrine-orm">
<copy todir="${build.dir}/${project.name}-${version}">
<fileset refid="common-sources"/>
<fileset refid="dbal-sources"/>
<fileset refid="orm-sources"/>
</copy>
<copy todir="${build.dir}/doctrine-orm/Doctrine">
<copy todir="${build.dir}/${project.name}-${version}/Doctrine">
<fileset refid="symfony-sources"/>
</copy>
<copy todir="${build.dir}/doctrine-orm/bin">
<copy todir="${build.dir}/${project.name}-${version}/bin">
<fileset refid="bin-scripts"/>
</copy>
<exec command="sed 's/${version}-DEV/${version}/' ${build.dir}/doctrine-orm/Doctrine/ORM/Version.php > ${build.dir}/doctrine-orm/Doctrine/ORM/Version2.php" passthru="true" />
<exec command="mv ${build.dir}/doctrine-orm/Doctrine/ORM/Version2.php ${build.dir}/doctrine-orm/Doctrine/ORM/Version.php" passthru="true" />
<delete dir="${build.dir}/doctrine-orm/Doctrine/Symfony/Component/Yaml/.git" includeemptydirs="true"/>
<delete dir="${build.dir}/doctrine-orm/Doctrine/Symfony/Component/Console/.git" includeemptydirs="true"/>
</target>
<target name="build" depends="test, build-orm"/>
<target name="package-phar" depends="build-orm">
<pharpackage basedir="${build.dir}/doctrine-orm/" destfile="${dist.dir}/doctrine-orm-${version}.phar" clistub="${build.dir}/doctrine-orm/bin/doctrine.php" signature="sha512">
<fileset dir="${build.dir}/doctrine-orm">
<include name="**/**" />
</fileset>
<metadata>
<element name="version" value="${version}" />
<element name="authors">
<element name="Guilherme Blanco"><element name="e-mail" value="guilhermeblanco@gmail.com" /></element>
<element name="Benjamin Eberlei"><element name="e-mail" value="kontakt@beberlei.de" /></element>
<element name="Jonathan H. Wage"><element name="e-mail" value="jonwage@gmail.com" /></element>
<element name="Roman Borschel"><element name="e-mail" value="roman@code-factory.org" /></element>
</element>
</metadata>
</pharpackage>
</target>
<!--
Runs the full test suite.
-->
<target name="test" depends="prepare">
<if><equals arg1="${test.phpunit_generate_coverage}" arg2="1" />
<then>
<property name="test.phpunit_coverage_file" value="${build.dir}/logs/clover.xml" />
</then>
<else>
<property name="test.phpunit_coverage_file" value="false" />
</else>
</if>
<nativephpunit
testfile="./tests/Doctrine/Tests/AllTests.php" junitlogfile="${build.dir}/logs/testsuites.xml"
testdirectory="./tests" coverageclover="${test.phpunit_coverage_file}" configuration="${test.phpunit_configuration_file}"
/>
<phpunitreport infile="${build.dir}/logs/testsuites.xml" format="frames" todir="${report.dir}/tests" />
<nativephpunit testfile="./tests/Doctrine/Tests/ORM/Performance/AllTests.php" testdirectory="./tests" haltonfailure="false" haltonerror="false" />
<tstamp/>
<copy file="${build.dir}/logs/testsuites.xml" tofile="${log.archive.dir}/latest/log.xml" overwrite="true"/>
<if><equals arg1="${test.pmd_reports}" arg2="1" />
<then>
<exec command="${test.pdepend_exec} --jdepend-xml=${build.dir}/logs/jdepend.xml ./lib/Doctrine" />
<exec command="${test.phpmd_exec} ./lib/Doctrine xml codesize --reportfile ${build.dir}/logs/phpmd.xml" />
<copy file="${build.dir}/logs/jdepend.xml" tofile="${log.archive.dir}/latest/jdepend.xml" overwrite="true"/>
<copy file="${build.dir}/logs/phpmd.xml" tofile="${log.archive.dir}/latest/phpmd.xml" overwrite="true"/>
</then>
</if>
</target>
<!--
Builds distributable PEAR packages.
-->
<target name="build-packages" depends="build-orm">
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/doctrine-orm">
<target name="define-pear-package" depends="copy-files">
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/${project.name}-${version}">
<name>DoctrineORM</name>
<summary>Doctrine Object Relational Mapper</summary>
<channel>pear.doctrine-project.org</channel>
@ -172,129 +86,29 @@
<lead user="romanb" name="Roman Borschel" email="roman@code-factory.org" />
<lead user="beberlei" name="Benjamin Eberlei" email="kontakt@beberlei.de" />
<license>LGPL</license>
<version release="${version}" api="${version}" />
<stability release="${stability}" api="${stability}" />
<version release="${pear.version}" api="${pear.version}" />
<stability release="${pear.stability}" api="${pear.stability}" />
<notes>-</notes>
<dependencies>
<php minimum_version="5.3.0" />
<pear minimum_version="1.6.0" recommended_version="1.6.1" />
<package name="DoctrineCommon" channel="pear.doctrine-project.org" minimum_version="${dependencies.common}" />
<package name="DoctrineDBAL" channel="pear.doctrine-project.org" minimum_version="${dependencies.dbal}" />
<package name="DoctrineSymfonyConsole" channel="pear.doctrine-project.org" minimum_version="2.0.0" />
<package name="DoctrineSymfonyYaml" channel="pear.doctrine-project.org" minimum_version="2.0.0" />
<package name="Console" channel="pear.symfony.org" minimum_version="2.0.0" />
<package name="Yaml" channel="pear.symfony.org" minimum_version="2.0.0" />
</dependencies>
<dirroles key="bin">script</dirroles>
<ignore>Doctrine/Common/</ignore>
<ignore>Doctrine/DBAL/</ignore>
<ignore>Symfony/Component/Yaml/</ignore>
<ignore>Symfony/Component/Yaml/</ignore>
<ignore>Symfony/Component/Console/</ignore>
<release>
<install as="doctrine" name="bin/doctrine" />
<install as="doctrine.php" name="bin/doctrine.php" />
<install as="doctrine.bat" name="bin/doctrine.bat" />
</release>
<replacement path="bin/doctrine.bat" type="pear-config" from="@php_bin@" to="php_bin" />
<replacement path="bin/doctrine" type="pear-config" from="@php_bin@" to="php_bin" />
<replacement path="bin/doctrine.bat" type="pear-config" from="@bin_dir@" to="bin_dir" />
</d51pearpkg2>
<exec command="pear package" dir="${build.dir}/doctrine-orm" passthru="true" />
<exec command="mv DoctrineORM-${version}.tgz ../../dist" dir="${build.dir}/doctrine-orm" passthru="true" />
<tar destfile="dist/DoctrineORM-${version}-full.tar.gz" compression="gzip" basedir="${build.dir}">
<fileset dir="${build.dir}">
<include name="**/**" />
<exclude name="logs/" />
<exclude name="doctrine-orm/package.xml" />
</fileset>
</tar>
</target>
<target name="git-tag">
<exec command="grep '${version}-DEV' ${project.basedir}/lib/Doctrine/ORM/Version.php" checkreturn="true"/>
<exec command="sed 's/${version}-DEV/${version}/' ${project.basedir}/lib/Doctrine/ORM/Version.php > ${project.basedir}/lib/Doctrine/ORM/Version2.php" passthru="true" />
<exec command="mv ${project.basedir}/lib/Doctrine/ORM/Version2.php ${project.basedir}/lib/Doctrine/ORM/Version.php" passthru="true" />
<exec command="git add ${project.basedir}/lib/Doctrine/ORM/Version.php" passthru="true" />
<exec command="git commit -m 'Release ${version}'" />
<exec command="git tag -m 'Tag ${version}' -a ${version}" passthru="true" />
</target>
<target name="pirum-release">
<exec command="sudo pirum add ${project.pirum_dir} ${project.basedir}/dist/DoctrineORM-${version}.tgz" dir="." passthru="true" />
<exec command="sudo pirum build ${project.pirum_dir}" passthru="true" />
</target>
<target name="distribute-download">
<copy file="dist/DoctrineORM-${version}-full.tar.gz" todir="${project.download_dir}" />
<!--<copy file="${dist.dir}/doctrine-orm-${version}.phar" todir="${project.download_dir}" />-->
</target>
<target name="distribute-xsd">
<php expression="substr('${version}', 0, 3)" returnProperty="minorVersion" /><!-- not too robust -->
<copy file="${project.basedir}/doctrine-mapping.xsd" tofile="${project.xsd_dir}/doctrine-mapping-${minorVersion}.xsd" />
</target>
<target name="update-dev-version">
<exec command="grep '${version}' ${project.basedir}/lib/Doctrine/ORM/Version.php" checkreturn="true"/>
<propertyprompt propertyName="next_version" defaultValue="${version}" promptText="Enter next version string (without -DEV)" />
<exec command="sed 's/${version}/${next_version}-DEV/' ${project.basedir}/lib/Doctrine/ORM/Version.php > ${project.basedir}/lib/Doctrine/ORM/Version2.php" passthru="true" />
<exec command="mv ${project.basedir}/lib/Doctrine/ORM/Version2.php ${project.basedir}/lib/Doctrine/ORM/Version.php" passthru="true" />
<exec command="git add ${project.basedir}/lib/Doctrine/ORM/Version.php" passthru="true" />
<exec command="git commit -m 'Bump Dev Version to ${next_version}-DEV'" passthru="true" />
</target>
<target name="release" depends="git-tag,build-packages,distribute-download,pirum-release,update-dev-version,distribute-xsd" />
<!--
Builds distributable PEAR packages for the Symfony Dependencies
-->
<target name="release-symfony-dependencies" depends="build-orm">
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/doctrine-orm">
<name>DoctrineSymfonyConsole</name>
<summary>Symfony Console Component</summary>
<channel>pear.doctrine-project.org</channel>
<description>A command line interface tool from the Symfony project. Packaged for shipping with Doctrine projects using ORM version numbers.</description>
<lead user="fabpot" name="Fabien Potencier" email="fabien.potencier@symfony-project.com" />
<license>NewBSD License</license>
<version release="${version}" api="${version}" />
<stability release="${stability}" api="${stability}" />
<notes>-</notes>
<dependencies>
<php minimum_version="5.3.0" />
<pear minimum_version="1.6.0" recommended_version="1.6.1" />
</dependencies>
<ignore>bin/</ignore>
<ignore>Doctrine/Common/</ignore>
<ignore>Doctrine/DBAL/</ignore>
<ignore>Doctrine/ORM/</ignore>
<ignore>Symfony/Component/Yaml/</ignore>
</d51pearpkg2>
<exec command="pear package" dir="${build.dir}/doctrine-orm" passthru="true" />
<exec command="mv DoctrineSymfonyConsole-${version}.tgz ../../dist" dir="${build.dir}/doctrine-orm" passthru="true" />
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/doctrine-orm">
<name>DoctrineSymfonyYaml</name>
<summary>Symfony Yaml Component</summary>
<channel>pear.doctrine-project.org</channel>
<description>A YAML Parser from the Symfony project. Packaged for shipping with Doctrine projects using ORM version numbers.</description>
<lead user="fabpot" name="Fabien Potencier" email="fabien.potencier@symfony-project.com" />
<license>NewBSD License</license>
<version release="${version}" api="${version}" />
<stability release="${stability}" api="${stability}" />
<notes>-</notes>
<dependencies>
<php minimum_version="5.3.0" />
<pear minimum_version="1.6.0" recommended_version="1.6.1" />
</dependencies>
<ignore>bin/</ignore>
<ignore>Doctrine/Common/</ignore>
<ignore>Doctrine/DBAL/</ignore>
<ignore>Doctrine/ORM/</ignore>
<ignore>Symfony/Component/Console/</ignore>
</d51pearpkg2>
<exec command="pear package" dir="${build.dir}/doctrine-orm" passthru="true" />
<exec command="mv DoctrineSymfonyYaml-${version}.tgz ../../dist" dir="${build.dir}/doctrine-orm" passthru="true" />
<exec command="sudo pirum add ${project.pirum_dir} ${project.basedir}/dist/DoctrineSymfonyConsole-${version}.tgz" dir="." passthru="true" />
<exec command="sudo pirum add ${project.pirum_dir} ${project.basedir}/dist/DoctrineSymfonyYaml-${version}.tgz" dir="." passthru="true" />
<exec command="sudo pirum build ${project.pirum_dir}" passthru="true" />
</target>
</project>

View File

@ -77,7 +77,7 @@ abstract class AbstractQuery
protected $_resultSetMapping;
/**
* @var Doctrine\ORM\EntityManager The entity manager used by this query object.
* @var \Doctrine\ORM\EntityManager The entity manager used by this query object.
*/
protected $_em;
@ -104,7 +104,7 @@ abstract class AbstractQuery
/**
* Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
*
* @param Doctrine\ORM\EntityManager $entityManager
* @param \Doctrine\ORM\EntityManager $entityManager
*/
public function __construct(EntityManager $em)
{
@ -114,7 +114,7 @@ abstract class AbstractQuery
/**
* Retrieves the associated EntityManager of this Query instance.
*
* @return Doctrine\ORM\EntityManager
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
@ -144,7 +144,7 @@ abstract class AbstractQuery
{
return $this->_params;
}
/**
* Get all defined parameter types.
*
@ -163,7 +163,11 @@ abstract class AbstractQuery
*/
public function getParameter($key)
{
return isset($this->_params[$key]) ? $this->_params[$key] : null;
if (isset($this->_params[$key])) {
return $this->_params[$key];
}
return null;
}
/**
@ -174,7 +178,11 @@ abstract class AbstractQuery
*/
public function getParameterType($key)
{
return isset($this->_paramTypes[$key]) ? $this->_paramTypes[$key] : null;
if (isset($this->_paramTypes[$key])) {
return $this->_paramTypes[$key];
}
return null;
}
/**
@ -194,19 +202,19 @@ abstract class AbstractQuery
* @param string $type The parameter type. If specified, the given value will be run through
* the type conversion of this type. This is usually not needed for
* strings and numeric types.
* @return Doctrine\ORM\AbstractQuery This query instance.
* @return \Doctrine\ORM\AbstractQuery This query instance.
*/
public function setParameter($key, $value, $type = null)
{
$key = trim($key, ':');
if ($type === null) {
$type = Query\ParameterTypeInferer::inferType($value);
}
$this->_paramTypes[$key] = $type;
$this->_params[$key] = $value;
return $this;
}
@ -215,17 +223,14 @@ abstract class AbstractQuery
*
* @param array $params
* @param array $types
* @return Doctrine\ORM\AbstractQuery This query instance.
* @return \Doctrine\ORM\AbstractQuery This query instance.
*/
public function setParameters(array $params, array $types = array())
{
foreach ($params as $key => $value) {
if (isset($types[$key])) {
$this->setParameter($key, $value, $types[$key]);
} else {
$this->setParameter($key, $value);
}
$this->setParameter($key, $value, isset($types[$key]) ? $types[$key] : null);
}
return $this;
}
@ -233,30 +238,31 @@ abstract class AbstractQuery
* Sets the ResultSetMapping that should be used for hydration.
*
* @param ResultSetMapping $rsm
* @return Doctrine\ORM\AbstractQuery
* @return \Doctrine\ORM\AbstractQuery
*/
public function setResultSetMapping(Query\ResultSetMapping $rsm)
{
$this->_resultSetMapping = $rsm;
return $this;
}
/**
* Defines a cache driver to be used for caching result sets and implictly enables caching.
*
* @param Doctrine\Common\Cache\Cache $driver Cache driver
* @return Doctrine\ORM\AbstractQuery
* @param \Doctrine\Common\Cache\Cache $driver Cache driver
* @return \Doctrine\ORM\AbstractQuery
*/
public function setResultCacheDriver($resultCacheDriver = null)
{
if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) {
throw ORMException::invalidResultCacheDriver();
}
if ($this->_queryCacheProfile) {
$this->_queryCacheProfile = $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver);
} else {
$this->_queryCacheProfile = new QueryCacheProfile(0, null, $resultCacheDriver);
}
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
: new QueryCacheProfile(0, null, $resultCacheDriver);
return $this;
}
@ -264,15 +270,15 @@ abstract class AbstractQuery
* Returns the cache driver used for caching result sets.
*
* @deprecated
* @return Doctrine\Common\Cache\Cache Cache driver
* @return \Doctrine\Common\Cache\Cache Cache driver
*/
public function getResultCacheDriver()
{
if ($this->_queryCacheProfile && $this->_queryCacheProfile->getResultCacheDriver()) {
return $this->_queryCacheProfile->getResultCacheDriver();
} else {
return $this->_em->getConfiguration()->getResultCacheImpl();
}
return $this->_em->getConfiguration()->getResultCacheImpl();
}
/**
@ -282,16 +288,19 @@ abstract class AbstractQuery
* @param boolean $bool
* @param integer $lifetime
* @param string $resultCacheId
* @return Doctrine\ORM\AbstractQuery This query instance.
* @return \Doctrine\ORM\AbstractQuery This query instance.
*/
public function useResultCache($bool, $lifetime = null, $resultCacheId = null)
{
if ($bool) {
$this->setResultCacheLifetime($lifetime);
$this->setResultCacheId($resultCacheId);
} else {
$this->_queryCacheProfile = null;
return $this;
}
$this->_queryCacheProfile = null;
return $this;
}
@ -299,20 +308,16 @@ abstract class AbstractQuery
* Defines how long the result cache will be active before expire.
*
* @param integer $lifetime How long the cache entry is valid.
* @return Doctrine\ORM\AbstractQuery This query instance.
* @return \Doctrine\ORM\AbstractQuery This query instance.
*/
public function setResultCacheLifetime($lifetime)
{
if ($lifetime === null) {
$lifetime = 0;
} else {
$lifetime = (int)$lifetime;
}
if ($this->_queryCacheProfile) {
$this->_queryCacheProfile = $this->_queryCacheProfile->setLifetime($lifetime);
} else {
$this->_queryCacheProfile = new QueryCacheProfile($lifetime);
}
$lifetime = ($lifetime !== null) ? (int) $lifetime : 0;
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setLifetime($lifetime)
: new QueryCacheProfile($lifetime);
return $this;
}
@ -331,11 +336,12 @@ abstract class AbstractQuery
* Defines if the result cache is active or not.
*
* @param boolean $expire Whether or not to force resultset cache expiration.
* @return Doctrine\ORM\AbstractQuery This query instance.
* @return \Doctrine\ORM\AbstractQuery This query instance.
*/
public function expireResultCache($expire = true)
{
$this->_expireResultCache = $expire;
return $this;
}
@ -374,6 +380,7 @@ abstract class AbstractQuery
}
$this->_hints['fetchMode'][$class][$assocName] = $fetchMode;
return $this;
}
@ -382,11 +389,12 @@ abstract class AbstractQuery
*
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Query::HYDRATE_* constants.
* @return Doctrine\ORM\AbstractQuery This query instance.
* @return \Doctrine\ORM\AbstractQuery This query instance.
*/
public function setHydrationMode($hydrationMode)
{
$this->_hydrationMode = $hydrationMode;
return $this;
}
@ -451,14 +459,15 @@ abstract class AbstractQuery
return null;
}
if (is_array($result)) {
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
if ( ! is_array($result)) {
return $result;
}
return $result;
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
}
/**
@ -482,14 +491,15 @@ abstract class AbstractQuery
throw new NoResultException;
}
if (is_array($result)) {
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
if ( ! is_array($result)) {
return $result;
}
return $result;
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
}
/**
@ -510,11 +520,12 @@ abstract class AbstractQuery
*
* @param string $name The name of the hint.
* @param mixed $value The value of the hint.
* @return Doctrine\ORM\AbstractQuery
* @return \Doctrine\ORM\AbstractQuery
*/
public function setHint($name, $value)
{
$this->_hints[$name] = $value;
return $this;
}
@ -531,7 +542,7 @@ abstract class AbstractQuery
/**
* Return the key value map of query hints that are currently set.
*
*
* @return array
*/
public function getHints()
@ -588,8 +599,8 @@ abstract class AbstractQuery
}
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
);
$stmt, $this->_resultSetMapping, $this->_hints
);
}
/**
@ -598,15 +609,14 @@ abstract class AbstractQuery
* generated for you.
*
* @param string $id
* @return Doctrine\ORM\AbstractQuery This query instance.
* @return \Doctrine\ORM\AbstractQuery This query instance.
*/
public function setResultCacheId($id)
{
if ($this->_queryCacheProfile) {
$this->_queryCacheProfile = $this->_queryCacheProfile->setCacheKey($id);
} else {
$this->_queryCacheProfile = new QueryCacheProfile(0, $id);
}
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setCacheKey($id)
: new QueryCacheProfile(0, $id);
return $this;
}
@ -624,7 +634,7 @@ abstract class AbstractQuery
/**
* Executes the query and returns a the resulting Statement object.
*
* @return Doctrine\DBAL\Driver\Statement The executed database statement that holds the results.
* @return \Doctrine\DBAL\Driver\Statement The executed database statement that holds the results.
*/
abstract protected function _doExecute();

View File

@ -495,17 +495,42 @@ class Configuration extends \Doctrine\DBAL\Configuration
}
return $this->_attributes['classMetadataFactoryName'];
}
/**
* Add a filter to the list of possible filters.
*
* @param string $name The name of the filter.
* @param string $className The class name of the filter.
*/
public function addFilter($name, $className)
{
$this->_attributes['filters'][$name] = $className;
}
/**
* Gets the class name for a given filter name.
*
* @param string $name The name of the filter.
*
* @return string The class name of the filter, or null of it is not
* defined.
*/
public function getFilterClassName($name)
{
return isset($this->_attributes['filters'][$name]) ?
$this->_attributes['filters'][$name] : null;
}
/**
* Set default repository class.
*
*
* @since 2.2
* @param string $className
* @throws ORMException If not is a Doctrine\ORM\EntityRepository
* @throws ORMException If not is a \Doctrine\ORM\EntityRepository
*/
public function setDefaultRepositoryClassName($className)
{
if ($className != "Doctrine\ORM\EntityRepository" &&
if ($className != "Doctrine\ORM\EntityRepository" &&
!is_subclass_of($className, 'Doctrine\ORM\EntityRepository')){
throw ORMException::invalidEntityRepository($className);
}
@ -514,7 +539,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Get default repository class.
*
*
* @since 2.2
* @return string
*/
@ -523,4 +548,4 @@ class Configuration extends \Doctrine\DBAL\Configuration
return isset($this->_attributes['defaultRepositoryClassName']) ?
$this->_attributes['defaultRepositoryClassName'] : 'Doctrine\ORM\EntityRepository';
}
}
}

View File

@ -27,7 +27,8 @@ use Closure, Exception,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataFactory,
Doctrine\ORM\Query\ResultSetMapping,
Doctrine\ORM\Proxy\ProxyFactory;
Doctrine\ORM\Proxy\ProxyFactory,
Doctrine\ORM\Query\FilterCollection;
/**
* The EntityManager is the central access point to ORM functionality.
@ -43,21 +44,21 @@ class EntityManager implements ObjectManager
/**
* The used Configuration.
*
* @var Doctrine\ORM\Configuration
* @var \Doctrine\ORM\Configuration
*/
private $config;
/**
* The database connection used by the EntityManager.
*
* @var Doctrine\DBAL\Connection
* @var \Doctrine\DBAL\Connection
*/
private $conn;
/**
* The metadata factory, used to retrieve the ORM metadata of entity classes.
*
* @var Doctrine\ORM\Mapping\ClassMetadataFactory
* @var \Doctrine\ORM\Mapping\ClassMetadataFactory
*/
private $metadataFactory;
@ -71,14 +72,14 @@ class EntityManager implements ObjectManager
/**
* The UnitOfWork used to coordinate object-level transactions.
*
* @var Doctrine\ORM\UnitOfWork
* @var \Doctrine\ORM\UnitOfWork
*/
private $unitOfWork;
/**
* The event manager that is the central point of the event system.
*
* @var Doctrine\Common\EventManager
* @var \Doctrine\Common\EventManager
*/
private $eventManager;
@ -92,14 +93,14 @@ class EntityManager implements ObjectManager
/**
* The proxy factory used to create dynamic proxies.
*
* @var Doctrine\ORM\Proxy\ProxyFactory
* @var \Doctrine\ORM\Proxy\ProxyFactory
*/
private $proxyFactory;
/**
* The expression builder instance used to generate query expressions.
*
* @var Doctrine\ORM\Query\Expr
* @var \Doctrine\ORM\Query\Expr
*/
private $expressionBuilder;
@ -110,13 +111,20 @@ class EntityManager implements ObjectManager
*/
private $closed = false;
/**
* Collection of query filters.
*
* @var Doctrine\ORM\Query\FilterCollection
*/
private $filterCollection;
/**
* Creates a new EntityManager that operates on the given database connection
* and uses the given Configuration and EventManager implementations.
*
* @param Doctrine\DBAL\Connection $conn
* @param Doctrine\ORM\Configuration $config
* @param Doctrine\Common\EventManager $eventManager
* @param \Doctrine\DBAL\Connection $conn
* @param \Doctrine\ORM\Configuration $config
* @param \Doctrine\Common\EventManager $eventManager
*/
protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
{
@ -130,16 +138,18 @@ class EntityManager implements ObjectManager
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
$this->unitOfWork = new UnitOfWork($this);
$this->proxyFactory = new ProxyFactory($this,
$config->getProxyDir(),
$config->getProxyNamespace(),
$config->getAutoGenerateProxyClasses());
$this->proxyFactory = new ProxyFactory(
$this,
$config->getProxyDir(),
$config->getProxyNamespace(),
$config->getAutoGenerateProxyClasses()
);
}
/**
* Gets the database connection object used by the EntityManager.
*
* @return Doctrine\DBAL\Connection
* @return \Doctrine\DBAL\Connection
*/
public function getConnection()
{
@ -149,7 +159,7 @@ class EntityManager implements ObjectManager
/**
* Gets the metadata factory used to gather the metadata of classes.
*
* @return Doctrine\ORM\Mapping\ClassMetadataFactory
* @return \Doctrine\ORM\Mapping\ClassMetadataFactory
*/
public function getMetadataFactory()
{
@ -168,13 +178,14 @@ class EntityManager implements ObjectManager
* ->where($expr->orX($expr->eq('u.id', 1), $expr->eq('u.id', 2)));
* </code>
*
* @return Doctrine\ORM\Query\Expr
* @return \Doctrine\ORM\Query\Expr
*/
public function getExpressionBuilder()
{
if ($this->expressionBuilder === null) {
$this->expressionBuilder = new Query\Expr;
}
return $this->expressionBuilder;
}
@ -250,7 +261,7 @@ class EntityManager implements ObjectManager
* MyProject\Domain\User
* sales:PriceRequest
*
* @return Doctrine\ORM\Mapping\ClassMetadata
* @return \Doctrine\ORM\Mapping\ClassMetadata
* @internal Performance-sensitive method.
*/
public function getClassMetadata($className)
@ -262,14 +273,16 @@ class EntityManager implements ObjectManager
* Creates a new Query object.
*
* @param string The DQL string.
* @return Doctrine\ORM\Query
* @return \Doctrine\ORM\Query
*/
public function createQuery($dql = "")
{
$query = new Query($this);
if ( ! empty($dql)) {
$query->setDql($dql);
}
return $query;
}
@ -277,7 +290,7 @@ class EntityManager implements ObjectManager
* Creates a Query from a named query.
*
* @param string $name
* @return Doctrine\ORM\Query
* @return \Doctrine\ORM\Query
*/
public function createNamedQuery($name)
{
@ -296,6 +309,7 @@ class EntityManager implements ObjectManager
$query = new NativeQuery($this);
$query->setSql($sql);
$query->setResultSetMapping($rsm);
return $query;
}
@ -303,11 +317,12 @@ class EntityManager implements ObjectManager
* Creates a NativeQuery from a named native query.
*
* @param string $name
* @return Doctrine\ORM\NativeQuery
* @return \Doctrine\ORM\NativeQuery
*/
public function createNamedNativeQuery($name)
{
list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
return $this->createNativeQuery($sql, $rsm);
}
@ -330,12 +345,13 @@ class EntityManager implements ObjectManager
* the cascade-persist semantics + scheduled inserts/removals are synchronized.
*
* @param object $entity
* @throws Doctrine\ORM\OptimisticLockException If a version check on an entity that
* @throws \Doctrine\ORM\OptimisticLockException If a version check on an entity that
* makes use of optimistic locking fails.
*/
public function flush($entity = null)
{
$this->errorIfClosed();
$this->unitOfWork->commit($entity);
}
@ -360,27 +376,39 @@ class EntityManager implements ObjectManager
* without actually loading it, if the entity is not yet loaded.
*
* @param string $entityName The name of the entity type.
* @param mixed $identifier The entity identifier.
* @param mixed $id The entity identifier.
* @return object The entity reference.
*/
public function getReference($entityName, $identifier)
public function getReference($entityName, $id)
{
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
if ( ! is_array($id)) {
$id = array($class->identifier[0] => $id);
}
$sortedId = array();
foreach ($class->identifier as $identifier) {
if (!isset($id[$identifier])) {
throw ORMException::missingIdentifierField($class->name, $identifier);
}
$sortedId[$identifier] = $id[$identifier];
}
// Check identity map first, if its already in there just return it.
if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
if ($entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName)) {
return ($entity instanceof $class->name) ? $entity : null;
}
if ($class->subClasses) {
$entity = $this->find($entityName, $identifier);
} else {
if ( ! is_array($identifier)) {
$identifier = array($class->identifier[0] => $identifier);
}
$entity = $this->proxyFactory->getProxy($class->name, $identifier);
$this->unitOfWork->registerManaged($entity, $identifier, array());
return $this->find($entityName, $sortedId);
}
if ( ! is_array($sortedId)) {
$sortedId = array($class->identifier[0] => $sortedId);
}
$entity = $this->proxyFactory->getProxy($class->name, $sortedId);
$this->unitOfWork->registerManaged($entity, $sortedId, array());
return $entity;
}
@ -411,6 +439,7 @@ class EntityManager implements ObjectManager
if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
return ($entity instanceof $class->name) ? $entity : null;
}
if ( ! is_array($identifier)) {
$identifier = array($class->identifier[0] => $identifier);
}
@ -461,7 +490,9 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->persist($entity);
}
@ -478,7 +509,9 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->remove($entity);
}
@ -493,7 +526,9 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->refresh($entity);
}
@ -511,6 +546,7 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->unitOfWork->detach($entity);
}
@ -527,7 +563,9 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
return $this->unitOfWork->merge($entity);
}
@ -567,20 +605,20 @@ class EntityManager implements ObjectManager
public function getRepository($entityName)
{
$entityName = ltrim($entityName, '\\');
if (isset($this->repositories[$entityName])) {
return $this->repositories[$entityName];
}
$metadata = $this->getClassMetadata($entityName);
$customRepositoryClassName = $metadata->customRepositoryClassName;
$repositoryClassName = $metadata->customRepositoryClassName;
if ($customRepositoryClassName !== null) {
$repository = new $customRepositoryClassName($this, $metadata);
} else {
$repositoryClass = $this->config->getDefaultRepositoryClassName();
$repository = new $repositoryClass($this, $metadata);
if ($repositoryClassName === null) {
$repositoryClassName = $this->config->getDefaultRepositoryClassName();
}
$repository = new $repositoryClassName($this, $metadata);
$this->repositories[$entityName] = $repository;
return $repository;
@ -594,15 +632,15 @@ class EntityManager implements ObjectManager
*/
public function contains($entity)
{
return $this->unitOfWork->isScheduledForInsert($entity) ||
$this->unitOfWork->isInIdentityMap($entity) &&
! $this->unitOfWork->isScheduledForDelete($entity);
return $this->unitOfWork->isScheduledForInsert($entity)
|| $this->unitOfWork->isInIdentityMap($entity)
&& ! $this->unitOfWork->isScheduledForDelete($entity);
}
/**
* Gets the EventManager used by the EntityManager.
*
* @return Doctrine\Common\EventManager
* @return \Doctrine\Common\EventManager
*/
public function getEventManager()
{
@ -612,7 +650,7 @@ class EntityManager implements ObjectManager
/**
* Gets the Configuration used by the EntityManager.
*
* @return Doctrine\ORM\Configuration
* @return \Doctrine\ORM\Configuration
*/
public function getConfiguration()
{
@ -644,7 +682,7 @@ class EntityManager implements ObjectManager
/**
* Gets the UnitOfWork used by the EntityManager to coordinate operations.
*
* @return Doctrine\ORM\UnitOfWork
* @return \Doctrine\ORM\UnitOfWork
*/
public function getUnitOfWork()
{
@ -658,7 +696,7 @@ class EntityManager implements ObjectManager
* selectively iterate over the result.
*
* @param int $hydrationMode
* @return Doctrine\ORM\Internal\Hydration\AbstractHydrator
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
*/
public function getHydrator($hydrationMode)
{
@ -673,35 +711,33 @@ class EntityManager implements ObjectManager
* Create a new instance for the given hydration mode.
*
* @param int $hydrationMode
* @return Doctrine\ORM\Internal\Hydration\AbstractHydrator
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
*/
public function newHydrator($hydrationMode)
{
switch ($hydrationMode) {
case Query::HYDRATE_OBJECT:
$hydrator = new Internal\Hydration\ObjectHydrator($this);
break;
return new Internal\Hydration\ObjectHydrator($this);
case Query::HYDRATE_ARRAY:
$hydrator = new Internal\Hydration\ArrayHydrator($this);
break;
return new Internal\Hydration\ArrayHydrator($this);
case Query::HYDRATE_SCALAR:
$hydrator = new Internal\Hydration\ScalarHydrator($this);
break;
return new Internal\Hydration\ScalarHydrator($this);
case Query::HYDRATE_SINGLE_SCALAR:
$hydrator = new Internal\Hydration\SingleScalarHydrator($this);
break;
return new Internal\Hydration\SingleScalarHydrator($this);
case Query::HYDRATE_SIMPLEOBJECT:
$hydrator = new Internal\Hydration\SimpleObjectHydrator($this);
break;
return new Internal\Hydration\SimpleObjectHydrator($this);
default:
if ($class = $this->config->getCustomHydrationMode($hydrationMode)) {
$hydrator = new $class($this);
break;
return new $class($this);
}
throw ORMException::invalidHydrationMode($hydrationMode);
}
return $hydrator;
throw ORMException::invalidHydrationMode($hydrationMode);
}
/**
@ -737,20 +773,62 @@ class EntityManager implements ObjectManager
*/
public static function create($conn, Configuration $config, EventManager $eventManager = null)
{
if (!$config->getMetadataDriverImpl()) {
if ( ! $config->getMetadataDriverImpl()) {
throw ORMException::missingMappingDriverImpl();
}
if (is_array($conn)) {
$conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, ($eventManager ?: new EventManager()));
} else if ($conn instanceof Connection) {
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
throw ORMException::mismatchedEventManager();
}
} else {
throw new \InvalidArgumentException("Invalid argument: " . $conn);
switch (true) {
case (is_array($conn)):
$conn = \Doctrine\DBAL\DriverManager::getConnection(
$conn, $config, ($eventManager ?: new EventManager())
);
break;
case ($conn instanceof Connection):
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
throw ORMException::mismatchedEventManager();
}
break;
default:
throw new \InvalidArgumentException("Invalid argument: " . $conn);
}
return new EntityManager($conn, $config, $conn->getEventManager());
}
/**
* Gets the enabled filters.
*
* @return FilterCollection The active filter collection.
*/
public function getFilters()
{
if (null === $this->filterCollection) {
$this->filterCollection = new FilterCollection($this);
}
return $this->filterCollection;
}
/**
* Checks whether the state of the filter collection is clean.
*
* @return boolean True, if the filter collection is clean.
*/
public function isFiltersStateClean()
{
return null === $this->filterCollection
|| $this->filterCollection->isClean();
}
/**
* Checks whether the Entity Manager has filters.
*
* @return True, if the EM has a filter collection.
*/
public function hasFilters()
{
return null !== $this->filterCollection;
}
}

View File

@ -48,7 +48,7 @@ class EntityRepository implements ObjectRepository
protected $_em;
/**
* @var Doctrine\ORM\Mapping\ClassMetadata
* @var \Doctrine\ORM\Mapping\ClassMetadata
*/
protected $_class;
@ -107,42 +107,51 @@ class EntityRepository implements ObjectRepository
*/
public function find($id, $lockMode = LockMode::NONE, $lockVersion = null)
{
if ( ! is_array($id)) {
$id = array($this->_class->identifier[0] => $id);
}
$sortedId = array();
foreach ($this->_class->identifier as $identifier) {
if (!isset($id[$identifier])) {
throw ORMException::missingIdentifierField($this->_class->name, $identifier);
}
$sortedId[$identifier] = $id[$identifier];
}
// Check identity map first
if ($entity = $this->_em->getUnitOfWork()->tryGetById($id, $this->_class->rootEntityName)) {
if (!($entity instanceof $this->_class->name)) {
if ($entity = $this->_em->getUnitOfWork()->tryGetById($sortedId, $this->_class->rootEntityName)) {
if ( ! ($entity instanceof $this->_class->name)) {
return null;
}
if ($lockMode != LockMode::NONE) {
if ($lockMode !== LockMode::NONE) {
$this->_em->lock($entity, $lockMode, $lockVersion);
}
return $entity; // Hit!
}
if ( ! is_array($id) || count($id) <= 1) {
// @todo FIXME: Not correct. Relies on specific order.
$value = is_array($id) ? array_values($id) : array($id);
$id = array_combine($this->_class->identifier, $value);
}
switch ($lockMode) {
case LockMode::NONE:
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId);
if ($lockMode == LockMode::NONE) {
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id);
} else if ($lockMode == LockMode::OPTIMISTIC) {
if (!$this->_class->isVersioned) {
throw OptimisticLockException::notVersioned($this->_entityName);
}
$entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id);
case LockMode::OPTIMISTIC:
if ( ! $this->_class->isVersioned) {
throw OptimisticLockException::notVersioned($this->_entityName);
}
$this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion);
$entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId);
return $entity;
} else {
if (!$this->_em->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id, null, null, array(), $lockMode);
$this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion);
return $entity;
default:
if ( ! $this->_em->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId, null, null, array(), $lockMode);
}
}
@ -191,30 +200,35 @@ class EntityRepository implements ObjectRepository
*/
public function __call($method, $arguments)
{
if (substr($method, 0, 6) == 'findBy') {
$by = substr($method, 6, strlen($method));
$method = 'findBy';
} else if (substr($method, 0, 9) == 'findOneBy') {
$by = substr($method, 9, strlen($method));
$method = 'findOneBy';
} else {
throw new \BadMethodCallException(
"Undefined method '$method'. The method name must start with ".
"either findBy or findOneBy!"
);
switch (true) {
case (substr($method, 0, 6) == 'findBy'):
$by = substr($method, 6, strlen($method));
$method = 'findBy';
break;
case (substr($method, 0, 9) == 'findOneBy'):
$by = substr($method, 9, strlen($method));
$method = 'findOneBy';
break;
default:
throw new \BadMethodCallException(
"Undefined method '$method'. The method name must start with ".
"either findBy or findOneBy!"
);
}
if (empty($arguments)) {
throw ORMException::findByRequiresParameter($method.$by);
throw ORMException::findByRequiresParameter($method . $by);
}
$fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by));
if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) {
return $this->$method(array($fieldName => $arguments[0]));
} else {
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
}
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
}
/**

View File

@ -1,122 +0,0 @@
<?php
/*
* 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.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event;
use Doctrine\Common\EventSubscriber;
use LogicException;
/**
* Delegate events only for certain entities they are registered for.
*
* @link www.doctrine-project.org
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @since 2.2
*/
class EntityEventDelegator implements EventSubscriber
{
/**
* Keeps track of all the event listeners.
*
* @var array
*/
private $listeners = array();
/**
* If frozen no new event listeners can be added.
*
* @var bool
*/
private $frozen = false;
/**
* Adds an event listener that listens on the specified events.
*
* @param string|array $events The event(s) to listen on.
* @param string|array $entities The entities to trigger this listener for
* @param object $listener The listener object.
*/
public function addEventListener($events, $entities, $listener)
{
if ($this->frozen) {
throw new LogicException(
"Cannot add event listeners after EntityEventDelegator::getSubscribedEvents() " .
"is called once. This happens when you register the delegator with the event manager."
);
}
// Picks the hash code related to that listener
$hash = spl_object_hash($listener);
$entities = array_flip((array) $entities);
foreach ((array) $events as $event) {
// Overrides listener if a previous one was associated already
// Prevents duplicate listeners on same event (same instance only)
$this->listeners[$event][$hash] = array(
'listener' => $listener,
'entities' => $entities
);
}
}
/**
* Adds an EventSubscriber. The subscriber is asked for all the events he is
* interested in and added as a listener for these events.
*
* @param Doctrine\Common\EventSubscriber $subscriber The subscriber.
* @param array $entities
*/
public function addEventSubscriber(EventSubscriber $subscriber, $entities)
{
$this->addEventListener($subscriber->getSubscribedEvents(), $entities, $subscriber);
}
/**
* Returns an array of events this subscriber wants to listen to.
*
* @return array
*/
public function getSubscribedEvents()
{
$this->frozen = true;
return array_keys($this->listeners);
}
/**
* Delegate the event to an appropriate listener
*
* @param string $eventName
* @param array $args
* @return void
*/
public function __call($eventName, $args)
{
$event = $args[0];
foreach ($this->listeners[$eventName] AS $listenerData) {
$class = get_class($event->getEntity());
if ( ! isset($listenerData['entities'][$class])) continue;
$listenerData['listener']->$eventName($event);
}
}
}

View File

@ -34,7 +34,7 @@ use Doctrine\ORM\EntityManager;
class LifecycleEventArgs extends EventArgs
{
/**
* @var Doctrine\ORM\EntityManager
* @var \Doctrine\ORM\EntityManager
*/
private $em;
@ -42,23 +42,23 @@ class LifecycleEventArgs extends EventArgs
* @var object
*/
private $entity;
/**
* Constructor
*
*
* @param object $entity
* @param Doctrine\ORM\EntityManager $em
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct($entity, EntityManager $em)
{
$this->entity = $entity;
$this->em = $em;
}
/**
* Retireve associated Entity.
*
* @return object
*
* @return object
*/
public function getEntity()
{
@ -67,8 +67,8 @@ class LifecycleEventArgs extends EventArgs
/**
* Retrieve associated EntityManager.
*
* @return Doctrine\ORM\EntityManager
*
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{

View File

@ -32,20 +32,20 @@ use Doctrine\ORM\EntityManager;
class LoadClassMetadataEventArgs extends EventArgs
{
/**
* @var Doctrine\ORM\Mapping\ClassMetadata
* @var \Doctrine\ORM\Mapping\ClassMetadata
*/
private $classMetadata;
/**
* @var Doctrine\ORM\EntityManager
* @var \Doctrine\ORM\EntityManager
*/
private $em;
/**
* Constructor.
*
* @param Doctrine\ORM\Mapping\ClassMetadataInfo $classMetadata
* @param Doctrine\ORM\EntityManager $em
*
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $classMetadata
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct(ClassMetadataInfo $classMetadata, EntityManager $em)
{
@ -55,8 +55,8 @@ class LoadClassMetadataEventArgs extends EventArgs
/**
* Retrieve associated ClassMetadata.
*
* @return Doctrine\ORM\Mapping\ClassMetadataInfo
*
* @return \Doctrine\ORM\Mapping\ClassMetadataInfo
*/
public function getClassMetadata()
{
@ -65,8 +65,8 @@ class LoadClassMetadataEventArgs extends EventArgs
/**
* Retrieve associated EntityManager.
*
* @return Doctrine\ORM\EntityManager
*
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{

View File

@ -31,7 +31,7 @@ namespace Doctrine\ORM\Event;
class OnClearEventArgs extends \Doctrine\Common\EventArgs
{
/**
* @var Doctrine\ORM\EntityManager
* @var \Doctrine\ORM\EntityManager
*/
private $em;
@ -42,8 +42,8 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
/**
* Constructor.
*
* @param Doctrine\ORM\EntityManager $em
*
* @param \Doctrine\ORM\EntityManager $em
* @param string $entityClass Optional entity class
*/
public function __construct($em, $entityClass = null)
@ -54,8 +54,8 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
/**
* Retrieve associated EntityManager.
*
* @return Doctrine\ORM\EntityManager
*
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{

View File

@ -38,14 +38,14 @@ class OnFlushEventArgs extends \Doctrine\Common\EventArgs
* @var Doctirne\ORM\EntityManager
*/
private $em;
//private $entitiesToPersist = array();
//private $entitiesToRemove = array();
/**
* Constructor.
*
* @param Doctrine\ORM\EntityManager $em
*
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
{
@ -54,30 +54,30 @@ class OnFlushEventArgs extends \Doctrine\Common\EventArgs
/**
* Retrieve associated EntityManager.
*
* @return Doctrine\ORM\EntityManager
*
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
return $this->em;
}
/*
public function addEntityToPersist($entity)
{
}
public function addEntityToRemove($entity)
{
}
public function addEntityToUpdate($entity)
{
}
public function getEntitiesToPersist()
{
return $this->_entitiesToPersist;

View File

@ -35,14 +35,14 @@ use Doctrine\Common\EventArgs;
class PostFlushEventArgs extends EventArgs
{
/**
* @var Doctrine\ORM\EntityManager
* @var \Doctrine\ORM\EntityManager
*/
private $em;
/**
* Constructor.
*
* @param Doctrine\ORM\EntityManager $em
*
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
{
@ -51,8 +51,8 @@ class PostFlushEventArgs extends EventArgs
/**
* Retrieve associated EntityManager.
*
* @return Doctrine\ORM\EntityManager
*
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{

View File

@ -41,21 +41,21 @@ class PreUpdateEventArgs extends LifecycleEventArgs
/**
* Constructor.
*
*
* @param object $entity
* @param Doctrine\ORM\EntityManager $em
* @param \Doctrine\ORM\EntityManager $em
* @param array $changeSet
*/
public function __construct($entity, EntityManager $em, array &$changeSet)
{
parent::__construct($entity, $em);
$this->entityChangeSet = &$changeSet;
}
/**
* Retrieve entity changeset.
*
*
* @return array
*/
public function getEntityChangeSet()
@ -75,7 +75,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
/**
* Get the old value of the changeset of the changed field.
*
*
* @param string $field
* @return mixed
*/
@ -101,7 +101,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
/**
* Set the new value of this field.
*
*
* @param string $field
* @param mixed $value
*/
@ -114,8 +114,8 @@ class PreUpdateEventArgs extends LifecycleEventArgs
/**
* Assert the field exists in changeset.
*
* @param string $field
*
* @param string $field
*/
private function assertValidField($field)
{

View File

@ -35,55 +35,55 @@ final class Events
/**
* The preRemove event occurs for a given entity before the respective
* EntityManager remove operation for that entity is executed.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const preRemove = 'preRemove';
/**
* The postRemove event occurs for an entity after the entity has
* The postRemove event occurs for an entity after the entity has
* been deleted. It will be invoked after the database delete operations.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postRemove = 'postRemove';
/**
* The prePersist event occurs for a given entity before the respective
* EntityManager persist operation for that entity is executed.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const prePersist = 'prePersist';
/**
* The postPersist event occurs for an entity after the entity has
* The postPersist event occurs for an entity after the entity has
* been made persistent. It will be invoked after the database insert operations.
* Generated primary key values are available in the postPersist event.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postPersist = 'postPersist';
/**
* The preUpdate event occurs before the database update operations to
* entity data.
*
* The preUpdate event occurs before the database update operations to
* entity data.
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const preUpdate = 'preUpdate';
/**
* The postUpdate event occurs after the database update operations to
* entity data.
*
* The postUpdate event occurs after the database update operations to
* entity data.
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postUpdate = 'postUpdate';
@ -91,24 +91,24 @@ final class Events
* The postLoad event occurs for an entity after the entity has been loaded
* into the current EntityManager from the database or after the refresh operation
* has been applied to it.
*
*
* Note that the postLoad event occurs for an entity before any associations have been
* initialized. Therefore it is not safe to access associations in a postLoad callback
* or event handler.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postLoad = 'postLoad';
/**
* The loadClassMetadata event occurs after the mapping metadata for a class
* has been loaded from a mapping source (annotations/xml/yaml).
*
*
* @var string
*/
const loadClassMetadata = 'loadClassMetadata';
/**
* The preFlush event occurs when the EntityManager#flush() operation is invoked,
* but before any changes to managed entites have been calculated. This event is
@ -122,7 +122,7 @@ final class Events
* actual database operations are executed. The event is only raised if there is
* actually something to do for the underlying UnitOfWork. If nothing needs to be done,
* the onFlush event is not raised.
*
*
* @var string
*/
const onFlush = 'onFlush';
@ -133,11 +133,11 @@ final class Events
* actually something to do for the underlying UnitOfWork. If nothing needs to be done,
* the postFlush event is not raised. The event won't be raised if an error occurs during the
* flush operation.
*
*
* @var string
*/
const postFlush = 'postFlush';
/**
* The onClear event occurs when the EntityManager#clear() operation is invoked,
* after all references to entities have been removed from the unit of work.

View File

@ -26,7 +26,7 @@ abstract class AbstractIdGenerator
/**
* Generates an identifier for an entity.
*
* @param Doctrine\ORM\Entity $entity
* @param \Doctrine\ORM\Entity $entity
* @return mixed
*/
abstract public function generate(EntityManager $em, $entity);
@ -35,7 +35,7 @@ abstract class AbstractIdGenerator
* Gets whether this generator is a post-insert generator which means that
* {@link generate()} must be called after the entity has been inserted
* into the database.
*
*
* By default, this method returns FALSE. Generators that have this requirement
* must override this method and return TRUE.
*

View File

@ -46,14 +46,14 @@ class AssignedGenerator extends AbstractIdGenerator
$class = $em->getClassMetadata(get_class($entity));
$idFields = $class->getIdentifierFieldNames();
$identifier = array();
foreach ($idFields as $idField) {
$value = $class->reflFields[$idField]->getValue($entity);
if ( ! isset($value)) {
throw ORMException::entityMissingAssignedIdForField($entity, $idField);
}
if (isset($class->associationMappings[$idField])) {
if ( ! $em->getUnitOfWork()->isInIdentityMap($value)) {
throw ORMException::entityMissingForeignAssignedId($entity, $value);
@ -62,10 +62,10 @@ class AssignedGenerator extends AbstractIdGenerator
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
$value = current($em->getUnitOfWork()->getEntityIdentifier($value));
}
$identifier[$idField] = $value;
}
return $identifier;
}
}

View File

@ -37,7 +37,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
/**
* Initializes a new sequence generator.
*
* @param Doctrine\ORM\EntityManager $em The EntityManager to use.
* @param \Doctrine\ORM\EntityManager $em The EntityManager to use.
* @param string $sequenceName The name of the sequence.
* @param integer $allocationSize The allocation size of the sequence.
*/

View File

@ -50,12 +50,12 @@ class TableGenerator extends AbstractIdGenerator
if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) {
// Allocate new values
$conn = $em->getConnection();
if ($conn->getTransactionNestingLevel() === 0) {
// use select for update
$sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName);
$currentLevel = $conn->fetchColumn($sql);
if ($currentLevel != null) {
$this->_nextValue = $currentLevel;
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
@ -63,7 +63,7 @@ class TableGenerator extends AbstractIdGenerator
$updateSql = $conn->getDatabasePlatform()->getTableHiLoUpdateNextValSql(
$this->_tableName, $this->_sequenceName, $this->_allocationSize
);
if ($conn->executeUpdate($updateSql, array(1 => $currentLevel, 2 => $currentLevel+1)) !== 1) {
// no affected rows, concurrency issue, throw exception
}
@ -75,7 +75,7 @@ class TableGenerator extends AbstractIdGenerator
// or do we want to work with table locks exclusively?
}
}
return $this->_nextValue++;
}
}

View File

@ -23,20 +23,21 @@ namespace Doctrine\ORM\Internal;
* The CommitOrderCalculator is used by the UnitOfWork to sort out the
* correct order in which changes to entities need to be persisted.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/
class CommitOrderCalculator
{
const NOT_VISITED = 1;
const IN_PROGRESS = 2;
const VISITED = 3;
private $_nodeStates = array();
private $_classes = array(); // The nodes to sort
private $_relatedClasses = array();
private $_sorted = array();
/**
* Clears the current graph.
*
@ -47,10 +48,10 @@ class CommitOrderCalculator
$this->_classes =
$this->_relatedClasses = array();
}
/**
* Gets a valid commit order for all current nodes.
*
*
* Uses a depth-first search (DFS) to traverse the graph.
* The desired topological sorting is the reverse postorder of these searches.
*
@ -60,17 +61,16 @@ class CommitOrderCalculator
{
// Check whether we need to do anything. 0 or 1 node is easy.
$nodeCount = count($this->_classes);
if ($nodeCount == 0) {
return array();
} else if ($nodeCount == 1) {
return array_values($this->_classes);
if ($nodeCount <= 1) {
return ($nodeCount == 1) ? array_values($this->_classes) : array();
}
// Init
foreach ($this->_classes as $node) {
$this->_nodeStates[$node->name] = self::NOT_VISITED;
}
// Go
foreach ($this->_classes as $node) {
if ($this->_nodeStates[$node->name] == self::NOT_VISITED) {
@ -100,17 +100,17 @@ class CommitOrderCalculator
$this->_nodeStates[$node->name] = self::VISITED;
$this->_sorted[] = $node;
}
public function addDependency($fromClass, $toClass)
{
$this->_relatedClasses[$fromClass->name][] = $toClass;
}
public function hasClass($className)
{
return isset($this->_classes[$className]);
}
public function addClass($class)
{
$this->_classes[$class->name] = $class;

View File

@ -60,7 +60,7 @@ abstract class AbstractHydrator
/**
* Initializes a new instance of a class derived from <tt>AbstractHydrator</tt>.
*
* @param Doctrine\ORM\EntityManager $em The EntityManager to use.
* @param \Doctrine\ORM\EntityManager $em The EntityManager to use.
*/
public function __construct(EntityManager $em)
{
@ -243,8 +243,11 @@ abstract class AbstractHydrator
}
if (isset($cache[$key]['isMetaColumn'])) {
if ( ! isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) || $value !== null) {
if ( ! isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) && $value !== null) {
$rowData[$dqlAlias][$cache[$key]['fieldName']] = $value;
if ($cache[$key]['isIdentifier']) {
$nonemptyComponents[$dqlAlias] = true;
}
}
continue;
@ -341,7 +344,7 @@ abstract class AbstractHydrator
/**
* Register entity as managed in UnitOfWork.
*
* @param Doctrine\ORM\Mapping\ClassMetadata $class
* @param \Doctrine\ORM\Mapping\ClassMetadata $class
* @param object $entity
* @param array $data
*

View File

@ -28,11 +28,6 @@ use PDO, Doctrine\DBAL\Connection, Doctrine\ORM\Mapping\ClassMetadata;
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*
* @todo General behavior is "wrong" if you define an alias to selected IdentificationVariable.
* Example: SELECT u AS user FROM User u
* The result should contains an array where each array index is an array: array('user' => [User object])
* Problem must be solved somehow by removing the isMixed in ResultSetMapping
*/
class ArrayHydrator extends AbstractHydrator
{
@ -281,7 +276,7 @@ class ArrayHydrator extends AbstractHydrator
*
* @param string $className
*
* @return Doctrine\ORM\Mapping\ClassMetadata
* @return \Doctrine\ORM\Mapping\ClassMetadata
*/
private function getClassMetadata($className)
{

View File

@ -29,7 +29,7 @@ namespace Doctrine\ORM\Internal\Hydration;
class IterableResult implements \Iterator
{
/**
* @var Doctrine\ORM\Internal\Hydration\AbstractHydrator
* @var \Doctrine\ORM\Internal\Hydration\AbstractHydrator
*/
private $_hydrator;
@ -49,7 +49,7 @@ class IterableResult implements \Iterator
private $_current = null;
/**
* @param Doctrine\ORM\Internal\Hydration\AbstractHydrator $hydrator
* @param \Doctrine\ORM\Internal\Hydration\AbstractHydrator $hydrator
*/
public function __construct($hydrator)
{

View File

@ -26,7 +26,8 @@ use PDO,
Doctrine\ORM\Event\LifecycleEventArgs,
Doctrine\ORM\Events,
Doctrine\Common\Collections\ArrayCollection,
Doctrine\Common\Collections\Collection;
Doctrine\Common\Collections\Collection,
Doctrine\ORM\Proxy\Proxy;
/**
* The ObjectHydrator constructs an object graph out of an SQL result set.
@ -36,11 +37,6 @@ use PDO,
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*
* @internal Highly performance-sensitive code.
*
* @todo General behavior is "wrong" if you define an alias to selected IdentificationVariable.
* Example: SELECT u AS user FROM User u
* The result should contains an array where each array index is an array: array('user' => [User object])
* Problem must be solved somehow by removing the isMixed in ResultSetMapping
*/
class ObjectHydrator extends AbstractHydrator
{
@ -237,20 +233,20 @@ class ObjectHydrator extends AbstractHydrator
}
$this->_hints['fetchAlias'] = $dqlAlias;
$entity = $this->_uow->createEntity($className, $data, $this->_hints);
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
if (isset($this->_ce[$className]->lifecycleCallbacks[Events::postLoad])) {
$this->_ce[$className]->invokeLifecycleCallbacks(Events::postLoad, $entity);
}
$evm = $this->_em->getEventManager();
if ($evm->hasListeners(Events::postLoad)) {
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
}
return $entity;
}
@ -363,6 +359,7 @@ class ObjectHydrator extends AbstractHydrator
continue;
}
$parentClass = $this->_ce[$this->_rsm->aliasMap[$parentAlias]];
$oid = spl_object_hash($parentObject);
$relationField = $this->_rsm->relationMap[$dqlAlias];
@ -417,7 +414,9 @@ class ObjectHydrator extends AbstractHydrator
} else {
// PATH B: Single-valued association
$reflFieldValue = $reflField->getValue($parentObject);
if ( ! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH])) {
if ( ! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && !$reflFieldValue->__isInitialized__)) {
// we only need to take action if this value is null,
// we refresh the entity or its an unitialized proxy.
if (isset($nonemptyComponents[$dqlAlias])) {
$element = $this->_getEntity($data, $dqlAlias);
$reflField->setValue($parentObject, $element);
@ -444,6 +443,8 @@ class ObjectHydrator extends AbstractHydrator
}
// Update result pointer
$this->_resultPointers[$dqlAlias] = $element;
} else {
$this->_uow->setOriginalEntityProperty($oid, $relationField, null);
}
// else leave $reflFieldValue null for single-valued associations
} else {

View File

@ -32,22 +32,22 @@ use Doctrine\DBAL\Connection;
*/
class ScalarHydrator extends AbstractHydrator
{
/**
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
{
$result = array();
$cache = array();
while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
$this->hydrateRowData($data, $cache, $result);
}
return $result;
}
/**
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $data, array &$cache, array &$result)

View File

@ -63,18 +63,18 @@ class SimpleObjectHydrator extends AbstractHydrator
if (count($this->_rsm->aliasMap) !== 1) {
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than one object result.");
}
if ($this->_rsm->scalarMappings) {
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings.");
}
$this->class = $this->_em->getClassMetadata(reset($this->_rsm->aliasMap));
// We only need to add declaring classes if we have inheritance.
if ($this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_NONE) {
return;
}
foreach ($this->_rsm->declaringClasses AS $column => $class) {
$this->declaringClasses[$column] = $this->_em->getClassMetadata($class);
}
@ -87,27 +87,27 @@ class SimpleObjectHydrator extends AbstractHydrator
{
$entityName = $this->class->name;
$data = array();
// We need to find the correct entity class name if we have inheritance in resultset
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
$discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']);
if ($sqlResult[$discrColumnName] === '') {
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
}
$entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]];
unset($sqlResult[$discrColumnName]);
}
foreach ($sqlResult as $column => $value) {
// Hydrate column information if not yet present
if ( ! isset($cache[$column])) {
if (($info = $this->hydrateColumnInfo($entityName, $column)) === null) {
continue;
}
$cache[$column] = $info;
}
@ -116,7 +116,7 @@ class SimpleObjectHydrator extends AbstractHydrator
$type = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type']);
$value = $type->convertToPHPValue($value, $this->_platform);
}
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
if (isset($cache[$column]) && ( ! isset($data[$cache[$column]['name']]) || $value !== null)) {
$data[$cache[$column]['name']] = $value;
@ -129,7 +129,7 @@ class SimpleObjectHydrator extends AbstractHydrator
$uow = $this->_em->getUnitOfWork();
$entity = $uow->createEntity($entityName, $data, $this->_hints);
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
if (isset($this->class->lifecycleCallbacks[Events::postLoad])) {
$this->class->invokeLifecycleCallbacks(Events::postLoad, $entity);
@ -140,24 +140,24 @@ class SimpleObjectHydrator extends AbstractHydrator
if ($evm->hasListeners(Events::postLoad)) {
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
}
$result[] = $entity;
}
/**
* Retrieve column information form ResultSetMapping.
*
*
* @param string $entityName
* @param string $column
*
* @return array
*
* @return array
*/
protected function hydrateColumnInfo($entityName, $column)
{
switch (true) {
case (isset($this->_rsm->fieldMappings[$column])):
$class = isset($this->declaringClasses[$column])
? $this->declaringClasses[$column]
$class = isset($this->declaringClasses[$column])
? $this->declaringClasses[$column]
: $this->class;
// If class is not part of the inheritance, ignore
@ -172,8 +172,8 @@ class SimpleObjectHydrator extends AbstractHydrator
);
case (isset($this->_rsm->relationMap[$column])):
$class = isset($this->_rsm->relationMap[$column])
? $this->_rsm->relationMap[$column]
$class = isset($this->_rsm->relationMap[$column])
? $this->_rsm->relationMap[$column]
: $this->class;
// If class is not self referencing, ignore
@ -181,7 +181,7 @@ class SimpleObjectHydrator extends AbstractHydrator
return null;
}
// TODO: Decide what to do with associations. It seems original code is incomplete.
// TODO: Decide what to do with associations. It seems original code is incomplete.
// One solution is to load the association, but it might require extra efforts.
return array('name' => $column);

View File

@ -33,24 +33,24 @@ use Doctrine\DBAL\Connection,
class SingleScalarHydrator extends AbstractHydrator
{
/**
* {@inheritdoc}
* {@inheritdoc}
*/
protected function hydrateAllData()
{
$data = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
$numRows = count($data);
if ($numRows === 0) {
throw new NoResultException();
}
if ($numRows > 1 || count($data[key($data)]) > 1) {
throw new NonUniqueResultException();
}
$cache = array();
$result = $this->gatherScalarRowData($data[key($data)], $cache);
return array_shift($result);
}
}

View File

@ -124,7 +124,7 @@ class AssociationBuilder
/**
* Add Join Columns
*
*
* @param string $columnName
* @param string $referencedColumnName
* @param bool $nullable

View File

@ -19,7 +19,8 @@
namespace Doctrine\ORM\Mapping\Builder;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataInfo;
/**
* Builder Object for ClassMetadata
@ -28,18 +29,19 @@ use Doctrine\ORM\Mapping\ClassMetadata;
* @link www.doctrine-project.com
* @since 2.2
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/
class ClassMetadataBuilder
{
/**
* @var ClassMetadata
* @var \Doctrine\ORM\Mapping\ClassMetadataInfo
*/
private $cm;
/**
* @param ClassMetadata $cm
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $cm
*/
public function __construct(ClassMetadata $cm)
public function __construct(ClassMetadataInfo $cm)
{
$this->cm = $cm;
}
@ -60,6 +62,7 @@ class ClassMetadataBuilder
public function setMappedSuperClass()
{
$this->cm->isMappedSuperclass = true;
return $this;
}
@ -72,6 +75,7 @@ class ClassMetadataBuilder
public function setCustomRepositoryClass($repositoryClassName)
{
$this->cm->setCustomRepositoryClass($repositoryClassName);
return $this;
}
@ -83,6 +87,7 @@ class ClassMetadataBuilder
public function setReadOnly()
{
$this->cm->markReadOnly();
return $this;
}
@ -95,6 +100,7 @@ class ClassMetadataBuilder
public function setTable($name)
{
$this->cm->setPrimaryTable(array('name' => $name));
return $this;
}
@ -110,7 +116,9 @@ class ClassMetadataBuilder
if (!isset($this->cm->table['indexes'])) {
$this->cm->table['indexes'] = array();
}
$this->cm->table['indexes'][$name] = array('columns' => $columns);
return $this;
}
@ -123,10 +131,12 @@ class ClassMetadataBuilder
*/
public function addUniqueConstraint(array $columns, $name)
{
if (!isset($this->cm->table['uniqueConstraints'])) {
if ( ! isset($this->cm->table['uniqueConstraints'])) {
$this->cm->table['uniqueConstraints'] = array();
}
$this->cm->table['uniqueConstraints'][$name] = array('columns' => $columns);
return $this;
}
@ -143,6 +153,7 @@ class ClassMetadataBuilder
'name' => $name,
'query' => $dqlQuery,
));
return $this;
}
@ -154,6 +165,7 @@ class ClassMetadataBuilder
public function setJoinedTableInheritance()
{
$this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_JOINED);
return $this;
}
@ -165,6 +177,7 @@ class ClassMetadataBuilder
public function setSingleTableInheritance()
{
$this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE);
return $this;
}
@ -181,12 +194,13 @@ class ClassMetadataBuilder
'type' => $type,
'length' => $length,
));
return $this;
}
/**
* Add a subclass to this inheritance hierachy.
*
*
* @param string $name
* @param string $class
* @return ClassMetadataBuilder
@ -194,6 +208,7 @@ class ClassMetadataBuilder
public function addDiscriminatorMapClass($name, $class)
{
$this->cm->addDiscriminatorMapClass($name, $class);
return $this;
}
@ -205,6 +220,7 @@ class ClassMetadataBuilder
public function setChangeTrackingPolicyDeferredExplicit()
{
$this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT);
return $this;
}
@ -216,12 +232,13 @@ class ClassMetadataBuilder
public function setChangeTrackingPolicyNotify()
{
$this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_NOTIFY);
return $this;
}
/**
* Add lifecycle event
*
*
* @param string $methodName
* @param string $event
* @return ClassMetadataBuilder
@ -229,6 +246,7 @@ class ClassMetadataBuilder
public function addLifecycleEvent($methodName, $event)
{
$this->cm->addLifecycleCallback($methodName, $event);
return $this;
}
@ -243,7 +261,9 @@ class ClassMetadataBuilder
{
$mapping['fieldName'] = $name;
$mapping['type'] = $type;
$this->cm->mapField($mapping);
return $this;
}
@ -256,12 +276,18 @@ class ClassMetadataBuilder
*/
public function createField($name, $type)
{
return new FieldBuilder($this, array('fieldName' => $name, 'type' => $type));
return new FieldBuilder(
$this,
array(
'fieldName' => $name,
'type' => $type
)
);
}
/**
* Add a simple many to one association, optionally with the inversed by field.
*
*
* @param string $name
* @param string $targetEntity
* @param string|null $inversedBy
@ -270,9 +296,11 @@ class ClassMetadataBuilder
public function addManyToOne($name, $targetEntity, $inversedBy = null)
{
$builder = $this->createManyToOne($name, $targetEntity);
if ($inversedBy) {
$builder->setInversedBy($inversedBy);
$builder->inversedBy($inversedBy);
}
return $builder->build();
}
@ -287,19 +315,33 @@ class ClassMetadataBuilder
*/
public function createManyToOne($name, $targetEntity)
{
return new AssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::MANY_TO_ONE);
return new AssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::MANY_TO_ONE
);
}
/**
* Create OneToOne Assocation Builder
*
*
* @param string $name
* @param string $targetEntity
* @return AssociationBuilder
*/
public function createOneToOne($name, $targetEntity)
{
return new AssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::ONE_TO_ONE);
return new AssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::ONE_TO_ONE
);
}
/**
@ -313,7 +355,8 @@ class ClassMetadataBuilder
public function addInverseOneToOne($name, $targetEntity, $mappedBy)
{
$builder = $this->createOneToOne($name, $targetEntity);
$builder->setMappedBy($mappedBy);
$builder->mappedBy($mappedBy);
return $builder->build();
}
@ -328,9 +371,11 @@ class ClassMetadataBuilder
public function addOwningOneToOne($name, $targetEntity, $inversedBy = null)
{
$builder = $this->createOneToOne($name, $targetEntity);
if ($inversedBy) {
$builder->setInversedBy($inversedBy);
$builder->inversedBy($inversedBy);
}
return $builder->build();
}
@ -343,12 +388,19 @@ class ClassMetadataBuilder
*/
public function createManyToMany($name, $targetEntity)
{
return new ManyToManyAssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::MANY_TO_MANY);
return new ManyToManyAssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::MANY_TO_MANY
);
}
/**
* Add a simple owning many to many assocation.
*
*
* @param string $name
* @param string $targetEntity
* @param string|null $inversedBy
@ -357,9 +409,11 @@ class ClassMetadataBuilder
public function addOwningManyToMany($name, $targetEntity, $inversedBy = null)
{
$builder = $this->createManyToMany($name, $targetEntity);
if ($inversedBy) {
$builder->setInversedBy($inversedBy);
$builder->inversedBy($inversedBy);
}
return $builder->build();
}
@ -374,25 +428,33 @@ class ClassMetadataBuilder
public function addInverseManyToMany($name, $targetEntity, $mappedBy)
{
$builder = $this->createManyToMany($name, $targetEntity);
$builder->setMappedBy($mappedBy);
$builder->mappedBy($mappedBy);
return $builder->build();
}
/**
* Create a one to many assocation builder
*
*
* @param string $name
* @param string $targetEntity
* @return OneToManyAssociationBuilder
*/
public function createOneToMany($name, $targetEntity)
{
return new OneToManyAssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::ONE_TO_MANY);
return new OneToManyAssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::ONE_TO_MANY
);
}
/**
* Add simple OneToMany assocation.
*
*
* @param string $name
* @param string $targetEntity
* @param string $mappedBy
@ -401,7 +463,8 @@ class ClassMetadataBuilder
public function addOneToMany($name, $targetEntity, $mappedBy)
{
$builder = $this->createOneToMany($name, $targetEntity);
$builder->setMappedBy($mappedBy);
$builder->mappedBy($mappedBy);
return $builder->build();
}
}

View File

@ -170,7 +170,7 @@ class FieldBuilder
/**
* Set Sequence Generator
*
*
* @param string $sequenceName
* @param int $allocationSize
* @param int $initialValue
@ -188,7 +188,7 @@ class FieldBuilder
/**
* Set column definition.
*
*
* @param string $def
* @return FieldBuilder
*/

View File

@ -20,11 +20,12 @@
namespace Doctrine\ORM\Mapping;
use ReflectionClass, ReflectionProperty;
use Doctrine\Common\Persistence\Mapping\ClassMetadata AS IClassMetadata;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
* of an entity and it's associations.
*
*
* Once populated, ClassMetadata instances are usually cached in a serialized form.
*
* <b>IMPORTANT NOTE:</b>
@ -39,7 +40,7 @@ use ReflectionClass, ReflectionProperty;
* @author Jonathan H. Wage <jonwage@gmail.com>
* @since 2.0
*/
class ClassMetadata extends ClassMetadataInfo
class ClassMetadata extends ClassMetadataInfo implements IClassMetadata
{
/**
* The ReflectionProperty instances of the mapped class.
@ -47,10 +48,10 @@ class ClassMetadata extends ClassMetadataInfo
* @var array
*/
public $reflFields = array();
/**
* The prototype from which new instances of the mapped class are created.
*
*
* @var object
*/
private $_prototype;
@ -103,13 +104,13 @@ class ClassMetadata extends ClassMetadataInfo
}
return $this->reflFields[$this->identifier[0]];
}
/**
* Validates & completes the given field mapping.
*
* @param array $mapping The field mapping to validated & complete.
* @return array The validated and completed field mapping.
*
*
* @throws MappingException
*/
protected function _validateAndCompleteFieldMapping(array &$mapping)
@ -124,7 +125,7 @@ class ClassMetadata extends ClassMetadataInfo
/**
* Extracts the identifier values of an entity of this class.
*
*
* For composite identifiers, the identifier values are returned as an array
* with the same order as the field order in {@link identifier}.
*
@ -135,20 +136,25 @@ class ClassMetadata extends ClassMetadataInfo
{
if ($this->isIdentifierComposite) {
$id = array();
foreach ($this->identifier as $idField) {
$value = $this->reflFields[$idField]->getValue($entity);
if ($value !== null) {
$id[$idField] = $value;
}
}
return $id;
} else {
$value = $this->reflFields[$this->identifier[0]]->getValue($entity);
if ($value !== null) {
return array($this->identifier[0] => $value);
}
return array();
}
$value = $this->reflFields[$this->identifier[0]]->getValue($entity);
if ($value !== null) {
return array($this->identifier[0] => $value);
}
return array();
}
/**
@ -215,18 +221,18 @@ class ClassMetadata extends ClassMetadataInfo
{
return __CLASS__ . '@' . spl_object_hash($this);
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
*
* Parts that are also NOT serialized because they can not be properly unserialized:
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
@ -301,7 +307,7 @@ class ClassMetadata extends ClassMetadataInfo
/**
* Restores some state that can not be serialized/unserialized.
*
*
* @return void
*/
public function __wakeup()
@ -310,30 +316,27 @@ class ClassMetadata extends ClassMetadataInfo
$this->reflClass = new ReflectionClass($this->name);
foreach ($this->fieldMappings as $field => $mapping) {
if (isset($mapping['declared'])) {
$reflField = new ReflectionProperty($mapping['declared'], $field);
} else {
$reflField = $this->reflClass->getProperty($field);
}
$reflField = isset($mapping['declared'])
? new ReflectionProperty($mapping['declared'], $field)
: $this->reflClass->getProperty($field);
$reflField->setAccessible(true);
$this->reflFields[$field] = $reflField;
}
foreach ($this->associationMappings as $field => $mapping) {
if (isset($mapping['declared'])) {
$reflField = new ReflectionProperty($mapping['declared'], $field);
} else {
$reflField = $this->reflClass->getProperty($field);
}
$reflField = isset($mapping['declared'])
? new ReflectionProperty($mapping['declared'], $field)
: $this->reflClass->getProperty($field);
$reflField->setAccessible(true);
$this->reflFields[$field] = $reflField;
}
}
/**
* Creates a new instance of the mapped class, without invoking the constructor.
*
*
* @return object
*/
public function newInstance()
@ -341,6 +344,7 @@ class ClassMetadata extends ClassMetadataInfo
if ($this->_prototype === null) {
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
}
return clone $this->_prototype;
}
@ -354,6 +358,7 @@ class ClassMetadata extends ClassMetadataInfo
($this->reflClass->getMethod($callback)->getModifiers() & \ReflectionMethod::IS_PUBLIC) == 0) {
throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callback);
}
return parent::addLifecycleCallback($callback, $event);
}
}

View File

@ -43,7 +43,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
* @var EntityManager
*/
private $em;
/**
* @var AbstractPlatform
*/
@ -73,7 +73,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
* @var bool
*/
private $initialized = false;
/**
* @param EntityManager $$em
*/
@ -85,7 +85,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Sets the cache driver used by the factory to cache ClassMetadata instances.
*
* @param Doctrine\Common\Cache\Cache $cacheDriver
* @param \Doctrine\Common\Cache\Cache $cacheDriver
*/
public function setCacheDriver($cacheDriver)
{
@ -95,22 +95,22 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Gets the cache driver used by the factory to cache ClassMetadata instances.
*
* @return Doctrine\Common\Cache\Cache
* @return \Doctrine\Common\Cache\Cache
*/
public function getCacheDriver()
{
return $this->cacheDriver;
}
public function getLoadedMetadata()
{
return $this->loadedMetadata;
}
/**
* Forces the factory to load the metadata of all classes known to the underlying
* mapping driver.
*
*
* @return array The ClassMetadata instances of all mapped classes.
*/
public function getAllMetadata()
@ -143,7 +143,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
* Gets the class metadata descriptor for a class.
*
* @param string $className The name of the class.
* @return Doctrine\ORM\Mapping\ClassMetadata
* @return \Doctrine\ORM\Mapping\ClassMetadata
*/
public function getMetadataFor($className)
{
@ -188,7 +188,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Checks whether the factory has the metadata for a class loaded already.
*
*
* @param string $className
* @return boolean TRUE if the metadata of the class in question is already loaded, FALSE otherwise.
*/
@ -199,7 +199,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Sets the metadata descriptor for a specific class.
*
*
* NOTE: This is only useful in very special cases, like when generating proxy classes.
*
* @param string $className
@ -308,11 +308,11 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
if ($parent && $parent->isInheritanceTypeSingleTable()) {
$class->setPrimaryTable($parent->table);
}
if ($parent && $parent->containsForeignIdentifier) {
$class->containsForeignIdentifier = true;
}
if ($parent && !empty ($parent->namedQueries)) {
$this->addInheritedNamedQueries($class, $parent);
}
@ -325,7 +325,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
}
$this->validateRuntimeMetadata($class, $parent);
$this->loadedMetadata[$className] = $class;
$parent = $class;
@ -371,13 +371,17 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
// second condition is necessary for mapped superclasses in the middle of an inheritance hierachy
throw MappingException::noInheritanceOnMappedSuperClass($class->name);
}
if ($class->usesIdGenerator() && $class->isIdentifierComposite) {
throw MappingException::compositeKeyAssignedIdGeneratorRequired($class->name);
}
}
/**
* Creates a new ClassMetadata instance for the given class name.
*
* @param string $className
* @return Doctrine\ORM\Mapping\ClassMetadata
* @return \Doctrine\ORM\Mapping\ClassMetadata
*/
protected function newClassMetadataInstance($className)
{
@ -387,8 +391,8 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Adds inherited fields to the subclass mapping.
*
* @param Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param Doctrine\ORM\Mapping\ClassMetadata $parentClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass)
{
@ -409,8 +413,8 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Adds inherited association mappings to the subclass mapping.
*
* @param Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param Doctrine\ORM\Mapping\ClassMetadata $parentClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass)
{
@ -432,13 +436,13 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
$subClass->addInheritedAssociationMapping($mapping);
}
}
/**
* Adds inherited named queries to the subclass mapping.
*
*
* @since 2.2
* @param Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param Doctrine\ORM\Mapping\ClassMetadata $parentClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass)
{
@ -456,7 +460,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
* Completes the ID generator mapping. If "auto" is specified we choose the generator
* most appropriate for the targeted database platform.
*
* @param Doctrine\ORM\Mapping\ClassMetadata $class
* @param \Doctrine\ORM\Mapping\ClassMetadata $class
*/
private function completeIdGeneratorMapping(ClassMetadataInfo $class)
{
@ -533,13 +537,13 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
if ( ! $this->initialized) {
$this->initialize();
}
// Check for namespace alias
if (strpos($class, ':') !== false) {
list($namespaceAlias, $simpleClassName) = explode(':', $class);
$class = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
}
return $this->driver->isTransient($class);
}
}

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\DBAL\Types\Type;
use ReflectionClass;
@ -41,7 +40,7 @@ use ReflectionClass;
* @author Jonathan H. Wage <jonwage@gmail.com>
* @since 2.0
*/
class ClassMetadataInfo implements ClassMetadata
class ClassMetadataInfo
{
/* The inheritance mapping types */
/**
@ -1271,7 +1270,7 @@ class ClassMetadataInfo implements ClassMetadata
* Gets the type of a field.
*
* @param string $fieldName
* @return Doctrine\DBAL\Types\Type
* @return \Doctrine\DBAL\Types\Type
*/
public function getTypeOfField($fieldName)
{
@ -1282,7 +1281,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Gets the type of a column.
*
* @return Doctrine\DBAL\Types\Type
* @return \Doctrine\DBAL\Types\Type
*/
public function getTypeOfColumn($columnName)
{

View File

@ -25,7 +25,7 @@ use Doctrine\ORM\Mapping\MappingException;
/**
* Base driver for file-based metadata drivers.
*
*
* A file driver operates in a mode where it loads the mapping files of individual
* classes on demand. This requires the user to adhere to the convention of 1 mapping
* file per class and the file names of the mapping files must correspond to the full
@ -56,16 +56,16 @@ abstract class AbstractFileDriver implements Driver
*/
protected $_fileExtension;
/**
* Initializes a new FileDriver that looks in the given path(s) for mapping
* documents and operates in the specified operating mode.
*
* @param string|array $paths One or multiple paths where mapping documents can be found.
*/
public function __construct($paths)
{
/**
* Initializes a new FileDriver that looks in the given path(s) for mapping
* documents and operates in the specified operating mode.
*
* @param string|array $paths One or multiple paths where mapping documents can be found.
*/
public function __construct($paths)
{
$this->addPaths((array) $paths);
}
}
/**
* Append lookup paths to metadata driver.
@ -117,7 +117,10 @@ abstract class AbstractFileDriver implements Driver
public function getElement($className)
{
$result = $this->_loadMappingFile($this->_findMappingFile($className));
if(!isset($result[$className])){
throw MappingException::invalidMappingFile($className, str_replace('\\', '.', $className) . $this->_fileExtension);
}
return $result[$className];
}
@ -145,7 +148,7 @@ abstract class AbstractFileDriver implements Driver
/**
* Gets the names of all mapped classes known to this driver.
*
*
* @return array The names of all mapped classes known to this driver.
*/
public function getAllClassNames()
@ -157,23 +160,23 @@ abstract class AbstractFileDriver implements Driver
if ( ! is_dir($path)) {
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
if (($fileName = $file->getBasename($this->_fileExtension)) == $file->getBasename()) {
continue;
}
// NOTE: All files found here means classes are not transient!
$classes[] = str_replace('.', '\\', $fileName);
}
}
}
return $classes;
}
@ -188,7 +191,7 @@ abstract class AbstractFileDriver implements Driver
protected function _findMappingFile($className)
{
$fileName = str_replace('\\', '.', $className) . $this->_fileExtension;
// Check whether file exists
foreach ((array) $this->_paths as $path) {
if (file_exists($path . DIRECTORY_SEPARATOR . $fileName)) {
@ -202,7 +205,7 @@ abstract class AbstractFileDriver implements Driver
/**
* Loads a mapping file with the given name and returns a map
* from class/entity names to their corresponding elements.
*
*
* @param string $file The mapping file to load.
* @return array
*/

View File

@ -99,7 +99,7 @@ class AnnotationDriver implements Driver
/**
* Retrieve the current annotation reader
*
*
* @return AnnotationReader
*/
public function getReader()
@ -192,7 +192,14 @@ class AnnotationDriver implements Driver
if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedQueries'])) {
$namedQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedQueries'];
if (!is_array($namedQueriesAnnot->value)) {
throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
}
foreach ($namedQueriesAnnot->value as $namedQuery) {
if (!($namedQuery instanceof \Doctrine\ORM\Mapping\NamedQuery)) {
throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
}
$metadata->addNamedQuery(array(
'name' => $namedQuery->name,
'query' => $namedQuery->query
@ -517,15 +524,15 @@ class AnnotationDriver implements Driver
new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS),
\RecursiveIteratorIterator::LEAVES_ONLY
),
'/^.+' . str_replace('.', '\.', $this->_fileExtension) . '$/i',
'/^.+' . str_replace('.', '\.', $this->_fileExtension) . '$/i',
\RecursiveRegexIterator::GET_MATCH
);
foreach ($iterator as $file) {
$sourceFile = realpath($file[0]);
require_once $sourceFile;
$includedFiles[] = $sourceFile;
}
}

View File

@ -76,7 +76,7 @@ class DatabaseDriver implements Driver
/**
* Initializes a new AnnotationDriver that uses the given AnnotationReader for reading
* docblock annotations.
*
*
* @param AnnotationReader $reader The AnnotationReader to use.
*/
public function __construct(AbstractSchemaManager $schemaManager)
@ -111,7 +111,7 @@ class DatabaseDriver implements Driver
}
$tables = array();
foreach ($this->_sm->listTableNames() as $tableName) {
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
}
@ -129,7 +129,7 @@ class DatabaseDriver implements Driver
foreach ($foreignKeys AS $foreignKey) {
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
}
$pkColumns = $table->getPrimaryKey()->getColumns();
sort($pkColumns);
sort($allForeignKeyColumns);
@ -145,7 +145,7 @@ class DatabaseDriver implements Driver
}
}
}
/**
* {@inheritdoc}
*/
@ -169,7 +169,7 @@ class DatabaseDriver implements Driver
} catch(SchemaException $e) {
$primaryKeyColumns = array();
}
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
$foreignKeys = $this->tables[$tableName]->getForeignKeys();
} else {

View File

@ -34,18 +34,18 @@ interface Driver
{
/**
* Loads the metadata for the specified class into the provided container.
*
*
* @param string $className
* @param ClassMetadataInfo $metadata
*/
function loadMetadataForClass($className, ClassMetadataInfo $metadata);
/**
* Gets the names of all mapped classes known to this driver.
*
*
* @return array The names of all mapped classes known to this driver.
*/
function getAllClassNames();
function getAllClassNames();
/**
* Whether the class with the specified name should have its metadata loaded.

View File

@ -94,7 +94,7 @@ class DriverChain implements Driver
if (!isset($driverClasses[$oid])) {
$driverClasses[$oid] = $driver->getAllClassNames();
}
foreach ($driverClasses[$oid] AS $className) {
if (strpos($className, $namespace) === 0) {
$classNames[$className] = true;

View File

@ -38,21 +38,21 @@ class StaticPHPDriver implements Driver
{
/**
* Paths of entity directories.
*
*
* @var array
*/
private $_paths = array();
/**
* Map of all class names.
*
*
* @var array
*/
private $_classNames;
/**
* The file extension of mapping documents.
*
*
* @var string
*/
private $_fileExtension = '.php';

View File

@ -216,7 +216,7 @@ class XmlDriver extends AbstractFileDriver
$associationIds = array();
foreach ($xmlRoot->id as $idElement) {
if ((bool)$idElement['association-key'] == true) {
$associationIds[(string)$idElement['fieldName']] = true;
$associationIds[(string)$idElement['name']] = true;
continue;
}
@ -233,6 +233,10 @@ class XmlDriver extends AbstractFileDriver
$mapping['columnName'] = (string)$idElement['column'];
}
if (isset($idElement['column-definition'])) {
$mapping['columnDefinition'] = (string)$idElement['column-definition'];
}
$metadata->mapField($mapping);
if (isset($idElement->generator)) {

View File

@ -182,6 +182,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['length'] = $idElement['length'];
}
if (isset($idElement['columnDefinition'])) {
$mapping['columnDefinition'] = $idElement['columnDefinition'];
}
$metadata->mapField($mapping);
if (isset($idElement['generator'])) {

View File

@ -25,6 +25,6 @@ namespace Doctrine\ORM\Mapping;
*/
final class JoinColumns implements Annotation
{
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */
public $value;
}

View File

@ -29,8 +29,8 @@ final class JoinTable implements Annotation
public $name;
/** @var string */
public $schema;
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */
public $joinColumns = array();
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */
public $inverseJoinColumns = array();
}

View File

@ -68,6 +68,11 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("No mapping file found named '$fileName' for class '$entityName'.");
}
public static function invalidMappingFile($entityName, $fileName)
{
return new self("Invalid mapping file '$fileName' for class '$entityName'.");
}
public static function mappingNotFound($className, $fieldName)
{
return new self("No mapping found for field '$fieldName' on class '$className'.");
@ -314,4 +319,9 @@ class MappingException extends \Doctrine\ORM\ORMException
{
return new self("Entity '" . $className . "' has a mapping with invalid fetch mode '" . $annotation . "'");
}
public static function compositeKeyAssignedIdGeneratorRequired($className)
{
return new self("Entity '". $className . "' has a composite identifier but uses an ID generator other than manually assigning (Identity, Sequence). This is not supported.");
}
}

View File

@ -25,6 +25,6 @@ namespace Doctrine\ORM\Mapping;
*/
final class NamedQueries implements Annotation
{
/** @var array<Doctrine\ORM\Mapping\NamedQuery> */
/** @var array<\Doctrine\ORM\Mapping\NamedQuery> */
public $value;
}

View File

@ -29,8 +29,8 @@ final class Table implements Annotation
public $name;
/** @var string */
public $schema;
/** @var array<Doctrine\ORM\Mapping\Index> */
/** @var array<\Doctrine\ORM\Mapping\Index> */
public $indexes;
/** @var array<Doctrine\ORM\Mapping\UniqueConstraint> */
/** @var array<\Doctrine\ORM\Mapping\UniqueConstraint> */
public $uniqueConstraints;
}

View File

@ -1,4 +1,4 @@
<?php
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@ -38,6 +38,7 @@ final class NativeQuery extends AbstractQuery
public function setSQL($sql)
{
$this->_sql = $sql;
return $this;
}
@ -58,16 +59,18 @@ final class NativeQuery extends AbstractQuery
protected function _doExecute()
{
$params = $this->_params;
$types = $this->_paramTypes;
if ($params) {
if (is_int(key($params))) {
ksort($params);
ksort($types);
$params = array_values($params);
$types = array_values($types);
}
$types = $this->_paramTypes;
if ($params && is_int(key($params))) {
ksort($params);
ksort($types);
$params = array_values($params);
$types = array_values($types);
}
return $this->_em->getConnection()->executeQuery($this->_sql, $params, $types, $this->_queryCacheProfile);
return $this->_em->getConnection()->executeQuery(
$this->_sql, $params, $types, $this->_queryCacheProfile
);
}
}

View File

@ -21,7 +21,7 @@ namespace Doctrine\ORM;
/**
* Exception thrown when an ORM query unexpectedly does not return any results.
*
*
* @author robo
* @since 2.0
*/

View File

@ -21,7 +21,7 @@ namespace Doctrine\ORM;
/**
* Exception thrown when an ORM query unexpectedly returns more than one result.
*
*
* @author robo
* @since 2.0
*/

View File

@ -144,4 +144,9 @@ class ORMException extends Exception
return new self("Invalid repository class '".$className."'. ".
"it must be a Doctrine\ORM\EntityRepository.");
}
public static function missingIdentifierField($className, $fieldName)
{
return new self("The identifier $fieldName is missing for a query of " . $className);
}
}

View File

@ -67,7 +67,7 @@ final class PersistentCollection implements Collection
/**
* The EntityManager that manages the persistence of the collection.
*
* @var Doctrine\ORM\EntityManager
* @var \Doctrine\ORM\EntityManager
*/
private $em;
@ -164,7 +164,7 @@ final class PersistentCollection implements Collection
// If _backRefFieldName is set and its a one-to-many association,
// we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) {
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
$element, $this->owner
@ -189,7 +189,7 @@ final class PersistentCollection implements Collection
// If _backRefFieldName is set, then the association is bidirectional
// and we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) {
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
$element, $this->owner
@ -284,7 +284,7 @@ final class PersistentCollection implements Collection
/**
* INTERNAL: Gets the association mapping of the collection.
*
* @return Doctrine\ORM\Mapping\AssociationMapping
* @return \Doctrine\ORM\Mapping\AssociationMapping
*/
public function getMapping()
{
@ -304,7 +304,7 @@ final class PersistentCollection implements Collection
if ($this->association !== null &&
$this->association['isOwningSide'] &&
$this->association['type'] == ClassMetadata::MANY_TO_MANY &&
$this->association['type'] === ClassMetadata::MANY_TO_MANY &&
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
}
@ -425,7 +425,7 @@ final class PersistentCollection implements Collection
$this->changed();
if ($this->association !== null &&
$this->association['type'] == ClassMetadata::ONE_TO_MANY &&
$this->association['type'] === ClassMetadata::ONE_TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
}
@ -448,7 +448,7 @@ final class PersistentCollection implements Collection
*/
public function contains($element)
{
if ( ! $this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $this->coll->contains($element) || $persister->contains($this, $element);
@ -514,7 +514,7 @@ final class PersistentCollection implements Collection
*/
public function count()
{
if ( ! $this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $persister->count($this) + ($this->isDirty ? $this->coll->count() : 0);
@ -630,7 +630,7 @@ final class PersistentCollection implements Collection
$uow = $this->em->getUnitOfWork();
if ($this->association['type'] == ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
if ($this->association['type'] === ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
// we need to initialize here, as orphan removal acts like implicit cascadeRemove,
// hence for event listeners we need the objects in memory.
$this->initialize();
@ -728,7 +728,7 @@ final class PersistentCollection implements Collection
/**
* Retrieves the wrapped Collection instance.
*
* @return Doctrine\Common\Collections\Collection
* @return \Doctrine\Common\Collections\Collection
*/
public function unwrap()
{

View File

@ -36,19 +36,19 @@ abstract class AbstractCollectionPersister
protected $_em;
/**
* @var Doctrine\DBAL\Connection
* @var \Doctrine\DBAL\Connection
*/
protected $_conn;
/**
* @var Doctrine\ORM\UnitOfWork
* @var \Doctrine\ORM\UnitOfWork
*/
protected $_uow;
/**
* Initializes a new instance of a class derived from AbstractCollectionPersister.
*
* @param Doctrine\ORM\EntityManager $em
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
{
@ -65,11 +65,11 @@ abstract class AbstractCollectionPersister
public function delete(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
if ( ! $mapping['isOwningSide']) {
return; // ignore inverse side
}
$sql = $this->_getDeleteSQL($coll);
$this->_conn->executeUpdate($sql, $this->_getDeleteSQLParameters($coll));
}
@ -98,34 +98,34 @@ abstract class AbstractCollectionPersister
public function update(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
if ( ! $mapping['isOwningSide']) {
return; // ignore inverse side
}
$this->deleteRows($coll);
//$this->updateRows($coll);
$this->insertRows($coll);
}
public function deleteRows(PersistentCollection $coll)
{
{
$deleteDiff = $coll->getDeleteDiff();
$sql = $this->_getDeleteRowSQL($coll);
foreach ($deleteDiff as $element) {
$this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element));
}
}
//public function updateRows(PersistentCollection $coll)
//{}
public function insertRows(PersistentCollection $coll)
{
$insertDiff = $coll->getInsertDiff();
$sql = $this->_getInsertRowSQL($coll);
foreach ($insertDiff as $element) {
$this->_conn->executeUpdate($sql, $this->_getInsertRowSQLParameters($coll, $element));
}
@ -168,7 +168,7 @@ abstract class AbstractCollectionPersister
/**
* Gets the SQL statement used for deleting a row from the collection.
*
*
* @param PersistentCollection $coll
*/
abstract protected function _getDeleteRowSQL(PersistentCollection $coll);

View File

@ -26,7 +26,7 @@ use Doctrine\ORM\Mapping\ClassMetadata,
* Base class for entity persisters that implement a certain inheritance mapping strategy.
* All these persisters are assumed to use a discriminator column to discriminate entity
* types in the hierarchy.
*
*
* @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @since 2.0
@ -39,18 +39,18 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
protected function _prepareInsertData($entity)
{
$data = parent::_prepareInsertData($entity);
// Populate the discriminator column
$discColumn = $this->_class->discriminatorColumn;
$this->_columnTypes[$discColumn['name']] = $discColumn['type'];
$data[$this->_getDiscriminatorColumnTableName()][$discColumn['name']] = $this->_class->discriminatorValue;
return $data;
}
/**
* Gets the name of the table that contains the discriminator column.
*
*
* @return string The table name.
*/
abstract protected function _getDiscriminatorColumnTableName();
@ -77,7 +77,7 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
{
$columnAlias = $this->getSQLColumnAlias($joinColumnName);
$this->_rsm->addMetaResult('r', $columnAlias, $joinColumnName);
return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias;
}
}

View File

@ -72,6 +72,7 @@ use PDO,
* @author Roman Borschel <roman@code-factory.org>
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Alexander <iam.asm89@gmail.com>
* @since 2.0
*/
class BasicEntityPersister
@ -79,28 +80,28 @@ class BasicEntityPersister
/**
* Metadata object that describes the mapping of the mapped entity class.
*
* @var Doctrine\ORM\Mapping\ClassMetadata
* @var \Doctrine\ORM\Mapping\ClassMetadata
*/
protected $_class;
/**
* The underlying DBAL Connection of the used EntityManager.
*
* @var Doctrine\DBAL\Connection $conn
* @var \Doctrine\DBAL\Connection $conn
*/
protected $_conn;
/**
* The database platform.
*
* @var Doctrine\DBAL\Platforms\AbstractPlatform
* @var \Doctrine\DBAL\Platforms\AbstractPlatform
*/
protected $_platform;
/**
* The EntityManager instance.
*
* @var Doctrine\ORM\EntityManager
* @var \Doctrine\ORM\EntityManager
*/
protected $_em;
@ -172,8 +173,8 @@ class BasicEntityPersister
* Initializes a new <tt>BasicEntityPersister</tt> that uses the given EntityManager
* and persists instances of the class described by the given ClassMetadata descriptor.
*
* @param Doctrine\ORM\EntityManager $em
* @param Doctrine\ORM\Mapping\ClassMetadata $class
* @param \Doctrine\ORM\EntityManager $em
* @param \Doctrine\ORM\Mapping\ClassMetadata $class
*/
public function __construct(EntityManager $em, ClassMetadata $class)
{
@ -184,7 +185,7 @@ class BasicEntityPersister
}
/**
* @return Doctrine\ORM\Mapping\ClassMetadata
* @return \Doctrine\ORM\Mapping\ClassMetadata
*/
public function getClassMetadata()
{
@ -272,7 +273,7 @@ class BasicEntityPersister
/**
* Fetch the current version value of a versioned entity.
*
* @param Doctrine\ORM\Mapping\ClassMetadata $versionedClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $versionedClass
* @param mixed $id
* @return mixed
*/
@ -340,7 +341,7 @@ class BasicEntityPersister
foreach ($updateData as $columnName => $value) {
$column = $columnName;
$placeholder = '?';
if (isset($this->_class->fieldNames[$columnName])) {
$column = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform);
@ -750,7 +751,7 @@ class BasicEntityPersister
* Load an array of entities from a given dbal statement.
*
* @param array $assoc
* @param Doctrine\DBAL\Statement $stmt
* @param \Doctrine\DBAL\Statement $stmt
*
* @return array
*/
@ -774,7 +775,7 @@ class BasicEntityPersister
* Hydrate a collection from a given dbal statement.
*
* @param array $assoc
* @param Doctrine\DBAL\Statement $stmt
* @param \Doctrine\DBAL\Statement $stmt
* @param PersistentCollection $coll
*
* @return array
@ -900,9 +901,19 @@ class BasicEntityPersister
$lockSql = ' ' . $this->_platform->getWriteLockSql();
}
$alias = $this->_getSQLTableAlias($this->_class->name);
if ($filterSql = $this->generateFilterConditionSQL($this->_class, $alias)) {
if ($conditionSql) {
$conditionSql .= ' AND ';
}
$conditionSql .= $filterSql;
}
return $this->_platform->modifyLimitQuery('SELECT ' . $this->_getSelectColumnListSQL()
. $this->_platform->appendLockHint(' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
. $this->_getSQLTableAlias($this->_class->name), $lockMode)
. $alias, $lockMode)
. $this->_selectJoinSql . $joinSql
. ($conditionSql ? ' WHERE ' . $conditionSql : '')
. $orderBySql, $limit, $offset)
@ -1014,14 +1025,20 @@ class BasicEntityPersister
$this->_selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($assoc['joinColumns']);
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON ';
$tableAlias = $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias);
foreach ($assoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
if ( ! $first) {
$this->_selectJoinSql .= ' AND ';
}
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
. $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.' . $targetCol;
. $tableAlias . '.' . $targetCol;
$first = false;
}
// Add filter SQL
if ($filterSql = $this->generateFilterConditionSQL($eagerEntity, $tableAlias)) {
$this->_selectJoinSql .= ' AND ' . $filterSql;
}
} else {
$eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']);
$owningAssoc = $eagerEntity->getAssociationMapping($assoc['mappedBy']);
@ -1290,7 +1307,7 @@ class BasicEntityPersister
foreach ($criteria as $field => $value) {
$conditionSql .= $conditionSql ? ' AND ' : '';
$placeholder = '?';
if (isset($this->_class->columnNames[$field])) {
@ -1368,7 +1385,7 @@ class BasicEntityPersister
* @param object $sourceEntity
* @param int|null $offset
* @param int|null $limit
* @return Doctrine\DBAL\Statement
* @return \Doctrine\DBAL\Statement
*/
private function getOneToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
@ -1433,7 +1450,7 @@ class BasicEntityPersister
{
switch (true) {
case (isset($this->_class->fieldMappings[$field])):
$type = Type::getType($this->_class->fieldMappings[$field]['type'])->getBindingType();
$type = $this->_class->fieldMappings[$field]['type'];
break;
case (isset($this->_class->associationMappings[$field])):
@ -1448,7 +1465,7 @@ class BasicEntityPersister
$type = null;
if (isset($targetClass->fieldNames[$targetColumn])) {
$type = Type::getType($targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type'])->getBindingType();
$type = $targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type'];
}
break;
@ -1456,8 +1473,8 @@ class BasicEntityPersister
default:
$type = null;
}
if (is_array($value)) {
$type = Type::getType( $type )->getBindingType();
$type += Connection::ARRAY_PARAM_OFFSET;
}
@ -1521,10 +1538,16 @@ class BasicEntityPersister
$criteria = array_merge($criteria, $extraConditions);
}
$alias = $this->_getSQLTableAlias($this->_class->name);
$sql = 'SELECT 1 '
. $this->getLockTablesSql()
. ' WHERE ' . $this->_getSelectConditionSQL($criteria);
if ($filterSql = $this->generateFilterConditionSQL($this->_class, $alias)) {
$sql .= ' AND ' . $filterSql;
}
list($params, $types) = $this->expandParameters($criteria);
return (bool) $this->_conn->fetchColumn($sql, $params);
@ -1539,8 +1562,8 @@ class BasicEntityPersister
protected function getJoinSQLForJoinColumns($joinColumns)
{
// if one of the join columns is nullable, return left join
foreach($joinColumns as $joinColumn) {
if(isset($joinColumn['nullable']) && $joinColumn['nullable']){
foreach ($joinColumns as $joinColumn) {
if (!isset($joinColumn['nullable']) || $joinColumn['nullable']) {
return 'LEFT JOIN';
}
}
@ -1562,4 +1585,26 @@ class BasicEntityPersister
substr($columnName . $this->_sqlAliasCounter++, -$this->_platform->getMaxIdentifierLength())
);
}
/**
* Generates the filter SQL for a given entity and table alias.
*
* @param ClassMetadata $targetEntity Metadata of the target entity.
* @param string $targetTableAlias The table alias of the joined/selected table.
*
* @return string The SQL query part to add to a query.
*/
protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
{
$filterClauses = array();
foreach ($this->_em->getFilters()->getEnabledFilters() as $filter) {
if ('' !== $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) {
$filterClauses[] = '(' . $filterExpr . ')';
}
}
$sql = implode(' AND ', $filterClauses);
return $sql ? "(" . $sql . ")" : ""; // Wrap again to avoid "X or Y and FilterConditionSQL"
}
}

View File

@ -31,6 +31,7 @@ use Doctrine\ORM\ORMException,
*
* @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Alexander <iam.asm89@gmail.com>
* @since 2.0
* @see http://martinfowler.com/eaaCatalog/classTableInheritance.html
*/
@ -67,7 +68,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
* This function finds the ClassMetadata instance in an inheritance hierarchy
* that is responsible for enabling versioning.
*
* @return Doctrine\ORM\Mapping\ClassMetadata
* @return \Doctrine\ORM\Mapping\ClassMetadata
*/
private function _getVersionedClassMetadata()
{
@ -374,6 +375,15 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
// If the current class in the root entity, add the filters
if ($filterSql = $this->generateFilterConditionSQL($this->_em->getClassMetadata($this->_class->rootEntityName), $this->_getSQLTableAlias($this->_class->rootEntityName))) {
if ($conditionSql) {
$conditionSql .= ' AND ';
}
$conditionSql .= $filterSql;
}
$orderBy = ($assoc !== null && isset($assoc['orderBy'])) ? $assoc['orderBy'] : $orderBy;
$orderBySql = $orderBy ? $this->_getOrderBySQL($orderBy, $baseTableAlias) : '';
@ -473,4 +483,5 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
$value = $this->fetchVersionValue($this->_getVersionedClassMetadata(), $id);
$this->_class->setFieldValue($entity, $this->_class->versionField, $value);
}
}

View File

@ -21,7 +21,8 @@
namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\PersistentCollection,
use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\PersistentCollection,
Doctrine\ORM\UnitOfWork;
/**
@ -29,6 +30,7 @@ use Doctrine\ORM\PersistentCollection,
*
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Alexander <iam.asm89@gmail.com>
* @since 2.0
*/
class ManyToManyPersister extends AbstractCollectionPersister
@ -42,8 +44,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
{
$mapping = $coll->getMapping();
$class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
. ' WHERE ' . implode(' = ? AND ', $mapping['joinTableColumns']) . ' = ?';
}
@ -79,9 +81,9 @@ class ManyToManyPersister extends AbstractCollectionPersister
$mapping = $coll->getMapping();
$columns = $mapping['joinTableColumns'];
$class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
$joinTable = $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform());
return 'INSERT INTO ' . $joinTable . ' (' . implode(', ', $columns) . ')'
. ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
}
@ -122,19 +124,19 @@ class ManyToManyPersister extends AbstractCollectionPersister
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
$isRelationToSource = isset($mapping['relationToSourceKeyColumns'][$joinTableColumn]);
if ( ! $isComposite) {
$params[] = $isRelationToSource ? array_pop($identifier1) : array_pop($identifier2);
continue;
}
if ($isRelationToSource) {
$params[] = $identifier1[$class1->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])];
continue;
}
$params[] = $identifier2[$class2->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])];
}
@ -150,8 +152,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
{
$class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
$mapping = $coll->getMapping();
return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
. ' WHERE ' . implode(' = ? AND ', array_keys($mapping['relationToSourceKeyColumns'])) . ' = ?';
}
@ -167,21 +169,21 @@ class ManyToManyPersister extends AbstractCollectionPersister
$identifier = $this->_uow->getEntityIdentifier($coll->getOwner());
$mapping = $coll->getMapping();
$params = array();
// Optimization for single column identifier
if (count($mapping['relationToSourceKeyColumns']) === 1) {
$params[] = array_pop($identifier);
return $params;
}
// Composite identifier
$sourceClass = $this->_em->getClassMetadata(get_class($mapping->getOwner()));
foreach ($mapping['relationToSourceKeyColumns'] as $relColumn => $srcColumn) {
$params[] = $identifier[$sourceClass->fieldNames[$srcColumn]];
}
return $params;
}
@ -203,22 +205,28 @@ class ManyToManyPersister extends AbstractCollectionPersister
$whereClauses = array();
$params = array();
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
if ( ! isset($joinColumns[$joinTableColumn])) {
continue;
}
$whereClauses[] = $joinTableColumn . ' = ?';
$params[] = ($class->containsForeignIdentifier)
? $id[$class->getFieldForColumn($joinColumns[$joinTableColumn])]
: $id[$class->fieldNames[$joinColumns[$joinTableColumn]]];
}
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
if ($filterSql) {
$whereClauses[] = $filterSql;
}
$sql = 'SELECT COUNT(*)'
. ' FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
. ' WHERE ' . implode(' AND ', $whereClauses);
. ' FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) . ' t'
. $joinTargetEntitySQL
. ' WHERE ' . implode(' AND ', $whereClauses);
return $this->_conn->fetchColumn($sql, $params);
}
@ -232,7 +240,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
public function slice(PersistentCollection $coll, $offset, $length = null)
{
$mapping = $coll->getMapping();
return $this->_em->getUnitOfWork()->getEntityPersister($mapping['targetEntity'])->getManyToManyCollection($mapping, $coll->getOwner(), $offset, $length);
}
@ -250,13 +258,13 @@ class ManyToManyPersister extends AbstractCollectionPersister
return false;
}
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, $element);
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, $element, true);
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
return (bool) $this->_conn->fetchColumn($sql, $params);
}
/**
* @param PersistentCollection $coll
* @param object $element
@ -271,29 +279,30 @@ class ManyToManyPersister extends AbstractCollectionPersister
return false;
}
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, $element);
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, $element, false);
$sql = 'DELETE FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
return (bool) $this->_conn->executeUpdate($sql, $params);
}
/**
* @param Doctrine\ORM\PersistentCollection $coll
* @param \Doctrine\ORM\PersistentCollection $coll
* @param object $element
* @param boolean $addFilters Whether the filter SQL should be included or not.
* @return array
*/
private function getJoinTableRestrictions(PersistentCollection $coll, $element)
private function getJoinTableRestrictions(PersistentCollection $coll, $element, $addFilters)
{
$uow = $this->_em->getUnitOfWork();
$mapping = $coll->getMapping();
if ( ! $mapping['isOwningSide']) {
$sourceClass = $this->_em->getClassMetadata($mapping['targetEntity']);
$targetClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
$sourceId = $uow->getEntityIdentifier($element);
$targetId = $uow->getEntityIdentifier($coll->getOwner());
$mapping = $sourceClass->associationMappings[$mapping['mappedBy']];
} else {
$sourceClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
@ -301,11 +310,11 @@ class ManyToManyPersister extends AbstractCollectionPersister
$sourceId = $uow->getEntityIdentifier($coll->getOwner());
$targetId = $uow->getEntityIdentifier($element);
}
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform());
$whereClauses = array();
$params = array();
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
$whereClauses[] = $joinTableColumn . ' = ?';
@ -315,13 +324,79 @@ class ManyToManyPersister extends AbstractCollectionPersister
: $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
continue;
}
// relationToSourceKeyColumns
$params[] = ($sourceClass->containsForeignIdentifier)
? $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])]
: $sourceId[$sourceClass->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
}
if ($addFilters) {
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
if ($filterSql) {
$quotedJoinTable .= ' t ' . $joinTargetEntitySQL;
$whereClauses[] = $filterSql;
}
}
return array($quotedJoinTable, $whereClauses, $params);
}
}
/**
* Generates the filter SQL for a given mapping.
*
* This method is not used for actually grabbing the related entities
* but when the extra-lazy collection methods are called on a filtered
* association. This is why besides the many to many table we also
* have to join in the actual entities table leading to additional
* JOIN.
*
* @param array $targetEntity Array containing mapping information.
*
* @return string The SQL query part to add to a query.
*/
public function getFilterSql($mapping)
{
$targetClass = $this->_em->getClassMetadata($mapping['targetEntity']);
$targetClass = $this->_em->getClassMetadata($targetClass->rootEntityName);
// A join is needed if there is filtering on the target entity
$joinTargetEntitySQL = '';
if ($filterSql = $this->generateFilterConditionSQL($targetClass, 'te')) {
$joinTargetEntitySQL = ' JOIN '
. $targetClass->getQuotedTableName($this->_conn->getDatabasePlatform()) . ' te'
. ' ON';
$joinTargetEntitySQLClauses = array();
foreach ($mapping['relationToTargetKeyColumns'] as $joinTableColumn => $targetTableColumn) {
$joinTargetEntitySQLClauses[] = ' t.' . $joinTableColumn . ' = ' . 'te.' . $targetTableColumn;
}
$joinTargetEntitySQL .= implode(' AND ', $joinTargetEntitySQLClauses);
}
return array($joinTargetEntitySQL, $filterSql);
}
/**
* Generates the filter SQL for a given entity and table alias.
*
* @param ClassMetadata $targetEntity Metadata of the target entity.
* @param string $targetTableAlias The table alias of the joined/selected table.
*
* @return string The SQL query part to add to a query.
*/
protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
{
$filterClauses = array();
foreach ($this->_em->getFilters()->getEnabledFilters() as $filter) {
if ($filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) {
$filterClauses[] = '(' . $filterExpr . ')';
}
}
$sql = implode(' AND ', $filterClauses);
return $sql ? "(" . $sql . ")" : "";
}
}

View File

@ -1,7 +1,5 @@
<?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
@ -29,6 +27,7 @@ use Doctrine\ORM\PersistentCollection,
*
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Alexander <iam.asm89@gmail.com>
* @since 2.0
*/
class OneToManyPersister extends AbstractCollectionPersister
@ -45,14 +44,14 @@ class OneToManyPersister extends AbstractCollectionPersister
{
$mapping = $coll->getMapping();
$class = $this->_em->getClassMetadata($mapping['targetEntity']);
return 'DELETE FROM ' . $class->getQuotedTableName($this->_conn->getDatabasePlatform())
. ' WHERE ' . implode('= ? AND ', $class->getIdentifierColumnNames()) . ' = ?';
}
/**
* {@inheritdoc}
*
*
*/
protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element)
{
@ -111,19 +110,25 @@ class OneToManyPersister extends AbstractCollectionPersister
$whereClauses = array();
$params = array();
foreach ($targetClass->associationMappings[$mapping['mappedBy']]['joinColumns'] AS $joinColumn) {
$whereClauses[] = $joinColumn['name'] . ' = ?';
$params[] = ($targetClass->containsForeignIdentifier)
? $id[$sourceClass->getFieldForColumn($joinColumn['referencedColumnName'])]
: $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]];
}
foreach ($this->_em->getFilters()->getEnabledFilters() as $filter) {
if ($filterExpr = $filter->addFilterConstraint($targetClass, 't')) {
$whereClauses[] = '(' . $filterExpr . ')';
}
}
$sql = 'SELECT count(*)'
. ' FROM ' . $targetClass->getQuotedTableName($this->_conn->getDatabasePlatform())
. ' FROM ' . $targetClass->getQuotedTableName($this->_conn->getDatabasePlatform()) . ' t'
. ' WHERE ' . implode(' AND ', $whereClauses);
return $this->_conn->fetchColumn($sql, $params);
}
@ -138,7 +143,7 @@ class OneToManyPersister extends AbstractCollectionPersister
$mapping = $coll->getMapping();
$uow = $this->_em->getUnitOfWork();
$persister = $uow->getEntityPersister($mapping['targetEntity']);
return $persister->getOneToManyCollection($mapping, $coll->getOwner(), $offset, $length);
}
@ -151,22 +156,22 @@ class OneToManyPersister extends AbstractCollectionPersister
{
$mapping = $coll->getMapping();
$uow = $this->_em->getUnitOfWork();
// shortcut for new entities
if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
return false;
}
$persister = $uow->getEntityPersister($mapping['targetEntity']);
// only works with single id identifier entities. Will throw an
// exception in Entity Persisters if that is not the case for the
// only works with single id identifier entities. Will throw an
// exception in Entity Persisters if that is not the case for the
// 'mappedBy' field.
$id = current( $uow->getEntityIdentifier($coll->getOwner()) );
return $persister->exists($element, array($mapping['mappedBy'] => $id));
}
/**
* @param PersistentCollection $coll
* @param object $element
@ -185,7 +190,7 @@ class OneToManyPersister extends AbstractCollectionPersister
$class = $this->_em->getClassMetadata($mapping['targetEntity']);
$sql = 'DELETE FROM ' . $class->getQuotedTableName($this->_conn->getDatabasePlatform())
. ' WHERE ' . implode('= ? AND ', $class->getIdentifierColumnNames()) . ' = ?';
return (bool) $this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element));
}
}

View File

@ -27,6 +27,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
*
* @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Alexander <iam.asm89@gmail.com>
* @since 2.0
* @link http://martinfowler.com/eaaCatalog/singleTableInheritance.html
*/
@ -50,33 +51,33 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
// Append discriminator column
$discrColumn = $this->_class->discriminatorColumn['name'];
$columnList .= ', ' . $discrColumn;
$rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName);
$tableAlias = $this->_getSQLTableAlias($rootClass->name);
$resultColumnName = $this->_platform->getSQLResultCasing($discrColumn);
$this->_rsm->setDiscriminatorColumn('r', $resultColumnName);
$this->_rsm->addMetaResult('r', $resultColumnName, $discrColumn);
// Append subclass columns
foreach ($this->_class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
// Regular columns
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
if ( ! isset($mapping['inherited'])) {
$columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass);
}
}
// Foreign key columns
foreach ($subClass->associationMappings as $assoc) {
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE && ! isset($assoc['inherited'])) {
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
if ($columnList != '') $columnList .= ', ';
$columnList .= $this->getSelectJoinColumnSQL(
$tableAlias,
$tableAlias,
$srcColumn,
isset($assoc['inherited']) ? $assoc['inherited'] : $this->_class->name
);
@ -93,7 +94,7 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
protected function _getInsertColumnList()
{
$columns = parent::_getInsertColumnList();
// Add discriminator column to the INSERT SQL
$columns[] = $this->_class->discriminatorColumn['name'];
@ -113,22 +114,32 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
// Append discriminator condition
if ($conditionSql) $conditionSql .= ' AND ';
$values = array();
if ($this->_class->discriminatorValue !== null) { // discriminators can be 0
$values[] = $this->_conn->quote($this->_class->discriminatorValue);
}
$discrValues = array_flip($this->_class->discriminatorMap);
foreach ($this->_class->subClasses as $subclassName) {
$values[] = $this->_conn->quote($discrValues[$subclassName]);
}
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.' . $this->_class->discriminatorColumn['name']
. ' IN (' . implode(', ', $values) . ')';
return $conditionSql;
}
/** {@inheritdoc} */
protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
{
// Ensure that the filters are applied to the root entity of the inheritance tree
$targetEntity = $this->_em->getClassMetadata($targetEntity->rootEntityName);
// we dont care about the $targetTableAlias, in a STI there is only one table.
return parent::generateFilterConditionSQL($targetEntity, $targetTableAlias);
}
}

View File

@ -4,5 +4,5 @@ namespace Doctrine\ORM\Persisters;
class UnionSubclassPersister extends BasicEntityPersister
{
}

View File

@ -23,7 +23,7 @@ namespace Doctrine\ORM\Proxy;
/**
* Interface for proxy classes.
*
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/

View File

@ -81,7 +81,7 @@ final class Query extends AbstractQuery
const HINT_INCLUDE_META_COLUMNS = 'doctrine.includeMetaColumns';
/**
* An array of class names that implement Doctrine\ORM\Query\TreeWalker and
* An array of class names that implement \Doctrine\ORM\Query\TreeWalker and
* are iterated and executed after the DQL has been parsed into an AST.
*
* @var string
@ -89,7 +89,7 @@ final class Query extends AbstractQuery
const HINT_CUSTOM_TREE_WALKERS = 'doctrine.customTreeWalkers';
/**
* A string with a class name that implements Doctrine\ORM\Query\TreeWalker
* A string with a class name that implements \Doctrine\ORM\Query\TreeWalker
* and is used for generating the target SQL from any DQL AST tree.
*
* @var string
@ -119,7 +119,7 @@ final class Query extends AbstractQuery
private $_dql = null;
/**
* @var Doctrine\ORM\Query\ParserResult The parser result that holds DQL => SQL information.
* @var \Doctrine\ORM\Query\ParserResult The parser result that holds DQL => SQL information.
*/
private $_parserResult;
@ -158,7 +158,7 @@ final class Query extends AbstractQuery
/**
* Initializes a new Query instance.
*
* @param Doctrine\ORM\EntityManager $entityManager
* @param \Doctrine\ORM\EntityManager $entityManager
*/
/*public function __construct(EntityManager $entityManager)
{
@ -179,9 +179,9 @@ final class Query extends AbstractQuery
/**
* Returns the corresponding AST for this DQL query.
*
* @return Doctrine\ORM\Query\AST\SelectStatement |
* Doctrine\ORM\Query\AST\UpdateStatement |
* Doctrine\ORM\Query\AST\DeleteStatement
* @return \Doctrine\ORM\Query\AST\SelectStatement |
* \Doctrine\ORM\Query\AST\UpdateStatement |
* \Doctrine\ORM\Query\AST\DeleteStatement
*/
public function getAST()
{
@ -194,34 +194,41 @@ final class Query extends AbstractQuery
*
* Note: Populates $this->_parserResult as a side-effect.
*
* @return Doctrine\ORM\Query\ParserResult
* @return \Doctrine\ORM\Query\ParserResult
*/
private function _parse()
{
if ($this->_state === self::STATE_CLEAN) {
// Return previous parser result if the query and the filter collection are both clean
if ($this->_state === self::STATE_CLEAN
&& $this->_em->isFiltersStateClean()
) {
return $this->_parserResult;
}
// Check query cache.
if ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver())) {
$hash = $this->_getQueryCacheId();
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
$this->_state = self::STATE_CLEAN;
if ($cached === false) {
// Cache miss.
$parser = new Parser($this);
$this->_parserResult = $parser->parse();
$queryCache->save($hash, $this->_parserResult, $this->_queryCacheTTL);
} else {
// Cache hit.
$this->_parserResult = $cached;
}
} else {
// Check query cache.
if ( ! ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver()))) {
$parser = new Parser($this);
$this->_parserResult = $parser->parse();
return $this->_parserResult;
}
$this->_state = self::STATE_CLEAN;
$hash = $this->_getQueryCacheId();
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
if ($cached !== false) {
// Cache hit.
$this->_parserResult = $cached;
return $this->_parserResult;
}
// Cache miss.
$parser = new Parser($this);
$this->_parserResult = $parser->parse();
$queryCache->save($hash, $this->_parserResult, $this->_queryCacheTTL);
return $this->_parserResult;
}
@ -232,6 +239,7 @@ final class Query extends AbstractQuery
protected function _doExecute()
{
$executor = $this->_parse()->getSqlExecutor();
if ($this->_queryCacheProfile) {
$executor->setQueryCacheProfile($this->_queryCacheProfile);
}
@ -339,6 +347,7 @@ final class Query extends AbstractQuery
public function setQueryCacheDriver($queryCache)
{
$this->_queryCache = $queryCache;
return $this;
}
@ -351,6 +360,7 @@ final class Query extends AbstractQuery
public function useQueryCache($bool)
{
$this->_useQueryCache = $bool;
return $this;
}
@ -364,9 +374,9 @@ final class Query extends AbstractQuery
{
if ($this->_queryCache) {
return $this->_queryCache;
} else {
return $this->_em->getConfiguration()->getQueryCacheImpl();
}
return $this->_em->getConfiguration()->getQueryCacheImpl();
}
/**
@ -380,6 +390,7 @@ final class Query extends AbstractQuery
if ($timeToLive !== null) {
$timeToLive = (int) $timeToLive;
}
$this->_queryCacheTTL = $timeToLive;
return $this;
@ -424,6 +435,7 @@ final class Query extends AbstractQuery
public function free()
{
parent::free();
$this->_dql = null;
$this->_state = self::STATE_CLEAN;
}
@ -432,7 +444,7 @@ final class Query extends AbstractQuery
* Sets a DQL query string.
*
* @param string $dqlQuery DQL Query
* @return Doctrine\ORM\AbstractQuery
* @return \Doctrine\ORM\AbstractQuery
*/
public function setDQL($dqlQuery)
{
@ -440,6 +452,7 @@ final class Query extends AbstractQuery
$this->_dql = $dqlQuery;
$this->_state = self::STATE_DIRTY;
}
return $this;
}
@ -489,6 +502,7 @@ final class Query extends AbstractQuery
{
$this->_firstResult = $firstResult;
$this->_state = self::STATE_DIRTY;
return $this;
}
@ -513,6 +527,7 @@ final class Query extends AbstractQuery
{
$this->_maxResults = $maxResults;
$this->_state = self::STATE_DIRTY;
return $this;
}
@ -538,6 +553,7 @@ final class Query extends AbstractQuery
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
{
$this->setHint(self::HINT_INTERNAL_ITERATION, true);
return parent::iterate($params, $hydrationMode);
}
@ -547,6 +563,7 @@ final class Query extends AbstractQuery
public function setHint($name, $value)
{
$this->_state = self::STATE_DIRTY;
return parent::setHint($name, $value);
}
@ -556,25 +573,27 @@ final class Query extends AbstractQuery
public function setHydrationMode($hydrationMode)
{
$this->_state = self::STATE_DIRTY;
return parent::setHydrationMode($hydrationMode);
}
/**
* Set the lock mode for this Query.
*
* @see Doctrine\DBAL\LockMode
* @see \Doctrine\DBAL\LockMode
* @param int $lockMode
* @return Query
*/
public function setLockMode($lockMode)
{
if ($lockMode == LockMode::PESSIMISTIC_READ || $lockMode == LockMode::PESSIMISTIC_WRITE) {
if (!$this->_em->getConnection()->isTransactionActive()) {
if ($lockMode === LockMode::PESSIMISTIC_READ || $lockMode === LockMode::PESSIMISTIC_WRITE) {
if ( ! $this->_em->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}
}
$this->setHint(self::HINT_LOCK_MODE, $lockMode);
return $this;
}
@ -586,9 +605,11 @@ final class Query extends AbstractQuery
public function getLockMode()
{
$lockMode = $this->getHint(self::HINT_LOCK_MODE);
if (!$lockMode) {
if ( ! $lockMode) {
return LockMode::NONE;
}
return $lockMode;
}
@ -605,6 +626,7 @@ final class Query extends AbstractQuery
return md5(
$this->getDql() . var_export($this->_hints, true) .
($this->_em->hasFilters() ? $this->_em->getFilters()->getHash() : '') .
'&firstResult=' . $this->_firstResult . '&maxResult=' . $this->_maxResults .
'&hydrationMode='.$this->_hydrationMode.'DOCTRINE_QUERY_CACHE_SALT'
);
@ -618,6 +640,7 @@ final class Query extends AbstractQuery
public function __clone()
{
parent::__clone();
$this->_state = self::STATE_DIRTY;
}
}
}

View File

@ -38,7 +38,7 @@ class ArithmeticFactor extends Node
* @var ArithmeticPrimary
*/
public $arithmeticPrimary;
/**
* @var null|boolean NULL represents no sign, TRUE means positive and FALSE means negative sign
*/

View File

@ -33,13 +33,13 @@ namespace Doctrine\ORM\Query\AST;
class CoalesceExpression extends Node
{
public $scalarExpressions = array();
public function __construct(array $scalarExpressions)
{
$this->scalarExpressions = $scalarExpressions;
}
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkCoalesceExpression($this);

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST;
/**

View File

@ -41,7 +41,7 @@ class DeleteStatement extends Node
{
$this->deleteClause = $deleteClause;
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkDeleteStatement($this);

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST;
/**

View File

@ -36,8 +36,8 @@ class FromClause extends Node
public function __construct(array $identificationVariableDeclarations)
{
$this->identificationVariableDeclarations = $identificationVariableDeclarations;
}
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkFromClause($this);

View File

@ -53,9 +53,9 @@ class AbsFunction extends FunctionNode
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -0,0 +1,63 @@
<?php
/*
* 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.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST\Functions;
use Doctrine\ORM\Query\Lexer;
/**
* "BIT_AND" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.2
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class BitAndFunction extends FunctionNode
{
public $firstArithmetic;
public $secondArithmetic;
/**
* @override
*/
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
return $platform->getBitAndComparisonExpression(
$this->firstArithmetic->dispatch($sqlWalker),
$this->secondArithmetic->dispatch($sqlWalker)
);
}
/**
* @override
*/
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->firstArithmetic = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_COMMA);
$this->secondArithmetic = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -0,0 +1,63 @@
<?php
/*
* 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.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST\Functions;
use Doctrine\ORM\Query\Lexer;
/**
* "BIT_OR" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.2
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class BitOrFunction extends FunctionNode
{
public $firstArithmetic;
public $secondArithmetic;
/**
* @override
*/
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
return $platform->getBitOrComparisonExpression(
$this->firstArithmetic->dispatch($sqlWalker),
$this->secondArithmetic->dispatch($sqlWalker)
);
}
/**
* @override
*/
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->firstArithmetic = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_COMMA);
$this->secondArithmetic = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -16,7 +16,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST\Functions;
use Doctrine\ORM\Query\Lexer;

View File

@ -42,13 +42,13 @@ class IdentityFunction extends FunctionNode
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
$dqlAlias = $this->pathExpression->identificationVariable;
$assocField = $this->pathExpression->field;
$qComp = $sqlWalker->getQueryComponent($dqlAlias);
$class = $qComp['metadata'];
$assoc = $class->associationMappings[$assocField];
$tableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias);
return $tableAlias . '.' . reset($assoc['targetToSourceKeyColumns']);;
}
@ -59,9 +59,9 @@ class IdentityFunction extends FunctionNode
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->pathExpression = $parser->SingleValuedAssociationPathExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -53,9 +53,9 @@ class LengthFunction extends FunctionNode
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->stringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -61,20 +61,20 @@ class LocateFunction extends FunctionNode
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->firstStringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->secondStringPrimary = $parser->StringPrimary();
$lexer = $parser->getLexer();
if ($lexer->isNextToken(Lexer::T_COMMA)) {
$parser->match(Lexer::T_COMMA);
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -53,9 +53,9 @@ class LowerFunction extends FunctionNode
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->stringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -55,13 +55,13 @@ class ModFunction extends FunctionNode
{
$parser->match(Lexer::T_MOD);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_COMMA);
$this->secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -45,7 +45,7 @@ class SizeFunction extends FunctionNode
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
$dqlAlias = $this->collectionPathExpression->identificationVariable;
$assocField = $this->collectionPathExpression->field;
$qComp = $sqlWalker->getQueryComponent($dqlAlias);
$class = $qComp['metadata'];
$assoc = $class->associationMappings[$assocField];
@ -61,7 +61,7 @@ class SizeFunction extends FunctionNode
$owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']];
$first = true;
foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) {
if ($first) $first = false; else $sql .= ' AND ';
@ -100,7 +100,7 @@ class SizeFunction extends FunctionNode
. $sourceTableAlias . '.' . $sourceColumnName;
}
}
return '(' . $sql . ')';
}
@ -110,12 +110,12 @@ class SizeFunction extends FunctionNode
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$lexer = $parser->getLexer();
$parser->match(Lexer::T_SIZE);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->collectionPathExpression = $parser->CollectionValuedPathExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -52,9 +52,9 @@ class SqrtFunction extends FunctionNode
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -64,15 +64,15 @@ class SubstringFunction extends FunctionNode
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->stringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$lexer = $parser->getLexer();
if ($lexer->isNextToken(Lexer::T_COMMA)) {
$parser->match(Lexer::T_COMMA);
$this->secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
}

View File

@ -53,9 +53,9 @@ class UpperFunction extends FunctionNode
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->stringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@ -20,7 +20,7 @@
namespace Doctrine\ORM\Query\AST;
/**
* GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END"
* GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END"
*
* @since 2.2
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
@ -39,8 +39,8 @@ class GeneralCaseExpression extends Node
{
$this->whenClauses = $whenClauses;
$this->elseScalarExpression = $elseScalarExpression;
}
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkGeneralCaseExpression($this);

View File

@ -44,7 +44,7 @@ class IdentificationVariableDeclaration extends Node
$this->indexBy = $indexBy;
$this->joinVariableDeclarations = $joinVariableDecls;
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkIdentificationVariableDeclaration($this);

View File

@ -35,13 +35,13 @@ namespace Doctrine\ORM\Query\AST;
class InExpression extends Node
{
public $not;
public $pathExpression;
public $expression;
public $literals = array();
public $subselect;
public function __construct($pathExpression)
public function __construct($expression)
{
$this->pathExpression = $pathExpression;
$this->expression = $expression;
}
public function dispatch($sqlWalker)

View File

@ -39,8 +39,8 @@ class IndexBy extends Node
public function __construct($simpleStateFieldPathExpression)
{
$this->simpleStateFieldPathExpression = $simpleStateFieldPathExpression;
}
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkIndexBy($this);

View File

@ -36,7 +36,7 @@ class InstanceOfExpression extends Node
public $not;
public $identificationVariable;
public $value;
public function __construct($identVariable)
{
$this->identificationVariable = $identVariable;

View File

@ -39,7 +39,7 @@ class Join extends Node
const JOIN_TYPE_LEFTOUTER = 2;
const JOIN_TYPE_INNER = 3;
public $joinType = self::JOIN_TYPE_INNER;
public $joinType = self::JOIN_TYPE_INNER;
public $joinAssociationPathExpression = null;
public $aliasIdentificationVariable = null;
public $conditionalExpression = null;
@ -50,7 +50,7 @@ class Join extends Node
$this->joinAssociationPathExpression = $joinAssocPathExpr;
$this->aliasIdentificationVariable = $aliasIdentVar;
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkJoin($this);

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST;
/**

View File

@ -42,7 +42,7 @@ class JoinVariableDeclaration extends Node
$this->join = $join;
$this->indexBy = $indexBy;
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkJoinVariableDeclaration($this);

View File

@ -7,16 +7,16 @@ class Literal extends Node
const STRING = 1;
const BOOLEAN = 2;
const NUMERIC = 3;
public $type;
public $value;
public function __construct($type, $value)
{
$this->type = $type;
$this->value = $value;
}
public function dispatch($walker)
{
return $walker->walkLiteral($this);

View File

@ -36,16 +36,16 @@ abstract class Node
{
/**
* Double-dispatch method, supposed to dispatch back to the walker.
*
*
* Implementation is not mandatory for all nodes.
*
*
* @param $walker
*/
public function dispatch($walker)
{
throw ASTException::noDispatchForNode($this);
}
/**
* Dumps the AST Node into a string representation for information purpose only
*
@ -55,36 +55,36 @@ abstract class Node
{
return $this->dump($this);
}
public function dump($obj)
{
static $ident = 0;
$str = '';
if ($obj instanceof Node) {
$str .= get_class($obj) . '(' . PHP_EOL;
$props = get_object_vars($obj);
foreach ($props as $name => $prop) {
$ident += 4;
$str .= str_repeat(' ', $ident) . '"' . $name . '": '
$str .= str_repeat(' ', $ident) . '"' . $name . '": '
. $this->dump($prop) . ',' . PHP_EOL;
$ident -= 4;
}
$str .= str_repeat(' ', $ident) . ')';
} else if (is_array($obj)) {
$ident += 4;
$str .= 'array(';
$some = false;
foreach ($obj as $k => $v) {
$str .= PHP_EOL . str_repeat(' ', $ident) . '"'
$str .= PHP_EOL . str_repeat(' ', $ident) . '"'
. $k . '" => ' . $this->dump($v) . ',';
$some = true;
}
$ident -= 4;
$str .= ($some ? PHP_EOL . str_repeat(' ', $ident) : '') . ')';
} else if (is_object($obj)) {
@ -92,7 +92,7 @@ abstract class Node
} else {
$str .= var_export($obj, true);
}
return $str;
}
}

View File

@ -36,7 +36,7 @@ class NullComparisonExpression extends Node
{
public $not;
public $expression;
public function __construct($expression)
{
$this->expression = $expression;

View File

@ -33,15 +33,15 @@ namespace Doctrine\ORM\Query\AST;
class NullIfExpression extends Node
{
public $firstExpression;
public $secondExpression;
public function __construct($firstExpression, $secondExpression)
{
$this->firstExpression = $firstExpression;
$this->secondExpression = $secondExpression;
}
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkNullIfExpression($this);

View File

@ -36,7 +36,7 @@ class OrderByItem extends Node
{
public $expression;
public $type;
public function __construct($expression)
{
$this->expression = $expression;

View File

@ -6,7 +6,7 @@ class PartialObjectExpression extends Node
{
public $identificationVariable;
public $partialFieldSet;
public function __construct($identificationVariable, array $partialFieldSet)
{
$this->identificationVariable = $identificationVariable;

View File

@ -16,7 +16,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST;
/**
@ -27,7 +27,7 @@ namespace Doctrine\ORM\Query\AST;
* CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
* StateField ::= {EmbeddedClassStateField "."}* SimpleStateField
* SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField
*
*
* @since 2.0
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
@ -38,19 +38,19 @@ class PathExpression extends Node
const TYPE_COLLECTION_VALUED_ASSOCIATION = 2;
const TYPE_SINGLE_VALUED_ASSOCIATION = 4;
const TYPE_STATE_FIELD = 8;
public $type;
public $expectedType;
public $identificationVariable;
public $field;
public function __construct($expectedType, $identificationVariable, $field = null)
{
$this->expectedType = $expectedType;
$this->identificationVariable = $identificationVariable;
$this->field = $field;
}
public function dispatch($walker)
{
return $walker->walkPathExpression($this);

View File

@ -41,8 +41,8 @@ class RangeVariableDeclaration extends Node
{
$this->abstractSchemaName = $abstractSchemaName;
$this->aliasIdentificationVariable = $aliasIdentificationVar;
}
}
public function dispatch($walker)
{
return $walker->walkRangeVariableDeclaration($this);

View File

@ -42,7 +42,7 @@ class SelectClause extends Node
$this->isDistinct = $isDistinct;
$this->selectExpressions = $selectExpressions;
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkSelectClause($this);

View File

@ -44,8 +44,8 @@ class SelectExpression extends Node
$this->expression = $expression;
$this->fieldIdentificationVariable = $fieldIdentificationVariable;
$this->hiddenAliasResultVariable = $hiddenAliasResultVariable;
}
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkSelectExpression($this);

Some files were not shown because too many files have changed in this diff Show More