Merge Upstream into Locking-Branch
This commit is contained in:
commit
f65a555d04
@ -1,11 +1,24 @@
|
||||
|
||||
# Upgrade from 2.0-ALPHA4 to 2.0-BETA1
|
||||
|
||||
## EntityRepository deprecates access to protected variables
|
||||
|
||||
Instead of accessing protected variables for the EntityManager in
|
||||
a custom EntityRepository it is now required to use the getter methods
|
||||
for all the three instance variables:
|
||||
|
||||
* `$this->_em` now accessible through `$this->getEntityManager()`
|
||||
* `$this->_class` now accessible through `$this->getClassMetadata()`
|
||||
* `$this->_entityName` now accessible through `$this->getEntityName()`
|
||||
|
||||
Important: For Beta 2 the protected visibility of these three properties will be
|
||||
changed to private!
|
||||
|
||||
## Console migrated to Symfony Console
|
||||
|
||||
The Doctrine Cli has been replaced by Symfony Console Configuration
|
||||
The Doctrine CLI has been replaced by Symfony Console Configuration
|
||||
|
||||
Instead of having to specifiy:
|
||||
Instead of having to specify:
|
||||
|
||||
[php]
|
||||
$cliConfig = new CliConfiguration();
|
||||
@ -100,9 +113,22 @@ The "default" option for database column defaults has been removed. If desired,
|
||||
be implemented by using the columnDefinition attribute of the @Column annotation (or the approriate XML and YAML equivalents).
|
||||
Prefer PHP default values, if possible.
|
||||
|
||||
## Partial Objects
|
||||
## Selecting Partial Objects
|
||||
|
||||
[TBD: New syntax, results, etc.]
|
||||
Querying for partial objects now has a new syntax. The old syntax to query for partial objects
|
||||
now has a different meaning. This is best illustrated by an example. If you previously
|
||||
had a DQL query like this:
|
||||
|
||||
[sql]
|
||||
SELECT u.id, u.name FROM User u
|
||||
|
||||
Since BETA1, simple state field path expressions in the select clause are used to select
|
||||
object fields as plain scalar values (something that was not possible before).
|
||||
To achieve the same result as previously (that is, a partial object with only id and name populated)
|
||||
you need to use the following, explicit syntax:
|
||||
|
||||
[sql]
|
||||
SELECT PARTIAL u.{id,name} FROM User u
|
||||
|
||||
## XML Mapping Driver
|
||||
|
||||
@ -133,3 +159,9 @@ by using the API on the `PreUpdateEventArgs` instance passed to the preUpdate li
|
||||
to the state of the entitys properties won't affect the database UPDATE statement anymore. This gives drastic
|
||||
performance benefits for the preUpdate event.
|
||||
|
||||
## Collection API
|
||||
|
||||
The Collection interface in the Common package has been updated with some missing methods
|
||||
that were present only on the default implementation, ArrayCollection. Custom collection
|
||||
implementations need to be updated to adhere to the updated interface.
|
||||
|
||||
|
14
build.xml
14
build.xml
@ -142,16 +142,16 @@
|
||||
|
||||
<nativephpunit testfile="./tests/Doctrine/Tests/ORM/Performance/AllTests.php" testdirectory="./tests" haltonfailure="false" haltonerror="false" />
|
||||
<tstamp/>
|
||||
<svnlastrevision svnpath="${svn.path}" workingcopy="." propertyname="svn.lastrevision"/>
|
||||
<copy file="${build.dir}/logs/testsuites.xml" tofile="${log.archive.dir}/${svn.lastrevision}/log.xml" overwrite="true"/>
|
||||
<!--<svnlastrevision svnpath="${svn.path}" workingcopy="." propertyname="svn.lastrevision"/>-->
|
||||
<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}/${svn.lastrevision}/jdepend.xml" overwrite="true"/>
|
||||
<copy file="${build.dir}/logs/phpmd.xml" tofile="${log.archive.dir}/${svn.lastrevision}/phpmd.xml" overwrite="true"/>
|
||||
<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>
|
||||
@ -163,7 +163,7 @@
|
||||
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/common/DoctrineCommon-${version}">
|
||||
<name>DoctrineCommon</name>
|
||||
<summary>Common Doctrine code</summary>
|
||||
<channel>pear.phpdoctrine.org</channel>
|
||||
<channel>pear.doctrine-project.org</channel>
|
||||
<description>The Doctrine Common package contains shared code between the other packages.</description>
|
||||
<lead user="jwage" name="Jonathan H. Wage" email="jonwage@gmail.com" />
|
||||
<lead user="guilhermeblanco" name="Guilherme Blanco" email="guilhermeblanco@gmail.com" />
|
||||
@ -182,7 +182,7 @@
|
||||
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/dbal/DoctrineDBAL-${version}">
|
||||
<name>DoctrineDBAL</name>
|
||||
<summary>Doctrine Database Abstraction Layer</summary>
|
||||
<channel>pear.phpdoctrine.org</channel>
|
||||
<channel>pear.doctrine-project.org</channel>
|
||||
<description>The Doctrine DBAL package is the database abstraction layer used to power the ORM package.</description>
|
||||
<lead user="jwage" name="Jonathan H. Wage" email="jonwage@gmail.com" />
|
||||
<lead user="guilhermeblanco" name="Guilherme Blanco" email="guilhermeblanco@gmail.com" />
|
||||
@ -201,7 +201,7 @@
|
||||
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/orm/DoctrineORM-${version}">
|
||||
<name>DoctrineORM</name>
|
||||
<summary>Doctrine Object Relationl Mapper</summary>
|
||||
<channel>pear.phpdoctrine.org</channel>
|
||||
<channel>pear.doctrine-project.org</channel>
|
||||
<description>The Doctrine ORM package is the primary package containing the object relational mapper.</description>
|
||||
<lead user="jwage" name="Jonathan H. Wage" email="jonwage@gmail.com" />
|
||||
<lead user="guilhermeblanco" name="Guilherme Blanco" email="guilhermeblanco@gmail.com" />
|
||||
|
@ -173,12 +173,19 @@
|
||||
<xs:complexType name="id">
|
||||
<xs:sequence>
|
||||
<xs:element name="generator" type="orm:generator" minOccurs="0" />
|
||||
<xs:element name="sequence-generator" type="orm:sequence-generator" minOccurs="0" maxOccurs="1" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="column" type="xs:NMTOKEN" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="sequence-generator">
|
||||
<xs:attribute name="sequence-name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="allocation-size" type="xs:integer" use="optional" default="1" />
|
||||
<xs:attribute name="initial-value" type="xs:integer" use="optional" default="1" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="inverse-join-columns">
|
||||
<xs:sequence>
|
||||
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />
|
||||
|
@ -27,7 +27,8 @@ namespace Doctrine\Common\Annotations;
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -52,14 +53,29 @@ class Annotation
|
||||
$this->$key = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Error handler for unknown property accessor in Annotation class.
|
||||
*
|
||||
* @param string $name Unknown property name
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
throw new \BadMethodCallException("Unknown annotation property '$name' on annotation '".get_class($this)."'.");
|
||||
throw new \BadMethodCallException(
|
||||
sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler for unknown property mutator in Annotation class.
|
||||
*
|
||||
* @param string $name Unkown property name
|
||||
* @param mixed $value Property value
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
throw new \BadMethodCallException("Unknown annotation property '$name' on annotation '".get_class($this)."'.");
|
||||
throw new \BadMethodCallException(
|
||||
sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
|
||||
);
|
||||
}
|
||||
}
|
@ -27,20 +27,32 @@ namespace Doctrine\Common\Annotations;
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class AnnotationException extends \Doctrine\Common\CommonException
|
||||
class AnnotationException extends \Exception
|
||||
{
|
||||
/**
|
||||
* Creates a new AnnotationException describing a Syntax error.
|
||||
*
|
||||
* @param string $message Exception message
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function syntaxError($message)
|
||||
{
|
||||
return new self('[Syntax Error] ' . $message);
|
||||
}
|
||||
|
||||
|
||||
public static function semanticalError($message)
|
||||
/**
|
||||
* Creates a new AnnotationException describing a Semantical error.
|
||||
*
|
||||
* @param string $message Exception message
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function semanticalError($message)
|
||||
{
|
||||
return new self('[Semantical Error] ' . $message);
|
||||
}
|
||||
|
@ -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,10 +27,7 @@ use \ReflectionClass,
|
||||
/**
|
||||
* A reader for docblock annotations.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
@ -46,7 +41,7 @@ class AnnotationReader
|
||||
* @var string
|
||||
* @static
|
||||
*/
|
||||
private static $CACHE_SALT = "@<Annot>";
|
||||
private static $CACHE_SALT = '@<Annot>';
|
||||
|
||||
/**
|
||||
* Annotations Parser
|
||||
@ -56,15 +51,14 @@ class AnnotationReader
|
||||
private $_parser;
|
||||
|
||||
/**
|
||||
* Cache machanism to store processed Annotations
|
||||
* Cache mechanism to store processed Annotations
|
||||
*
|
||||
* @var Doctrine\Common\Cache\Cache
|
||||
*/
|
||||
private $_cache;
|
||||
|
||||
/**
|
||||
* Constructor. Initializes a new AnnotationReader that uses the given
|
||||
* Cache provider.
|
||||
* Constructor. Initializes a new AnnotationReader that uses the given Cache provider.
|
||||
*
|
||||
* @param Cache $cache The cache provider to use. If none is provided, ArrayCache is used.
|
||||
*/
|
||||
@ -112,7 +106,7 @@ class AnnotationReader
|
||||
return $data;
|
||||
}
|
||||
|
||||
$annotations = $this->_parser->parse($class->getDocComment(), "class ".$class->getName());
|
||||
$annotations = $this->_parser->parse($class->getDocComment(), 'class ' . $class->getName());
|
||||
$this->_cache->save($cacheKey, $annotations, null);
|
||||
|
||||
return $annotations;
|
||||
@ -128,6 +122,7 @@ class AnnotationReader
|
||||
public function getClassAnnotation(ReflectionClass $class, $annotation)
|
||||
{
|
||||
$annotations = $this->getClassAnnotations($class);
|
||||
|
||||
return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
|
||||
}
|
||||
|
||||
@ -148,7 +143,7 @@ class AnnotationReader
|
||||
return $data;
|
||||
}
|
||||
|
||||
$context = "property ".$property->getDeclaringClass()->getName()."::\$".$property->getName();
|
||||
$context = 'property ' . $property->getDeclaringClass()->getName() . "::\$" . $property->getName();
|
||||
$annotations = $this->_parser->parse($property->getDocComment(), $context);
|
||||
$this->_cache->save($cacheKey, $annotations, null);
|
||||
|
||||
@ -165,6 +160,7 @@ class AnnotationReader
|
||||
public function getPropertyAnnotation(ReflectionProperty $property, $annotation)
|
||||
{
|
||||
$annotations = $this->getPropertyAnnotations($property);
|
||||
|
||||
return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
|
||||
}
|
||||
|
||||
@ -185,7 +181,7 @@ class AnnotationReader
|
||||
return $data;
|
||||
}
|
||||
|
||||
$context = "method ".$method->getDeclaringClass()->getName()."::".$method->getName()."()";
|
||||
$context = 'method ' . $method->getDeclaringClass()->getName() . '::' . $method->getName() . '()';
|
||||
$annotations = $this->_parser->parse($method->getDocComment(), $context);
|
||||
$this->_cache->save($cacheKey, $annotations, null);
|
||||
|
||||
@ -202,6 +198,7 @@ class AnnotationReader
|
||||
public function getMethodAnnotation(ReflectionMethod $method, $annotation)
|
||||
{
|
||||
$annotations = $this->getMethodAnnotations($method);
|
||||
|
||||
return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
|
||||
}
|
||||
}
|
@ -27,7 +27,8 @@ namespace Doctrine\Common\Annotations;
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -80,7 +81,7 @@ class Lexer extends \Doctrine\Common\Lexer
|
||||
$newVal = $this->_getNumeric($value);
|
||||
|
||||
// Checking numeric value
|
||||
if ($newVal !== false){
|
||||
if ($newVal !== false) {
|
||||
$value = $newVal;
|
||||
|
||||
return (strpos($value, '.') !== false || stripos($value, 'e') !== false)
|
||||
@ -93,16 +94,34 @@ class Lexer extends \Doctrine\Common\Lexer
|
||||
return self::T_STRING;
|
||||
} else {
|
||||
switch (strtolower($value)) {
|
||||
case '@': return self::T_AT;
|
||||
case ',': return self::T_COMMA;
|
||||
case '(': return self::T_OPEN_PARENTHESIS;
|
||||
case ')': return self::T_CLOSE_PARENTHESIS;
|
||||
case '{': return self::T_OPEN_CURLY_BRACES;
|
||||
case '@':
|
||||
return self::T_AT;
|
||||
|
||||
case ',':
|
||||
return self::T_COMMA;
|
||||
|
||||
case '(':
|
||||
return self::T_OPEN_PARENTHESIS;
|
||||
|
||||
case ')':
|
||||
return self::T_CLOSE_PARENTHESIS;
|
||||
|
||||
case '{':
|
||||
return self::T_OPEN_CURLY_BRACES;
|
||||
|
||||
case '}': return self::T_CLOSE_CURLY_BRACES;
|
||||
case '=': return self::T_EQUALS;
|
||||
case '\\': return self::T_NAMESPACE_SEPARATOR;
|
||||
case 'true': return self::T_TRUE;
|
||||
case 'false': return self::T_FALSE;
|
||||
case '=':
|
||||
return self::T_EQUALS;
|
||||
|
||||
case '\\':
|
||||
return self::T_NAMESPACE_SEPARATOR;
|
||||
|
||||
case 'true':
|
||||
return self::T_TRUE;
|
||||
|
||||
case 'false':
|
||||
return self::T_FALSE;
|
||||
|
||||
default:
|
||||
if (ctype_alpha($value[0]) || $value[0] === '_') {
|
||||
return self::T_IDENTIFIER;
|
||||
@ -126,6 +145,7 @@ class Lexer extends \Doctrine\Common\Lexer
|
||||
if ( ! is_scalar($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checking for valid numeric numbers: 1.234, -1.234e-2
|
||||
if (is_numeric($value)) {
|
||||
return $value;
|
||||
|
@ -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
|
||||
@ -24,14 +22,11 @@ namespace Doctrine\Common\Annotations;
|
||||
/**
|
||||
* A simple parser for docblock annotations.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class Parser
|
||||
{
|
||||
@ -173,9 +168,10 @@ class Parser
|
||||
$message .= "'{$token['value']}' at position {$token['position']}";
|
||||
}
|
||||
|
||||
if(strlen($this->_context)) {
|
||||
$message .= ' in '.$this->_context;
|
||||
if (strlen($this->_context)) {
|
||||
$message .= ' in ' . $this->_context;
|
||||
}
|
||||
|
||||
$message .= '.';
|
||||
|
||||
throw AnnotationException::syntaxError($message);
|
||||
@ -236,7 +232,7 @@ class Parser
|
||||
$nameParts[] = $this->_lexer->token['value'];
|
||||
}
|
||||
|
||||
// Effectively pick the name of class (append default NS if none, grab from NS alias, etc)
|
||||
// Effectively pick the name of the class (append default NS if none, grab from NS alias, etc)
|
||||
if (count($nameParts) == 1) {
|
||||
if (strpos($nameParts[0], ':')) {
|
||||
list ($alias, $simpleName) = explode(':', $nameParts[0]);
|
||||
@ -250,7 +246,7 @@ class Parser
|
||||
|
||||
// Is it really an annotation class?
|
||||
if (
|
||||
(! $this->_isNestedAnnotation && $this->_lexer->lookahead != null &&
|
||||
( ! $this->_isNestedAnnotation && $this->_lexer->lookahead != null &&
|
||||
! $this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS) &&
|
||||
! $this->_lexer->isNextToken(Lexer::T_AT)) ||
|
||||
! class_exists($name, false)
|
||||
@ -411,6 +407,7 @@ class Parser
|
||||
|
||||
foreach ($values as $value) {
|
||||
list ($key, $val) = $value;
|
||||
|
||||
if ($key !== null) {
|
||||
$array[$key] = $val;
|
||||
} else {
|
||||
|
@ -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
|
||||
@ -24,10 +22,7 @@ namespace Doctrine\Common\Cache;
|
||||
/**
|
||||
* Base class for cache driver implementations.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
@ -21,16 +19,12 @@
|
||||
|
||||
namespace Doctrine\Common\Collections;
|
||||
|
||||
use \Closure, \ArrayIterator;
|
||||
use Closure, ArrayIterator;
|
||||
|
||||
/**
|
||||
* An ArrayCollection is a Collection implementation that uses a regular PHP array
|
||||
* internally.
|
||||
* An ArrayCollection is a Collection implementation that wraps a regular PHP array.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -39,7 +33,6 @@ class ArrayCollection implements Collection
|
||||
{
|
||||
/**
|
||||
* An array containing the entries of this collection.
|
||||
* This is the internal php array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
@ -54,7 +47,7 @@ class ArrayCollection implements Collection
|
||||
{
|
||||
$this->_elements = $elements;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the PHP array representation of this collection.
|
||||
*
|
||||
@ -121,7 +114,7 @@ class ArrayCollection implements Collection
|
||||
* Removes an element with a specific key/index from the collection.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
* @return mixed The removed element or NULL, if no element exists for the given key.
|
||||
*/
|
||||
public function remove($key)
|
||||
{
|
||||
@ -131,7 +124,7 @@ class ArrayCollection implements Collection
|
||||
|
||||
return $removed;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -413,6 +406,7 @@ class ArrayCollection implements Collection
|
||||
/**
|
||||
* Returns a string representation of this object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@ -421,7 +415,6 @@ class ArrayCollection implements Collection
|
||||
|
||||
/**
|
||||
* Clears the collection.
|
||||
*
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
|
@ -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
|
||||
@ -40,10 +38,7 @@ use Closure, Countable, IteratorAggregate, ArrayAccess;
|
||||
* position unless you explicitly positioned it before. Prefer iteration with
|
||||
* external iterators.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
|
@ -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
|
||||
@ -22,15 +20,13 @@
|
||||
namespace Doctrine\Common;
|
||||
|
||||
/**
|
||||
* Simple generic lexical scanner.
|
||||
* Base class for writing simple lexers, i.e. for creating small DSLs.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @todo Rename: AbstractLexer
|
||||
*/
|
||||
abstract class Lexer
|
||||
{
|
||||
@ -50,7 +46,7 @@ abstract class Lexer
|
||||
private $_peek = 0;
|
||||
|
||||
/**
|
||||
* @var array The next token in the query string.
|
||||
* @var array The next token in the input.
|
||||
*/
|
||||
public $lookahead;
|
||||
|
||||
@ -60,9 +56,12 @@ abstract class Lexer
|
||||
public $token;
|
||||
|
||||
/**
|
||||
* Inputs data to be tokenized
|
||||
* Sets the input data to be tokenized.
|
||||
*
|
||||
* @param string $input input to be tokenized
|
||||
* The Lexer is immediately reset and the new input tokenized.
|
||||
* Any unprocessed tokens from any previous input are lost.
|
||||
*
|
||||
* @param string $input The input to be tokenized.
|
||||
*/
|
||||
public function setInput($input)
|
||||
{
|
||||
@ -72,20 +71,18 @@ abstract class Lexer
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the scanner
|
||||
*
|
||||
* Resets the lexer.
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->lookahead = null;
|
||||
$this->token = null;
|
||||
$this->_peek = 0;
|
||||
$this->token = null;
|
||||
$this->_peek = 0;
|
||||
$this->_position = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resets the peek pointer to 0
|
||||
*
|
||||
* Resets the peek pointer to 0.
|
||||
*/
|
||||
public function resetPeek()
|
||||
{
|
||||
@ -93,7 +90,7 @@ abstract class Lexer
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the lexer position on the input to the given position
|
||||
* Resets the lexer position on the input to the given position.
|
||||
*
|
||||
* @param integer $position Position to place the lexical scanner
|
||||
*/
|
||||
@ -235,14 +232,14 @@ abstract class Lexer
|
||||
}
|
||||
|
||||
/**
|
||||
* Lexical catchable patterns
|
||||
* Lexical catchable patterns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getCatchablePatterns();
|
||||
|
||||
/**
|
||||
* Lexical non-catchable patterns
|
||||
* Lexical non-catchable patterns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
@ -21,15 +19,12 @@
|
||||
|
||||
namespace Doctrine\DBAL;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Logging\SQLLogger;
|
||||
|
||||
/**
|
||||
* Configuration container for the Doctrine DBAL.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -46,22 +41,12 @@ class Configuration
|
||||
*/
|
||||
protected $_attributes = array();
|
||||
|
||||
/**
|
||||
* Creates a new DBAL configuration instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_attributes = array(
|
||||
'sqlLogger' => null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SQL logger to use. Defaults to NULL which means SQL logging is disabled.
|
||||
*
|
||||
* @param SQLLogger $logger
|
||||
*/
|
||||
public function setSQLLogger($logger)
|
||||
public function setSQLLogger(SQLLogger $logger)
|
||||
{
|
||||
$this->_attributes['sqlLogger'] = $logger;
|
||||
}
|
||||
@ -73,6 +58,7 @@ class Configuration
|
||||
*/
|
||||
public function getSQLLogger()
|
||||
{
|
||||
return $this->_attributes['sqlLogger'];
|
||||
return isset($this->_attributes['sqlLogger']) ?
|
||||
$this->_attributes['sqlLogger'] : null;
|
||||
}
|
||||
}
|
@ -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
|
||||
@ -791,7 +789,7 @@ class Connection implements DriverConnection
|
||||
* Gets the SchemaManager that can be used to inspect or change the
|
||||
* database schema through the connection.
|
||||
*
|
||||
* @return Doctrine\DBAL\Schema\SchemaManager
|
||||
* @return Doctrine\DBAL\Schema\AbstractSchemaManager
|
||||
*/
|
||||
public function getSchemaManager()
|
||||
{
|
||||
|
115
lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php
Normal file
115
lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2;
|
||||
|
||||
class DB2Connection implements \Doctrine\DBAL\Driver\Connection
|
||||
{
|
||||
private $_conn = null;
|
||||
|
||||
public function __construct(array $params, $username, $password, $driverOptions = array())
|
||||
{
|
||||
$isPersistant = (isset($params['persistent']) && $params['persistent'] == true);
|
||||
|
||||
if ($isPersistant) {
|
||||
$this->_conn = db2_pconnect($params['dbname'], $username, $password, $driverOptions);
|
||||
} else {
|
||||
$this->_conn = db2_connect($params['dbname'], $username, $password, $driverOptions);
|
||||
}
|
||||
if (!$this->_conn) {
|
||||
throw new DB2Exception(db2_conn_errormsg());
|
||||
}
|
||||
}
|
||||
|
||||
function prepare($sql)
|
||||
{
|
||||
$stmt = @db2_prepare($this->_conn, $sql);
|
||||
if (!$stmt) {
|
||||
throw new DB2Exception(db2_stmt_errormsg());
|
||||
}
|
||||
return new DB2Statement($stmt);
|
||||
}
|
||||
|
||||
function query()
|
||||
{
|
||||
$args = func_get_args();
|
||||
$sql = $args[0];
|
||||
$stmt = $this->prepare($sql);
|
||||
$stmt->execute();
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
function quote($input, $type=\PDO::PARAM_STR)
|
||||
{
|
||||
$input = db2_escape_string($input);
|
||||
if ($type == \PDO::PARAM_INT ) {
|
||||
return $input;
|
||||
} else {
|
||||
return "'".$input."'";
|
||||
}
|
||||
}
|
||||
|
||||
function exec($statement)
|
||||
{
|
||||
$stmt = $this->prepare($statement);
|
||||
$stmt->execute();
|
||||
return $stmt->rowCount();
|
||||
}
|
||||
|
||||
function lastInsertId($name = null)
|
||||
{
|
||||
return db2_last_insert_id($this->_conn);
|
||||
}
|
||||
|
||||
function beginTransaction()
|
||||
{
|
||||
db2_autocommit($this->_conn, DB2_AUTOCOMMIT_OFF);
|
||||
}
|
||||
|
||||
function commit()
|
||||
{
|
||||
if (!db2_commit($this->_conn)) {
|
||||
throw new DB2Exception(db2_conn_errormsg($this->_conn));
|
||||
}
|
||||
db2_autocommit($this->_conn, DB2_AUTOCOMMIT_ON);
|
||||
}
|
||||
|
||||
function rollBack()
|
||||
{
|
||||
if (!db2_rollback($this->_conn)) {
|
||||
throw new DB2Exception(db2_conn_errormsg($this->_conn));
|
||||
}
|
||||
db2_autocommit($this->_conn, DB2_AUTOCOMMIT_ON);
|
||||
}
|
||||
|
||||
function errorCode()
|
||||
{
|
||||
return db2_conn_error($this->_conn);
|
||||
}
|
||||
|
||||
function errorInfo()
|
||||
{
|
||||
return array(
|
||||
0 => db2_conn_errormsg($this->_conn),
|
||||
1 => $this->errorCode(),
|
||||
);
|
||||
}
|
||||
}
|
113
lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php
Normal file
113
lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2;
|
||||
|
||||
use Doctrine\DBAL\Driver,
|
||||
Doctrine\DBAL\Connection;
|
||||
|
||||
/**
|
||||
* IBM Db2 Driver
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class DB2Driver implements Driver
|
||||
{
|
||||
/**
|
||||
* Attempts to create a connection with the database.
|
||||
*
|
||||
* @param array $params All connection parameters passed by the user.
|
||||
* @param string $username The username to use when connecting.
|
||||
* @param string $password The password to use when connecting.
|
||||
* @param array $driverOptions The driver options to use when connecting.
|
||||
* @return Doctrine\DBAL\Driver\Connection The database connection.
|
||||
*/
|
||||
public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
|
||||
{
|
||||
if ( !isset($params['schema']) ) {
|
||||
|
||||
}
|
||||
|
||||
if ($params['host'] !== 'localhost' && $params['host'] != '127.0.0.1') {
|
||||
// if the host isn't localhost, use extended connection params
|
||||
$params['dbname'] = 'DRIVER={IBM DB2 ODBC DRIVER}' .
|
||||
';DATABASE=' . $params['dbname'] .
|
||||
';HOSTNAME=' . $params['host'] .
|
||||
';PORT=' . $params['port'] .
|
||||
';PROTOCOL=' . $params['protocol'] .
|
||||
';UID=' . $username .
|
||||
';PWD=' . $password .';';
|
||||
$username = null;
|
||||
$password = null;
|
||||
}
|
||||
|
||||
return new DB2Connection($params, $username, $password, $driverOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DatabasePlatform instance that provides all the metadata about
|
||||
* the platform this driver connects to.
|
||||
*
|
||||
* @return Doctrine\DBAL\Platforms\AbstractPlatform The database platform.
|
||||
*/
|
||||
public function getDatabasePlatform()
|
||||
{
|
||||
return new \Doctrine\DBAL\Platforms\DB2Platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SchemaManager that can be used to inspect and change the underlying
|
||||
* database schema of the platform this driver connects to.
|
||||
*
|
||||
* @param Doctrine\DBAL\Connection $conn
|
||||
* @return Doctrine\DBAL\SchemaManager
|
||||
*/
|
||||
public function getSchemaManager(Connection $conn)
|
||||
{
|
||||
return new \Doctrine\DBAL\Schema\DB2SchemaManager($conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the driver.
|
||||
*
|
||||
* @return string The name of the driver.
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'ibm_db2';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the database connected to for this driver.
|
||||
*
|
||||
* @param Doctrine\DBAL\Connection $conn
|
||||
* @return string $database
|
||||
*/
|
||||
public function getDatabase(\Doctrine\DBAL\Connection $conn)
|
||||
{
|
||||
$params = $conn->getParams();
|
||||
return $params['dbname'];
|
||||
}
|
||||
}
|
27
lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php
Normal file
27
lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2;
|
||||
|
||||
class DB2Exception extends \Exception
|
||||
{
|
||||
|
||||
}
|
297
lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php
Normal file
297
lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php
Normal file
@ -0,0 +1,297 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2;
|
||||
|
||||
class DB2Statement implements \Doctrine\DBAL\Driver\Statement
|
||||
{
|
||||
private $_stmt = null;
|
||||
|
||||
private $_bindParam = array();
|
||||
|
||||
/**
|
||||
* DB2_BINARY, DB2_CHAR, DB2_DOUBLE, or DB2_LONG
|
||||
* @var <type>
|
||||
*/
|
||||
static private $_typeMap = array(
|
||||
\PDO::PARAM_INT => DB2_LONG,
|
||||
\PDO::PARAM_STR => DB2_CHAR,
|
||||
);
|
||||
|
||||
public function __construct($stmt)
|
||||
{
|
||||
$this->_stmt = $stmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a value to a corresponding named or positional
|
||||
* placeholder in the SQL statement that was used to prepare the statement.
|
||||
*
|
||||
* @param mixed $param Parameter identifier. For a prepared statement using named placeholders,
|
||||
* this will be a parameter name of the form :name. For a prepared statement
|
||||
* using question mark placeholders, this will be the 1-indexed position of the parameter
|
||||
*
|
||||
* @param mixed $value The value to bind to the parameter.
|
||||
* @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants.
|
||||
*
|
||||
* @return boolean Returns TRUE on success or FALSE on failure.
|
||||
*/
|
||||
function bindValue($param, $value, $type = null)
|
||||
{
|
||||
return $this->bindParam($param, $value, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a PHP variable to a corresponding named or question mark placeholder in the
|
||||
* SQL statement that was use to prepare the statement. Unlike PDOStatement->bindValue(),
|
||||
* the variable is bound as a reference and will only be evaluated at the time
|
||||
* that PDOStatement->execute() is called.
|
||||
*
|
||||
* Most parameters are input parameters, that is, parameters that are
|
||||
* used in a read-only fashion to build up the query. Some drivers support the invocation
|
||||
* of stored procedures that return data as output parameters, and some also as input/output
|
||||
* parameters that both send in data and are updated to receive it.
|
||||
*
|
||||
* @param mixed $param Parameter identifier. For a prepared statement using named placeholders,
|
||||
* this will be a parameter name of the form :name. For a prepared statement
|
||||
* using question mark placeholders, this will be the 1-indexed position of the parameter
|
||||
*
|
||||
* @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter.
|
||||
*
|
||||
* @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. To return
|
||||
* an INOUT parameter from a stored procedure, use the bitwise OR operator to set the
|
||||
* PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter.
|
||||
* @return boolean Returns TRUE on success or FALSE on failure.
|
||||
*/
|
||||
function bindParam($column, &$variable, $type = null)
|
||||
{
|
||||
$this->_bindParam[$column] =& $variable;
|
||||
|
||||
if ($type && isset(self::$_typeMap[$type])) {
|
||||
$type = self::$_typeMap[$type];
|
||||
} else {
|
||||
$type = DB2_CHAR;
|
||||
}
|
||||
|
||||
if (!db2_bind_param($this->_stmt, $column, "variable", DB2_PARAM_IN, $type)) {
|
||||
throw new DB2Exception(db2_stmt_errormsg());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the cursor, enabling the statement to be executed again.
|
||||
*
|
||||
* @return boolean Returns TRUE on success or FALSE on failure.
|
||||
*/
|
||||
function closeCursor()
|
||||
{
|
||||
if (!$this->_stmt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->_bindParam = array();
|
||||
db2_free_result($this->_stmt);
|
||||
$ret = db2_free_stmt($this->_stmt);
|
||||
$this->_stmt = false;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* columnCount
|
||||
* Returns the number of columns in the result set
|
||||
*
|
||||
* @return integer Returns the number of columns in the result set represented
|
||||
* by the PDOStatement object. If there is no result set,
|
||||
* this method should return 0.
|
||||
*/
|
||||
function columnCount()
|
||||
{
|
||||
if (!$this->_stmt) {
|
||||
return false;
|
||||
}
|
||||
return db2_num_fields($this->_stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* errorCode
|
||||
* Fetch the SQLSTATE associated with the last operation on the statement handle
|
||||
*
|
||||
* @see Doctrine_Adapter_Interface::errorCode()
|
||||
* @return string error code string
|
||||
*/
|
||||
function errorCode()
|
||||
{
|
||||
return db2_stmt_error();
|
||||
}
|
||||
|
||||
/**
|
||||
* errorInfo
|
||||
* Fetch extended error information associated with the last operation on the statement handle
|
||||
*
|
||||
* @see Doctrine_Adapter_Interface::errorInfo()
|
||||
* @return array error info array
|
||||
*/
|
||||
function errorInfo()
|
||||
{
|
||||
return array(
|
||||
0 => db2_stmt_errormsg(),
|
||||
1 => db2_stmt_error(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a prepared statement
|
||||
*
|
||||
* If the prepared statement included parameter markers, you must either:
|
||||
* call PDOStatement->bindParam() to bind PHP variables to the parameter markers:
|
||||
* bound variables pass their value as input and receive the output value,
|
||||
* if any, of their associated parameter markers or pass an array of input-only
|
||||
* parameter values
|
||||
*
|
||||
*
|
||||
* @param array $params An array of values with as many elements as there are
|
||||
* bound parameters in the SQL statement being executed.
|
||||
* @return boolean Returns TRUE on success or FALSE on failure.
|
||||
*/
|
||||
function execute($params = null)
|
||||
{
|
||||
if (!$this->_stmt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*$retval = true;
|
||||
if ($params !== null) {
|
||||
$retval = @db2_execute($this->_stmt, $params);
|
||||
} else {
|
||||
$retval = @db2_execute($this->_stmt);
|
||||
}*/
|
||||
if ($params === null) {
|
||||
ksort($this->_bindParam);
|
||||
$params = array_values($this->_bindParam);
|
||||
}
|
||||
$retval = @db2_execute($this->_stmt, $params);
|
||||
|
||||
if ($retval === false) {
|
||||
throw new DB2Exception(db2_stmt_errormsg());
|
||||
}
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch
|
||||
*
|
||||
* @see Query::HYDRATE_* constants
|
||||
* @param integer $fetchStyle Controls how the next row will be returned to the caller.
|
||||
* This value must be one of the Query::HYDRATE_* constants,
|
||||
* defaulting to Query::HYDRATE_BOTH
|
||||
*
|
||||
* @param integer $cursorOrientation For a PDOStatement object representing a scrollable cursor,
|
||||
* this value determines which row will be returned to the caller.
|
||||
* This value must be one of the Query::HYDRATE_ORI_* constants, defaulting to
|
||||
* Query::HYDRATE_ORI_NEXT. To request a scrollable cursor for your
|
||||
* PDOStatement object,
|
||||
* you must set the PDO::ATTR_CURSOR attribute to Doctrine::CURSOR_SCROLL when you
|
||||
* prepare the SQL statement with Doctrine_Adapter_Interface->prepare().
|
||||
*
|
||||
* @param integer $cursorOffset For a PDOStatement object representing a scrollable cursor for which the
|
||||
* $cursorOrientation parameter is set to Query::HYDRATE_ORI_ABS, this value specifies
|
||||
* the absolute number of the row in the result set that shall be fetched.
|
||||
*
|
||||
* For a PDOStatement object representing a scrollable cursor for
|
||||
* which the $cursorOrientation parameter is set to Query::HYDRATE_ORI_REL, this value
|
||||
* specifies the row to fetch relative to the cursor position before
|
||||
* PDOStatement->fetch() was called.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function fetch($fetchStyle = \PDO::FETCH_BOTH)
|
||||
{
|
||||
switch ($fetchStyle) {
|
||||
case \PDO::FETCH_BOTH:
|
||||
return db2_fetch_both($this->_stmt);
|
||||
case \PDO::FETCH_ASSOC:
|
||||
return db2_fetch_assoc($this->_stmt);
|
||||
case \PDO::FETCH_NUM:
|
||||
return db2_fetch_array($this->_stmt);
|
||||
default:
|
||||
throw new DB2Exception("Given Fetch-Style " . $fetchStyle . " is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the result set rows
|
||||
*
|
||||
* @param integer $fetchStyle Controls how the next row will be returned to the caller.
|
||||
* This value must be one of the Query::HYDRATE_* constants,
|
||||
* defaulting to Query::HYDRATE_BOTH
|
||||
*
|
||||
* @param integer $columnIndex Returns the indicated 0-indexed column when the value of $fetchStyle is
|
||||
* Query::HYDRATE_COLUMN. Defaults to 0.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function fetchAll($fetchStyle = \PDO::FETCH_BOTH)
|
||||
{
|
||||
$rows = array();
|
||||
while ($row = $this->fetch($fetchStyle)) {
|
||||
$rows[] = $row;
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetchColumn
|
||||
* Returns a single column from the next row of a
|
||||
* result set or FALSE if there are no more rows.
|
||||
*
|
||||
* @param integer $columnIndex 0-indexed number of the column you wish to retrieve from the row. If no
|
||||
* value is supplied, PDOStatement->fetchColumn()
|
||||
* fetches the first column.
|
||||
*
|
||||
* @return string returns a single column in the next row of a result set.
|
||||
*/
|
||||
function fetchColumn($columnIndex = 0)
|
||||
{
|
||||
$row = $this->fetch(\PDO::FETCH_NUM);
|
||||
if ($row && isset($row[$columnIndex])) {
|
||||
return $row[$columnIndex];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* rowCount
|
||||
* rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement
|
||||
* executed by the corresponding object.
|
||||
*
|
||||
* If the last SQL statement executed by the associated Statement object was a SELECT statement,
|
||||
* some databases may return the number of rows returned by that statement. However,
|
||||
* this behaviour is not guaranteed for all databases and should not be
|
||||
* relied on for portable applications.
|
||||
*
|
||||
* @return integer Returns the number of rows.
|
||||
*/
|
||||
function rowCount()
|
||||
{
|
||||
return (@db2_num_rows($this->_stmt))?:0;
|
||||
}
|
||||
}
|
@ -60,6 +60,7 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
|
||||
* placeholders and converted to a named parameter.
|
||||
*
|
||||
* @param string $statement The SQL statement to convert.
|
||||
* @todo review and test for lost spaces. we experienced missing spaces with oci8 in some sql statements.
|
||||
*/
|
||||
private function _convertPositionalToNamedPlaceholders($statement)
|
||||
{
|
||||
|
126
lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php
Normal file
126
lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Driver\PDOIbm;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
/**
|
||||
* Driver for the PDO IBM extension
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class Driver implements \Doctrine\DBAL\Driver
|
||||
{
|
||||
/**
|
||||
* Attempts to establish a connection with the underlying driver.
|
||||
*
|
||||
* @param array $params
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param array $driverOptions
|
||||
* @return Doctrine\DBAL\Driver\Connection
|
||||
*/
|
||||
public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
|
||||
{
|
||||
$conn = new \Doctrine\DBAL\Driver\PDOConnection(
|
||||
$this->_constructPdoDsn($params),
|
||||
$username,
|
||||
$password,
|
||||
$driverOptions
|
||||
);
|
||||
return $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the MySql PDO DSN.
|
||||
*
|
||||
* @return string The DSN.
|
||||
*/
|
||||
private function _constructPdoDsn(array $params)
|
||||
{
|
||||
$dsn = 'ibm:';
|
||||
if (isset($params['host'])) {
|
||||
$dsn .= 'HOSTNAME=' . $params['host'] . ';';
|
||||
}
|
||||
if (isset($params['port'])) {
|
||||
$dsn .= 'PORT=' . $params['port'] . ';';
|
||||
}
|
||||
$dsn .= 'PROTOCOL=TCPIP;';
|
||||
if (isset($params['dbname'])) {
|
||||
$dsn .= 'DATABASE=' . $params['dbname'] . ';';
|
||||
}
|
||||
|
||||
return $dsn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DatabasePlatform instance that provides all the metadata about
|
||||
* the platform this driver connects to.
|
||||
*
|
||||
* @return Doctrine\DBAL\Platforms\AbstractPlatform The database platform.
|
||||
*/
|
||||
public function getDatabasePlatform()
|
||||
{
|
||||
return new \Doctrine\DBAL\Platforms\DB2Platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SchemaManager that can be used to inspect and change the underlying
|
||||
* database schema of the platform this driver connects to.
|
||||
*
|
||||
* @param Doctrine\DBAL\Connection $conn
|
||||
* @return Doctrine\DBAL\SchemaManager
|
||||
*/
|
||||
public function getSchemaManager(Connection $conn)
|
||||
{
|
||||
return new \Doctrine\DBAL\Schema\DB2SchemaManager($conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the driver.
|
||||
*
|
||||
* @return string The name of the driver.
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'pdo_ibm';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the database connected to for this driver.
|
||||
*
|
||||
* @param Doctrine\DBAL\Connection $conn
|
||||
* @return string $database
|
||||
*/
|
||||
public function getDatabase(\Doctrine\DBAL\Connection $conn)
|
||||
{
|
||||
$params = $conn->getParams();
|
||||
return $params['dbname'];
|
||||
}
|
||||
}
|
@ -43,7 +43,9 @@ final class DriverManager
|
||||
'pdo_pgsql' => 'Doctrine\DBAL\Driver\PDOPgSql\Driver',
|
||||
'pdo_oci' => 'Doctrine\DBAL\Driver\PDOOracle\Driver',
|
||||
'pdo_mssql' => 'Doctrine\DBAL\Driver\PDOMsSql\Driver',
|
||||
'oci8' => 'Doctrine\DBAL\Driver\OCI8\Driver'
|
||||
'oci8' => 'Doctrine\DBAL\Driver\OCI8\Driver',
|
||||
'ibm_db2' => 'Doctrine\DBAL\Driver\IBMDB2\DB2Driver',
|
||||
'pdo_ibm' => 'Doctrine\DBAL\Driver\PDOIbm\Driver',
|
||||
);
|
||||
|
||||
/** Private constructor. This class cannot be instantiated. */
|
||||
|
@ -1132,7 +1132,7 @@ abstract class AbstractPlatform
|
||||
throw \InvalidArgumentException("Incomplete definition. 'columns' required.");
|
||||
}
|
||||
|
||||
return 'CONSTRAINT' . $name . ' UNIQUE ('
|
||||
return 'CONSTRAINT ' . $name . ' UNIQUE ('
|
||||
. $this->getIndexFieldDeclarationListSQL($index->getColumns())
|
||||
. ')';
|
||||
}
|
||||
@ -1214,6 +1214,17 @@ abstract class AbstractPlatform
|
||||
return 'TEMPORARY';
|
||||
}
|
||||
|
||||
/**
|
||||
* Some vendors require temporary table names to be qualified specially.
|
||||
*
|
||||
* @param string $tableName
|
||||
* @return string
|
||||
*/
|
||||
public function getTemporaryTableName($tableName)
|
||||
{
|
||||
return $tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sql query to show a list of database.
|
||||
*
|
||||
@ -1727,6 +1738,16 @@ abstract class AbstractPlatform
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some databases don't allow to create and drop databases at all or only with certain tools.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function supportsCreateDropDatabase()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
516
lib/Doctrine/DBAL/Platforms/DB2Platform.php
Normal file
516
lib/Doctrine/DBAL/Platforms/DB2Platform.php
Normal file
@ -0,0 +1,516 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Platforms;
|
||||
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use Doctrine\DBAL\Schema\Index;
|
||||
use Doctrine\DBAL\Schema\TableDiff;
|
||||
|
||||
class DB2Platform extends AbstractPlatform
|
||||
{
|
||||
/**
|
||||
* Gets the SQL snippet used to declare a VARCHAR column type.
|
||||
*
|
||||
* @param array $field
|
||||
*/
|
||||
public function getVarcharTypeDeclarationSQL(array $field)
|
||||
{
|
||||
if ( ! isset($field['length'])) {
|
||||
if (array_key_exists('default', $field)) {
|
||||
$field['length'] = $this->getVarcharMaxLength();
|
||||
} else {
|
||||
$field['length'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
$length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
|
||||
$fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
|
||||
|
||||
return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
|
||||
: ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL snippet used to declare a CLOB column type.
|
||||
*
|
||||
* @param array $field
|
||||
*/
|
||||
public function getClobTypeDeclarationSQL(array $field)
|
||||
{
|
||||
// todo clob(n) with $field['length'];
|
||||
return 'CLOB(1M)';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the platform.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'db2';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the SQL snippet that declares a boolean column.
|
||||
*
|
||||
* @param array $columnDef
|
||||
* @return string
|
||||
*/
|
||||
public function getBooleanTypeDeclarationSQL(array $columnDef)
|
||||
{
|
||||
return 'SMALLINT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL snippet that declares a 4 byte integer column.
|
||||
*
|
||||
* @param array $columnDef
|
||||
* @return string
|
||||
*/
|
||||
public function getIntegerTypeDeclarationSQL(array $columnDef)
|
||||
{
|
||||
return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL snippet that declares an 8 byte integer column.
|
||||
*
|
||||
* @param array $columnDef
|
||||
* @return string
|
||||
*/
|
||||
public function getBigIntTypeDeclarationSQL(array $columnDef)
|
||||
{
|
||||
return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL snippet that declares a 2 byte integer column.
|
||||
*
|
||||
* @param array $columnDef
|
||||
* @return string
|
||||
*/
|
||||
public function getSmallIntTypeDeclarationSQL(array $columnDef)
|
||||
{
|
||||
return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL snippet that declares common properties of an integer column.
|
||||
*
|
||||
* @param array $columnDef
|
||||
* @return string
|
||||
*/
|
||||
protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
|
||||
{
|
||||
$autoinc = '';
|
||||
if ( ! empty($columnDef['autoincrement'])) {
|
||||
$autoinc = ' GENERATED BY DEFAULT AS IDENTITY';
|
||||
}
|
||||
return $autoinc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain DBMS specific SQL to be used to create datetime fields in
|
||||
* statements like CREATE TABLE
|
||||
*
|
||||
* @param array $fieldDeclaration
|
||||
* @return string
|
||||
*/
|
||||
public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
|
||||
{
|
||||
if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) {
|
||||
return "TIMESTAMP(0) WITH DEFAULT";
|
||||
}
|
||||
|
||||
return 'TIMESTAMP(0)';
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain DBMS specific SQL to be used to create date fields in statements
|
||||
* like CREATE TABLE.
|
||||
*
|
||||
* @param array $fieldDeclaration
|
||||
* @return string
|
||||
*/
|
||||
public function getDateTypeDeclarationSQL(array $fieldDeclaration)
|
||||
{
|
||||
return 'DATE';
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain DBMS specific SQL to be used to create time fields in statements
|
||||
* like CREATE TABLE.
|
||||
*
|
||||
* @param array $fieldDeclaration
|
||||
* @return string
|
||||
*/
|
||||
public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
|
||||
{
|
||||
return 'TIME';
|
||||
}
|
||||
|
||||
public function getListDatabasesSQL()
|
||||
{
|
||||
throw DBALException::notSupported(__METHOD__);
|
||||
}
|
||||
|
||||
public function getListSequencesSQL($database)
|
||||
{
|
||||
throw DBALException::notSupported(__METHOD__);
|
||||
}
|
||||
|
||||
public function getListTableConstraintsSQL($table)
|
||||
{
|
||||
throw DBALException::notSupported(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* This code fragment is originally from the Zend_Db_Adapter_Db2 class.
|
||||
*
|
||||
* @license New BSD License
|
||||
* @param string $table
|
||||
* @return string
|
||||
*/
|
||||
public function getListTableColumnsSQL($table)
|
||||
{
|
||||
return "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno,
|
||||
c.typename, c.default, c.nulls, c.length, c.scale,
|
||||
c.identity, tc.type AS tabconsttype, k.colseq
|
||||
FROM syscat.columns c
|
||||
LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc
|
||||
ON (k.tabschema = tc.tabschema
|
||||
AND k.tabname = tc.tabname
|
||||
AND tc.type = 'P'))
|
||||
ON (c.tabschema = k.tabschema
|
||||
AND c.tabname = k.tabname
|
||||
AND c.colname = k.colname)
|
||||
WHERE UPPER(c.tabname) = UPPER('" . $table . "') ORDER BY c.colno";
|
||||
}
|
||||
|
||||
public function getListTablesSQL()
|
||||
{
|
||||
return "SELECT NAME FROM SYSIBM.SYSTABLES WHERE TYPE = 'T'";
|
||||
}
|
||||
|
||||
public function getListUsersSQL()
|
||||
{
|
||||
throw DBALException::notSupported(__METHOD__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL to list all views of a database or user.
|
||||
*
|
||||
* @param string $database
|
||||
* @return string
|
||||
*/
|
||||
public function getListViewsSQL($database)
|
||||
{
|
||||
return "SELECT NAME, TEXT FROM SYSIBM.SYSVIEWS";
|
||||
}
|
||||
|
||||
public function getListTableIndexesSQL($table)
|
||||
{
|
||||
return "SELECT NAME, COLNAMES, UNIQUERULE FROM SYSIBM.SYSINDEXES WHERE TBNAME = UPPER('" . $table . "')";
|
||||
}
|
||||
|
||||
public function getListTableForeignKeysSQL($table)
|
||||
{
|
||||
return "SELECT TBNAME, RELNAME, REFTBNAME, DELETERULE, UPDATERULE, FKCOLNAMES, PKCOLNAMES ".
|
||||
"FROM SYSIBM.SYSRELS WHERE TBNAME = UPPER('".$table."')";
|
||||
}
|
||||
|
||||
public function getCreateViewSQL($name, $sql)
|
||||
{
|
||||
return "CREATE VIEW ".$name." AS ".$sql;
|
||||
}
|
||||
|
||||
public function getDropViewSQL($name)
|
||||
{
|
||||
return "DROP VIEW ".$name;
|
||||
}
|
||||
|
||||
public function getDropSequenceSQL($sequence)
|
||||
{
|
||||
throw DBALException::notSupported(__METHOD__);
|
||||
}
|
||||
|
||||
public function getSequenceNextValSQL($sequenceName)
|
||||
{
|
||||
throw DBALException::notSupported(__METHOD__);
|
||||
}
|
||||
|
||||
public function getCreateDatabaseSQL($database)
|
||||
{
|
||||
return "CREATE DATABASE ".$database;
|
||||
}
|
||||
|
||||
public function getDropDatabaseSQL($database)
|
||||
{
|
||||
return "DROP DATABASE ".$database.";";
|
||||
}
|
||||
|
||||
public function supportsCreateDropDatabase()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL specific for the platform to get the current date.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrentDateSQL()
|
||||
{
|
||||
return 'VALUES CURRENT DATE';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL specific for the platform to get the current time.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrentTimeSQL()
|
||||
{
|
||||
return 'VALUES CURRENT TIME';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL specific for the platform to get the current timestamp
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
||||
public function getCurrentTimestampSQL()
|
||||
{
|
||||
return "VALUES CURRENT TIMESTAMP";
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain DBMS specific SQL code portion needed to set an index
|
||||
* declaration to be used in statements like CREATE TABLE.
|
||||
*
|
||||
* @param string $name name of the index
|
||||
* @param Index $index index definition
|
||||
* @return string DBMS specific SQL code portion needed to set an index
|
||||
*/
|
||||
public function getIndexDeclarationSQL($name, Index $index)
|
||||
{
|
||||
return $this->getUniqueConstraintDeclarationSQL($name, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
* @param array $columns
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
|
||||
{
|
||||
$indexes = array();
|
||||
if (isset($options['indexes'])) {
|
||||
$indexes = $options['indexes'];
|
||||
}
|
||||
$options['indexes'] = array();
|
||||
|
||||
$sqls = parent::_getCreateTableSQL($tableName, $columns, $options);
|
||||
|
||||
foreach ($indexes as $index => $definition) {
|
||||
$sqls[] = $this->getCreateIndexSQL($definition, $tableName);
|
||||
}
|
||||
return $sqls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL to alter an existing table.
|
||||
*
|
||||
* @param TableDiff $diff
|
||||
* @return array
|
||||
*/
|
||||
public function getAlterTableSQL(TableDiff $diff)
|
||||
{
|
||||
$sql = array();
|
||||
|
||||
$queryParts = array();
|
||||
foreach ($diff->addedColumns AS $fieldName => $column) {
|
||||
$queryParts[] = 'ADD COLUMN ' . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
|
||||
}
|
||||
|
||||
foreach ($diff->removedColumns AS $column) {
|
||||
$queryParts[] = 'DROP COLUMN ' . $column->getName();
|
||||
}
|
||||
|
||||
foreach ($diff->changedColumns AS $columnDiff) {
|
||||
/* @var $columnDiff Doctrine\DBAL\Schema\ColumnDiff */
|
||||
$column = $columnDiff->column;
|
||||
$queryParts[] = 'ALTER ' . ($columnDiff->oldColumnName) . ' '
|
||||
. $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
|
||||
}
|
||||
|
||||
foreach ($diff->renamedColumns AS $oldColumnName => $column) {
|
||||
$queryParts[] = 'RENAME ' . $oldColumnName . ' TO ' . $column->getName();
|
||||
}
|
||||
|
||||
if (count($queryParts) > 0) {
|
||||
$sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(" ", $queryParts);
|
||||
}
|
||||
|
||||
$sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
|
||||
|
||||
if ($diff->newName !== false) {
|
||||
$sql[] = 'RENAME TABLE TO ' . $diff->newName;
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function getDefaultValueDeclarationSQL($field)
|
||||
{
|
||||
if (isset($field['notnull']) && $field['notnull'] && !isset($field['default'])) {
|
||||
if (in_array((string)$field['type'], array("Integer", "BigInteger", "SmallInteger"))) {
|
||||
$field['default'] = 0;
|
||||
} else if((string)$field['type'] == "DateTime") {
|
||||
$field['default'] = "00-00-00 00:00:00";
|
||||
} else if ((string)$field['type'] == "Date") {
|
||||
$field['default'] = "00-00-00";
|
||||
} else if((string)$field['type'] == "Time") {
|
||||
$field['default'] = "00:00:00";
|
||||
} else {
|
||||
$field['default'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
unset($field['default']); // @todo this needs fixing
|
||||
if (isset($field['version']) && $field['version']) {
|
||||
if ((string)$field['type'] != "DateTime") {
|
||||
$field['default'] = "1";
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getDefaultValueDeclarationSQL($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the insert sql for an empty insert statement
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param string $identifierColumnName
|
||||
* @return string $sql
|
||||
*/
|
||||
public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName)
|
||||
{
|
||||
return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (DEFAULT)';
|
||||
}
|
||||
|
||||
public function getCreateTemporaryTableSnippetSQL()
|
||||
{
|
||||
return "DECLARE GLOBAL TEMPORARY TABLE";
|
||||
}
|
||||
|
||||
/**
|
||||
* DB2 automatically moves temporary tables into the SESSION. schema.
|
||||
*
|
||||
* @param string $tableName
|
||||
* @return string
|
||||
*/
|
||||
public function getTemporaryTableName($tableName)
|
||||
{
|
||||
return "SESSION." . $tableName;
|
||||
}
|
||||
|
||||
public function modifyLimitQuery($query, $limit, $offset = null)
|
||||
{
|
||||
if ($limit === null && $offset === null) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
$limit = (int)$limit;
|
||||
$offset = (int)(($offset)?:0);
|
||||
|
||||
// Todo OVER() needs ORDER BY data!
|
||||
$sql = 'SELECT db22.* FROM (SELECT ROW_NUMBER() OVER() AS DC_ROWNUM, db21.* '.
|
||||
'FROM (' . $query . ') db21) db22 WHERE db22.DC_ROWNUM BETWEEN ' . ($offset+1) .' AND ' . ($offset+$limit);
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the position of the first occurrence of substring $substr in string $str
|
||||
*
|
||||
* @param string $substr literal string to find
|
||||
* @param string $str literal string
|
||||
* @param int $pos position to start at, beginning of string by default
|
||||
* @return integer
|
||||
*/
|
||||
public function getLocateExpression($str, $substr, $startPos = false)
|
||||
{
|
||||
if ($startPos == false) {
|
||||
return 'LOCATE(' . $substr . ', ' . $str . ')';
|
||||
} else {
|
||||
return 'LOCATE(' . $substr . ', ' . $str . ', '.$startPos.')';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return string to call a function to get a substring inside an SQL statement
|
||||
*
|
||||
* Note: Not SQL92, but common functionality.
|
||||
*
|
||||
* SQLite only supports the 2 parameter variant of this function
|
||||
*
|
||||
* @param string $value an sql string literal or column name/alias
|
||||
* @param integer $from where to start the substring portion
|
||||
* @param integer $len the substring portion length
|
||||
* @return string
|
||||
*/
|
||||
public function getSubstringExpression($value, $from, $len = null)
|
||||
{
|
||||
if ($len === null)
|
||||
return 'SUBSTR(' . $value . ', ' . $from . ')';
|
||||
else {
|
||||
return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
|
||||
}
|
||||
}
|
||||
|
||||
public function supportsIdentityColumns()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function prefersIdentityColumns()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character casing of a column in an SQL result set of this platform.
|
||||
*
|
||||
* DB2 returns all column names in SQL result sets in uppercase.
|
||||
*
|
||||
* @param string $column The column name for which to get the correct character casing.
|
||||
* @return string The column name in the character casing used in SQL result sets.
|
||||
*/
|
||||
public function getSQLResultCasing($column)
|
||||
{
|
||||
return strtoupper($column);
|
||||
}
|
||||
}
|
@ -412,91 +412,8 @@ class MySqlPlatform extends AbstractPlatform
|
||||
/**
|
||||
* Gets the SQL to alter an existing table.
|
||||
*
|
||||
* @param string $name The name of the table that is intended to be changed.
|
||||
* @param array $changes Associative array that contains the details of each type
|
||||
* of change that is intended to be performed. The types of
|
||||
* changes that are currently supported are defined as follows:
|
||||
*
|
||||
* name
|
||||
*
|
||||
* New name for the table.
|
||||
*
|
||||
* add
|
||||
*
|
||||
* Associative array with the names of fields to be added as
|
||||
* indexes of the array. The value of each entry of the array
|
||||
* should be set to another associative array with the properties
|
||||
* of the fields to be added. The properties of the fields should
|
||||
* be the same as defined by the Metabase parser.
|
||||
*
|
||||
*
|
||||
* remove
|
||||
*
|
||||
* Associative array with the names of fields to be removed as indexes
|
||||
* of the array. Currently the values assigned to each entry are ignored.
|
||||
* An empty array should be used for future compatibility.
|
||||
*
|
||||
* rename
|
||||
*
|
||||
* Associative array with the names of fields to be renamed as indexes
|
||||
* of the array. The value of each entry of the array should be set to
|
||||
* another associative array with the entry named name with the new
|
||||
* field name and the entry named Declaration that is expected to contain
|
||||
* the portion of the field declaration already in DBMS specific SQL code
|
||||
* as it is used in the CREATE TABLE statement.
|
||||
*
|
||||
* change
|
||||
*
|
||||
* Associative array with the names of the fields to be changed as indexes
|
||||
* of the array. Keep in mind that if it is intended to change either the
|
||||
* name of a field and any other properties, the change array entries
|
||||
* should have the new names of the fields as array indexes.
|
||||
*
|
||||
* The value of each entry of the array should be set to another associative
|
||||
* array with the properties of the fields to that are meant to be changed as
|
||||
* array entries. These entries should be assigned to the new values of the
|
||||
* respective properties. The properties of the fields should be the same
|
||||
* as defined by the Metabase parser.
|
||||
*
|
||||
* Example
|
||||
* array(
|
||||
* 'name' => 'userlist',
|
||||
* 'add' => array(
|
||||
* 'quota' => array(
|
||||
* 'type' => 'integer',
|
||||
* 'unsigned' => 1
|
||||
* )
|
||||
* ),
|
||||
* 'remove' => array(
|
||||
* 'file_limit' => array(),
|
||||
* 'time_limit' => array()
|
||||
* ),
|
||||
* 'change' => array(
|
||||
* 'name' => array(
|
||||
* 'length' => '20',
|
||||
* 'definition' => array(
|
||||
* 'type' => 'text',
|
||||
* 'length' => 20,
|
||||
* ),
|
||||
* )
|
||||
* ),
|
||||
* 'rename' => array(
|
||||
* 'sex' => array(
|
||||
* 'name' => 'gender',
|
||||
* 'definition' => array(
|
||||
* 'type' => 'text',
|
||||
* 'length' => 1,
|
||||
* 'default' => 'M',
|
||||
* ),
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @param boolean $check indicates whether the function should just check if the DBMS driver
|
||||
* can perform the requested table alterations if the value is true or
|
||||
* actually perform them otherwise.
|
||||
* @return boolean
|
||||
* @override
|
||||
* @param TableDiff $diff
|
||||
* @return array
|
||||
*/
|
||||
public function getAlterTableSQL(TableDiff $diff)
|
||||
{
|
||||
|
200
lib/Doctrine/DBAL/Schema/DB2SchemaManager.php
Normal file
200
lib/Doctrine/DBAL/Schema/DB2SchemaManager.php
Normal file
@ -0,0 +1,200 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Schema;
|
||||
|
||||
/**
|
||||
* IBM Db2 Schema Manager
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class DB2SchemaManager extends AbstractSchemaManager
|
||||
{
|
||||
/**
|
||||
* Return a list of all tables in the current database
|
||||
*
|
||||
* Apparently creator is the schema not the user who created it:
|
||||
* {@link http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.sqlref/db2z_sysibmsystablestable.htm}
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listTableNames()
|
||||
{
|
||||
$sql = $this->_platform->getListTablesSQL();
|
||||
$sql .= " AND CREATOR = UPPER('".$this->_conn->getUsername()."')";
|
||||
|
||||
$tables = $this->_conn->fetchAll($sql);
|
||||
|
||||
return $this->_getPortableTablesList($tables);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Table Column Definition
|
||||
*
|
||||
* @param array $tableColumn
|
||||
* @return Column
|
||||
*/
|
||||
protected function _getPortableTableColumnDefinition($tableColumn)
|
||||
{
|
||||
$tableColumn = array_change_key_case($tableColumn, \CASE_LOWER);
|
||||
|
||||
$length = null;
|
||||
$fixed = null;
|
||||
$unsigned = false;
|
||||
$scale = false;
|
||||
$precision = false;
|
||||
|
||||
switch (strtolower($tableColumn['typename'])) {
|
||||
case 'smallint':
|
||||
case 'bigint':
|
||||
case 'integer':
|
||||
case 'time':
|
||||
case 'date':
|
||||
$type = strtolower($tableColumn['typename']);
|
||||
break;
|
||||
case 'varchar':
|
||||
$type = 'string';
|
||||
$length = $tableColumn['length'];
|
||||
$fixed = false;
|
||||
break;
|
||||
case 'character':
|
||||
$type = 'string';
|
||||
$length = $tableColumn['length'];
|
||||
$fixed = true;
|
||||
break;
|
||||
case 'clob':
|
||||
$type = 'text';
|
||||
$length = $tableColumn['length'];
|
||||
break;
|
||||
case 'decimal':
|
||||
case 'double':
|
||||
case 'real':
|
||||
$type = 'decimal';
|
||||
$scale = $tableColumn['scale'];
|
||||
$precision = $tableColumn['length'];
|
||||
break;
|
||||
case 'timestamp':
|
||||
$type = 'datetime';
|
||||
break;
|
||||
default:
|
||||
throw new \Doctrine\DBAL\DBALException("Unknown Type: ".$tableColumn['typename']);
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'length' => $length,
|
||||
'unsigned' => (bool)$unsigned,
|
||||
'fixed' => (bool)$fixed,
|
||||
'default' => ($tableColumn['default'] == "NULL") ? null : $tableColumn['default'],
|
||||
'notnull' => (bool) ($tableColumn['nulls'] == 'N'),
|
||||
'scale' => null,
|
||||
'precision' => null,
|
||||
'platformOptions' => array(),
|
||||
);
|
||||
|
||||
if ($scale !== null && $precision !== null) {
|
||||
$options['scale'] = $scale;
|
||||
$options['precision'] = $precision;
|
||||
}
|
||||
|
||||
return new Column($tableColumn['colname'], \Doctrine\DBAL\Types\Type::getType($type), $options);
|
||||
}
|
||||
|
||||
protected function _getPortableTablesList($tables)
|
||||
{
|
||||
$tableNames = array();
|
||||
foreach ($tables AS $tableRow) {
|
||||
$tableRow = array_change_key_case($tableRow, \CASE_LOWER);
|
||||
$tableNames[] = $tableRow['name'];
|
||||
}
|
||||
return $tableNames;
|
||||
}
|
||||
|
||||
protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
|
||||
{
|
||||
$tableIndexRows = array();
|
||||
$indexes = array();
|
||||
foreach($tableIndexes AS $indexKey => $data) {
|
||||
$data = array_change_key_case($data, \CASE_LOWER);
|
||||
$unique = ($data['uniquerule'] == "D") ? false : true;
|
||||
$primary = ($data['uniquerule'] == "P");
|
||||
|
||||
$indexName = strtolower($data['name']);
|
||||
if ($primary) {
|
||||
$keyName = 'primary';
|
||||
} else {
|
||||
$keyName = $indexName;
|
||||
}
|
||||
|
||||
$indexes[$keyName] = new Index($indexName, explode("+", ltrim($data['colnames'], '+')), $unique, $primary);
|
||||
}
|
||||
|
||||
return $indexes;
|
||||
}
|
||||
|
||||
protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
|
||||
{
|
||||
$tableForeignKey = array_change_key_case($tableForeignKey, CASE_LOWER);
|
||||
|
||||
$tableForeignKey['deleterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['deleterule']);
|
||||
$tableForeignKey['updaterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['updaterule']);
|
||||
|
||||
return new ForeignKeyConstraint(
|
||||
array_map('trim', (array)$tableForeignKey['fkcolnames']),
|
||||
$tableForeignKey['reftbname'],
|
||||
array_map('trim', (array)$tableForeignKey['pkcolnames']),
|
||||
$tableForeignKey['relname'],
|
||||
array(
|
||||
'onUpdate' => $tableForeignKey['updaterule'],
|
||||
'onDelete' => $tableForeignKey['deleterule'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function _getPortableForeignKeyRuleDef($def)
|
||||
{
|
||||
if ($def == "C") {
|
||||
return "CASCADE";
|
||||
} else if ($def == "N") {
|
||||
return "SET NULL";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function _getPortableViewDefinition($view)
|
||||
{
|
||||
$view = array_change_key_case($view, \CASE_LOWER);
|
||||
// sadly this still segfaults on PDO_IBM, see http://pecl.php.net/bugs/bug.php?id=17199
|
||||
//$view['text'] = (is_resource($view['text']) ? stream_get_contents($view['text']) : $view['text']);
|
||||
if (!is_resource($view['text'])) {
|
||||
$pos = strpos($view['text'], ' AS ');
|
||||
$sql = substr($view['text'], $pos+4);
|
||||
} else {
|
||||
$sql = '';
|
||||
}
|
||||
|
||||
return new View($view['name'], $sql);
|
||||
}
|
||||
}
|
@ -510,7 +510,24 @@ class Table extends AbstractAsset
|
||||
*/
|
||||
public function getColumns()
|
||||
{
|
||||
return $this->_columns;
|
||||
$columns = $this->_columns;
|
||||
|
||||
$pkCols = array();
|
||||
$fkCols = array();
|
||||
|
||||
if ($this->hasIndex($this->_primaryKeyName)) {
|
||||
$pkCols = $this->getPrimaryKey()->getColumns();
|
||||
}
|
||||
foreach ($this->getForeignKeys() AS $fk) {
|
||||
/* @var $fk ForeignKeyConstraint */
|
||||
$fkCols = array_merge($fkCols, $fk->getColumns());
|
||||
}
|
||||
$colNames = array_unique(array_merge($pkCols, $fkCols, array_keys($columns)));
|
||||
|
||||
uksort($columns, function($a, $b) use($colNames) {
|
||||
return (array_search($a, $colNames) >= array_search($b, $colNames));
|
||||
});
|
||||
return $columns;
|
||||
}
|
||||
|
||||
|
||||
|
@ -78,7 +78,7 @@ EOT
|
||||
if (preg_match('/^select/i', $sql)) {
|
||||
$resultSet = $conn->fetchAll($sql);
|
||||
} else {
|
||||
$resultSet = $em->getConnection()->executeUpdate($sql);
|
||||
$resultSet = $conn->executeUpdate($sql);
|
||||
}
|
||||
|
||||
\Doctrine\Common\Util\Debug::dump($resultSet, (int) $depth);
|
||||
|
@ -40,6 +40,7 @@ class ArrayType extends Type
|
||||
|
||||
public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
|
||||
{
|
||||
$value = (is_resource($value)) ? stream_get_contents($value) : $value;
|
||||
return unserialize($value);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ class ObjectType extends Type
|
||||
|
||||
public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
|
||||
{
|
||||
$value = (is_resource($value)) ? stream_get_contents($value) : $value;
|
||||
return unserialize($value);
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,19 @@ class TextType extends Type
|
||||
return $platform->getClobTypeDeclarationSQL($fieldDeclaration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a value from its database representation to its PHP representation
|
||||
* of this type.
|
||||
*
|
||||
* @param mixed $value The value to convert.
|
||||
* @param AbstractPlatform $platform The currently used database platform.
|
||||
* @return mixed The PHP representation of the value.
|
||||
*/
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
return (is_resource($value)) ? stream_get_contents($value) : $value;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return Type::TEXT;
|
||||
|
@ -27,8 +27,7 @@ use Doctrine\Common\Cache\Cache,
|
||||
* It combines all configuration options from DBAL & ORM.
|
||||
*
|
||||
* @since 2.0
|
||||
* @internal When adding a new configuration option just write a getter/setter
|
||||
* pair and add the option to the _attributes array with a proper default value.
|
||||
* @internal When adding a new configuration option just write a getter/setter pair.
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
@ -36,24 +35,6 @@ use Doctrine\Common\Cache\Cache,
|
||||
*/
|
||||
class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
/**
|
||||
* Creates a new configuration that can be used for Doctrine.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->_attributes = array_merge($this->_attributes, array(
|
||||
'resultCacheImpl' => null,
|
||||
'queryCacheImpl' => null,
|
||||
'metadataCacheImpl' => null,
|
||||
'metadataDriverImpl' => null,
|
||||
'proxyDir' => null,
|
||||
'useCExtension' => false,
|
||||
'autoGenerateProxyClasses' => true,
|
||||
'proxyNamespace' => null
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the directory where Doctrine generates any necessary proxy class files.
|
||||
*
|
||||
@ -71,7 +52,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getProxyDir()
|
||||
{
|
||||
return $this->_attributes['proxyDir'];
|
||||
return isset($this->_attributes['proxyDir']) ?
|
||||
$this->_attributes['proxyDir'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,7 +64,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getAutoGenerateProxyClasses()
|
||||
{
|
||||
return $this->_attributes['autoGenerateProxyClasses'];
|
||||
return isset($this->_attributes['autoGenerateProxyClasses']) ?
|
||||
$this->_attributes['autoGenerateProxyClasses'] : true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,7 +86,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getProxyNamespace()
|
||||
{
|
||||
return $this->_attributes['proxyNamespace'];
|
||||
return isset($this->_attributes['proxyNamespace']) ?
|
||||
$this->_attributes['proxyNamespace'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,7 +172,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getMetadataDriverImpl()
|
||||
{
|
||||
return $this->_attributes['metadataDriverImpl'];
|
||||
return isset($this->_attributes['metadataDriverImpl']) ?
|
||||
$this->_attributes['metadataDriverImpl'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,7 +183,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getResultCacheImpl()
|
||||
{
|
||||
return $this->_attributes['resultCacheImpl'];
|
||||
return isset($this->_attributes['resultCacheImpl']) ?
|
||||
$this->_attributes['resultCacheImpl'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -218,7 +204,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getQueryCacheImpl()
|
||||
{
|
||||
return $this->_attributes['queryCacheImpl'];
|
||||
return isset($this->_attributes['queryCacheImpl']) ?
|
||||
$this->_attributes['queryCacheImpl'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -238,7 +225,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getMetadataCacheImpl()
|
||||
{
|
||||
return $this->_attributes['metadataCacheImpl'];
|
||||
return isset($this->_attributes['metadataCacheImpl']) ?
|
||||
$this->_attributes['metadataCacheImpl'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -259,7 +247,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getUseCExtension()
|
||||
{
|
||||
return $this->_attributes['useCExtension'];
|
||||
return isset($this->_attributes['useCExtension']) ?
|
||||
$this->_attributes['useCExtension'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -350,6 +339,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* Such a function can then be used in any DQL statement in any place where string
|
||||
* functions are allowed.
|
||||
*
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $className
|
||||
*/
|
||||
@ -366,15 +357,33 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getCustomStringFunction($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
return isset($this->_attributes['customStringFunctions'][$name]) ?
|
||||
$this->_attributes['customStringFunctions'][$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of custom DQL string functions.
|
||||
*
|
||||
* Keys must be function names and values the FQCN of the implementing class.
|
||||
* The function names will be case-insensitive in DQL.
|
||||
*
|
||||
* Any previously added string functions are discarded.
|
||||
*
|
||||
* @param array $functions The map of custom DQL string functions.
|
||||
*/
|
||||
public function setCustomStringFunctions(array $functions)
|
||||
{
|
||||
$this->_attributes['customStringFunctions'] = array_change_key_case($functions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a custom DQL function that produces a numeric value.
|
||||
* Such a function can then be used in any DQL statement in any place where numeric
|
||||
* functions are allowed.
|
||||
*
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $className
|
||||
*/
|
||||
@ -391,15 +400,33 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getCustomNumericFunction($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
return isset($this->_attributes['customNumericFunctions'][$name]) ?
|
||||
$this->_attributes['customNumericFunctions'][$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of custom DQL numeric functions.
|
||||
*
|
||||
* Keys must be function names and values the FQCN of the implementing class.
|
||||
* The function names will be case-insensitive in DQL.
|
||||
*
|
||||
* Any previously added numeric functions are discarded.
|
||||
*
|
||||
* @param array $functions The map of custom DQL numeric functions.
|
||||
*/
|
||||
public function setCustomNumericFunctions(array $functions)
|
||||
{
|
||||
$this->_attributes['customNumericFunctions'] = array_change_key_case($functions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a custom DQL function that produces a date/time value.
|
||||
* Such a function can then be used in any DQL statement in any place where date/time
|
||||
* functions are allowed.
|
||||
*
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $className
|
||||
*/
|
||||
@ -416,7 +443,23 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getCustomDatetimeFunction($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
return isset($this->_attributes['customDatetimeFunctions'][$name]) ?
|
||||
$this->_attributes['customDatetimeFunctions'][$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of custom DQL date/time functions.
|
||||
*
|
||||
* Keys must be function names and values the FQCN of the implementing class.
|
||||
* The function names will be case-insensitive in DQL.
|
||||
*
|
||||
* Any previously added date/time functions are discarded.
|
||||
*
|
||||
* @param array $functions The map of custom DQL date/time functions.
|
||||
*/
|
||||
public function setCustomDatetimeFunctions(array $functions)
|
||||
{
|
||||
$this->_attributes['customDatetimeFunctions'] = array_change_key_case($functions);
|
||||
}
|
||||
}
|
@ -442,7 +442,8 @@ class EntityManager
|
||||
*
|
||||
* @param object $entity The entity to copy.
|
||||
* @return object The new entity.
|
||||
* @todo Implementation or remove.
|
||||
* @todo Implementation need. This is necessary since $e2 = clone $e1; throws an E_FATAL when access anything on $e:
|
||||
* Fatal error: Maximum function nesting level of '100' reached, aborting!
|
||||
*/
|
||||
public function copy($entity, $deep = false)
|
||||
{
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?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;
|
||||
|
||||
@ -12,6 +29,6 @@ class EntityNotFoundException extends ORMException
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('Entity was found although one item was expected.');
|
||||
parent::__construct('Entity was not found.');
|
||||
}
|
||||
}
|
@ -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
|
||||
@ -28,10 +26,7 @@ namespace Doctrine\ORM;
|
||||
* This class is designed for inheritance and users can subclass this class to
|
||||
* write their own repositories with business-specific methods to locate entities.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
@ -203,4 +198,28 @@ class EntityRepository
|
||||
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getEntityName()
|
||||
{
|
||||
return $this->_entityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityManager
|
||||
*/
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->_em;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Mapping\ClassMetadata
|
||||
*/
|
||||
protected function getClassMetadata()
|
||||
{
|
||||
return $this->_class;
|
||||
}
|
||||
}
|
@ -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
|
||||
@ -25,12 +23,9 @@ namespace Doctrine\ORM\Event;
|
||||
* Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions
|
||||
* of entities.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class LifecycleEventArgs extends \Doctrine\Common\EventArgs
|
||||
{
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?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\Id;
|
||||
|
||||
|
@ -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
|
||||
@ -27,10 +25,7 @@ use Doctrine\ORM\ORMException;
|
||||
/**
|
||||
* Special generator for application-assigned identifiers (doesnt really generate anything).
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?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\Id;
|
||||
|
||||
|
@ -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
|
||||
@ -21,7 +19,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Serializable, Doctrine\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* Represents an ID generator that uses a database sequence.
|
||||
@ -29,7 +27,7 @@ use Doctrine\ORM\EntityManager;
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class SequenceGenerator extends AbstractIdGenerator implements \Serializable
|
||||
class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
{
|
||||
private $_allocationSize;
|
||||
private $_sequenceName;
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?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\Id;
|
||||
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?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\Id;
|
||||
|
||||
@ -7,10 +24,7 @@ use Doctrine\ORM\EntityManager;
|
||||
/**
|
||||
* Id generator that uses a single-row database table and a hi/lo algorithm.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
|
@ -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
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id: Hydrate.php 3192 2007-11-19 17:55:23Z romanb $
|
||||
*
|
||||
* 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
|
||||
@ -30,10 +28,7 @@ use PDO,
|
||||
* Base class for all hydrators. A hydrator is a class that provides some form
|
||||
* of transformation of an SQL result set into another structure.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3192 $
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id: UnitOfWork.php 4947 2008-09-12 13:16:05Z romanb $
|
||||
*
|
||||
* 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
|
||||
|
@ -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
|
||||
@ -242,8 +240,8 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* specified by the FROM clause in a DQL query.
|
||||
*
|
||||
* @param array $data The data of the row to process.
|
||||
* @param array $cache
|
||||
* @param array $result
|
||||
* @param array $cache The cache to use.
|
||||
* @param array $result The result array to fill.
|
||||
*/
|
||||
protected function _hydrateRow(array $data, array &$cache, array &$result)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
@ -43,6 +41,7 @@ class SingleScalarHydrator extends AbstractHydrator
|
||||
} else if ($num > 1 || count($result[key($result)]) > 1) {
|
||||
throw new \Doctrine\ORM\NonUniqueResultException;
|
||||
}
|
||||
|
||||
$result = $this->_gatherScalarRowData($result[key($result)], $cache);
|
||||
|
||||
return array_shift($result);
|
||||
|
@ -32,6 +32,7 @@ namespace Doctrine\ORM\Mapping;
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
|
||||
*/
|
||||
abstract class AssociationMapping
|
||||
{
|
||||
@ -58,7 +59,7 @@ abstract class AssociationMapping
|
||||
public $isCascadeRemove;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Whether the association cascades save() operations from the source entity
|
||||
* READ-ONLY: Whether the association cascades persist() operations from the source entity
|
||||
* to the target entity/entities.
|
||||
*
|
||||
* @var boolean
|
||||
@ -340,5 +341,59 @@ abstract class AssociationMapping
|
||||
? $platform->quoteIdentifier($this->joinTable['name'])
|
||||
: $this->joinTable['name'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return array The names of all the fields that should be serialized.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
$serialized = array(
|
||||
'sourceEntityName',
|
||||
'targetEntityName',
|
||||
'sourceFieldName',
|
||||
'fetchMode'
|
||||
);
|
||||
|
||||
if ($this->isCascadeDetach) {
|
||||
$serialized[] = 'isCascadeDetach';
|
||||
}
|
||||
if ($this->isCascadeMerge) {
|
||||
$serialized[] = 'isCascadeMerge';
|
||||
}
|
||||
if ($this->isCascadePersist) {
|
||||
$serialized[] = 'isCascadePersist';
|
||||
}
|
||||
if ($this->isCascadeRefresh) {
|
||||
$serialized[] = 'isCascadeRefresh';
|
||||
}
|
||||
if ($this->isCascadeRemove) {
|
||||
$serialized[] = 'isCascadeRemove';
|
||||
}
|
||||
if ( ! $this->isOwningSide) {
|
||||
$serialized[] = 'isOwningSide';
|
||||
}
|
||||
if ($this->mappedBy) {
|
||||
$serialized[] = 'mappedBy';
|
||||
}
|
||||
if ($this->inversedBy) {
|
||||
$serialized[] = 'inversedBy';
|
||||
}
|
||||
if ($this->joinTable) {
|
||||
$serialized[] = 'joinTable';
|
||||
}
|
||||
if ($this->inherited) {
|
||||
$serialized[] = 'inherited';
|
||||
}
|
||||
if ($this->declared) {
|
||||
$serialized[] = 'declared';
|
||||
}
|
||||
|
||||
return $serialized;
|
||||
}
|
||||
}
|
||||
|
@ -41,13 +41,6 @@ use ReflectionClass, ReflectionProperty;
|
||||
*/
|
||||
class ClassMetadata extends ClassMetadataInfo
|
||||
{
|
||||
/**
|
||||
* The ReflectionClass instance of the mapped class.
|
||||
*
|
||||
* @var ReflectionClass
|
||||
*/
|
||||
public $reflClass;
|
||||
|
||||
/**
|
||||
* The ReflectionProperty instances of the mapped class.
|
||||
*
|
||||
@ -76,16 +69,6 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
$this->table['name'] = $this->reflClass->getShortName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ReflectionClass instance of the mapped class.
|
||||
*
|
||||
* @return ReflectionClass
|
||||
*/
|
||||
public function getReflectionClass()
|
||||
{
|
||||
return $this->reflClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ReflectionPropertys of the mapped class.
|
||||
*
|
||||
@ -264,8 +247,12 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
|
||||
/**
|
||||
* 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 NOT serialized because they can not be properly unserialized:
|
||||
* Parts that are also NOT serialized because they can not be properly unserialized:
|
||||
* - reflClass (ReflectionClass)
|
||||
* - reflFields (ReflectionProperty array)
|
||||
*
|
||||
@ -273,31 +260,57 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
return array(
|
||||
'associationMappings', // unserialization "bottleneck" with many associations
|
||||
'changeTrackingPolicy',
|
||||
// This metadata is always serialized/cached.
|
||||
$serialized = array(
|
||||
'associationMappings',
|
||||
'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName']
|
||||
'customRepositoryClassName',
|
||||
'discriminatorColumn',
|
||||
'discriminatorValue',
|
||||
'discriminatorMap',
|
||||
'fieldMappings',//TODO: Not all of this stuff needs to be serialized. Only type, columnName and fieldName.
|
||||
'fieldNames',
|
||||
'generatorType',
|
||||
'fieldMappings',
|
||||
'fieldNames',
|
||||
'identifier',
|
||||
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
|
||||
'inheritanceType',
|
||||
'isIdentifierComposite',
|
||||
'isMappedSuperclass',
|
||||
'isVersioned',
|
||||
'lifecycleCallbacks',
|
||||
'isIdentifierComposite', // TODO: REMOVE
|
||||
'name',
|
||||
'parentClasses',
|
||||
'namespace', // TODO: REMOVE
|
||||
'table',
|
||||
'rootEntityName',
|
||||
'subClasses',
|
||||
'versionField'
|
||||
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
|
||||
);
|
||||
|
||||
// The rest of the metadata is only serialized if necessary.
|
||||
if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) {
|
||||
$serialized[] = 'changeTrackingPolicy';
|
||||
}
|
||||
|
||||
if ($this->customRepositoryClassName) {
|
||||
$serialized[] = 'customRepositoryClassName';
|
||||
}
|
||||
|
||||
if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) {
|
||||
$serialized[] = 'inheritanceType';
|
||||
$serialized[] = 'discriminatorColumn';
|
||||
$serialized[] = 'discriminatorValue';
|
||||
$serialized[] = 'discriminatorMap';
|
||||
$serialized[] = 'parentClasses';
|
||||
$serialized[] = 'subClasses';
|
||||
}
|
||||
|
||||
if ($this->generatorType != self::GENERATOR_TYPE_NONE) {
|
||||
$serialized[] = 'generatorType';
|
||||
}
|
||||
|
||||
if ($this->isMappedSuperclass) {
|
||||
$serialized[] = 'isMappedSuperclass';
|
||||
}
|
||||
|
||||
if ($this->isVersioned) {
|
||||
$serialized[] = 'isVersioned';
|
||||
$serialized[] = 'versionField';
|
||||
}
|
||||
|
||||
if ($this->lifecycleCallbacks) {
|
||||
$serialized[] = 'lifecycleCallbacks';
|
||||
}
|
||||
|
||||
return $serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
|
||||
* of an entity and it's associations.
|
||||
@ -366,6 +368,13 @@ class ClassMetadataInfo
|
||||
*/
|
||||
public $versionField;
|
||||
|
||||
/**
|
||||
* The ReflectionClass instance of the mapped class.
|
||||
*
|
||||
* @var ReflectionClass
|
||||
*/
|
||||
public $reflClass;
|
||||
|
||||
/**
|
||||
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
|
||||
* metadata of the class with the given name.
|
||||
@ -378,6 +387,19 @@ class ClassMetadataInfo
|
||||
$this->rootEntityName = $entityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ReflectionClass instance of the mapped class.
|
||||
*
|
||||
* @return ReflectionClass
|
||||
*/
|
||||
public function getReflectionClass()
|
||||
{
|
||||
if ( ! $this->reflClass) {
|
||||
$this->reflClass = new ReflectionClass($entityName);
|
||||
}
|
||||
return $this->reflClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the change tracking policy used by this class.
|
||||
*
|
||||
|
@ -143,7 +143,7 @@ class AnnotationDriver implements Driver
|
||||
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
|
||||
}
|
||||
|
||||
// Evaluate DoctrineTable annotation
|
||||
// Evaluate Table annotation
|
||||
if (isset($classAnnotations['Doctrine\ORM\Mapping\Table'])) {
|
||||
$tableAnnot = $classAnnotations['Doctrine\ORM\Mapping\Table'];
|
||||
$primaryTable = array(
|
||||
|
@ -26,12 +26,9 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
/**
|
||||
* Contract for metadata drivers.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 2.0
|
||||
* @version $Revision: 1393 $
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @todo Rename: MetadataDriver
|
||||
* @since 2.0
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @todo Rename: MetadataDriver or MappingDriver
|
||||
*/
|
||||
interface Driver
|
||||
{
|
||||
|
@ -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,14 +27,12 @@ use Doctrine\ORM\Mapping\Driver\Driver,
|
||||
* The DriverChain allows you to add multiple other mapping drivers for
|
||||
* certain namespaces
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @todo Rename: MappingDriverChain or MetadataDriverChain
|
||||
*/
|
||||
class DriverChain implements Driver
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ use Doctrine\Common\Cache\ArrayCache,
|
||||
Doctrine\ORM\Mapping\Driver\AbstractFileDriver;
|
||||
|
||||
/**
|
||||
* The PhpDriver includes php files which just populate ClassMetadataInfo
|
||||
* The PHPDriver includes php files which just populate ClassMetadataInfo
|
||||
* instances with plain php code
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
@ -43,7 +43,7 @@ use Doctrine\Common\Cache\ArrayCache,
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @todo Rename: PHPDriver
|
||||
*/
|
||||
class PhpDriver extends AbstractFileDriver
|
||||
class PHPDriver extends AbstractFileDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
122
lib/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php
Normal file
122
lib/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo,
|
||||
Doctrine\ORM\Mapping\MappingException;
|
||||
|
||||
/**
|
||||
* The StaticPHPDriver calls a static loadMetadata() method on your entity
|
||||
* classes where you can manually populate the ClassMetadata instance.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class StaticPHPDriver implements Driver
|
||||
{
|
||||
private $_paths = array();
|
||||
|
||||
public function __construct($paths)
|
||||
{
|
||||
$this->addPaths((array) $paths);
|
||||
}
|
||||
|
||||
public function addPaths(array $paths)
|
||||
{
|
||||
$this->_paths = array_unique(array_merge($this->_paths, $paths));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
|
||||
{
|
||||
call_user_func_array(array($className, 'loadMetadata'), array($metadata));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @todo Same code exists in AnnotationDriver, should we re-use it somehow or not worry about it?
|
||||
*/
|
||||
public function getAllClassNames()
|
||||
{
|
||||
if ($this->_classNames !== null) {
|
||||
return $this->_classNames;
|
||||
}
|
||||
|
||||
if (!$this->_paths) {
|
||||
throw MappingException::pathRequired();
|
||||
}
|
||||
|
||||
$classes = array();
|
||||
$includedFiles = array();
|
||||
|
||||
foreach ($this->_paths as $path) {
|
||||
if ( ! is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath();
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($path),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
if (($fileName = $file->getBasename($this->_fileExtension)) == $file->getBasename()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sourceFile = realpath($file->getPathName());
|
||||
require_once $sourceFile;
|
||||
$includedFiles[] = $sourceFile;
|
||||
}
|
||||
}
|
||||
|
||||
$declared = get_declared_classes();
|
||||
|
||||
foreach ($declared as $className) {
|
||||
$rc = new \ReflectionClass($className);
|
||||
$sourceFile = $rc->getFileName();
|
||||
if (in_array($sourceFile, $includedFiles) && ! $this->isTransient($className)) {
|
||||
$classes[] = $className;
|
||||
}
|
||||
}
|
||||
|
||||
$this->_classNames = $classes;
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isTransient($className)
|
||||
{
|
||||
return method_exists($className, 'loadMetadata') ? false : true;
|
||||
}
|
||||
}
|
@ -118,15 +118,17 @@ class XmlDriver extends AbstractFileDriver
|
||||
// Evaluate <unique-constraints..>
|
||||
if (isset($xmlRoot->{'unique-constraints'})) {
|
||||
foreach ($xmlRoot->{'unique-constraints'}->{'unique-constraint'} as $unique) {
|
||||
if (is_string($unique['columns'])) {
|
||||
$columns = explode(',', $unique['columns']);
|
||||
$columns = explode(',', (string)$unique['columns']);
|
||||
|
||||
if (isset($unique['name'])) {
|
||||
$metadata->table['uniqueConstraints'][(string)$unique['name']] = array(
|
||||
'columns' => $columns
|
||||
);
|
||||
} else {
|
||||
$columns = $unique['columns'];
|
||||
$metadata->table['uniqueConstraints'][] = array(
|
||||
'columns' => $columns
|
||||
);
|
||||
}
|
||||
|
||||
$metadata->table['uniqueConstraints'][$unique['name']] = array(
|
||||
'columns' => $columns
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,9 +205,9 @@ class XmlDriver extends AbstractFileDriver
|
||||
if (isset($idElement->{'sequence-generator'})) {
|
||||
$seqGenerator = $idElement->{'sequence-generator'};
|
||||
$metadata->setSequenceGeneratorDefinition(array(
|
||||
'sequenceName' => $seqGenerator->{'sequence-name'},
|
||||
'allocationSize' => $seqGenerator->{'allocation-size'},
|
||||
'initialValue' => $seqGeneratorAnnot->{'initial-value'}
|
||||
'sequenceName' => (string)$seqGenerator['sequence-name'],
|
||||
'allocationSize' => (string)$seqGenerator['allocation-size'],
|
||||
'initialValue' => (string)$seqGenerator['initial-value']
|
||||
));
|
||||
} else if (isset($idElement->{'table-generator'})) {
|
||||
throw MappingException::tableIdGeneratorNotImplemented($className);
|
||||
|
@ -135,6 +135,10 @@ class YamlDriver extends AbstractFileDriver
|
||||
if (isset($element['id'])) {
|
||||
// Evaluate identifier settings
|
||||
foreach ($element['id'] as $name => $idElement) {
|
||||
if (!isset($idElement['type'])) {
|
||||
throw MappingException::propertyTypeIsRequired($className, $name);
|
||||
}
|
||||
|
||||
$mapping = array(
|
||||
'id' => true,
|
||||
'fieldName' => $name,
|
||||
@ -151,6 +155,12 @@ class YamlDriver extends AbstractFileDriver
|
||||
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
|
||||
. strtoupper($idElement['generator']['strategy'])));
|
||||
}
|
||||
// Check for SequenceGenerator/TableGenerator definition
|
||||
if (isset($idElement['sequenceGenerator'])) {
|
||||
$metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']);
|
||||
} else if (isset($idElement['tableGenerator'])) {
|
||||
throw MappingException::tableIdGeneratorNotImplemented($className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,12 +187,6 @@ class YamlDriver extends AbstractFileDriver
|
||||
. strtoupper($fieldMapping['generator']['strategy'])));
|
||||
}
|
||||
}
|
||||
// Check for SequenceGenerator/TableGenerator definition
|
||||
if (isset($fieldMapping['sequenceGenerator'])) {
|
||||
$metadata->setSequenceGeneratorDefinition($fieldMapping['sequenceGenerator']);
|
||||
} else if (isset($fieldMapping['tableGenerator'])) {
|
||||
throw MappingException::tableIdGeneratorNotImplemented($className);
|
||||
}
|
||||
if (isset($fieldMapping['column'])) {
|
||||
$mapping['columnName'] = $fieldMapping['column'];
|
||||
}
|
||||
|
@ -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
|
||||
@ -39,6 +37,7 @@ namespace Doctrine\ORM\Mapping;
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
|
||||
*/
|
||||
class ManyToManyMapping extends AssociationMapping
|
||||
{
|
||||
@ -142,39 +141,11 @@ class ManyToManyMapping extends AssociationMapping
|
||||
* @param object The owner of the collection.
|
||||
* @param object The collection to populate.
|
||||
* @param array
|
||||
* @todo Remove
|
||||
*/
|
||||
public function load($sourceEntity, $targetCollection, $em, array $joinColumnValues = array())
|
||||
{
|
||||
$sourceClass = $em->getClassMetadata($this->sourceEntityName);
|
||||
$joinTableConditions = array();
|
||||
if ($this->isOwningSide) {
|
||||
foreach ($this->relationToSourceKeyColumns as $relationKeyColumn => $sourceKeyColumn) {
|
||||
// getting id
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$joinTableConditions[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$owningAssoc = $em->getClassMetadata($this->targetEntityName)->associationMappings[$this->mappedBy];
|
||||
// TRICKY: since the association is inverted source and target are flipped
|
||||
foreach ($owningAssoc->relationToTargetKeyColumns as $relationKeyColumn => $sourceKeyColumn) {
|
||||
// getting id
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$joinTableConditions[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$persister = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName);
|
||||
$persister->loadManyToManyCollection($this, $joinTableConditions, $targetCollection);
|
||||
$em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->loadManyToManyCollection($this, $sourceEntity, $targetCollection);
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
@ -182,4 +153,25 @@ class ManyToManyMapping extends AssociationMapping
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return array The names of all the fields that should be serialized.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
$serialized = parent::__sleep();
|
||||
$serialized[] = 'joinTableColumns';
|
||||
$serialized[] = 'relationToSourceKeyColumns';
|
||||
$serialized[] = 'relationToTargetKeyColumns';
|
||||
if ($this->orderBy) {
|
||||
$serialized[] = 'orderBy';
|
||||
}
|
||||
return $serialized;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
@ -43,6 +41,7 @@ namespace Doctrine\ORM\Mapping;
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @since 2.0
|
||||
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
|
||||
*/
|
||||
class OneToManyMapping extends AssociationMapping
|
||||
{
|
||||
@ -101,8 +100,6 @@ class OneToManyMapping extends AssociationMapping
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
public function isOneToMany()
|
||||
{
|
||||
@ -117,23 +114,31 @@ class OneToManyMapping extends AssociationMapping
|
||||
* @param $em The EntityManager to use.
|
||||
* @param $joinColumnValues
|
||||
* @return void
|
||||
* @todo Remove
|
||||
*/
|
||||
public function load($sourceEntity, $targetCollection, $em, array $joinColumnValues = array())
|
||||
{
|
||||
$persister = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName);
|
||||
// a one-to-many is always inverse (does not have foreign key)
|
||||
$sourceClass = $em->getClassMetadata($this->sourceEntityName);
|
||||
$owningAssoc = $em->getClassMetadata($this->targetEntityName)->associationMappings[$this->mappedBy];
|
||||
// TRICKY: since the association is specular source and target are flipped
|
||||
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
|
||||
// getting id
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$conditions[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
$conditions[$targetKeyColumn] = $joinColumnValues[$sourceKeyColumn];
|
||||
}
|
||||
}
|
||||
$em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->loadOneToManyCollection($this, $sourceEntity, $targetCollection);
|
||||
}
|
||||
|
||||
$persister->loadOneToManyCollection($this, $conditions, $targetCollection);
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return array The names of all the fields that should be serialized.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
$serialized = parent::__sleep();
|
||||
if ($this->orderBy) {
|
||||
$serialized[] = 'orderBy';
|
||||
}
|
||||
if ($this->orphanRemoval) {
|
||||
$serialized[] = 'orphanRemoval';
|
||||
}
|
||||
return $serialized;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
@ -39,6 +37,7 @@ namespace Doctrine\ORM\Mapping;
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
|
||||
*/
|
||||
class OneToOneMapping extends AssociationMapping
|
||||
{
|
||||
@ -135,56 +134,32 @@ class OneToOneMapping extends AssociationMapping
|
||||
* @param object $targetEntity the entity to load data in
|
||||
* @param EntityManager $em
|
||||
* @param array $joinColumnValues Values of the join columns of $sourceEntity.
|
||||
* @todo Remove
|
||||
*/
|
||||
public function load($sourceEntity, $targetEntity, $em, array $joinColumnValues = array())
|
||||
{
|
||||
$targetClass = $em->getClassMetadata($this->targetEntityName);
|
||||
return $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->loadOneToOneEntity($this, $sourceEntity, $targetEntity, $joinColumnValues);
|
||||
}
|
||||
|
||||
if ($this->isOwningSide) {
|
||||
// Mark inverse side as fetched in the hints, otherwise the UoW would
|
||||
// try to load it in a separate query (remember: to-one inverse sides can not be lazy).
|
||||
$hints = array();
|
||||
if ($this->inversedBy) {
|
||||
$hints['fetched'][$targetClass->name][$this->inversedBy] = true;
|
||||
if ($targetClass->subClasses) {
|
||||
foreach ($targetClass->subClasses as $targetSubclassName) {
|
||||
$hints['fetched'][$targetSubclassName][$this->inversedBy] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* cascade read-only status
|
||||
if ($em->getUnitOfWork()->isReadOnly($sourceEntity)) {
|
||||
$hints[Query::HINT_READ_ONLY] = true;
|
||||
}
|
||||
*/
|
||||
|
||||
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($joinColumnValues, $targetEntity, $this, $hints);
|
||||
|
||||
if ($targetEntity !== null && $this->inversedBy && ! $targetClass->isCollectionValuedAssociation($this->inversedBy)) {
|
||||
$targetClass->reflFields[$this->inversedBy]->setValue($targetEntity, $sourceEntity);
|
||||
}
|
||||
} else {
|
||||
$conditions = array();
|
||||
$sourceClass = $em->getClassMetadata($this->sourceEntityName);
|
||||
$owningAssoc = $targetClass->getAssociationMapping($this->mappedBy);
|
||||
// TRICKY: since the association is specular source and target are flipped
|
||||
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$conditions[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity, $this);
|
||||
|
||||
if ($targetEntity !== null) {
|
||||
$targetClass->setFieldValue($targetEntity, $this->mappedBy, $sourceEntity);
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return array The names of all the fields that should be serialized.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
$serialized = parent::__sleep();
|
||||
$serialized[] = 'joinColumns';
|
||||
$serialized[] = 'joinColumnFieldNames';
|
||||
$serialized[] = 'sourceToTargetKeyColumns';
|
||||
$serialized[] = 'targetToSourceKeyColumns';
|
||||
if ($this->orphanRemoval) {
|
||||
$serialized[] = 'orphanRemoval';
|
||||
}
|
||||
|
||||
return $targetEntity;
|
||||
return $serialized;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?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;
|
||||
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?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;
|
||||
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
@ -361,7 +359,7 @@ final class PersistentCollection implements Collection
|
||||
$this->_em->getUnitOfWork()->scheduleOrphanRemoval($removed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $removed;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ use Doctrine\ORM\Mapping\ClassMetadata,
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class AbstractEntityInheritancePersister extends StandardEntityPersister
|
||||
abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
{
|
||||
/**
|
||||
* Map from column names to class names that declare the field the column is mapped to.
|
||||
@ -91,7 +91,7 @@ abstract class AbstractEntityInheritancePersister extends StandardEntityPersiste
|
||||
protected function _getSelectColumnSQL($field, ClassMetadata $class)
|
||||
{
|
||||
$columnName = $class->columnNames[$field];
|
||||
$sql = $this->_getSQLTableAlias($class) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$sql = $this->_getSQLTableAlias($class->name) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
|
||||
if ( ! isset($this->_resultColumnNames[$columnAlias])) {
|
||||
$this->_resultColumnNames[$columnAlias] = $columnName;
|
||||
|
@ -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
|
||||
@ -28,19 +26,52 @@ use PDO,
|
||||
Doctrine\ORM\EntityManager,
|
||||
Doctrine\ORM\Query,
|
||||
Doctrine\ORM\PersistentCollection,
|
||||
Doctrine\ORM\Mapping\ClassMetadata;
|
||||
Doctrine\ORM\Mapping\MappingException,
|
||||
Doctrine\ORM\Mapping\ClassMetadata,
|
||||
Doctrine\ORM\Mapping\OneToOneMapping,
|
||||
Doctrine\ORM\Mapping\OneToManyMapping,
|
||||
Doctrine\ORM\Mapping\ManyToManyMapping;
|
||||
|
||||
/**
|
||||
* A basic entity persister that maps an entity with no (mapped) inheritance to a single table
|
||||
* in the relational database.
|
||||
* A BasicEntityPersiter maps an entity to a single table in a relational database.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @since 2.0
|
||||
* @todo Rename: BasicEntityPersister
|
||||
* A persister is always responsible for a single entity type.
|
||||
*
|
||||
* EntityPersisters are used during a UnitOfWork to apply any changes to the persistent
|
||||
* state of entities onto a relational database when the UnitOfWork is committed,
|
||||
* as well as for basic querying of entities and their associations (not DQL).
|
||||
*
|
||||
* The persisting operations that are invoked during a commit of a UnitOfWork to
|
||||
* persist the persistent entity state are:
|
||||
*
|
||||
* - {@link addInsert} : To schedule an entity for insertion.
|
||||
* - {@link executeInserts} : To execute all scheduled insertions.
|
||||
* - {@link update} : To update the persistent state of an entity.
|
||||
* - {@link delete} : To delete the persistent state of an entity.
|
||||
*
|
||||
* As can be seen from the above list, insertions are batched and executed all at once
|
||||
* for increased efficiency.
|
||||
*
|
||||
* The querying operations invoked during a UnitOfWork, either through direct find
|
||||
* requests or lazy-loading, are the following:
|
||||
*
|
||||
* - {@link load} : Loads (the state of) a single, managed entity.
|
||||
* - {@link loadAll} : Loads multiple, managed entities.
|
||||
* - {@link loadOneToOneEntity} : Loads a one/many-to-one association (lazy-loading).
|
||||
* - {@link loadOneToManyCollection} : Loads a one-to-many association (lazy-loading).
|
||||
* - {@link loadManyToManyCollection} : Loads a many-to-many association (lazy-loading).
|
||||
*
|
||||
* The BasicEntityPersister implementation provides the default behavior for
|
||||
* persisting and querying entities that are mapped to a single database table.
|
||||
*
|
||||
* Subclasses can be created to provide custom persisting and querying strategies,
|
||||
* i.e. spanning multiple tables.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class StandardEntityPersister
|
||||
class BasicEntityPersister
|
||||
{
|
||||
/**
|
||||
* Metadata object that describes the mapping of the mapped entity class.
|
||||
@ -50,16 +81,16 @@ class StandardEntityPersister
|
||||
protected $_class;
|
||||
|
||||
/**
|
||||
* The underlying Connection of the used EntityManager.
|
||||
* The underlying DBAL Connection of the used EntityManager.
|
||||
*
|
||||
* @var Doctrine\DBAL\Connection $conn
|
||||
*/
|
||||
protected $_conn;
|
||||
|
||||
|
||||
/**
|
||||
* The database platform.
|
||||
*
|
||||
* @var AbstractPlatform
|
||||
* @var Doctrine\DBAL\Platforms\AbstractPlatform
|
||||
*/
|
||||
protected $_platform;
|
||||
|
||||
@ -87,8 +118,8 @@ class StandardEntityPersister
|
||||
protected $_resultColumnNames = array();
|
||||
|
||||
/**
|
||||
* The map of column names to DBAL mapping types of all prepared columns used when INSERTing
|
||||
* or UPDATEing an entity.
|
||||
* The map of column names to DBAL mapping types of all prepared columns used
|
||||
* when INSERTing or UPDATEing an entity.
|
||||
*
|
||||
* @var array
|
||||
* @see _prepareInsertData($entity)
|
||||
@ -127,7 +158,7 @@ class StandardEntityPersister
|
||||
protected $_sqlTableAliases = array();
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>StandardEntityPersister</tt> that uses the given EntityManager
|
||||
* 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
|
||||
@ -143,9 +174,9 @@ class StandardEntityPersister
|
||||
|
||||
/**
|
||||
* Adds an entity to the queued insertions.
|
||||
* The entity remains queued until {@link executeInserts()} is invoked.
|
||||
* The entity remains queued until {@link executeInserts} is invoked.
|
||||
*
|
||||
* @param object $entity The entitiy to queue for insertion.
|
||||
* @param object $entity The entity to queue for insertion.
|
||||
*/
|
||||
public function addInsert($entity)
|
||||
{
|
||||
@ -171,7 +202,7 @@ class StandardEntityPersister
|
||||
$idGen = $this->_class->idGenerator;
|
||||
$isPostInsertId = $idGen->isPostInsertGenerator();
|
||||
|
||||
$stmt = $this->_conn->prepare($this->getInsertSQL());
|
||||
$stmt = $this->_conn->prepare($this->_getInsertSQL());
|
||||
$tableName = $this->_class->table['name'];
|
||||
|
||||
foreach ($this->_queuedInserts as $entity) {
|
||||
@ -209,9 +240,9 @@ class StandardEntityPersister
|
||||
* by the preceding INSERT statement and assigns it back in to the
|
||||
* entities version field.
|
||||
*
|
||||
* @param $class
|
||||
* @param $entity
|
||||
* @param $id
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $class
|
||||
* @param object $entity
|
||||
* @param mixed $id
|
||||
*/
|
||||
protected function _assignDefaultVersionValue($class, $entity, $id)
|
||||
{
|
||||
@ -226,7 +257,16 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an entity.
|
||||
* Updates a managed entity. The entity is updated according to its current changeset
|
||||
* in the running UnitOfWork. If there is no changeset, nothing is updated.
|
||||
*
|
||||
* The data to update is retrieved through {@link _prepareUpdateData}.
|
||||
* Subclasses that override this method are supposed to obtain the update data
|
||||
* in the same way, through {@link _prepareUpdateData}.
|
||||
*
|
||||
* Subclasses are also supposed to take care of versioning when overriding this method,
|
||||
* if necessary. The {@link _updateTable} method can be used to apply the data retrieved
|
||||
* from {@_prepareUpdateData} on the target tables, thereby optionally applying versioning.
|
||||
*
|
||||
* @param object $entity The entity to update.
|
||||
*/
|
||||
@ -241,14 +281,14 @@ class StandardEntityPersister
|
||||
|
||||
/**
|
||||
* Performs an UPDATE statement for an entity on a specific table.
|
||||
* The UPDATE can be optionally versioned, which requires the entity to have a version field.
|
||||
* The UPDATE can optionally be versioned, which requires the entity to have a version field.
|
||||
*
|
||||
* @param object $entity The entity object being updated.
|
||||
* @param string $tableName The name of the table to apply the UPDATE on.
|
||||
* @param array $updateData The map of columns to update (column => value).
|
||||
* @param boolean $versioned Whether the UPDATE should be versioned.
|
||||
*/
|
||||
protected function _updateTable($entity, $tableName, $updateData, $versioned = false)
|
||||
protected final function _updateTable($entity, $tableName, array $updateData, $versioned = false)
|
||||
{
|
||||
$set = $params = $types = array();
|
||||
|
||||
@ -261,7 +301,7 @@ class StandardEntityPersister
|
||||
$params[] = $value;
|
||||
$types[] = $this->_columnTypes[$columnName];
|
||||
}
|
||||
|
||||
|
||||
$where = array();
|
||||
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity);
|
||||
foreach ($this->_class->identifier as $idField) {
|
||||
@ -284,7 +324,7 @@ class StandardEntityPersister
|
||||
$types[] = $this->_class->fieldMappings[$versionField]['type'];
|
||||
}
|
||||
|
||||
$sql = 'UPDATE ' . $tableName . ' SET ' . implode(', ', $set)
|
||||
$sql = "UPDATE $tableName SET " . implode(', ', $set)
|
||||
. ' WHERE ' . implode(' = ? AND ', $where) . ' = ?';
|
||||
|
||||
$result = $this->_conn->executeUpdate($sql, $params, $types);
|
||||
@ -295,7 +335,12 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an entity.
|
||||
* Deletes a managed entity.
|
||||
*
|
||||
* The entity to delete must be managed and have a persistent identifier.
|
||||
* The deletion happens instantaneously.
|
||||
*
|
||||
* Subclasses may override this method to customize the semantics of entity deletion.
|
||||
*
|
||||
* @param object $entity The entity to delete.
|
||||
*/
|
||||
@ -319,7 +364,9 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the data changeset of an entity for database insertion.
|
||||
* Prepares the changeset of an entity for database insertion (UPDATE).
|
||||
*
|
||||
* The changeset is obtained from the currently running UnitOfWork.
|
||||
*
|
||||
* During this preparation the array that is passed as the second parameter is filled with
|
||||
* <columnName> => <value> pairs, grouped by table name.
|
||||
@ -333,8 +380,6 @@ class StandardEntityPersister
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* Notes to inheritors: Be sure to call <code>parent::_prepareData($entity, $result, $isInsert);</code>
|
||||
*
|
||||
* @param object $entity The entity for which to prepare the data.
|
||||
* @return array The prepared data.
|
||||
*/
|
||||
@ -348,7 +393,7 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
foreach ($uow->getEntityChangeSet($entity) as $field => $change) {
|
||||
if ($versioned && $versionField == $field) {
|
||||
if ($versioned && $versionField == $field) { //TODO: Needed?
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -356,9 +401,9 @@ class StandardEntityPersister
|
||||
$newVal = $change[1];
|
||||
|
||||
if (isset($this->_class->associationMappings[$field])) {
|
||||
$assocMapping = $this->_class->associationMappings[$field];
|
||||
$assoc = $this->_class->associationMappings[$field];
|
||||
// Only owning side of x-1 associations can have a FK column.
|
||||
if ( ! $assocMapping->isOwningSide || ! $assocMapping->isOneToOne()) {
|
||||
if ( ! $assoc->isOwningSide || ! $assoc->isOneToOne()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -379,10 +424,10 @@ class StandardEntityPersister
|
||||
$newValId = $uow->getEntityIdentifier($newVal);
|
||||
}
|
||||
|
||||
$targetClass = $this->_em->getClassMetadata($assocMapping->targetEntityName);
|
||||
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
|
||||
$owningTable = $this->getOwningTable($field);
|
||||
|
||||
foreach ($assocMapping->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
|
||||
foreach ($assoc->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
|
||||
if ($newVal === null) {
|
||||
$result[$owningTable][$sourceColumn] = null;
|
||||
} else {
|
||||
@ -399,6 +444,16 @@ class StandardEntityPersister
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the data changeset of a managed entity for database insertion (initial INSERT).
|
||||
* The changeset of the entity is obtained from the currently running UnitOfWork.
|
||||
*
|
||||
* The default insert data preparation is the same as for updates.
|
||||
*
|
||||
* @param object $entity The entity for which to prepare the data.
|
||||
* @return array The prepared data for the tables to update.
|
||||
* @see _prepareUpdateData
|
||||
*/
|
||||
protected function _prepareInsertData($entity)
|
||||
{
|
||||
return $this->_prepareUpdateData($entity);
|
||||
@ -407,8 +462,12 @@ class StandardEntityPersister
|
||||
/**
|
||||
* Gets the name of the table that owns the column the given field is mapped to.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @return string
|
||||
* The default implementation in BasicEntityPersister always returns the name
|
||||
* of the table the entity type of this persister is mapped to, since an entity
|
||||
* is always persisted to a single table with a BasicEntityPersister.
|
||||
*
|
||||
* @param string $fieldName The field name.
|
||||
* @return string The table name.
|
||||
*/
|
||||
public function getOwningTable($fieldName)
|
||||
{
|
||||
@ -424,13 +483,13 @@ class StandardEntityPersister
|
||||
* @param $assoc The association that connects the entity to load to another entity, if any.
|
||||
* @param array $hints Hints for entity creation.
|
||||
* @param int $lockMode
|
||||
* @return The loaded entity instance or NULL if the entity/the data can not be found.
|
||||
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
|
||||
* @todo Check identity map? loadById method? Try to guess whether $criteria is the id?
|
||||
*/
|
||||
public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = 0)
|
||||
{
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, null, $lockMode);
|
||||
$params = array_values($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, $lockMode);
|
||||
$stmt = $this->_conn->executeQuery($sql, array_values($criteria));
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
@ -438,17 +497,80 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes an entity.
|
||||
* Loads an entity of this persister's mapped class as part of a single-valued
|
||||
* association from another entity.
|
||||
*
|
||||
* @param OneToOneMapping $assoc The association to load.
|
||||
* @param object $sourceEntity The entity that owns the association (not necessarily the "owning side").
|
||||
* @param object $targetEntity The existing ghost entity (proxy) to load, if any.
|
||||
* @param array $identifier The identifier of the entity to load. Must be provided if
|
||||
* the association to load represents the owning side, otherwise
|
||||
* the identifier is derived from the $sourceEntity.
|
||||
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
|
||||
*/
|
||||
public function loadOneToOneEntity(OneToOneMapping $assoc, $sourceEntity, $targetEntity, array $identifier = array())
|
||||
{
|
||||
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
|
||||
|
||||
if ($assoc->isOwningSide) {
|
||||
// Mark inverse side as fetched in the hints, otherwise the UoW would
|
||||
// try to load it in a separate query (remember: to-one inverse sides can not be lazy).
|
||||
$hints = array();
|
||||
if ($assoc->inversedBy) {
|
||||
$hints['fetched'][$targetClass->name][$assoc->inversedBy] = true;
|
||||
if ($targetClass->subClasses) {
|
||||
foreach ($targetClass->subClasses as $targetSubclassName) {
|
||||
$hints['fetched'][$targetSubclassName][$assoc->inversedBy] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* cascade read-only status
|
||||
if ($this->_em->getUnitOfWork()->isReadOnly($sourceEntity)) {
|
||||
$hints[Query::HINT_READ_ONLY] = true;
|
||||
}
|
||||
*/
|
||||
|
||||
$targetEntity = $this->load($identifier, $targetEntity, $assoc, $hints);
|
||||
|
||||
// Complete bidirectional association, if necessary
|
||||
if ($targetEntity !== null && $assoc->inversedBy && ! $targetClass->isCollectionValuedAssociation($assoc->inversedBy)) {
|
||||
$targetClass->reflFields[$assoc->inversedBy]->setValue($targetEntity, $sourceEntity);
|
||||
}
|
||||
} else {
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc->sourceEntityName);
|
||||
$owningAssoc = $targetClass->getAssociationMapping($assoc->mappedBy);
|
||||
// TRICKY: since the association is specular source and target are flipped
|
||||
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$identifier[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$targetEntity = $this->load($identifier, $targetEntity, $assoc);
|
||||
|
||||
if ($targetEntity !== null) {
|
||||
$targetClass->setFieldValue($targetEntity, $assoc->mappedBy, $sourceEntity);
|
||||
}
|
||||
}
|
||||
|
||||
return $targetEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes a managed entity.
|
||||
*
|
||||
* @param array $id The identifier of the entity as an associative array from column names to values.
|
||||
* @param array $id The identifier of the entity as an associative array from
|
||||
* column or field names to values.
|
||||
* @param object $entity The entity to refresh.
|
||||
*/
|
||||
public function refresh(array $id, $entity)
|
||||
{
|
||||
$sql = $this->_getSelectEntitiesSQL($id);
|
||||
$params = array_values($id);
|
||||
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
$stmt = $this->_conn->executeQuery($sql, array_values($id));
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
@ -528,10 +650,8 @@ class StandardEntityPersister
|
||||
public function loadAll(array $criteria = array())
|
||||
{
|
||||
$entities = array();
|
||||
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria);
|
||||
$params = array_values($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
$stmt = $this->_conn->executeQuery($sql, array_values($criteria));
|
||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
@ -542,37 +662,44 @@ class StandardEntityPersister
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a collection of entities in a one-to-many association.
|
||||
*
|
||||
* @param OneToManyMapping $assoc
|
||||
* @param array $criteria The criteria by which to select the entities.
|
||||
* @param PersistentCollection The collection to fill.
|
||||
*/
|
||||
public function loadOneToManyCollection($assoc, array $criteria, PersistentCollection $coll)
|
||||
{
|
||||
$owningAssoc = $this->_class->associationMappings[$coll->getMapping()->mappedBy];
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $owningAssoc, $assoc->orderBy);
|
||||
$params = array_values($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$coll->hydrateAdd($this->_createEntity($result));
|
||||
}
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a collection of entities of a many-to-many association.
|
||||
*
|
||||
* @param ManyToManyMapping $assoc
|
||||
* @param array $criteria
|
||||
* @param ManyToManyMapping $assoc The association mapping of the association being loaded.
|
||||
* @param object $sourceEntity The entity that owns the collection.
|
||||
* @param PersistentCollection $coll The collection to fill.
|
||||
*/
|
||||
public function loadManyToManyCollection($assoc, array $criteria, PersistentCollection $coll)
|
||||
public function loadManyToManyCollection(ManyToManyMapping $assoc, $sourceEntity, PersistentCollection $coll)
|
||||
{
|
||||
$sql = $this->_getSelectManyToManyEntityCollectionSQL($assoc, $criteria);
|
||||
$params = array_values($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
$criteria = array();
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc->sourceEntityName);
|
||||
$joinTableConditions = array();
|
||||
if ($assoc->isOwningSide) {
|
||||
foreach ($assoc->relationToSourceKeyColumns as $relationKeyColumn => $sourceKeyColumn) {
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$criteria[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$owningAssoc = $this->_em->getClassMetadata($assoc->targetEntityName)->associationMappings[$assoc->mappedBy];
|
||||
// TRICKY: since the association is inverted source and target are flipped
|
||||
foreach ($owningAssoc->relationToTargetKeyColumns as $relationKeyColumn => $sourceKeyColumn) {
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$criteria[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc);
|
||||
$stmt = $this->_conn->executeQuery($sql, array_values($criteria));
|
||||
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$coll->hydrateAdd($this->_createEntity($result));
|
||||
}
|
||||
@ -614,10 +741,15 @@ class StandardEntityPersister
|
||||
/**
|
||||
* Processes an SQL result set row that contains data for an entity of the type
|
||||
* this persister is responsible for.
|
||||
*
|
||||
* Subclasses are supposed to override this method if they need to change the
|
||||
* hydration procedure for entities loaded through basic find operations or
|
||||
* lazy-loading (not DQL).
|
||||
*
|
||||
* @param array $sqlResult The SQL result set row to process.
|
||||
* @return array A tuple where the first value is the actual type of the entity and
|
||||
* the second value the prepared data of the entity.
|
||||
* the second value the prepared data of the entity (a map from field
|
||||
* names to values).
|
||||
*/
|
||||
protected function _processSQLResult(array $sqlResult)
|
||||
{
|
||||
@ -644,34 +776,18 @@ class StandardEntityPersister
|
||||
* @param string $orderBy
|
||||
* @param int $lockMode
|
||||
* @return string
|
||||
* @todo Refactor: _getSelectSQL(...)
|
||||
*/
|
||||
protected function _getSelectEntitiesSQL(array &$criteria, $assoc = null, $orderBy = null, $lockMode = 0)
|
||||
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0)
|
||||
{
|
||||
// Construct WHERE conditions
|
||||
$conditionSql = '';
|
||||
foreach ($criteria as $field => $value) {
|
||||
if ($conditionSql != '') {
|
||||
$conditionSql .= ' AND ';
|
||||
}
|
||||
|
||||
if (isset($this->_class->columnNames[$field])) {
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
} else if (isset($this->_class->fieldNames[$field])) {
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($this->_class->fieldNames[$field], $this->_platform);
|
||||
} else if ($assoc !== null) {
|
||||
$conditionSql .= $field;
|
||||
} else {
|
||||
throw ORMException::unrecognizedField($field);
|
||||
}
|
||||
$conditionSql .= ' = ?';
|
||||
}
|
||||
$joinSql = $assoc != null && $assoc->isManyToMany() ?
|
||||
$this->_getSelectManyToManyJoinSQL($assoc) : '';
|
||||
|
||||
$orderBySql = '';
|
||||
if ($orderBy !== null) {
|
||||
$orderBySql = $this->_getCollectionOrderBySQL(
|
||||
$orderBy, $this->_getSQLTableAlias($this->_class)
|
||||
);
|
||||
}
|
||||
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
|
||||
|
||||
$orderBySql = $assoc !== null && isset($assoc->orderBy) ?
|
||||
$this->_getCollectionOrderBySQL($assoc->orderBy, $this->_getSQLTableAlias($this->_class->name))
|
||||
: '';
|
||||
|
||||
$lockSql = '';
|
||||
if ($lockMode == \Doctrine\ORM\LockMode::PESSIMISTIC_READ) {
|
||||
@ -682,18 +798,22 @@ class StandardEntityPersister
|
||||
|
||||
return 'SELECT ' . $this->_getSelectColumnListSQL()
|
||||
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->_getSQLTableAlias($this->_class)
|
||||
. ($conditionSql ? ' WHERE ' . $conditionSql : '') . $orderBySql . $lockSql;
|
||||
. $this->_getSQLTableAlias($this->_class->name)
|
||||
. $joinSql
|
||||
. ($conditionSql ? ' WHERE ' . $conditionSql : '')
|
||||
. $orderBySql
|
||||
. $lockSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate ORDER BY SQL snippet for ordered collections.
|
||||
* Gets the ORDER BY SQL snippet for ordered collections.
|
||||
*
|
||||
* @param array $orderBy
|
||||
* @param string $baseTableAlias
|
||||
* @return string
|
||||
* @todo Rename: _getOrderBySQL
|
||||
*/
|
||||
protected function _getCollectionOrderBySQL(array $orderBy, $baseTableAlias)
|
||||
protected final function _getCollectionOrderBySQL(array $orderBy, $baseTableAlias)
|
||||
{
|
||||
$orderBySql = '';
|
||||
foreach ($orderBy as $fieldName => $orientation) {
|
||||
@ -702,27 +822,28 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
$tableAlias = isset($this->_class->fieldMappings[$fieldName]['inherited']) ?
|
||||
$this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->fieldMappings[$fieldName]['inherited']))
|
||||
$this->_getSQLTableAlias($this->_class->fieldMappings[$fieldName]['inherited'])
|
||||
: $baseTableAlias;
|
||||
|
||||
$columnName = $this->_class->getQuotedColumnName($fieldName, $this->_platform);
|
||||
if ($orderBySql != '') {
|
||||
$orderBySql .= ', ';
|
||||
} else {
|
||||
$orderBySql = ' ORDER BY ';
|
||||
}
|
||||
$orderBySql .= $orderBySql ? ', ' : ' ORDER BY ';
|
||||
$orderBySql .= $tableAlias . '.' . $columnName . ' ' . $orientation;
|
||||
}
|
||||
|
||||
return $orderBySql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the SQL fragment with the list of columns to select when querying for
|
||||
* an entity within this persister.
|
||||
* an entity in this persister.
|
||||
*
|
||||
* Subclasses should override this method to alter or change the select column
|
||||
* list SQL fragment. Note that in the implementation of BasicEntityPersister
|
||||
* the resulting SQL fragment is generated only once and cached in {@link _selectColumnListSql}.
|
||||
* Subclasses may or may not do the same.
|
||||
*
|
||||
* @return string The SQL fragment.
|
||||
* @todo Rename: _getSelectColumnListSQL()
|
||||
* @todo Rename: _getSelectColumnsSQL()
|
||||
*/
|
||||
protected function _getSelectColumnListSQL()
|
||||
{
|
||||
@ -734,7 +855,7 @@ class StandardEntityPersister
|
||||
|
||||
// Add regular columns to select list
|
||||
foreach ($this->_class->fieldNames as $field) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
if ($columnList) $columnList .= ', ';
|
||||
$columnList .= $this->_getSelectColumnSQL($field, $this->_class);
|
||||
}
|
||||
|
||||
@ -742,15 +863,15 @@ class StandardEntityPersister
|
||||
|
||||
return $this->_selectColumnListSql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the SQL to select a collection of entities in a many-many association.
|
||||
* Gets the SQL join fragment used when selecting entities from a
|
||||
* many-to-many association.
|
||||
*
|
||||
* @param ManyToManyMapping $manyToMany
|
||||
* @param array $criteria
|
||||
* @return string
|
||||
*/
|
||||
protected function _getSelectManyToManyEntityCollectionSQL($manyToMany, array &$criteria)
|
||||
protected function _getSelectManyToManyJoinSQL(ManyToManyMapping $manyToMany)
|
||||
{
|
||||
if ($manyToMany->isOwningSide) {
|
||||
$owningAssoc = $manyToMany;
|
||||
@ -765,32 +886,12 @@ class StandardEntityPersister
|
||||
$joinSql = '';
|
||||
foreach ($joinClauses as $joinTableColumn => $sourceColumn) {
|
||||
if ($joinSql != '') $joinSql .= ' AND ';
|
||||
$joinSql .= $this->_getSQLTableAlias($this->_class) .
|
||||
$joinSql .= $this->_getSQLTableAlias($this->_class->name) .
|
||||
'.' . $this->_class->getQuotedColumnName($this->_class->fieldNames[$sourceColumn], $this->_platform) . ' = '
|
||||
. $joinTableName . '.' . $joinTableColumn;
|
||||
}
|
||||
|
||||
$joinSql = ' INNER JOIN ' . $joinTableName . ' ON ' . $joinSql;
|
||||
|
||||
$conditionSql = '';
|
||||
foreach ($criteria as $joinColumn => $value) {
|
||||
if ($conditionSql != '') $conditionSql .= ' AND ';
|
||||
$columnName = $joinTableName . '.' . $joinColumn;
|
||||
$conditionSql .= $columnName . ' = ?';
|
||||
}
|
||||
|
||||
$orderBySql = '';
|
||||
if ($manyToMany->orderBy !== null) {
|
||||
$orderBySql = $this->_getCollectionOrderBySQL(
|
||||
$manyToMany->orderBy, $this->_getSQLTableAlias($this->_class)
|
||||
);
|
||||
}
|
||||
|
||||
return 'SELECT ' . $this->_getSelectColumnListSQL()
|
||||
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->_getSQLTableAlias($this->_class)
|
||||
. $joinSql
|
||||
. ' WHERE ' . $conditionSql . $orderBySql;
|
||||
return " INNER JOIN $joinTableName ON $joinSql";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -798,19 +899,36 @@ class StandardEntityPersister
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInsertSQL()
|
||||
protected function _getInsertSQL()
|
||||
{
|
||||
if ($this->_insertSql === null) {
|
||||
$this->_insertSql = $this->_generateInsertSQL();
|
||||
$insertSql = '';
|
||||
$columns = $this->_getInsertColumnList();
|
||||
if (empty($columns)) {
|
||||
$insertSql = $this->_platform->getEmptyIdentityInsertSQL(
|
||||
$this->_class->getQuotedTableName($this->_platform),
|
||||
$this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform)
|
||||
);
|
||||
} else {
|
||||
$columns = array_unique($columns);
|
||||
$values = array_fill(0, count($columns), '?');
|
||||
|
||||
$insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform)
|
||||
. ' (' . implode(', ', $columns) . ') '
|
||||
. 'VALUES (' . implode(', ', $values) . ')';
|
||||
}
|
||||
$this->_insertSql = $insertSql;
|
||||
}
|
||||
return $this->_insertSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of columns to put in the INSERT SQL statement.
|
||||
*
|
||||
*
|
||||
* Subclasses should override this method to alter or change the list of
|
||||
* columns placed in the INSERT statements used by the persister.
|
||||
*
|
||||
* @return array The list of columns.
|
||||
* @internal INSERT SQL is cached by getInsertSQL() per request.
|
||||
*/
|
||||
protected function _getInsertColumnList()
|
||||
{
|
||||
@ -835,33 +953,6 @@ class StandardEntityPersister
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the INSERT SQL used by the persister to persist entities.
|
||||
*
|
||||
* @return string
|
||||
* @internal Result is cached by getInsertSQL() per request.
|
||||
*/
|
||||
protected function _generateInsertSQL()
|
||||
{
|
||||
$insertSql = '';
|
||||
$columns = $this->_getInsertColumnList();
|
||||
if (empty($columns)) {
|
||||
$insertSql = $this->_platform->getEmptyIdentityInsertSQL(
|
||||
$this->_class->getQuotedTableName($this->_platform),
|
||||
$this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform)
|
||||
);
|
||||
} else {
|
||||
$columns = array_unique($columns);
|
||||
$values = array_fill(0, count($columns), '?');
|
||||
|
||||
$insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform)
|
||||
. ' (' . implode(', ', $columns) . ') '
|
||||
. 'VALUES (' . implode(', ', $values) . ')';
|
||||
}
|
||||
|
||||
return $insertSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL snippet of a qualified column name for the given field name.
|
||||
*
|
||||
@ -872,7 +963,7 @@ class StandardEntityPersister
|
||||
protected function _getSelectColumnSQL($field, ClassMetadata $class)
|
||||
{
|
||||
$columnName = $class->columnNames[$field];
|
||||
$sql = $this->_getSQLTableAlias($class) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$sql = $this->_getSQLTableAlias($class->name) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
|
||||
if ( ! isset($this->_resultColumnNames[$columnAlias])) {
|
||||
$this->_resultColumnNames[$columnAlias] = $columnName;
|
||||
@ -884,17 +975,19 @@ class StandardEntityPersister
|
||||
/**
|
||||
* Gets the SQL snippet for all join columns of the given class that are to be
|
||||
* placed in an SQL SELECT statement.
|
||||
*
|
||||
*
|
||||
* @param $class
|
||||
* @return string
|
||||
* @todo Not reused... inline?
|
||||
*/
|
||||
protected function _getSelectJoinColumnsSQL(ClassMetadata $class)
|
||||
private function _getSelectJoinColumnsSQL(ClassMetadata $class)
|
||||
{
|
||||
$sql = '';
|
||||
foreach ($class->associationMappings as $assoc) {
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
|
||||
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$sql .= ', ' . $this->_getSQLTableAlias($this->_class) . ".$srcColumn AS $columnAlias";
|
||||
$sql .= ', ' . $this->_getSQLTableAlias($this->_class->name) . ".$srcColumn AS $columnAlias";
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
if ( ! isset($this->_resultColumnNames[$resultColumnName])) {
|
||||
$this->_resultColumnNames[$resultColumnName] = $srcColumn;
|
||||
@ -907,18 +1000,19 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL table alias for the given class.
|
||||
* Gets the SQL table alias for the given class name.
|
||||
*
|
||||
* @param ClassMetadata $class
|
||||
* @param string $className
|
||||
* @return string The SQL table alias.
|
||||
* @todo Remove. Binding table aliases to class names is not such a good idea.
|
||||
*/
|
||||
protected function _getSQLTableAlias(ClassMetadata $class)
|
||||
protected function _getSQLTableAlias($className)
|
||||
{
|
||||
if (isset($this->_sqlTableAliases[$class->name])) {
|
||||
return $this->_sqlTableAliases[$class->name];
|
||||
if (isset($this->_sqlTableAliases[$className])) {
|
||||
return $this->_sqlTableAliases[$className];
|
||||
}
|
||||
$tableAlias = $class->table['name'][0] . $this->_sqlAliasCounter++;
|
||||
$this->_sqlTableAliases[$class->name] = $tableAlias;
|
||||
$tableAlias = 't' . $this->_sqlAliasCounter++;
|
||||
$this->_sqlTableAliases[$className] = $tableAlias;
|
||||
|
||||
return $tableAlias;
|
||||
}
|
||||
@ -932,24 +1026,7 @@ class StandardEntityPersister
|
||||
*/
|
||||
public function lock(array $criteria, $lockMode)
|
||||
{
|
||||
// @todo Extract method to remove duplicate code from _getSelectEntitiesSQL()?
|
||||
$conditionSql = '';
|
||||
foreach ($criteria as $field => $value) {
|
||||
if ($conditionSql != '') {
|
||||
$conditionSql .= ' AND ';
|
||||
}
|
||||
|
||||
if (isset($this->_class->columnNames[$field])) {
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
} else if (isset($this->_class->fieldNames[$field])) {
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($this->_class->fieldNames[$field], $this->_platform);
|
||||
} else if ($assoc !== null) {
|
||||
$conditionSql .= $field;
|
||||
} else {
|
||||
throw ORMException::unrecognizedField($field);
|
||||
}
|
||||
$conditionSql .= ' = ?';
|
||||
}
|
||||
$conditionSql = $this->_getSelectConditionSQL($criteria);
|
||||
|
||||
if ($lockMode == \Doctrine\ORM\LockMode::PESSIMISTIC_READ) {
|
||||
$lockSql = $this->_platform->getReadLockSql();
|
||||
@ -958,9 +1035,80 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
$sql = 'SELECT 1 FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->_getSQLTableAlias($this->_class)
|
||||
. $this->_getSQLTableAlias($this->_class->name)
|
||||
. ($conditionSql ? ' WHERE ' . $conditionSql : '') . ' ' . $lockSql;
|
||||
$params = array_values($criteria);
|
||||
$this->_conn->executeQuery($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the conditional SQL fragment used in the WHERE clause when selecting
|
||||
* entities in this persister.
|
||||
*
|
||||
* Subclasses are supposed to override this method if they intend to change
|
||||
* or alter the criteria by which entities are selected.
|
||||
*
|
||||
* @param array $criteria
|
||||
* @param AssociationMapping $assoc
|
||||
* @return string
|
||||
*/
|
||||
protected function _getSelectConditionSQL(array $criteria, $assoc = null)
|
||||
{
|
||||
$conditionSql = '';
|
||||
foreach ($criteria as $field => $value) {
|
||||
$conditionSql .= $conditionSql ? ' AND ' : '';
|
||||
|
||||
if (isset($this->_class->columnNames[$field])) {
|
||||
if (isset($this->_class->fieldMappings[$field]['inherited'])) {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->fieldMappings[$field]['inherited']) . '.';
|
||||
} else {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
|
||||
}
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
} else if ($assoc !== null) {
|
||||
if ($assoc->isManyToMany()) {
|
||||
$owningAssoc = $assoc->isOwningSide ? $assoc : $this->_em->getClassMetadata($assoc->targetEntityName)
|
||||
->associationMappings[$assoc->mappedBy];
|
||||
$conditionSql .= $owningAssoc->getQuotedJoinTableName($this->_platform) . '.' . $field;
|
||||
} else {
|
||||
$conditionSql .= $field;
|
||||
}
|
||||
} else {
|
||||
throw ORMException::unrecognizedField($field);
|
||||
}
|
||||
$conditionSql .= ' = ?';
|
||||
}
|
||||
return $conditionSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a collection of entities in a one-to-many association.
|
||||
*
|
||||
* @param OneToManyMapping $assoc
|
||||
* @param array $criteria The criteria by which to select the entities.
|
||||
* @param PersistentCollection The collection to load/fill.
|
||||
*/
|
||||
public function loadOneToManyCollection(OneToManyMapping $assoc, $sourceEntity, PersistentCollection $coll)
|
||||
{
|
||||
$criteria = array();
|
||||
$owningAssoc = $this->_class->associationMappings[$assoc->mappedBy];
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc->sourceEntityName);
|
||||
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
|
||||
$criteria[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
}
|
||||
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc);
|
||||
$params = array_values($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$coll->hydrateAdd($this->_createEntity($result));
|
||||
}
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
|
||||
//TODO
|
||||
/*protected function _getOneToOneEagerFetchSQL()
|
||||
{
|
||||
|
||||
}*/
|
||||
}
|
@ -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
|
||||
@ -21,15 +19,14 @@
|
||||
|
||||
namespace Doctrine\ORM\Persisters;
|
||||
|
||||
use Doctrine\ORM\ORMException;
|
||||
use Doctrine\ORM\ORMException,
|
||||
Doctrine\ORM\Mapping\ManyToManyMapping;
|
||||
|
||||
/**
|
||||
* The joined subclass persister maps a single entity instance to several tables in the
|
||||
* database as it is defined by the <tt>Class Table Inheritance</tt> strategy.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @see http://martinfowler.com/eaaCatalog/classTableInheritance.html
|
||||
*/
|
||||
@ -116,19 +113,19 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$this->_class : $this->_em->getClassMetadata($this->_class->rootEntityName);
|
||||
$rootPersister = $this->_em->getUnitOfWork()->getEntityPersister($rootClass->name);
|
||||
$rootTableName = $rootClass->table['name'];
|
||||
$rootTableStmt = $this->_conn->prepare($rootPersister->getInsertSQL());
|
||||
$rootTableStmt = $this->_conn->prepare($rootPersister->_getInsertSQL());
|
||||
|
||||
// Prepare statements for sub tables.
|
||||
$subTableStmts = array();
|
||||
if ($rootClass !== $this->_class) {
|
||||
$subTableStmts[$this->_class->table['name']] = $this->_conn->prepare($this->getInsertSQL());
|
||||
$subTableStmts[$this->_class->table['name']] = $this->_conn->prepare($this->_getInsertSQL());
|
||||
}
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$parentTableName = $parentClass->table['name'];
|
||||
if ($parentClass !== $rootClass) {
|
||||
$parentPersister = $this->_em->getUnitOfWork()->getEntityPersister($parentClassName);
|
||||
$subTableStmts[$parentTableName] = $this->_conn->prepare($parentPersister->getInsertSQL());
|
||||
$subTableStmts[$parentTableName] = $this->_conn->prepare($parentPersister->_getInsertSQL());
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,27 +228,30 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function _getSelectEntitiesSQL(array &$criteria, $assoc = null, $orderBy = null, $lockMode = 0)
|
||||
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0)
|
||||
{
|
||||
$idColumns = $this->_class->getIdentifierColumnNames();
|
||||
$baseTableAlias = $this->_getSQLTableAlias($this->_class);
|
||||
$baseTableAlias = $this->_getSQLTableAlias($this->_class->name);
|
||||
|
||||
// Create the column list fragment only once
|
||||
if ($this->_selectColumnListSql === null) {
|
||||
// Add regular columns
|
||||
$columnList = '';
|
||||
foreach ($this->_class->fieldMappings as $fieldName => $mapping) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
$columnList .= $this->_getSelectColumnSQL($fieldName,
|
||||
isset($mapping['inherited']) ? $this->_em->getClassMetadata($mapping['inherited']) : $this->_class);
|
||||
isset($mapping['inherited']) ?
|
||||
$this->_em->getClassMetadata($mapping['inherited']) :
|
||||
$this->_class);
|
||||
}
|
||||
|
||||
// Add foreign key columns
|
||||
foreach ($this->_class->associationMappings as $assoc) {
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
|
||||
$tableAlias = $assoc->inherited ?
|
||||
$this->_getSQLTableAlias($this->_em->getClassMetadata($assoc->inherited))
|
||||
foreach ($this->_class->associationMappings as $assoc2) {
|
||||
if ($assoc2->isOwningSide && $assoc2->isOneToOne()) {
|
||||
$tableAlias = $assoc2->inherited ?
|
||||
$this->_getSQLTableAlias($assoc2->inherited)
|
||||
: $baseTableAlias;
|
||||
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
||||
foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$columnList .= ", $tableAlias.$srcColumn AS $columnAlias";
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
@ -262,12 +262,12 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
}
|
||||
|
||||
// Add discriminator column (DO NOT ALIAS THIS COLUMN, see StandardEntityPersister#_processSQLResultInheritanceAware).
|
||||
// Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#_processSQLResult).
|
||||
$discrColumn = $this->_class->discriminatorColumn['name'];
|
||||
if ($this->_class->rootEntityName == $this->_class->name) {
|
||||
$columnList .= ", $baseTableAlias.$discrColumn";
|
||||
} else {
|
||||
$columnList .= ', ' . $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->rootEntityName))
|
||||
$columnList .= ', ' . $this->_getSQLTableAlias($this->_class->rootEntityName)
|
||||
. ".$discrColumn";
|
||||
}
|
||||
|
||||
@ -279,7 +279,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$joinSql = '';
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$tableAlias = $this->_getSQLTableAlias($parentClass);
|
||||
$tableAlias = $this->_getSQLTableAlias($parentClassName);
|
||||
$joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
foreach ($idColumns as $idColumn) {
|
||||
@ -291,7 +291,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
// OUTER JOIN sub tables
|
||||
foreach ($this->_class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
$tableAlias = $this->_getSQLTableAlias($subClass);
|
||||
$tableAlias = $this->_getSQLTableAlias($subClassName);
|
||||
|
||||
if ($this->_selectColumnListSql === null) {
|
||||
// Add subclass columns
|
||||
@ -326,27 +326,14 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
}
|
||||
|
||||
$conditionSql = '';
|
||||
foreach ($criteria as $field => $value) {
|
||||
if ($conditionSql != '') $conditionSql .= ' AND ';
|
||||
if (isset($this->_class->fieldMappings[$field]['inherited'])) {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->fieldMappings[$field]['inherited'])) . '.';
|
||||
} else {
|
||||
$conditionSql .= $baseTableAlias . '.';
|
||||
}
|
||||
if (isset($this->_class->columnNames[$field])) {
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
} else if ($assoc !== null) {
|
||||
$conditionSql .= $field;
|
||||
} else {
|
||||
throw ORMException::unrecognizedField($field);
|
||||
}
|
||||
$conditionSql .= ' = ?';
|
||||
}
|
||||
$joinSql .= $assoc != null && $assoc->isManyToMany() ?
|
||||
$this->_getSelectManyToManyJoinSQL($assoc) : '';
|
||||
|
||||
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
|
||||
|
||||
$orderBySql = '';
|
||||
if ($orderBy !== null) {
|
||||
$orderBySql = $this->_getCollectionOrderBySQL($orderBy, $baseTableAlias);
|
||||
if ($assoc != null && isset($assoc->orderBy)) {
|
||||
$orderBySql = $this->_getCollectionOrderBySQL($assoc->orderBy, $baseTableAlias);
|
||||
}
|
||||
|
||||
if ($this->_selectColumnListSql === null) {
|
||||
@ -358,11 +345,23 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
. $joinSql
|
||||
. ($conditionSql != '' ? ' WHERE ' . $conditionSql : '') . $orderBySql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock all rows of this entity matching the given criteria with the specified pessimistic lock mode
|
||||
*
|
||||
* @param array $criteria
|
||||
* @param int $lockMode
|
||||
* @return void
|
||||
*/
|
||||
public function lock(array $criteria, $lockMode)
|
||||
{
|
||||
throw new \BadMethodCallException("lock() is not yet supported for JoinedSubclassPersister");
|
||||
}
|
||||
|
||||
/** Ensure this method is never called. This persister overrides _getSelectEntitiesSQL directly. */
|
||||
/* Ensure this method is never called. This persister overrides _getSelectEntitiesSQL directly. */
|
||||
protected function _getSelectColumnListSQL()
|
||||
{
|
||||
throw new \BadMethodCallException("Illegal invocation of ".__METHOD__." on JoinedSubclassPersister.");
|
||||
throw new \BadMethodCallException("Illegal invocation of ".__METHOD__.".");
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
@ -398,17 +397,4 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL to select a collection of entities in a many-many association.
|
||||
*
|
||||
* @param ManyToManyMapping $manyToMany
|
||||
* @param array $criteria
|
||||
* @return string
|
||||
*/
|
||||
protected function _getSelectManyToManyEntityCollectionSQL($manyToMany, array &$criteria)
|
||||
{
|
||||
// @todo
|
||||
throw new \BadMethodCallException("Not yet implemented, see http://www.doctrine-project.org/jira/browse/DDC-342");
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
* SINGLE_TABLE strategy.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @since 2.0
|
||||
* @link http://martinfowler.com/eaaCatalog/singleTableInheritance.html
|
||||
*/
|
||||
@ -42,24 +41,25 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
protected function _getSelectColumnListSQL()
|
||||
{
|
||||
$columnList = parent::_getSelectColumnListSQL();
|
||||
|
||||
// Append discriminator column
|
||||
$discrColumn = $this->_class->discriminatorColumn['name'];
|
||||
$columnList .= ", $discrColumn";
|
||||
$rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName);
|
||||
$tableAlias = $this->_getSQLTableAlias($rootClass);
|
||||
$tableAlias = $this->_getSQLTableAlias($rootClass->name);
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($discrColumn);
|
||||
$this->_resultColumnNames[$resultColumnName] = $discrColumn;
|
||||
|
||||
// Append subclass columns
|
||||
foreach ($this->_class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
// Append subclass columns
|
||||
// Regular columns
|
||||
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
|
||||
if ( ! isset($mapping['inherited'])) {
|
||||
$columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass);
|
||||
}
|
||||
}
|
||||
|
||||
// Append subclass foreign keys
|
||||
// Foreign key columns
|
||||
foreach ($subClass->associationMappings as $assoc) {
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne() && ! $assoc->inherited) {
|
||||
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
||||
@ -88,14 +88,27 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function _getSQLTableAlias(ClassMetadata $class)
|
||||
protected function _getSQLTableAlias($className)
|
||||
{
|
||||
if (isset($this->_sqlTableAliases[$class->rootEntityName])) {
|
||||
return $this->_sqlTableAliases[$class->rootEntityName];
|
||||
}
|
||||
$tableAlias = $this->_em->getClassMetadata($class->rootEntityName)->table['name'][0] . $this->_sqlAliasCounter++;
|
||||
$this->_sqlTableAliases[$class->rootEntityName] = $tableAlias;
|
||||
return parent::_getSQLTableAlias($this->_class->rootEntityName);
|
||||
}
|
||||
|
||||
return $tableAlias;
|
||||
/** {@inheritdoc} */
|
||||
protected function _getSelectConditionSQL(array $criteria, $assoc = null)
|
||||
{
|
||||
$conditionSql = parent::_getSelectConditionSQL($criteria, $assoc);
|
||||
|
||||
// Append discriminator condition
|
||||
if ($conditionSql) $conditionSql .= ' AND ';
|
||||
$values = array($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;
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Persisters;
|
||||
|
||||
class UnionSubclassPersister extends StandardEntityPersister
|
||||
class UnionSubclassPersister extends BasicEntityPersister
|
||||
{
|
||||
|
||||
}
|
@ -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
|
||||
@ -44,13 +42,13 @@ class ProxyFactory
|
||||
private $_proxyDir;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the <tt>ProxyFactory</tt> class that is
|
||||
* connected to the given <tt>EntityManager</tt>.
|
||||
*
|
||||
* @param EntityManager $em The EntityManager the new factory works for.
|
||||
* @param string $proxyDir The directory to use for the proxy classes. It must exist.
|
||||
* @param string $proxyNs The namespace to use for the proxy classes.
|
||||
* @param boolean $autoGenerate Whether to automatically generate proxy classes.
|
||||
* Initializes a new instance of the <tt>ProxyFactory</tt> class that is
|
||||
* connected to the given <tt>EntityManager</tt>.
|
||||
*
|
||||
* @param EntityManager $em The EntityManager the new factory works for.
|
||||
* @param string $proxyDir The directory to use for the proxy classes. It must exist.
|
||||
* @param string $proxyNs The namespace to use for the proxy classes.
|
||||
* @param boolean $autoGenerate Whether to automatically generate proxy classes.
|
||||
*/
|
||||
public function __construct(EntityManager $em, $proxyDir, $proxyNs, $autoGenerate = false)
|
||||
{
|
||||
@ -240,7 +238,7 @@ class ProxyFactory
|
||||
return $sleepImpl;
|
||||
}
|
||||
|
||||
/** Reference Proxy class code template */
|
||||
/** Proxy class code template */
|
||||
private static $_proxyClassTemplate =
|
||||
'<?php
|
||||
|
||||
|
@ -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
|
||||
@ -31,10 +29,7 @@ namespace Doctrine\ORM\Query\AST;
|
||||
* SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField
|
||||
* SimpleStateFieldAssociationPathExpression ::= SingleValuedAssociationPathExpression "." StateField
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
|
@ -58,7 +58,7 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
||||
$primaryDqlAlias = $AST->deleteClause->aliasIdentificationVariable;
|
||||
$rootClass = $em->getClassMetadata($primaryClass->rootEntityName);
|
||||
|
||||
$tempTable = $rootClass->getTemporaryIdTableName();
|
||||
$tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName());
|
||||
$idColumnNames = $rootClass->getIdentifierColumnNames();
|
||||
$idColumnList = implode(', ', $idColumnNames);
|
||||
|
||||
@ -95,8 +95,7 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
||||
);
|
||||
}
|
||||
$this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' ('
|
||||
. $platform->getColumnDeclarationListSQL($columnDefinitions)
|
||||
. ', PRIMARY KEY(' . $idColumnList . '))';
|
||||
. $platform->getColumnDeclarationListSQL($columnDefinitions) . ')';
|
||||
$this->_dropTempTableSql = 'DROP TABLE ' . $tempTable;
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
||||
|
||||
$updateItems = $updateClause->updateItems;
|
||||
|
||||
$tempTable = $rootClass->getTemporaryIdTableName();
|
||||
$tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName());
|
||||
$idColumnNames = $rootClass->getIdentifierColumnNames();
|
||||
$idColumnList = implode(', ', $idColumnNames);
|
||||
|
||||
@ -126,8 +126,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
||||
);
|
||||
}
|
||||
$this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' ('
|
||||
. $platform->getColumnDeclarationListSQL($columnDefinitions)
|
||||
. ', PRIMARY KEY(' . $idColumnList . '))';
|
||||
. $platform->getColumnDeclarationListSQL($columnDefinitions) . ')';
|
||||
$this->_dropTempTableSql = 'DROP TABLE ' . $tempTable;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
@ -27,10 +25,7 @@ use Doctrine\ORM\Query;
|
||||
* An LL(*) recursive-descent parser for the context-free grammar of the Doctrine Query Language.
|
||||
* Parses a DQL query, reports any errors in it, and generates an AST.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -208,12 +203,15 @@ class Parser
|
||||
// Process any deferred validations of some nodes in the AST.
|
||||
// This also allows post-processing of the AST for modification purposes.
|
||||
$this->_processDeferredIdentificationVariables();
|
||||
|
||||
if ($this->_deferredPartialObjectExpressions) {
|
||||
$this->_processDeferredPartialObjectExpressions();
|
||||
}
|
||||
|
||||
if ($this->_deferredPathExpressions) {
|
||||
$this->_processDeferredPathExpressions($AST);
|
||||
}
|
||||
|
||||
if ($this->_deferredResultVariables) {
|
||||
$this->_processDeferredResultVariables();
|
||||
}
|
||||
@ -461,7 +459,7 @@ class Parser
|
||||
// Check if IdentificationVariable exists in queryComponents
|
||||
if ( ! isset($this->_queryComponents[$identVariable])) {
|
||||
$this->semanticalError(
|
||||
"'$identVariable' is not defined.", $deferredItem['token']
|
||||
"'$identVariable' is not defined.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
@ -470,14 +468,14 @@ class Parser
|
||||
// Check if queryComponent points to an AbstractSchemaName or a ResultVariable
|
||||
if ( ! isset($qComp['metadata'])) {
|
||||
$this->semanticalError(
|
||||
"'$identVariable' does not point to a Class.", $deferredItem['token']
|
||||
"'$identVariable' does not point to a Class.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
// Validate if identification variable nesting level is lower or equal than the current one
|
||||
if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) {
|
||||
$this->semanticalError(
|
||||
"'$identVariable' is used outside the scope of its declaration.", $deferredItem['token']
|
||||
"'$identVariable' is used outside the scope of its declaration.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -491,15 +489,15 @@ class Parser
|
||||
foreach ($expr->partialFieldSet as $field) {
|
||||
if ( ! isset($class->fieldMappings[$field])) {
|
||||
$this->semanticalError(
|
||||
"There is no mapped field named '$field' on class " . $class->name . ".",
|
||||
$deferredItem['token']
|
||||
"There is no mapped field named '$field' on class " . $class->name . ".",
|
||||
$deferredItem['token']
|
||||
);
|
||||
}
|
||||
}
|
||||
if (array_intersect($class->identifier, $expr->partialFieldSet) != $class->identifier) {
|
||||
$this->semanticalError(
|
||||
"The partial field selection of class " . $class->name . " must contain the identifier.",
|
||||
$deferredItem['token']
|
||||
"The partial field selection of class " . $class->name . " must contain the identifier.",
|
||||
$deferredItem['token']
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -519,7 +517,7 @@ class Parser
|
||||
// Check if ResultVariable exists in queryComponents
|
||||
if ( ! isset($this->_queryComponents[$resultVariable])) {
|
||||
$this->semanticalError(
|
||||
"'$resultVariable' is not defined.", $deferredItem['token']
|
||||
"'$resultVariable' is not defined.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
@ -528,14 +526,14 @@ class Parser
|
||||
// Check if queryComponent points to an AbstractSchemaName or a ResultVariable
|
||||
if ( ! isset($qComp['resultVariable'])) {
|
||||
$this->semanticalError(
|
||||
"'$identVariable' does not point to a ResultVariable.", $deferredItem['token']
|
||||
"'$identVariable' does not point to a ResultVariable.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
// Validate if identification variable nesting level is lower or equal than the current one
|
||||
if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) {
|
||||
$this->semanticalError(
|
||||
"'$resultVariable' is used outside the scope of its declaration.", $deferredItem['token']
|
||||
"'$resultVariable' is used outside the scope of its declaration.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -557,11 +555,16 @@ class Parser
|
||||
{
|
||||
foreach ($this->_deferredPathExpressions as $deferredItem) {
|
||||
$pathExpression = $deferredItem['expression'];
|
||||
$parts = $pathExpression->parts;
|
||||
$numParts = count($parts);
|
||||
|
||||
$qComp = $this->_queryComponents[$pathExpression->identificationVariable];
|
||||
$numParts = count($pathExpression->parts);
|
||||
|
||||
if ($numParts == 0) {
|
||||
$pathExpression->parts = array($qComp['metadata']->identifier[0]);
|
||||
$numParts++;
|
||||
}
|
||||
|
||||
$parts = $pathExpression->parts;
|
||||
$aliasIdentificationVariable = $pathExpression->identificationVariable;
|
||||
$parentField = $pathExpression->identificationVariable;
|
||||
$class = $qComp['metadata'];
|
||||
@ -572,24 +575,24 @@ class Parser
|
||||
// Check if it is not in a state field
|
||||
if ($fieldType & AST\PathExpression::TYPE_STATE_FIELD) {
|
||||
$this->semanticalError(
|
||||
'Cannot navigate through state field named ' . $field . ' on ' . $parentField,
|
||||
$deferredItem['token']
|
||||
'Cannot navigate through state field named ' . $field . ' on ' . $parentField,
|
||||
$deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
// Check if it is not a collection field
|
||||
if ($fieldType & AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION) {
|
||||
$this->semanticalError(
|
||||
'Cannot navigate through collection field named ' . $field . ' on ' . $parentField,
|
||||
$deferredItem['token']
|
||||
'Cannot navigate through collection field named ' . $field . ' on ' . $parentField,
|
||||
$deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
// Check if field or association exists
|
||||
if ( ! isset($class->associationMappings[$field]) && ! isset($class->fieldMappings[$field])) {
|
||||
$this->semanticalError(
|
||||
'Class ' . $class->name . ' has no field or association named ' . $field,
|
||||
$deferredItem['token']
|
||||
'Class ' . $class->name . ' has no field or association named ' . $field,
|
||||
$deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
@ -602,8 +605,8 @@ class Parser
|
||||
$class = $this->_em->getClassMetadata($assoc->targetEntityName);
|
||||
|
||||
if (
|
||||
($curIndex != $numParts - 1) &&
|
||||
! isset($this->_queryComponents[$aliasIdentificationVariable . '.' . $field])
|
||||
($curIndex != $numParts - 1) &&
|
||||
! isset($this->_queryComponents[$aliasIdentificationVariable . '.' . $field])
|
||||
) {
|
||||
// Building queryComponent
|
||||
$joinQueryComponent = array(
|
||||
@ -617,14 +620,15 @@ class Parser
|
||||
|
||||
// Create AST node
|
||||
$joinVariableDeclaration = new AST\JoinVariableDeclaration(
|
||||
new AST\Join(
|
||||
AST\Join::JOIN_TYPE_INNER,
|
||||
new AST\JoinAssociationPathExpression($aliasIdentificationVariable, $field),
|
||||
$aliasIdentificationVariable . '.' . $field,
|
||||
false
|
||||
),
|
||||
null
|
||||
new AST\Join(
|
||||
AST\Join::JOIN_TYPE_INNER,
|
||||
new AST\JoinAssociationPathExpression($aliasIdentificationVariable, $field),
|
||||
$aliasIdentificationVariable . '.' . $field,
|
||||
false
|
||||
),
|
||||
null
|
||||
);
|
||||
|
||||
$AST->fromClause->identificationVariableDeclarations[0]->joinVariableDeclarations[] = $joinVariableDeclaration;
|
||||
|
||||
$this->_queryComponents[$aliasIdentificationVariable . '.' . $field] = $joinQueryComponent;
|
||||
@ -915,12 +919,12 @@ class Parser
|
||||
$identVariable = $this->IdentificationVariable();
|
||||
$parts = array();
|
||||
|
||||
do {
|
||||
while ($this->_lexer->isNextToken(Lexer::T_DOT)) {
|
||||
$this->match(Lexer::T_DOT);
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
|
||||
$parts[] = $this->_lexer->token['value'];
|
||||
} while ($this->_lexer->isNextToken(Lexer::T_DOT));
|
||||
}
|
||||
|
||||
// Creating AST node
|
||||
$pathExpr = new AST\PathExpression($expectedTypes, $identVariable, $parts);
|
||||
@ -2168,7 +2172,7 @@ class Parser
|
||||
return $this->SingleValuedPathExpression();
|
||||
}
|
||||
|
||||
return $this->IdentificationVariable();
|
||||
return $this->SimpleStateFieldPathExpression();
|
||||
|
||||
case Lexer::T_INPUT_PARAMETER:
|
||||
return $this->InputParameter();
|
||||
@ -2619,9 +2623,10 @@ class Parser
|
||||
|
||||
public function CustomFunctionsReturningNumerics()
|
||||
{
|
||||
$funcNameLower = strtolower($this->_lexer->lookahead['value']);
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomNumericFunction($funcNameLower);
|
||||
$function = new $funcClass($funcNameLower);
|
||||
$funcName = strtolower($this->_lexer->lookahead['value']);
|
||||
// getCustomNumericFunction is case-insensitive
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomNumericFunction($funcName);
|
||||
$function = new $funcClass($funcName);
|
||||
$function->parse($this);
|
||||
|
||||
return $function;
|
||||
@ -2642,9 +2647,10 @@ class Parser
|
||||
|
||||
public function CustomFunctionsReturningDatetime()
|
||||
{
|
||||
$funcNameLower = strtolower($this->_lexer->lookahead['value']);
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomDatetimeFunction($funcNameLower);
|
||||
$function = new $funcClass($funcNameLower);
|
||||
$funcName = $this->_lexer->lookahead['value'];
|
||||
// getCustomDatetimeFunction is case-insensitive
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomDatetimeFunction($funcName);
|
||||
$function = new $funcClass($funcName);
|
||||
$function->parse($this);
|
||||
|
||||
return $function;
|
||||
@ -2670,9 +2676,10 @@ class Parser
|
||||
|
||||
public function CustomFunctionsReturningStrings()
|
||||
{
|
||||
$funcNameLower = strtolower($this->_lexer->lookahead['value']);
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomStringFunction($funcNameLower);
|
||||
$function = new $funcClass($funcNameLower);
|
||||
$funcName = $this->_lexer->lookahead['value'];
|
||||
// getCustomStringFunction is case-insensitive
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomStringFunction($funcName);
|
||||
$function = new $funcClass($funcName);
|
||||
$function->parse($this);
|
||||
|
||||
return $function;
|
||||
|
@ -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
|
||||
@ -240,16 +238,17 @@ class SqlWalker implements TreeWalker
|
||||
{
|
||||
$sql = '';
|
||||
|
||||
$baseTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
|
||||
$baseTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
|
||||
// INNER JOIN parent class tables
|
||||
foreach ($class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$tableAlias = $this->getSqlTableAlias($parentClass->table['name'], $dqlAlias);
|
||||
$sql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform)
|
||||
$tableAlias = $this->getSQLTableAlias($parentClass->table['name'], $dqlAlias);
|
||||
// If this is a joined association we must use left joins to preserve the correct result.
|
||||
$sql .= isset($this->_queryComponents[$dqlAlias]['relation']) ? ' LEFT ' : ' INNER ';
|
||||
$sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform)
|
||||
. ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
|
||||
foreach ($class->identifier as $idField) {
|
||||
if ($first) $first = false; else $sql .= ' AND ';
|
||||
|
||||
@ -260,14 +259,13 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
}
|
||||
|
||||
// LEFT JOIN subclass tables, if partial objects disallowed
|
||||
// LEFT JOIN subclass tables, if partial objects disallowed.
|
||||
if ( ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
|
||||
foreach ($class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
$tableAlias = $this->getSqlTableAlias($subClass->table['name'], $dqlAlias);
|
||||
$tableAlias = $this->getSQLTableAlias($subClass->table['name'], $dqlAlias);
|
||||
$sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform)
|
||||
. ' ' . $tableAlias . ' ON ';
|
||||
|
||||
$first = true;
|
||||
foreach ($class->identifier as $idField) {
|
||||
if ($first) $first = false; else $sql .= ' AND ';
|
||||
@ -288,9 +286,7 @@ class SqlWalker implements TreeWalker
|
||||
$sql = '';
|
||||
foreach ($this->_selectedClasses AS $dqlAlias => $class) {
|
||||
$qComp = $this->_queryComponents[$dqlAlias];
|
||||
if (isset($qComp['relation']) && ($qComp['relation']->isManyToMany() || $qComp['relation']->isOneToMany())
|
||||
&& $qComp['relation']->orderBy != null) {
|
||||
|
||||
if (isset($qComp['relation']->orderBy)) {
|
||||
foreach ($qComp['relation']->orderBy AS $fieldName => $orientation) {
|
||||
if ($qComp['metadata']->isInheritanceTypeJoined()) {
|
||||
$tableName = $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName);
|
||||
@ -301,8 +297,8 @@ class SqlWalker implements TreeWalker
|
||||
if ($sql != '') {
|
||||
$sql .= ', ';
|
||||
}
|
||||
$sql .= $this->getSqlTableAlias($tableName, $dqlAlias) . "." .
|
||||
$qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform) . " ".$orientation;
|
||||
$sql .= $this->getSqlTableAlias($tableName, $dqlAlias) . '.' .
|
||||
$qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform) . " $orientation";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -315,7 +311,7 @@ class SqlWalker implements TreeWalker
|
||||
* @param string $dqlAlias
|
||||
* @return string
|
||||
*/
|
||||
private function _generateDiscriminatorColumnConditionSql($dqlAlias)
|
||||
private function _generateDiscriminatorColumnConditionSQL($dqlAlias)
|
||||
{
|
||||
$sql = '';
|
||||
|
||||
@ -340,7 +336,6 @@ class SqlWalker implements TreeWalker
|
||||
return $sql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Walks down a SelectStatement AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
@ -353,7 +348,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
if (($whereClause = $AST->whereClause) !== null) {
|
||||
$sql .= $this->walkWhereClause($whereClause);
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias)) !== '') {
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSQL($this->_currentRootAlias)) !== '') {
|
||||
$sql .= ' WHERE ' . $discSql;
|
||||
}
|
||||
|
||||
@ -406,7 +401,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
if (($whereClause = $AST->whereClause) !== null) {
|
||||
$sql .= $this->walkWhereClause($whereClause);
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias)) !== '') {
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSQL($this->_currentRootAlias)) !== '') {
|
||||
$sql .= ' WHERE ' . $discSql;
|
||||
}
|
||||
|
||||
@ -426,7 +421,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
if (($whereClause = $AST->whereClause) !== null) {
|
||||
$sql .= $this->walkWhereClause($whereClause);
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias)) !== '') {
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSQL($this->_currentRootAlias)) !== '') {
|
||||
$sql .= ' WHERE ' . $discSql;
|
||||
}
|
||||
|
||||
@ -477,6 +472,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
$sql .= $class->getQuotedColumnName($fieldName, $this->_platform);
|
||||
break;
|
||||
|
||||
case AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION:
|
||||
// 1- the owning side:
|
||||
// Just use the foreign key, i.e. u.group_id
|
||||
@ -496,13 +492,18 @@ class SqlWalker implements TreeWalker
|
||||
if (count($assoc->sourceToTargetKeyColumns) > 1) {
|
||||
throw QueryException::associationPathCompositeKeyNotSupported();
|
||||
}
|
||||
$sql .= $this->getSqlTableAlias($class->table['name'], $dqlAlias) . '.'
|
||||
. reset($assoc->targetToSourceKeyColumns);
|
||||
|
||||
if ($this->_useSqlTableAliases) {
|
||||
$sql .= $this->getSqlTableAlias($class->table['name'], $dqlAlias) . '.';
|
||||
}
|
||||
|
||||
$sql .= reset($assoc->targetToSourceKeyColumns);
|
||||
} else {
|
||||
// 2- Inverse side: NOT (YET?) SUPPORTED
|
||||
throw QueryException::associationPathInverseSideNotSupported();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw QueryException::invalidPathExpression($pathExpr);
|
||||
}
|
||||
@ -799,7 +800,7 @@ class SqlWalker implements TreeWalker
|
||||
). ')';
|
||||
}
|
||||
|
||||
$discrSql = $this->_generateDiscriminatorColumnConditionSql($joinedDqlAlias);
|
||||
$discrSql = $this->_generateDiscriminatorColumnConditionSQL($joinedDqlAlias);
|
||||
|
||||
if ($discrSql) {
|
||||
$sql .= ' AND ' . $discrSql;
|
||||
@ -1236,7 +1237,7 @@ class SqlWalker implements TreeWalker
|
||||
' OR ', array_map(array($this, 'walkConditionalTerm'), $condExpr->conditionalTerms)
|
||||
);
|
||||
|
||||
$discrSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias);
|
||||
$discrSql = $this->_generateDiscriminatorColumnConditionSQL($this->_currentRootAlias);
|
||||
|
||||
if ($discrSql) {
|
||||
$sql .= ' AND ' . $discrSql;
|
||||
|
@ -134,16 +134,16 @@ EOT
|
||||
}
|
||||
|
||||
$converter = new ConvertDoctrine1Schema($fromPaths);
|
||||
$metadatas = $converter->getMetadatas();
|
||||
$metadata = $converter->getMetadata();
|
||||
|
||||
if ($metadatas) {
|
||||
$output->write(PHP_EOL);
|
||||
|
||||
foreach ($metadatas as $metadata) {
|
||||
$output->write(sprintf('Processing entity "<info>%s</info>"', $metadata->name) . PHP_EOL);
|
||||
foreach ($metadata as $class) {
|
||||
$output->write(sprintf('Processing entity "<info>%s</info>"', $class->name) . PHP_EOL);
|
||||
}
|
||||
|
||||
$exporter->setMetadatas($metadatas);
|
||||
$exporter->setMetadata($metadata);
|
||||
$exporter->export();
|
||||
|
||||
$output->write(PHP_EOL . sprintf(
|
||||
|
@ -97,8 +97,8 @@ EOT
|
||||
}
|
||||
|
||||
$cmf = new DisconnectedClassMetadataFactory($em);
|
||||
$metadatas = $cmf->getAllMetadata();
|
||||
$metadatas = MetadataFilter::filter($metadatas, $input->getOption('filter'));
|
||||
$metadata = $cmf->getAllMetadata();
|
||||
$metadata = MetadataFilter::filter($metadata, $input->getOption('filter'));
|
||||
|
||||
// Process destination directory
|
||||
if ( ! is_dir($destPath = $input->getArgument('dest-path'))) {
|
||||
@ -132,12 +132,12 @@ EOT
|
||||
}
|
||||
}
|
||||
|
||||
if (count($metadatas)) {
|
||||
foreach ($metadatas as $metadata) {
|
||||
$output->write(sprintf('Processing entity "<info>%s</info>"', $metadata->name) . PHP_EOL);
|
||||
if (count($metadata)) {
|
||||
foreach ($metadata as $class) {
|
||||
$output->write(sprintf('Processing entity "<info>%s</info>"', $class->name) . PHP_EOL);
|
||||
}
|
||||
|
||||
$exporter->setMetadatas($metadatas);
|
||||
$exporter->setMetadata($metadata);
|
||||
$exporter->export();
|
||||
|
||||
$output->write(PHP_EOL . sprintf(
|
||||
|
@ -113,7 +113,7 @@ EOT
|
||||
);
|
||||
}
|
||||
|
||||
if ( count($metadatas)) {
|
||||
if (count($metadatas)) {
|
||||
// Create EntityGenerator
|
||||
$entityGenerator = new EntityGenerator();
|
||||
|
||||
|
@ -24,7 +24,8 @@ namespace Doctrine\ORM\Tools\Console\Command;
|
||||
use Symfony\Components\Console\Input\InputArgument,
|
||||
Symfony\Components\Console\Input\InputOption,
|
||||
Symfony\Components\Console,
|
||||
Doctrine\ORM\Tools\Console\MetadataFilter;
|
||||
Doctrine\ORM\Tools\Console\MetadataFilter,
|
||||
Doctrine\ORM\Tools\EntityRepositoryGenerator;
|
||||
|
||||
/**
|
||||
* Command to generate repository classes for mapping information.
|
||||
@ -40,23 +41,6 @@ use Symfony\Components\Console\Input\InputArgument,
|
||||
*/
|
||||
class GenerateRepositoriesCommand extends Console\Command\Command
|
||||
{
|
||||
private static $_template =
|
||||
'<?php
|
||||
|
||||
namespace <namespace>;
|
||||
|
||||
use \Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* <className>
|
||||
*
|
||||
* This class was generated by the Doctrine ORM. Add your own custom
|
||||
* repository methods below.
|
||||
*/
|
||||
class <className> extends EntityRepository
|
||||
{
|
||||
}';
|
||||
|
||||
/**
|
||||
* @see Console\Command\Command
|
||||
*/
|
||||
@ -103,8 +87,9 @@ EOT
|
||||
);
|
||||
}
|
||||
|
||||
if ( count($metadatas)) {
|
||||
if (count($metadatas)) {
|
||||
$numRepositories = 0;
|
||||
$generator = new EntityRepositoryGenerator();
|
||||
|
||||
foreach ($metadatas as $metadata) {
|
||||
if ($metadata->customRepositoryClassName) {
|
||||
@ -112,7 +97,7 @@ EOT
|
||||
sprintf('Processing repository "<info>%s</info>"', $metadata->customRepositoryClassName) . PHP_EOL
|
||||
);
|
||||
|
||||
$this->_generateRepositoryClass($metadata, $destPath);
|
||||
$generator->writeEntityRepositoryClass($metadata->customRepositoryClassName, $destPath);
|
||||
|
||||
$numRepositories++;
|
||||
}
|
||||
@ -128,19 +113,4 @@ EOT
|
||||
$output->write('No Metadata Classes to process.' . PHP_EOL);
|
||||
}
|
||||
}
|
||||
|
||||
private function _generateRepositoryClass($metadata, $destPath)
|
||||
{
|
||||
$code = $this->_generateRepositoryClass($metadata->customRepositoryClassName);
|
||||
|
||||
$path = $destPath . DIRECTORY_SEPARATOR
|
||||
. str_replace('\\', \DIRECTORY_SEPARATOR, $metadata->customRepositoryClassName) . '.php';
|
||||
$dir = dirname($path);
|
||||
|
||||
if ( ! is_dir($dir)) {
|
||||
mkdir($dir, 0777, true);
|
||||
}
|
||||
|
||||
file_put_contents($path, $code);
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools\Console\Command;
|
||||
|
||||
use Symfony\Components\Console\Input\InputArgument,
|
||||
Symfony\Components\Console\Input\InputOption,
|
||||
Symfony\Components\Console;
|
||||
|
||||
/**
|
||||
* Validate that the current mapping is valid
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class ValidateSchemaCommand extends Console\Command\Command
|
||||
{
|
||||
/**
|
||||
* @see Console\Command\Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('orm:validate-schema')
|
||||
->setDescription('Validate that the current metadata schema is valid.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*/
|
||||
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
|
||||
{
|
||||
$emHelper = $this->getHelper('em');
|
||||
|
||||
/* @var $em \Doctrine\ORM\EntityManager */
|
||||
$em = $emHelper->getEntityManager();
|
||||
|
||||
$metadatas = $em->getMetadataFactory()->getAllMetadata();
|
||||
|
||||
if ( ! empty($metadatas)) {
|
||||
// Create SchemaTool
|
||||
$tool = new \Doctrine\ORM\Tools\SchemaTool($em);
|
||||
$updateSql = $tool->getUpdateSchemaSql($metadatas, false);
|
||||
|
||||
if (count($updateSql) == 0) {
|
||||
$output->write("[Database] OK - Metadata schema exactly matches the database schema.");
|
||||
} else {
|
||||
$output->write("[Database] FAIL - There are differences between metadata and database schema.");
|
||||
}
|
||||
} else {
|
||||
$output->write("No metadata mappings found");
|
||||
}
|
||||
}
|
||||
}
|
@ -41,7 +41,8 @@ class ConvertDoctrine1Schema
|
||||
private $_legacyTypeMap = array(
|
||||
// TODO: This list may need to be updated
|
||||
'clob' => 'text',
|
||||
'timestamp' => 'datetime'
|
||||
'timestamp' => 'datetime',
|
||||
'enum' => 'string'
|
||||
);
|
||||
|
||||
/**
|
||||
@ -238,6 +239,7 @@ class ConvertDoctrine1Schema
|
||||
if (isset($relation['refClass'])) {
|
||||
$type = 'many';
|
||||
$foreignType = 'many';
|
||||
$joinColumns = array();
|
||||
} else {
|
||||
$type = isset($relation['type']) ? $relation['type'] : 'one';
|
||||
$foreignType = isset($relation['foreignType']) ? $relation['foreignType'] : 'many';
|
||||
|
@ -98,7 +98,7 @@ class EntityGenerator
|
||||
*/
|
||||
public function <methodName>()
|
||||
{
|
||||
return $this-><fieldName>;
|
||||
<spaces>return $this-><fieldName>;
|
||||
}';
|
||||
|
||||
private static $_setMethodTemplate =
|
||||
@ -109,7 +109,7 @@ public function <methodName>()
|
||||
*/
|
||||
public function <methodName>(<methodTypeHint>$<variableName>)
|
||||
{
|
||||
$this-><fieldName> = $<variableName>;
|
||||
<spaces>$this-><fieldName> = $<variableName>;
|
||||
}';
|
||||
|
||||
private static $_addMethodTemplate =
|
||||
@ -120,7 +120,7 @@ public function <methodName>(<methodTypeHint>$<variableName>)
|
||||
*/
|
||||
public function <methodName>(<methodTypeHint>$<variableName>)
|
||||
{
|
||||
$this-><fieldName>[] = $<variableName>;
|
||||
<spaces>$this-><fieldName>[] = $<variableName>;
|
||||
}';
|
||||
|
||||
private static $_lifecycleCallbackMethodTemplate =
|
||||
@ -129,7 +129,7 @@ public function <methodName>(<methodTypeHint>$<variableName>)
|
||||
*/
|
||||
public function <methodName>()
|
||||
{
|
||||
// Add your code here
|
||||
<spaces>// Add your code here
|
||||
}';
|
||||
|
||||
/**
|
||||
@ -203,7 +203,8 @@ public function <methodName>()
|
||||
$this->_generateEntityBody($metadata)
|
||||
);
|
||||
|
||||
return str_replace($placeHolders, $replacements, self::$_classTemplate);
|
||||
$code = str_replace($placeHolders, $replacements, self::$_classTemplate);
|
||||
return str_replace('<spaces>', $this->_spaces, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -218,9 +219,10 @@ public function <methodName>()
|
||||
$currentCode = file_get_contents($path);
|
||||
|
||||
$body = $this->_generateEntityBody($metadata);
|
||||
$body = str_replace('<spaces>', $this->_spaces, $body);
|
||||
$last = strrpos($currentCode, '}');
|
||||
|
||||
return substr($currentCode, 0, $last) . $body . '}';
|
||||
return substr($currentCode, 0, $last) . $body . "\n}";
|
||||
}
|
||||
|
||||
/**
|
||||
|
83
lib/Doctrine/ORM/Tools/EntityRepositoryGenerator.php
Normal file
83
lib/Doctrine/ORM/Tools/EntityRepositoryGenerator.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools;
|
||||
|
||||
/**
|
||||
* Class to generate entity repository classes
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class EntityRepositoryGenerator
|
||||
{
|
||||
protected static $_template =
|
||||
'<?php
|
||||
|
||||
namespace <namespace>;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* <className>
|
||||
*
|
||||
* This class was generated by the Doctrine ORM. Add your own custom
|
||||
* repository methods below.
|
||||
*/
|
||||
class <className> extends EntityRepository
|
||||
{
|
||||
}';
|
||||
|
||||
public function generateEntityRepositoryClass($fullClassName)
|
||||
{
|
||||
$namespace = substr($fullClassName, 0, strrpos($fullClassName, '\\'));
|
||||
$className = substr($fullClassName, strrpos($fullClassName, '\\') + 1, strlen($fullClassName));
|
||||
|
||||
$variables = array(
|
||||
'<namespace>' => $namespace,
|
||||
'<className>' => $className
|
||||
);
|
||||
return str_replace(array_keys($variables), array_values($variables), self::$_template);
|
||||
}
|
||||
|
||||
public function writeEntityRepositoryClass($fullClassName, $outputDirectory)
|
||||
{
|
||||
$code = $this->generateEntityRepositoryClass($fullClassName);
|
||||
|
||||
$path = $outputDirectory . DIRECTORY_SEPARATOR
|
||||
. str_replace('\\', \DIRECTORY_SEPARATOR, $fullClassName) . '.php';
|
||||
$dir = dirname($path);
|
||||
|
||||
if ( ! is_dir($dir)) {
|
||||
mkdir($dir, 0777, true);
|
||||
}
|
||||
|
||||
if ( ! file_exists($path)) {
|
||||
file_put_contents($path, $code);
|
||||
}
|
||||
}
|
||||
}
|
@ -63,7 +63,7 @@ class ClassMetadataExporter
|
||||
* @param string $source The directory where the exporter will export to
|
||||
* @return AbstractExporter $exporter
|
||||
*/
|
||||
public function getExporter($type, $dest)
|
||||
public function getExporter($type, $dest = null)
|
||||
{
|
||||
if ( ! isset(self::$_exporterDrivers[$type])) {
|
||||
throw ExportException::invalidExporterDriverType($type);
|
||||
|
@ -49,6 +49,9 @@ class AnnotationExporter extends AbstractExporter
|
||||
*/
|
||||
public function exportClassMetadata(ClassMetadataInfo $metadata)
|
||||
{
|
||||
if ( ! $this->_entityGenerator) {
|
||||
throw new \RuntimeException('For the AnnotationExporter you must set an EntityGenerator instance with the setEntityGenerator() method.');
|
||||
}
|
||||
$this->_entityGenerator->setGenerateAnnotations(true);
|
||||
$this->_entityGenerator->setGenerateStubMethods(false);
|
||||
$this->_entityGenerator->setRegenerateEntityIfExists(false);
|
||||
|
@ -53,7 +53,7 @@ class XmlExporter extends AbstractExporter
|
||||
|
||||
$xml->addAttribute('xmlns', 'http://doctrine-project.org/schemas/orm/doctrine-mapping');
|
||||
$xml->addAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
|
||||
$xml->addAttribute('xsi:schemaLocation', 'http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd');
|
||||
$xml->addAttribute('xsi:schemaLocation', 'http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd');
|
||||
|
||||
if ($metadata->isMappedSuperclass) {
|
||||
$root = $xml->addChild('mapped-superclass');
|
||||
|
@ -2,8 +2,12 @@
|
||||
|
||||
namespace Doctrine\ORM\Tools;
|
||||
|
||||
class ToolsException extends ORMException {
|
||||
public static function couldNotMapDoctrine1Type($type) {
|
||||
use Doctrine\ORM\ORMException;
|
||||
|
||||
class ToolsException extends ORMException
|
||||
{
|
||||
public static function couldNotMapDoctrine1Type($type)
|
||||
{
|
||||
return new self("Could not map doctrine 1 type '$type'!");
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id: UnitOfWork.php 4947 2008-09-12 13:16:05Z romanb $
|
||||
*
|
||||
* 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
|
||||
@ -33,15 +31,12 @@ use Doctrine\Common\Collections\ArrayCollection,
|
||||
* "object-level" transaction and for writing out changes to the database
|
||||
* in the correct order.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @internal This class contains performance-critical code.
|
||||
* @internal This class contains highly performance-sensitive code.
|
||||
*/
|
||||
class UnitOfWork implements PropertyChangedListener
|
||||
{
|
||||
@ -2013,7 +2008,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
if ( ! isset($this->_persisters[$entityName])) {
|
||||
$class = $this->_em->getClassMetadata($entityName);
|
||||
if ($class->isInheritanceTypeNone()) {
|
||||
$persister = new Persisters\StandardEntityPersister($this->_em, $class);
|
||||
$persister = new Persisters\BasicEntityPersister($this->_em, $class);
|
||||
} else if ($class->isInheritanceTypeSingleTable()) {
|
||||
$persister = new Persisters\SingleTablePersister($this->_em, $class);
|
||||
} else if ($class->isInheritanceTypeJoined()) {
|
||||
|
@ -488,7 +488,7 @@ class Application
|
||||
{
|
||||
// namespace
|
||||
$namespace = '';
|
||||
if (false !== $pos = strpos($name, ':'))
|
||||
if (false !== $pos = strrpos($name, ':'))
|
||||
{
|
||||
$namespace = $this->findNamespace(substr($name, 0, $pos));
|
||||
$name = substr($name, $pos + 1);
|
||||
|
@ -276,7 +276,7 @@ class Command
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
if (false !== $pos = strpos($name, ':'))
|
||||
if (false !== $pos = strrpos($name, ':'))
|
||||
{
|
||||
$namespace = substr($name, 0, $pos);
|
||||
$name = substr($name, $pos + 1);
|
||||
@ -375,6 +375,28 @@ class Command
|
||||
return $this->help;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the processed help for the command replacing the %command.name% and
|
||||
* %command.full_name% patterns with the real values dynamically.
|
||||
*
|
||||
* @return string The processed help for the command
|
||||
*/
|
||||
public function getProcessedHelp()
|
||||
{
|
||||
$name = $this->namespace.':'.$this->name;
|
||||
|
||||
$placeholders = array(
|
||||
'%command.name%',
|
||||
'%command.full_name%'
|
||||
);
|
||||
$replacements = array(
|
||||
$name,
|
||||
$_SERVER['PHP_SELF'].' '.$name
|
||||
);
|
||||
|
||||
return str_replace($placeholders, $replacements, $this->getHelp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases for the command.
|
||||
*
|
||||
@ -457,7 +479,7 @@ class Command
|
||||
|
||||
$messages[] = $this->definition->asText();
|
||||
|
||||
if ($help = $this->getHelp())
|
||||
if ($help = $this->getProcessedHelp())
|
||||
{
|
||||
$messages[] = '<comment>Help:</comment>';
|
||||
$messages[] = ' '.implode("\n ", explode("\n", $help))."\n";
|
||||
|
@ -70,7 +70,7 @@ class ArgvInput extends Input
|
||||
protected function parse()
|
||||
{
|
||||
$this->parsed = $this->tokens;
|
||||
while ($token = array_shift($this->parsed))
|
||||
while (null !== ($token = array_shift($this->parsed)))
|
||||
{
|
||||
if ('--' === substr($token, 0, 2))
|
||||
{
|
||||
|
@ -25,6 +25,7 @@ class AllTests
|
||||
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\MySqlSchemaManagerTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\PostgreSqlSchemaManagerTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\OracleSchemaManagerTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\Db2SchemaManagerTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\ConnectionTest');
|
||||
|
||||
return $suite;
|
||||
|
61
tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php
Normal file
61
tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Models\DBAL\Functional;
|
||||
|
||||
class DataAccessTest extends \Doctrine\Tests\DbalFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
/* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */
|
||||
$table = new \Doctrine\DBAL\Schema\Table("fetch_table");
|
||||
$table->addColumn('test_int', 'integer');
|
||||
$table->addColumn('test_string', 'string');
|
||||
|
||||
$sm = $this->_conn->getSchemaManager();
|
||||
$sm->createTable($table);
|
||||
|
||||
$this->_conn->insert('fetch_table', array('test_int' => 1, 'test_string' => 'foo'));
|
||||
} catch(\Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function testFetchAll()
|
||||
{
|
||||
$sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
|
||||
$data = $this->_conn->fetchAll($sql, array(1, 'foo'));
|
||||
|
||||
$this->assertEquals(1, count($data));
|
||||
|
||||
$row = $data[0];
|
||||
$this->assertEquals(2, count($row));
|
||||
|
||||
$row = array_change_key_case($row, \CASE_LOWER);
|
||||
$this->assertEquals(1, $row['test_int']);
|
||||
$this->assertEquals('foo', $row['test_string']);
|
||||
}
|
||||
|
||||
public function testFetchRow()
|
||||
{
|
||||
$sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
|
||||
$row = $this->_conn->fetchRow($sql, array(1, 'foo'));
|
||||
|
||||
$row = array_change_key_case($row, \CASE_LOWER);
|
||||
|
||||
$this->assertEquals(1, $row['test_int']);
|
||||
$this->assertEquals('foo', $row['test_string']);
|
||||
}
|
||||
|
||||
public function testFetchArray()
|
||||
{
|
||||
$sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
|
||||
$row = $this->_conn->fetchArray($sql, array(1, 'foo'));
|
||||
|
||||
$this->assertEquals(1, $row[0]);
|
||||
$this->assertEquals('foo', $row[1]);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\DBAL\Functional\Schema;
|
||||
|
||||
use Doctrine\DBAL\Schema;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
class Db2SchemaManagerTest extends SchemaManagerFunctionalTestCase
|
||||
{
|
||||
|
||||
}
|
@ -28,6 +28,8 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
|
||||
$this->markTestSkipped('The ' . $testClass .' requires the use of ' . $dbms);
|
||||
}
|
||||
|
||||
#$this->_conn->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
|
||||
|
||||
$this->_sm = $this->_conn->getSchemaManager();
|
||||
}
|
||||
|
||||
@ -59,6 +61,10 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
|
||||
|
||||
public function testListDatabases()
|
||||
{
|
||||
if (!$this->_sm->getDatabasePlatform()->supportsCreateDropDatabase()) {
|
||||
$this->markTestSkipped('Cannot drop Database client side with this Driver.');
|
||||
}
|
||||
|
||||
$this->_sm->dropAndCreateDatabase('test_create_database');
|
||||
$databases = $this->_sm->listDatabases();
|
||||
|
||||
@ -73,12 +79,12 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
|
||||
$tables = $this->_sm->listTables();
|
||||
|
||||
$this->assertType('array', $tables);
|
||||
$this->assertTrue(count($tables) > 0);
|
||||
$this->assertTrue(count($tables) > 0, "List Tables has to find at least one table named 'list_tables_test'.");
|
||||
|
||||
$foundTable = false;
|
||||
foreach ($tables AS $table) {
|
||||
$this->assertType('Doctrine\DBAL\Schema\Table', $table);
|
||||
if ($table->getName() == 'list_tables_test') {
|
||||
if (strtolower($table->getName()) == 'list_tables_test') {
|
||||
$foundTable = true;
|
||||
|
||||
$this->assertTrue($table->hasColumn('id'));
|
||||
@ -86,6 +92,8 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
|
||||
$this->assertTrue($table->hasColumn('foreign_key_test'));
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertTrue( $foundTable , "The 'list_tables_test' table has to be found.");
|
||||
}
|
||||
|
||||
public function testListTableColumns()
|
||||
@ -122,7 +130,6 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
|
||||
|
||||
$this->assertEquals('foo', strtolower($columns['foo']->getname()));
|
||||
$this->assertType('Doctrine\DBAL\Types\TextType', $columns['foo']->gettype());
|
||||
$this->assertEquals(null, $columns['foo']->getlength());
|
||||
$this->assertEquals(false, $columns['foo']->getunsigned());
|
||||
$this->assertEquals(false, $columns['foo']->getfixed());
|
||||
$this->assertEquals(true, $columns['foo']->getnotnull());
|
||||
@ -171,6 +178,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
|
||||
|
||||
$this->assertEquals(3, count($tableIndexes));
|
||||
|
||||
$this->assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.');
|
||||
$this->assertEquals(array('id'), array_map('strtolower', $tableIndexes['primary']->getColumns()));
|
||||
$this->assertTrue($tableIndexes['primary']->isUnique());
|
||||
$this->assertTrue($tableIndexes['primary']->isPrimary());
|
||||
@ -218,7 +226,7 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
|
||||
$this->_sm->dropAndCreateTable($tableA);
|
||||
|
||||
$fkConstraints = $this->_sm->listTableForeignKeys('test_create_fk');
|
||||
$this->assertEquals(1, count($fkConstraints));
|
||||
$this->assertEquals(1, count($fkConstraints), "Table 'test_create_fk1' has to have one foreign key.");
|
||||
|
||||
$fkConstraint = current($fkConstraints);
|
||||
$this->assertType('\Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkConstraint);
|
||||
@ -237,22 +245,20 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
|
||||
$this->createTestTable('test_create_fk2');
|
||||
|
||||
$foreignKey = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(
|
||||
array('foreign_key_test'), 'test_create_fk2', array('id'), 'foreign_key_test_fk', array('onUpdate' => 'CASCADE', 'onDelete' => 'CASCADE')
|
||||
array('foreign_key_test'), 'test_create_fk2', array('id'), 'foreign_key_test_fk', array('onDelete' => 'CASCADE')
|
||||
);
|
||||
|
||||
$this->_sm->createForeignKey($foreignKey, 'test_create_fk1');
|
||||
|
||||
$fkeys = $this->_sm->listTableForeignKeys('test_create_fk1');
|
||||
|
||||
$this->assertEquals(1, count($fkeys));
|
||||
$this->assertEquals(1, count($fkeys), "Table 'test_create_fk1' has to have one foreign key.");
|
||||
|
||||
$this->assertType('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]);
|
||||
$this->assertEquals(array('foreign_key_test'), array_map('strtolower', $fkeys[0]->getLocalColumns()));
|
||||
$this->assertEquals(array('id'), array_map('strtolower', $fkeys[0]->getForeignColumns()));
|
||||
$this->assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName()));
|
||||
|
||||
if($fkeys[0]->hasOption('onUpdate')) {
|
||||
$this->assertEquals('CASCADE', $fkeys[0]->getOption('onUpdate'));
|
||||
}
|
||||
if($fkeys[0]->hasOption('onDelete')) {
|
||||
$this->assertEquals('CASCADE', $fkeys[0]->getOption('onDelete'));
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user