[2.0] Fixed several referential integrity issues. Fixed critical issue with inserts being run twice on postgresql/oracle. Added support for additional tree walkers that modify the AST prior to SQL construction and started to play with it in a testcase.
This commit is contained in:
parent
8452108e21
commit
e578bad687
@ -97,7 +97,7 @@
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</phpunit>
|
||||
<!-- <phpunitreport infile="build/logs/testsuites.xml" format="frames" todir="reports/tests" />-->
|
||||
<phpunitreport infile="build/logs/testsuites.xml" format="frames" todir="reports/tests" />
|
||||
</target>
|
||||
|
||||
<!--
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://schemas.doctrine-project.org/orm/doctrine-mapping"
|
||||
xmlns:orm="http://schemas.doctrine-project.org/orm/doctrine-mapping"
|
||||
targetNamespace="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:orm="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<xs:annotation>
|
||||
|
269
lib/Doctrine/Common/Util/Inflector.php
Normal file
269
lib/Doctrine/Common/Util/Inflector.php
Normal file
@ -0,0 +1,269 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id: Inflector.php 3189 2007-11-18 20:37:44Z meus $
|
||||
*
|
||||
* 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\Common\Util;
|
||||
|
||||
/**
|
||||
* Doctrine inflector has static methods for inflecting text
|
||||
*
|
||||
* The methods in these classes are from several different sources collected
|
||||
* across several different php projects and several different authors. The
|
||||
* original author names and emails are not known
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 1.0
|
||||
* @version $Revision: 3189 $
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
*/
|
||||
class Inflector
|
||||
{
|
||||
/**
|
||||
* Convert word in to the format for a Doctrine table name. Converts 'ModelName' to 'model_name'
|
||||
*
|
||||
* @param string $word Word to tableize
|
||||
* @return string $word Tableized word
|
||||
*/
|
||||
public static function tableize($word)
|
||||
{
|
||||
return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $word));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a word in to the format for a Doctrine class name. Converts 'table_name' to 'TableName'
|
||||
*
|
||||
* @param string $word Word to classify
|
||||
* @return string $word Classified word
|
||||
*/
|
||||
public static function classify($word)
|
||||
{
|
||||
$word = preg_replace('/[$]/', '', $word);
|
||||
return preg_replace_callback('~(_?)(_)([\w])~', array(__CLASS__, "classifyCallback"), ucfirst(strtolower($word)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to classify a classname properly.
|
||||
*
|
||||
* @param array $matches An array of matches from a pcre_replace call
|
||||
* @return string $string A string with matches 1 and mathces 3 in upper case.
|
||||
*/
|
||||
public static function classifyCallback($matches)
|
||||
{
|
||||
return $matches[1] . strtoupper($matches[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string has utf7 characters in it
|
||||
*
|
||||
* By bmorel at ssi dot fr
|
||||
*
|
||||
* @param string $string
|
||||
* @return boolean $bool
|
||||
*/
|
||||
public static function seemsUtf8($string)
|
||||
{
|
||||
for ($i = 0; $i < strlen($string); $i++) {
|
||||
if (ord($string[$i]) < 0x80) continue; # 0bbbbbbb
|
||||
elseif ((ord($string[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
|
||||
elseif ((ord($string[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
|
||||
elseif ((ord($string[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
|
||||
elseif ((ord($string[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
|
||||
elseif ((ord($string[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b
|
||||
else return false; # Does not match any model
|
||||
for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
|
||||
if ((++$i == strlen($string)) || ((ord($string[$i]) & 0xC0) != 0x80))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any illegal characters, accents, etc.
|
||||
*
|
||||
* @param string $string String to unaccent
|
||||
* @return string $string Unaccented string
|
||||
*/
|
||||
public static function unaccent($string)
|
||||
{
|
||||
if ( ! preg_match('/[\x80-\xff]/', $string) ) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
if (self::seemsUtf8($string)) {
|
||||
$chars = array(
|
||||
// Decompositions for Latin-1 Supplement
|
||||
chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
|
||||
chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
|
||||
chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
|
||||
chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
|
||||
chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
|
||||
chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
|
||||
chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
|
||||
chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
|
||||
chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
|
||||
chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
|
||||
chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
|
||||
chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
|
||||
chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
|
||||
chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
|
||||
chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
|
||||
chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
|
||||
chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
|
||||
chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
|
||||
chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
|
||||
chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
|
||||
chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
|
||||
chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
|
||||
chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
|
||||
chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
|
||||
chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
|
||||
chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
|
||||
chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
|
||||
chr(195).chr(191) => 'y',
|
||||
// Decompositions for Latin Extended-A
|
||||
chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
|
||||
chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
|
||||
chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
|
||||
chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
|
||||
chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
|
||||
chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
|
||||
chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
|
||||
chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
|
||||
chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
|
||||
chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
|
||||
chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
|
||||
chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
|
||||
chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
|
||||
chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
|
||||
chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
|
||||
chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
|
||||
chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
|
||||
chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
|
||||
chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
|
||||
chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
|
||||
chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
|
||||
chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
|
||||
chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
|
||||
chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
|
||||
chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
|
||||
chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
|
||||
chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
|
||||
chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
|
||||
chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
|
||||
chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
|
||||
chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
|
||||
chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
|
||||
chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
|
||||
chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
|
||||
chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
|
||||
chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
|
||||
chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
|
||||
chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
|
||||
chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
|
||||
chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
|
||||
chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
|
||||
chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
|
||||
chr(197).chr(148) => 'R', chr(197).chr(149) => 'r',
|
||||
chr(197).chr(150) => 'R', chr(197).chr(151) => 'r',
|
||||
chr(197).chr(152) => 'R', chr(197).chr(153) => 'r',
|
||||
chr(197).chr(154) => 'S', chr(197).chr(155) => 's',
|
||||
chr(197).chr(156) => 'S', chr(197).chr(157) => 's',
|
||||
chr(197).chr(158) => 'S', chr(197).chr(159) => 's',
|
||||
chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
|
||||
chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
|
||||
chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
|
||||
chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
|
||||
chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
|
||||
chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
|
||||
chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
|
||||
chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
|
||||
chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
|
||||
chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
|
||||
chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
|
||||
chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
|
||||
chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
|
||||
chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
|
||||
chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
|
||||
chr(197).chr(190) => 'z', chr(197).chr(191) => 's',
|
||||
// Euro Sign
|
||||
chr(226).chr(130).chr(172) => 'E',
|
||||
// GBP (Pound) Sign
|
||||
chr(194).chr(163) => '',
|
||||
'Ä' => 'Ae', 'ä' => 'ae', 'Ü' => 'Ue', 'ü' => 'ue',
|
||||
'Ö' => 'Oe', 'ö' => 'oe', 'ß' => 'ss');
|
||||
|
||||
$string = strtr($string, $chars);
|
||||
} else {
|
||||
// Assume ISO-8859-1 if not UTF-8
|
||||
$chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
|
||||
.chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194)
|
||||
.chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202)
|
||||
.chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
|
||||
.chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218)
|
||||
.chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227)
|
||||
.chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235)
|
||||
.chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243)
|
||||
.chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251)
|
||||
.chr(252).chr(253).chr(255);
|
||||
|
||||
$chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
|
||||
|
||||
$string = strtr($string, $chars['in'], $chars['out']);
|
||||
$doubleChars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
|
||||
$doubleChars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
|
||||
$string = str_replace($doubleChars['in'], $doubleChars['out'], $string);
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert any passed string to a url friendly string. Converts 'My first blog post' to 'my-first-blog-post'
|
||||
*
|
||||
* @param string $text Text to urlize
|
||||
* @return string $text Urlized text
|
||||
*/
|
||||
public static function urlize($text)
|
||||
{
|
||||
// Remove all non url friendly characters with the unaccent function
|
||||
$text = self::unaccent($text);
|
||||
|
||||
if (function_exists('mb_strtolower'))
|
||||
{
|
||||
$text = mb_strtolower($text);
|
||||
} else {
|
||||
$text = strtolower($text);
|
||||
}
|
||||
|
||||
// Remove all none word characters
|
||||
$text = preg_replace('/\W/', ' ', $text);
|
||||
|
||||
// More stripping. Replace spaces with dashes
|
||||
$text = strtolower(preg_replace('/[^A-Z^a-z^0-9^\/]+/', '-',
|
||||
preg_replace('/([a-z\d])([A-Z])/', '\1_\2',
|
||||
preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2',
|
||||
preg_replace('/::/', '/', $text)))));
|
||||
|
||||
return trim($text, '-');
|
||||
}
|
||||
}
|
@ -87,7 +87,7 @@ class Configuration
|
||||
public function setCustomTypes(array $types, $override = false)
|
||||
{
|
||||
foreach ($types as $name => $typeClassName) {
|
||||
$method = (Type::hasType($name) ? 'override' : 'add') . 'Type';
|
||||
$method = (Type::hasType($name) && $override ? 'override' : 'add') . 'Type';
|
||||
|
||||
Type::$method($name, $typeClassName);
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ class Driver implements \Doctrine\DBAL\Driver
|
||||
$password,
|
||||
$driverOptions
|
||||
);
|
||||
$conn->setAttribute(Connection::ATTR_AUTOCOMMIT, false);
|
||||
return $conn;
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ interface Statement
|
||||
* bound parameters in the SQL statement being executed.
|
||||
* @return boolean Returns TRUE on success or FALSE on failure.
|
||||
*/
|
||||
function execute($params = null);
|
||||
function execute($params = array());
|
||||
|
||||
/**
|
||||
* fetch
|
||||
|
@ -585,19 +585,18 @@ class EntityManager
|
||||
*/
|
||||
public static function create($conn, Configuration $config = null, EventManager $eventManager = null)
|
||||
{
|
||||
$config = $config ?: new Configuration();
|
||||
|
||||
if (is_array($conn)) {
|
||||
$conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, $eventManager);
|
||||
} else if ( ! $conn instanceof Connection) {
|
||||
$conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, ($eventManager ?: new EventManager()));
|
||||
} else if ($conn instanceof Connection) {
|
||||
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
|
||||
throw DoctrineException::updateMe("Cannot use different EventManagers for EntityManager and Connection.");
|
||||
}
|
||||
} else {
|
||||
throw DoctrineException::updateMe("Invalid parameter '$conn'.");
|
||||
}
|
||||
|
||||
if ($config === null) {
|
||||
$config = new Configuration();
|
||||
}
|
||||
if ($eventManager === null) {
|
||||
$eventManager = new EventManager();
|
||||
}
|
||||
|
||||
return new EntityManager($conn, $config, $eventManager);
|
||||
|
||||
return new EntityManager($conn, $config, $conn->getEventManager());
|
||||
}
|
||||
}
|
||||
|
@ -26,13 +26,12 @@ namespace Doctrine\ORM;
|
||||
* business specific methods for retrieving entities.
|
||||
*
|
||||
* This class is designed for inheritance and users can subclass this class to
|
||||
* write their own repositories.
|
||||
* 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 Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class EntityRepository
|
||||
{
|
||||
@ -53,21 +52,6 @@ class EntityRepository
|
||||
$this->_class = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Doctrine_Query object and adds the component name
|
||||
* of this table as the query 'from' part.
|
||||
*
|
||||
* @param string Optional alias name for component aliasing.
|
||||
* @return Doctrine_Query
|
||||
*/
|
||||
protected function _createQuery($alias = '')
|
||||
{
|
||||
if ( ! empty($alias)) {
|
||||
$alias = ' ' . trim($alias);
|
||||
}
|
||||
return $this->_em->createQuery()->from($this->_entityName . $alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the repository, causing all managed entities to become detached.
|
||||
*/
|
||||
@ -81,9 +65,9 @@ class EntityRepository
|
||||
*
|
||||
* @param $id The identifier.
|
||||
* @param int $hydrationMode The hydration mode to use.
|
||||
* @return mixed Array or Object or false if no result.
|
||||
* @return object The entity.
|
||||
*/
|
||||
public function find($id, $hydrationMode = null)
|
||||
public function find($id)
|
||||
{
|
||||
// Check identity map first
|
||||
if ($entity = $this->_em->getUnitOfWork()->tryGetById($id, $this->_class->rootEntityName)) {
|
||||
@ -102,48 +86,41 @@ class EntityRepository
|
||||
* Finds all entities in the repository.
|
||||
*
|
||||
* @param int $hydrationMode
|
||||
* @return mixed
|
||||
* @return array The entities.
|
||||
*/
|
||||
public function findAll($hydrationMode = null)
|
||||
public function findAll()
|
||||
{
|
||||
return $this->_createQuery()->execute(array(), $hydrationMode);
|
||||
return $this->findBy(array());
|
||||
}
|
||||
|
||||
/**
|
||||
* findBy
|
||||
* Finds entities by a set of criteria.
|
||||
*
|
||||
* @param string $column
|
||||
* @param string $value
|
||||
* @param string $hydrationMode
|
||||
* @return void
|
||||
* @return array
|
||||
*/
|
||||
protected function findBy($fieldName, $value, $hydrationMode = null)
|
||||
public function findBy(array $criteria)
|
||||
{
|
||||
return $this->_createQuery()->where($fieldName . ' = ?')->execute(array($value), $hydrationMode);
|
||||
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->loadAll($criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* findOneBy
|
||||
* Finds a single entity by a set of criteria.
|
||||
*
|
||||
* @param string $column
|
||||
* @param string $value
|
||||
* @param string $hydrationMode
|
||||
* @return void
|
||||
* @param string $value
|
||||
* @return object
|
||||
*/
|
||||
protected function findOneBy($fieldName, $value, $hydrationMode = null)
|
||||
public function findOneBy(array $criteria)
|
||||
{
|
||||
$results = $this->_createQuery()->where($fieldName . ' = ?')
|
||||
->setMaxResults(1)
|
||||
->execute(array($value), $hydrationMode);
|
||||
return $hydrationMode === Query::HYDRATE_ARRAY ? array_shift($results) : $results->getFirst();
|
||||
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds support for magic finders.
|
||||
* findByColumnName, findByRelationAlias
|
||||
* findById, findByContactId, etc.
|
||||
*
|
||||
* @return void
|
||||
* @return array|object The found entity/entities.
|
||||
* @throws BadMethodCallException If the method called is an invalid find* method
|
||||
* or no find* method at all and therefore an invalid
|
||||
* method call.
|
||||
@ -160,25 +137,16 @@ class EntityRepository
|
||||
throw new BadMethodCallException("Undefined method '$method'.");
|
||||
}
|
||||
|
||||
if (isset($by)) {
|
||||
if ( ! isset($arguments[0])) {
|
||||
throw DoctrineException::updateMe('You must specify the value to findBy.');
|
||||
}
|
||||
|
||||
$fieldName = Doctrine::tableize($by);
|
||||
$hydrationMode = isset($arguments[1]) ? $arguments[1]:null;
|
||||
|
||||
if ($this->_class->hasField($fieldName)) {
|
||||
return $this->$method($fieldName, $arguments[0], $hydrationMode);
|
||||
} else if ($this->_class->hasRelation($by)) {
|
||||
$relation = $this->_class->getRelation($by);
|
||||
if ($relation['type'] === Doctrine_Relation::MANY) {
|
||||
throw DoctrineException::updateMe('Cannot findBy many relationship.');
|
||||
}
|
||||
return $this->$method($relation['local'], $arguments[0], $hydrationMode);
|
||||
} else {
|
||||
throw DoctrineException::updateMe('Cannot find by: ' . $by . '. Invalid field or relationship alias.');
|
||||
}
|
||||
if ( ! isset($arguments[0])) {
|
||||
throw DoctrineException::updateMe('You must specify the value to findBy.');
|
||||
}
|
||||
|
||||
$fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by));
|
||||
|
||||
if ($this->_class->hasField($fieldName)) {
|
||||
return $this->$method(array($fieldName => $arguments[0]));
|
||||
} else {
|
||||
throw \Doctrine\Common\DoctrineException::updateMe('Cannot find by: ' . $by . '. Invalid field.');
|
||||
}
|
||||
}
|
||||
}
|
@ -207,11 +207,11 @@ class ObjectHydrator extends AbstractHydrator
|
||||
);
|
||||
$pColl->setOwner($entity, $assoc);
|
||||
$reflField->setValue($entity, $pColl);
|
||||
if ( ! $assoc->isLazilyFetched()) {
|
||||
if ($assoc->isLazilyFetched()) {
|
||||
$pColl->setInitialized(false);
|
||||
} else {
|
||||
//TODO: Allow more efficient and configurable batching of these loads
|
||||
$assoc->load($entity, $pColl, $this->_em);
|
||||
} else {
|
||||
$pColl->setInitialized(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -415,6 +415,28 @@ class StandardEntityPersister
|
||||
return $this->_createEntity($result, $entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all entities by a list of field criteria.
|
||||
*
|
||||
* @param array $criteria
|
||||
* @return array
|
||||
*/
|
||||
public function loadAll(array $criteria = array())
|
||||
{
|
||||
$entities = array();
|
||||
|
||||
$stmt = $this->_conn->prepare($this->_getSelectEntitiesSql($criteria));
|
||||
$stmt->execute(array_values($criteria));
|
||||
$result = $stmt->fetchAll(Connection::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
foreach ($result as $row) {
|
||||
$entities[] = $this->_createEntity($row);
|
||||
}
|
||||
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a collection of entities into a one-to-many association.
|
||||
*
|
||||
@ -570,7 +592,7 @@ class StandardEntityPersister
|
||||
return 'SELECT ' . $columnList
|
||||
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform)
|
||||
. $joinSql
|
||||
. ' WHERE ' . $conditionSql;
|
||||
. ($conditionSql ? ' WHERE ' . $conditionSql : '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,8 +21,8 @@
|
||||
|
||||
namespace Doctrine\ORM\Proxy;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\EntityManager,
|
||||
Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* The ProxyClassGenerator is used to generate proxy objects for entities at runtime.
|
||||
@ -42,7 +42,8 @@ class ProxyClassGenerator
|
||||
* Generates and stores proxy class files in the given cache directory.
|
||||
*
|
||||
* @param EntityManager $em
|
||||
* @param string $cacheDir
|
||||
* @param string $cacheDir The directory where generated proxy classes will be saved.
|
||||
* If not set, sys_get_temp_dir() is used.
|
||||
*/
|
||||
public function __construct(EntityManager $em, $cacheDir = null)
|
||||
{
|
||||
@ -84,7 +85,7 @@ class ProxyClassGenerator
|
||||
return $this->_generateClass($originalClassName, $proxyClassName, self::$_assocProxyClassTemplate);
|
||||
}
|
||||
|
||||
protected function _generateClass($originalClassName, $proxyClassName, $file)
|
||||
private function _generateClass($originalClassName, $proxyClassName, $file)
|
||||
{
|
||||
$proxyFullyQualifiedClassName = self::$_ns . $proxyClassName;
|
||||
|
||||
@ -124,7 +125,7 @@ class ProxyClassGenerator
|
||||
return $proxyFullyQualifiedClassName;
|
||||
}
|
||||
|
||||
protected function _generateMethods(ClassMetadata $class)
|
||||
private function _generateMethods(ClassMetadata $class)
|
||||
{
|
||||
$methods = '';
|
||||
|
||||
@ -165,7 +166,7 @@ class ProxyClassGenerator
|
||||
return $methods;
|
||||
}
|
||||
|
||||
public function _generateSleep(ClassMetadata $class)
|
||||
private function _generateSleep(ClassMetadata $class)
|
||||
{
|
||||
$sleepImpl = '';
|
||||
|
||||
|
@ -21,8 +21,8 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Query\Parser,
|
||||
Doctrine\ORM\Query\QueryException;
|
||||
|
||||
/**
|
||||
* A Query object represents a DQL query.
|
||||
@ -75,6 +75,7 @@ final class Query extends AbstractQuery
|
||||
*/
|
||||
const HINT_INCLUDE_META_COLUMNS = 'doctrine.includeMetaColumns';
|
||||
|
||||
const HINT_CUSTOM_TREE_WALKERS = 'doctrine.customTreeWalkers';
|
||||
//const HINT_READ_ONLY = 'doctrine.readOnly';
|
||||
|
||||
/**
|
||||
@ -169,6 +170,8 @@ final class Query extends AbstractQuery
|
||||
// Check query cache
|
||||
if ($queryCache = $this->getQueryCacheDriver()) {
|
||||
// Calculate hash for dql query.
|
||||
// TODO: Probably need to include query hints in hash calculation, because query hints
|
||||
// can have influence on the SQL.
|
||||
$hash = md5($this->getDql() . 'DOCTRINE_QUERY_CACHE_SALT');
|
||||
$cached = ($this->_expireQueryCache) ? false : $queryCache->fetch($hash);
|
||||
|
||||
|
@ -42,11 +42,6 @@ class QuantifiedExpression extends Node
|
||||
$this->subselect = $subselect;
|
||||
}
|
||||
|
||||
public function getSubselect()
|
||||
{
|
||||
return $this->_subselect;
|
||||
}
|
||||
|
||||
public function isAll()
|
||||
{
|
||||
return strtoupper($this->type) == 'ALL';
|
||||
|
@ -116,11 +116,18 @@ class Parser
|
||||
private $_nestingLevel = 0;
|
||||
|
||||
/**
|
||||
* Tree walker chain
|
||||
* Any additional custom tree walkers that modify the AST.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_customTreeWalkers = array();
|
||||
|
||||
/**
|
||||
* The custom last tree walker, if any, that is responsible for producing the output.
|
||||
*
|
||||
* @var TreeWalker
|
||||
*/
|
||||
private $_treeWalker = 'Doctrine\ORM\Query\SqlWalker';
|
||||
private $_customOutputWalker;
|
||||
|
||||
/**
|
||||
* Creates a new query parser object.
|
||||
@ -136,13 +143,24 @@ class Parser
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom tree walker.
|
||||
* Sets a custom tree walker that produces output.
|
||||
* This tree walker will be run last over the AST, after any other walkers.
|
||||
*
|
||||
* @param string $treeWalker
|
||||
* @param string $className
|
||||
*/
|
||||
public function setTreeWalker($treeWalker)
|
||||
public function setCustomOutputTreeWalker($className)
|
||||
{
|
||||
$this->_treeWalker = $treeWalker;
|
||||
$this->_customOutputWalker = $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom tree walker for modifying the AST.
|
||||
*
|
||||
* @param string $className
|
||||
*/
|
||||
public function addCustomTreeWalker($className)
|
||||
{
|
||||
$this->_customTreeWalkers[] = $className;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,26 +280,38 @@ class Parser
|
||||
if ($this->_lexer->lookahead !== null) {
|
||||
$this->syntaxError('end of string');
|
||||
}
|
||||
|
||||
if ($customWalkers = $this->_query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) {
|
||||
$this->_customTreeWalkers = $customWalkers;
|
||||
}
|
||||
|
||||
// Create TreeWalker who creates the SQL from the AST
|
||||
$treeWalker = new $this->_treeWalker(
|
||||
$this->_query, $this->_parserResult, $this->_queryComponents
|
||||
);
|
||||
/*if ($this->_treeWalkers) {
|
||||
// We got additional walkers, so build a chain.
|
||||
$treeWalker = new TreeWalkerChain($this->_query, $this->_parserResult, $this->_queryComponents);
|
||||
foreach ($this->_treeWalkers as $walker) {
|
||||
$treeWalker->addTreeWalker(new $walker($this->_query, $this->_parserResult, $this->_queryComponents));
|
||||
// Run any custom tree walkers over the AST
|
||||
if ($this->_customTreeWalkers) {
|
||||
$treeWalkerChain = new TreeWalkerChain($this->_query, $this->_parserResult, $this->_queryComponents);
|
||||
foreach ($this->_customTreeWalkers as $walker) {
|
||||
$treeWalkerChain->addTreeWalker($walker);
|
||||
}
|
||||
$treeWalker->setLastTreeWalker('Doctrine\ORM\Query\SqlWalker');
|
||||
} else {
|
||||
$treeWalker = new SqlWalker(
|
||||
if ($AST instanceof AST\SelectStatement) {
|
||||
$treeWalkerChain->walkSelectStatement($AST);
|
||||
} else if ($AST instanceof AST\UpdateStatement) {
|
||||
$treeWalkerChain->walkUpdateStatement($AST);
|
||||
} else {
|
||||
$treeWalkerChain->walkDeleteStatement($AST);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->_customOutputWalker) {
|
||||
$outputWalker = new $this->_customOutputWalker(
|
||||
$this->_query, $this->_parserResult, $this->_queryComponents
|
||||
);
|
||||
}*/
|
||||
} else {
|
||||
$outputWalker = new SqlWalker(
|
||||
$this->_query, $this->_parserResult, $this->_queryComponents
|
||||
);
|
||||
}
|
||||
|
||||
// Assign an SQL executor to the parser result
|
||||
$this->_parserResult->setSqlExecutor($treeWalker->getExecutor($AST));
|
||||
$this->_parserResult->setSqlExecutor($outputWalker->getExecutor($AST));
|
||||
|
||||
return $this->_parserResult;
|
||||
}
|
||||
|
@ -30,8 +30,6 @@ use Doctrine\ORM\Query,
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
* @todo Code review for schema usage with table names.
|
||||
* (Prepend schema name to tables IF schema is defined AND platform supports them)
|
||||
*/
|
||||
class SqlWalker implements TreeWalker
|
||||
{
|
||||
@ -417,14 +415,7 @@ class SqlWalker implements TreeWalker
|
||||
$sql .= $this->walkIdentificationVariable($dqlAlias, $fieldName) . '.';
|
||||
}
|
||||
|
||||
if (isset($class->associationMappings[$fieldName])) {
|
||||
//FIXME: Inverse side support
|
||||
//FIXME: Throw exception on composite key
|
||||
$assoc = $class->associationMappings[$fieldName];
|
||||
$sql .= $assoc->getQuotedJoinColumnName($assoc->joinColumns[0]['name'], $this->_platform);
|
||||
} else {
|
||||
$sql .= $class->getQuotedColumnName($fieldName, $this->_platform);
|
||||
}
|
||||
$sql .= $class->getQuotedColumnName($fieldName, $this->_platform);
|
||||
break;
|
||||
|
||||
case AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION:
|
||||
@ -604,7 +595,7 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
public function walkHavingClause($havingClause)
|
||||
{
|
||||
$condExpr = $havingClause->getConditionalExpression();
|
||||
$condExpr = $havingClause->conditionalExpression;
|
||||
|
||||
return ' HAVING ' . implode(
|
||||
' OR ', array_map(array($this, 'walkConditionalTerm'), $condExpr->conditionalTerms)
|
||||
@ -846,7 +837,7 @@ class SqlWalker implements TreeWalker
|
||||
public function walkQuantifiedExpression($qExpr)
|
||||
{
|
||||
return ' ' . strtoupper($qExpr->type)
|
||||
. '(' . $this->walkSubselect($qExpr->getSubselect()) . ')';
|
||||
. '(' . $this->walkSubselect($qExpr->subselect) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -921,7 +912,6 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
if ($expr instanceof AST\PathExpression) {
|
||||
$sql .= ' ' . $this->walkPathExpression($expr);
|
||||
//...
|
||||
} else if ($expr instanceof AST\AggregateExpression) {
|
||||
if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
|
||||
$alias = $this->_scalarAliasCounter++;
|
||||
@ -932,8 +922,8 @@ class SqlWalker implements TreeWalker
|
||||
$sql .= $this->walkAggregateExpression($expr) . ' AS dctrn__' . $alias;
|
||||
} else {
|
||||
// IdentificationVariable
|
||||
// FIXME: Composite key support, or select all columns? Does that make
|
||||
// in a subquery?
|
||||
// FIXME: Composite key support, or select all columns? Does that make sense
|
||||
// in a subquery?
|
||||
$class = $this->_queryComponents[$expr]['metadata'];
|
||||
$sql .= ' ' . $this->getSqlTableAlias($class->getTableName(), $expr) . '.'
|
||||
. $class->getQuotedColumnName($class->identifier[0], $this->_platform);
|
||||
@ -1420,7 +1410,7 @@ class SqlWalker implements TreeWalker
|
||||
if ($leftExpr instanceof AST\Node) {
|
||||
$sql .= $leftExpr->dispatch($this);
|
||||
} else {
|
||||
$sql .= $this->_conn->quote($leftExpr);
|
||||
$sql .= is_numeric($leftExpr) ? $leftExpr : $this->_conn->quote($leftExpr);
|
||||
}
|
||||
|
||||
$sql .= ' ' . $compExpr->operator . ' ';
|
||||
@ -1428,7 +1418,7 @@ class SqlWalker implements TreeWalker
|
||||
if ($rightExpr instanceof AST\Node) {
|
||||
$sql .= $rightExpr->dispatch($this);
|
||||
} else {
|
||||
$sql .= $this->_conn->quote($rightExpr);
|
||||
$sql .= is_numeric($rightExpr) ? $rightExpr : $this->_conn->quote($rightExpr);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
|
@ -30,10 +30,24 @@ namespace Doctrine\ORM\Query;
|
||||
*/
|
||||
abstract class TreeWalkerAdapter implements TreeWalker
|
||||
{
|
||||
private $_query;
|
||||
private $_parserResult;
|
||||
private $_queryComponents;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __construct($query, $parserResult, array $queryComponents) {}
|
||||
public function __construct($query, $parserResult, array $queryComponents)
|
||||
{
|
||||
$this->_query = $query;
|
||||
$this->_parserResult = $parserResult;
|
||||
$this->_queryComponents = $queryComponents;
|
||||
}
|
||||
|
||||
protected function _getQueryComponents()
|
||||
{
|
||||
return $this->_queryComponents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a SelectStatement AST node, thereby generating the appropriate SQL.
|
||||
@ -366,4 +380,11 @@ abstract class TreeWalkerAdapter implements TreeWalker
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkPathExpression($pathExpr) {}
|
||||
|
||||
/**
|
||||
* Gets an executor that can be used to execute the result of this walker.
|
||||
*
|
||||
* @return AbstractExecutor
|
||||
*/
|
||||
public function getExecutor($AST) {}
|
||||
}
|
612
lib/Doctrine/ORM/Query/TreeWalkerChain.php
Normal file
612
lib/Doctrine/ORM/Query/TreeWalkerChain.php
Normal file
@ -0,0 +1,612 @@
|
||||
<?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\Query;
|
||||
|
||||
/**
|
||||
* Represents a chain of tree walkers that modify an AST and finally emit output.
|
||||
* Only the last walker in the chain can emit output. Any previous walkers can modify
|
||||
* the AST to influence the final output produced by the last walker.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
*/
|
||||
class TreeWalkerChain implements TreeWalker
|
||||
{
|
||||
/** The tree walkers. */
|
||||
private $_walkers = array();
|
||||
/** The original Query. */
|
||||
private $_query;
|
||||
/** The ParserResult of the original query that was produced by the Parser. */
|
||||
private $_parserResult;
|
||||
/** The query components of the original query (the "symbol table") that was produced by the Parser. */
|
||||
private $_queryComponents;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __construct($query, $parserResult, array $queryComponents)
|
||||
{
|
||||
$this->_query = $query;
|
||||
$this->_parserResult = $parserResult;
|
||||
$this->_queryComponents = $queryComponents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tree walker to the chain.
|
||||
*
|
||||
* @param string $walkerClass The class of the walker to instantiate.
|
||||
*/
|
||||
public function addTreeWalker($walkerClass)
|
||||
{
|
||||
$this->_walkers[] = new $walkerClass($this->_query, $this->_parserResult, $this->_queryComponents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a SelectStatement AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkSelectStatement(AST\SelectStatement $AST)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkSelectStatement($AST);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a SelectClause AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkSelectClause($selectClause)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkSelectClause($selectClause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a FromClause AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkFromClause($fromClause)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkFromClause($fromClause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a FunctionNode AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkFunction($function)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkFunction($function);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an OrderByClause AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param OrderByClause
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkOrderByClause($orderByClause)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkOrderByClause($orderByClause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an OrderByItem AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param OrderByItem
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkOrderByItem($orderByItem)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkOrderByItem($orderByItem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a HavingClause AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param HavingClause
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkHavingClause($havingClause)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkHavingClause($havingClause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a JoinVariableDeclaration AST node and creates the corresponding SQL.
|
||||
*
|
||||
* @param JoinVariableDeclaration $joinVarDecl
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkJoinVariableDeclaration($joinVarDecl)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkJoinVariableDeclaration($joinVarDecl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a SelectExpression AST node and generates the corresponding SQL.
|
||||
*
|
||||
* @param SelectExpression $selectExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkSelectExpression($selectExpression)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkSelectExpression($selectExpression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a QuantifiedExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param QuantifiedExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkQuantifiedExpression($qExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkQuantifiedExpression($qExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a Subselect AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param Subselect
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkSubselect($subselect)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkSubselect($subselect);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a SubselectFromClause AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param SubselectFromClause
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkSubselectFromClause($subselectFromClause)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkSubselectFromClause($subselectFromClause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a SimpleSelectClause AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param SimpleSelectClause
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkSimpleSelectClause($simpleSelectClause)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkSimpleSelectClause($simpleSelectClause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a SimpleSelectExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param SimpleSelectExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkSimpleSelectExpression($simpleSelectExpression)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkSimpleSelectExpression($simpleSelectExpression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an AggregateExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param AggregateExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkAggregateExpression($aggExpression)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkAggregateExpression($aggExpression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a GroupByClause AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param GroupByClause
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkGroupByClause($groupByClause)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkGroupByClause($groupByClause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a GroupByItem AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param GroupByItem
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkGroupByItem(AST\PathExpression $pathExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkGroupByItem($pathExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an UpdateStatement AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param UpdateStatement
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkUpdateStatement(AST\UpdateStatement $AST)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkUpdateStatement($AST);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a DeleteStatement AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param DeleteStatement
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkDeleteStatement(AST\DeleteStatement $AST)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkDeleteStatement($AST);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a DeleteClause AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param DeleteClause
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkDeleteClause(AST\DeleteClause $deleteClause)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkDeleteClause($deleteClause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an UpdateClause AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param UpdateClause
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkUpdateClause($updateClause)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkUpdateClause($updateClause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an UpdateItem AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param UpdateItem
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkUpdateItem($updateItem)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkUpdateItem($updateItem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a WhereClause AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param WhereClause
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkWhereClause($whereClause)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkWhereClause($whereClause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a ConditionalTerm AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param ConditionalTerm
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkConditionalTerm($condTerm)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkConditionalTerm($condTerm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a ConditionalFactor AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param ConditionalFactor
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkConditionalFactor($factor)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkConditionalFactor($factor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an ExistsExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param ExistsExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkExistsExpression($existsExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkExistsExpression($existsExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a CollectionMemberExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param CollectionMemberExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkCollectionMemberExpression($collMemberExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkCollectionMemberExpression($collMemberExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an EmptyCollectionComparisonExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param EmptyCollectionComparisonExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkEmptyCollectionComparisonExpression($emptyCollCompExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkEmptyCollectionComparisonExpression($emptyCollCompExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param NullComparisonExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkNullComparisonExpression($nullCompExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkNullComparisonExpression($nullCompExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an InExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param InExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkInExpression($inExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkInExpression($inExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a literal that represents an AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param mixed
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkLiteral($literal)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkLiteral($literal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a BetweenExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param BetweenExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkBetweenExpression($betweenExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkBetweenExpression($betweenExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a LikeExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param LikeExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkLikeExpression($likeExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkLikeExpression($likeExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a StateFieldPathExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param StateFieldPathExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkStateFieldPathExpression($stateFieldPathExpression)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkStateFieldPathExpression($stateFieldPathExpression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a ComparisonExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param ComparisonExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkComparisonExpression($compExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkComparisonExpression($compExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an InputParameter AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param InputParameter
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkInputParameter($inputParam)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkInputParameter($inputParam);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an ArithmeticExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param ArithmeticExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkArithmeticExpression($arithmeticExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkArithmeticExpression($arithmeticExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an ArithmeticTerm AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param mixed
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkArithmeticTerm($term)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkArithmeticTerm($term);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down a StringPrimary that represents an AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param mixed
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkStringPrimary($stringPrimary)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkStringPrimary($stringPrimary);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an ArithmeticFactor that represents an AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param mixed
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkArithmeticFactor($factor)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkArithmeticFactor($factor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an SimpleArithmeticExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param SimpleArithmeticExpression
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkSimpleArithmeticExpression($simpleArithmeticExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkSimpleArithmeticExpression($simpleArithmeticExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an PathExpression AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
* @param mixed
|
||||
* @return string The SQL.
|
||||
*/
|
||||
public function walkPathExpression($pathExpr)
|
||||
{
|
||||
foreach ($this->_walkers as $walker) {
|
||||
$walker->walkPathExpression($pathExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an executor that can be used to execute the result of this walker.
|
||||
*
|
||||
* @return AbstractExecutor
|
||||
*/
|
||||
public function getExecutor($AST)
|
||||
{}
|
||||
}
|
@ -158,13 +158,6 @@ class UnitOfWork implements PropertyChangedListener
|
||||
*/
|
||||
private $_collectionDeletions = array();
|
||||
|
||||
/**
|
||||
* All pending collection creations.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
//private $_collectionCreations = array();
|
||||
|
||||
/**
|
||||
* All pending collection updates.
|
||||
*
|
||||
@ -304,7 +297,6 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$this->getCollectionPersister($collectionToUpdate->getMapping())
|
||||
->update($collectionToUpdate);
|
||||
}
|
||||
//TODO: collection recreations (insertions of complete collections)
|
||||
|
||||
// Entity deletions come last and need to be in reverse commit order
|
||||
if ($this->_entityDeletions) {
|
||||
@ -377,7 +369,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
public function computeChangeSets()
|
||||
{
|
||||
// Compute changes for INSERTed entities first. This must always happen.
|
||||
foreach ($this->_entityInsertions as $entity) {
|
||||
foreach ($this->_entityInsertions as $oid => $entity) {
|
||||
$class = $this->_em->getClassMetadata(get_class($entity));
|
||||
$this->_computeEntityChanges($class, $entity);
|
||||
// Look for changes in associations of the entity
|
||||
@ -403,9 +395,9 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$this->_scheduledForDirtyCheck[$className] : $entities;
|
||||
|
||||
foreach ($entitiesToProcess as $entity) {
|
||||
// Only MANAGED entities that are NOT INSERTED are processed here.
|
||||
// Only MANAGED entities that are NOT SCHEDULED FOR INSERTION are processed here.
|
||||
$oid = spl_object_hash($entity);
|
||||
if (isset($this->_entityStates[$oid]) && ! isset($entityInsertions[$oid])) {
|
||||
if ( ! isset($this->_entityInsertions[$oid]) && isset($this->_entityStates[$oid])) {
|
||||
$this->_computeEntityChanges($class, $entity);
|
||||
// Look for changes in associations of the entity
|
||||
foreach ($class->associationMappings as $assoc) {
|
||||
@ -581,7 +573,6 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$data[$name] = $refProp->getValue($entry);
|
||||
$changeSet[$name] = array(null, $data[$name]);
|
||||
if (isset($targetClass->associationMappings[$name])) {
|
||||
//TODO: Prevent infinite recursion
|
||||
$this->_computeAssociationChanges($targetClass->associationMappings[$name], $data[$name]);
|
||||
}
|
||||
}
|
||||
@ -600,7 +591,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL, EXPERIMENTAL:
|
||||
* INTERNAL:
|
||||
* Computes the changeset of an individual entity, independently of the
|
||||
* computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit().
|
||||
*
|
||||
@ -810,7 +801,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
if ( ! $this->_commitOrderCalculator->hasClass($targetClass->name)) {
|
||||
$this->_commitOrderCalculator->addClass($targetClass);
|
||||
}
|
||||
// add dependency
|
||||
// add dependency ($targetClass before $class)
|
||||
$this->_commitOrderCalculator->addDependency($targetClass, $class);
|
||||
}
|
||||
}
|
||||
@ -823,7 +814,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
* Schedules an entity for insertion into the database.
|
||||
* If the entity already has an identifier, it will be added to the identity map.
|
||||
*
|
||||
* @param object $entity
|
||||
* @param object $entity The entity to schedule for insertion.
|
||||
*/
|
||||
public function scheduleForInsert($entity)
|
||||
{
|
||||
@ -840,13 +831,14 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
|
||||
$this->_entityInsertions[$oid] = $entity;
|
||||
|
||||
if (isset($this->_entityIdentifiers[$oid])) {
|
||||
$this->addToIdentityMap($entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an entity is registered as new on this unit of work.
|
||||
* Checks whether an entity is scheduled for insertion.
|
||||
*
|
||||
* @param object $entity
|
||||
* @return boolean
|
||||
@ -857,9 +849,9 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a dirty entity.
|
||||
* Schedules an entity for being updated.
|
||||
*
|
||||
* @param object $entity
|
||||
* @param object $entity The entity to schedule for being updated.
|
||||
*/
|
||||
public function scheduleForUpdate($entity)
|
||||
{
|
||||
@ -880,7 +872,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Schedules an extra update that will be executed immediately after the
|
||||
* regular entity updates.
|
||||
* regular entity updates within the currently running commit cycle.
|
||||
*
|
||||
* @param $entity
|
||||
* @param $changeset
|
||||
@ -1588,7 +1580,6 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$this->_entityUpdates =
|
||||
$this->_entityDeletions =
|
||||
$this->_collectionDeletions =
|
||||
//$this->_collectionCreations =
|
||||
$this->_collectionUpdates =
|
||||
$this->_orphanRemovals = array();
|
||||
$this->_commitOrderCalculator->clear();
|
||||
@ -1778,7 +1769,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
*/
|
||||
public function tryGetById($id, $rootClassName)
|
||||
{
|
||||
$idHash = implode(' ', (array)$id);
|
||||
$idHash = implode(' ', (array) $id);
|
||||
if (isset($this->_identityMap[$rootClassName][$idHash])) {
|
||||
return $this->_identityMap[$rootClassName][$idHash];
|
||||
}
|
||||
@ -1924,23 +1915,4 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$this->_entityUpdates[$oid] = $entity;
|
||||
}
|
||||
}
|
||||
|
||||
public function dump()
|
||||
{
|
||||
var_dump($this->_identityMap);
|
||||
var_dump($this->_entityIdentifiers);
|
||||
var_dump($this->_originalEntityData);
|
||||
var_dump($this->_entityChangeSets);
|
||||
var_dump($this->_entityStates);
|
||||
var_dump($this->_scheduledForDirtyCheck);
|
||||
var_dump($this->_entityInsertions);
|
||||
var_dump($this->_entityUpdates);
|
||||
var_dump($this->_entityDeletions);
|
||||
var_dump($this->_collectionDeletions);
|
||||
//$this->_collectionCreations =
|
||||
var_dump($this->_collectionUpdates);
|
||||
var_dump($this->_orphanRemovals);
|
||||
//var_dump($this->_commitOrderCalculator->clear();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ class AllTests
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\EntityManagerTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\CommitOrderCalculatorTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\QueryBuilderTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\Proxy\ProxyClassGeneratorTest');
|
||||
$suite->addTest(Query\AllTests::suite());
|
||||
$suite->addTest(Hydration\AllTests::suite());
|
||||
$suite->addTest(Entity\AllTests::suite());
|
||||
@ -32,6 +31,7 @@ class AllTests
|
||||
$suite->addTest(Mapping\AllTests::suite());
|
||||
$suite->addTest(Functional\AllTests::suite());
|
||||
$suite->addTest(Id\AllTests::suite());
|
||||
$suite->addTest(Proxy\AllTests::suite());
|
||||
|
||||
return $suite;
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
}
|
||||
|
||||
public function testBasicManyToMany()
|
||||
{
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Guilherme';
|
||||
$user->username = 'gblanco';
|
||||
|
116
tests/Doctrine/Tests/ORM/Functional/CustomTreeWalkersTest.php
Normal file
116
tests/Doctrine/Tests/ORM/Functional/CustomTreeWalkersTest.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?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\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
/**
|
||||
* Test case for custom AST walking and modification.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
*/
|
||||
class CustomTreeWalkersTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp() {
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testSupportsQueriesWithoutWhere()
|
||||
{
|
||||
|
||||
$q = $this->_em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u where u.name = :name or u.name = :otherName');
|
||||
$q->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\Tests\ORM\Functional\CustomTreeWalker'));
|
||||
|
||||
$this->assertEquals("SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (c0_.name = ? OR c0_.name = ?) AND c0_.id = 1", $q->getSql());
|
||||
|
||||
$q->setDql('select u from Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
$this->assertEquals("SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.id = 1", $q->getSql());
|
||||
|
||||
$q->setDql('select u from Doctrine\Tests\Models\CMS\CmsUser u where u.name = :name');
|
||||
$this->assertEquals("SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.name = ? AND c0_.id = 1", $q->getSql());
|
||||
}
|
||||
}
|
||||
|
||||
class CustomTreeWalker extends Query\TreeWalkerAdapter
|
||||
{
|
||||
public function walkSelectStatement(Query\AST\SelectStatement $selectStatement)
|
||||
{
|
||||
// Get the DQL aliases of all the classes we want to modify
|
||||
$dqlAliases = array();
|
||||
foreach ($this->_getQueryComponents() as $dqlAlias => $comp) {
|
||||
// Hard-coded check just for demonstration: We want to modify the query if
|
||||
// it involves the CmsUser class.
|
||||
if ($comp['metadata']->name == 'Doctrine\Tests\Models\CMS\CmsUser') {
|
||||
$dqlAliases[] = $dqlAlias;
|
||||
}
|
||||
}
|
||||
|
||||
// Create our conditions for all involved classes
|
||||
$factors = array();
|
||||
foreach ($dqlAliases as $alias) {
|
||||
$pathExpr = new Query\AST\PathExpression(Query\AST\PathExpression::TYPE_STATE_FIELD, $alias, array('id'));
|
||||
$pathExpr->type = Query\AST\PathExpression::TYPE_STATE_FIELD;
|
||||
$comparisonExpr = new Query\AST\ComparisonExpression($pathExpr, '=', 1);
|
||||
|
||||
$condPrimary = new Query\AST\ConditionalPrimary;
|
||||
$condPrimary->simpleConditionalExpression = $comparisonExpr;
|
||||
|
||||
$factor = new Query\AST\ConditionalFactor($condPrimary);
|
||||
$factors[] = $factor;
|
||||
}
|
||||
|
||||
if ($selectStatement->whereClause !== null) {
|
||||
// There is already a WHERE clause, so append the conditions
|
||||
|
||||
$existingTerms = $selectStatement->whereClause->conditionalExpression->conditionalTerms;
|
||||
if (count($existingTerms) > 1) {
|
||||
// More than one term, so we need to wrap all these terms in a single root term
|
||||
// i.e: "WHERE u.name = :foo or u.other = :bar" => "WHERE (u.name = :foo or u.other = :bar) AND <our condition>"
|
||||
|
||||
$primary = new Query\AST\ConditionalPrimary;
|
||||
$primary->conditionalExpression = new Query\AST\ConditionalExpression($existingTerms);
|
||||
$existingFactor = new Query\AST\ConditionalFactor($primary);
|
||||
$term = new Query\AST\ConditionalTerm(array_merge(array($existingFactor), $factors));
|
||||
|
||||
$selectStatement->whereClause->conditionalExpression->conditionalTerms = array($term);
|
||||
} else {
|
||||
// Just one term so we can simply append our factors to that term
|
||||
|
||||
$singleTerm = $selectStatement->whereClause->conditionalExpression->conditionalTerms[0];
|
||||
$singleTerm->conditionalFactors = array_merge($singleTerm->conditionalFactors, $factors);
|
||||
$selectStatement->whereClause->conditionalExpression->conditionalTerms = array($singleTerm);
|
||||
}
|
||||
} else {
|
||||
// Create a new WHERE clause with our factors
|
||||
$term = new Query\AST\ConditionalTerm($factors);
|
||||
$condExpr = new Query\AST\ConditionalExpression(array($term));
|
||||
$whereClause = new Query\AST\WhereClause($condExpr);
|
||||
$selectStatement->whereClause = $whereClause;
|
||||
}
|
||||
}
|
||||
}
|
@ -58,6 +58,10 @@ class OneToOneSelfReferentialAssociationTest extends \Doctrine\Tests\OrmFunction
|
||||
$this->assertLoadingOfAssociation($customer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group mine
|
||||
* @return unknown_type
|
||||
*/
|
||||
public function testLazyLoadsAssociation()
|
||||
{
|
||||
$this->_createFixture();
|
||||
@ -66,7 +70,7 @@ class OneToOneSelfReferentialAssociationTest extends \Doctrine\Tests\OrmFunction
|
||||
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCustomer');
|
||||
$metadata->getAssociationMapping('mentor')->fetchMode = AssociationMapping::FETCH_LAZY;
|
||||
|
||||
$query = $this->_em->createQuery('select c from Doctrine\Tests\Models\ECommerce\ECommerceCustomer c');
|
||||
$query = $this->_em->createQuery("select c from Doctrine\Tests\Models\ECommerce\ECommerceCustomer c where c.name='Luke Skywalker'");
|
||||
$result = $query->getResult();
|
||||
$customer = $result[0];
|
||||
$this->assertLoadingOfAssociation($customer);
|
||||
|
@ -87,11 +87,11 @@ class SingleTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$affected = $query->execute();
|
||||
$this->assertEquals(1, $affected);
|
||||
|
||||
|
||||
$query = $this->_em->createQuery("delete Doctrine\Tests\ORM\Functional\ParentEntity e");
|
||||
|
||||
$affected = $query->execute();
|
||||
$this->assertEquals(2, $affected);
|
||||
$this->assertEquals(2, $affected);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<doctrine-mapping xmlns="http://schemas.doctrine-project.org/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://schemas.doctrine-project.org/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
/Users/robo/dev/php/Doctrine/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="XmlMappingTest\User" table="cms_users">
|
||||
|
30
tests/Doctrine/Tests/ORM/Proxy/AllTests.php
Normal file
30
tests/Doctrine/Tests/ORM/Proxy/AllTests.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Proxy;
|
||||
|
||||
if (!defined('PHPUnit_MAIN_METHOD')) {
|
||||
define('PHPUnit_MAIN_METHOD', 'Orm_Proxy_AllTests::main');
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
class AllTests
|
||||
{
|
||||
public static function main()
|
||||
{
|
||||
\PHPUnit_TextUI_TestRunner::run(self::suite());
|
||||
}
|
||||
|
||||
public static function suite()
|
||||
{
|
||||
$suite = new \Doctrine\Tests\DoctrineTestSuite('Doctrine Orm Proxy');
|
||||
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\Proxy\ProxyClassGeneratorTest');
|
||||
|
||||
return $suite;
|
||||
}
|
||||
}
|
||||
|
||||
if (PHPUnit_MAIN_METHOD == 'Orm_Proxy_AllTests::main') {
|
||||
AllTests::main();
|
||||
}
|
@ -109,14 +109,16 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
||||
$proxy->getDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException PHPUnit_Framework_Error
|
||||
*/
|
||||
public function testReferenceProxyRespectsMethodsParametersTypeHinting()
|
||||
{
|
||||
$proxyClass = $this->_generator->generateReferenceProxyClass('Doctrine\Tests\Models\ECommerce\ECommerceFeature');
|
||||
$proxy = new $proxyClass($this->_getMockPersister(), null);
|
||||
$proxy->setProduct(array('invalid parameter'));
|
||||
|
||||
$method = new \ReflectionMethod(get_class($proxy), 'setProduct');
|
||||
$params = $method->getParameters();
|
||||
|
||||
$this->assertEquals(1, count($params));
|
||||
$this->assertEquals('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $params[0]->getClass()->getName());
|
||||
}
|
||||
|
||||
protected function _getMockPersister()
|
||||
|
@ -47,8 +47,8 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
}
|
||||
|
||||
$parser = new \Doctrine\ORM\Query\Parser($query);
|
||||
// We do NOT test SQL construction here. That only unnecessarily slows down the tests!
|
||||
$parser->setTreeWalker(new \Doctrine\Tests\Mocks\MockTreeWalker(null, null, array()));
|
||||
// We do NOT test SQL output here. That only unnecessarily slows down the tests!
|
||||
$parser->setCustomOutputTreeWalker('Doctrine\Tests\Mocks\MockTreeWalker');
|
||||
|
||||
return $parser->parse();
|
||||
}
|
||||
@ -340,6 +340,12 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.phonenumbers IS EMPTY');
|
||||
}
|
||||
|
||||
public function testSingleValuedAssociationFieldInWhere()
|
||||
{
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.address = ?1');
|
||||
$this->assertValidDql('SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user = ?1');
|
||||
}
|
||||
|
||||
/**
|
||||
* This checks for invalid attempt to hydrate a proxy. It should throw an exception
|
||||
*
|
||||
|
@ -382,4 +382,17 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (SELECT COUNT(c1_.user_id) FROM cms_phonenumbers c1_ WHERE c1_.user_id = c0_.id) > 0"
|
||||
);
|
||||
}
|
||||
|
||||
/* Not yet implemented, needs more thought
|
||||
public function testSingleValuedAssociationFieldInWhere()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user = ?1",
|
||||
"SELECT c0_.phonenumber AS phonenumber0 FROM cms_phonenumbers c0_ WHERE c0_.user_id = ?"
|
||||
);
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.address = ?1",
|
||||
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.id = (SELECT c1_.user_id FROM cms_addresses c1_ WHERE c1_.id = ?)"
|
||||
);
|
||||
}*/
|
||||
}
|
||||
|
@ -21,8 +21,8 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM;
|
||||
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\QueryBuilder,
|
||||
Doctrine\ORM\Query\Expr;
|
||||
|
||||
require_once __DIR__ . '/../TestInit.php';
|
||||
|
||||
@ -36,8 +36,6 @@ require_once __DIR__ . '/../TestInit.php';
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @todo Remove QueryBuilder::create. Use constructor in tests instead. Users will use
|
||||
* $em->createQueryBuilder().
|
||||
*/
|
||||
class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
|
@ -85,12 +85,14 @@ class OrmFunctionalTestCase extends OrmTestCase
|
||||
$conn->executeUpdate('DELETE FROM ecommerce_features');
|
||||
$conn->executeUpdate('DELETE FROM ecommerce_products');
|
||||
$conn->executeUpdate('DELETE FROM ecommerce_shippings');
|
||||
$conn->executeUpdate('UPDATE ecommerce_categories SET parent_id = NULL');
|
||||
$conn->executeUpdate('DELETE FROM ecommerce_categories');
|
||||
}
|
||||
if (isset($this->_usedModelSets['company'])) {
|
||||
$conn->executeUpdate('DELETE FROM company_persons_friends');
|
||||
$conn->executeUpdate('DELETE FROM company_managers');
|
||||
$conn->executeUpdate('DELETE FROM company_employees');
|
||||
$conn->executeUpdate('UPDATE company_persons SET spouse_id = NULL');
|
||||
$conn->executeUpdate('DELETE FROM company_persons');
|
||||
}
|
||||
if (isset($this->_usedModelSets['generic'])) {
|
||||
@ -155,9 +157,8 @@ class OrmFunctionalTestCase extends OrmTestCase
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$config->setMetadataCacheImpl(self::$_metadataCacheImpl);
|
||||
$config->setQueryCacheImpl(self::$_queryCacheImpl);
|
||||
$eventManager = new \Doctrine\Common\EventManager();
|
||||
$conn = $this->sharedFixture['conn'];
|
||||
|
||||
return \Doctrine\ORM\EntityManager::create($conn, $config, $eventManager);
|
||||
return \Doctrine\ORM\EntityManager::create($conn, $config);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user