Compare commits

...

37 Commits
2.2.1 ... 2.2.2

Author SHA1 Message Date
Benjamin Eberlei
4e9438ba60 Release 2.2.2 2012-04-13 10:02:34 +02:00
Benjamin Eberlei
73483bf003 Bump Versions 2012-04-13 10:01:15 +02:00
Benjamin Eberlei
245c30a1a0 Merge branch 'DDC-1534' into 2.2 2012-04-07 10:43:49 +02:00
Benjamin Eberlei
15dc64f2f9 [DDC-1534] YamlDriver wrongly used "inversedBy" inside join table condition although its independent. 2012-04-07 10:43:21 +02:00
Benjamin Eberlei
66951f3c47 Merge remote-tracking branch 'origin/2.2' into 2.2 2012-04-07 10:35:59 +02:00
Benjamin Eberlei
5f21f177e9 Merge branch 'DDC-1771' into 2.2 2012-04-07 10:31:02 +02:00
Benjamin Eberlei
7af877d17e [DDC-1771] Abstract classes cannot be proxies and should be skipped in complete generation. 2012-04-07 10:30:32 +02:00
Benjamin Eberlei
f628a7f609 Merge pull request #327 from Netpositive/2.2
2.2 addDiscriminatorMapClass fix
2012-04-07 00:44:16 -07:00
Benjamin Eberlei
64c222e4d3 Merge branch 'DDC-1766' into 2.2 2012-04-07 09:12:17 +02:00
Benjamin Eberlei
13db27609c [DDC-1766] Rewrite getHydrationCacheId() to use existing processParameterValue() method. Other code style changes. 2012-04-07 09:11:18 +02:00
Benjamin Eberlei
f039902a44 [DDC-1766] More cleanups 2012-04-07 09:11:18 +02:00
Benjamin Eberlei
59d0c02aa9 [DDC-1766] Cleaned up code. 2012-04-07 09:11:18 +02:00
Benjamin Eberlei
63d1d847ac [DDC-1766] Explain details of Hydration cache, introduce AbstractQuery#setResultCacheProfile method 2012-04-07 09:11:18 +02:00
Benjamin Eberlei
ce4aacaaee [DDC-1766] Add usage of default result cache driver, add more docs. 2012-04-07 09:11:18 +02:00
Benjamin Eberlei
dadcc7e9fc [DDC-1766] Add test with explicit cache key. 2012-04-07 09:11:18 +02:00
Benjamin Eberlei
cc9b96e259 [DDC-1766] Remove some testcode 2012-04-07 09:11:18 +02:00
Benjamin Eberlei
006412bad9 [DDC-1766] Rename closure 2012-04-07 09:11:18 +02:00
Benjamin Eberlei
ffbaaece93 [DDC-1766] Initial implementation of hydration cache. 2012-04-07 09:11:18 +02:00
Somfai Mátyás
c3fa29f298 Fixing a bug when calling setDiscriminatorMap from multiple sources (ie: from Events::loadClassMetadata and annotation). 2012-04-04 14:47:42 +02:00
Benjamin Eberlei
aa82a75726 Merge branch 'DDC-1705' into 2.2 2012-04-01 12:51:53 +02:00
Benjamin Eberlei
fba85d481f [DDC-1705] Fix notice 2012-04-01 12:51:35 +02:00
Benjamin Eberlei
5bdfad9e0a Merge branch 'DDC-1648' into 2.2 2012-03-14 21:40:19 +01:00
rivaros
d69a79c723 Convention fix 2012-03-14 21:39:45 +01:00
Rivaros
f51409b627 convention fixes #2 2012-03-14 21:39:45 +01:00
Rivaros
8c8deb9c9b Convention fixes 2012-03-14 21:39:45 +01:00
Rivaros
79c8f42483 Primary Keys as Foreign Keys - reverse engineering 2012-03-14 21:39:45 +01:00
Benjamin Eberlei
04ae8f2c64 Merge branch 'DDC-1692' into 2.2 2012-03-14 21:10:44 +01:00
Benjamin Eberlei
ecb495d293 [DBAL-1692] Throw exception if table has no primary key instead of fatal error. 2012-03-14 21:10:09 +01:00
Benjamin Eberlei
1418173870 Merge branch 'DDC-1683' into 2.2 2012-03-14 20:50:27 +01:00
Benjamin Eberlei
26a6b69993 [DDC-1683] Fix bug with booleans not handled by Expr#literal() in query builder. 2012-03-14 20:49:51 +01:00
Benjamin Eberlei
fa5ee57faf Merge branch 'DDC-1698' into 2.2 2012-03-14 20:05:55 +01:00
Benjamin Eberlei
2a2f010788 [DDC-1698] Add autoloader especially for the non PSR-0 Proxy class names. This is necessary when you want to deserialize your proxy classes from the session. 2012-03-14 20:03:34 +01:00
Benjamin Eberlei
e958085559 Merge branch 'DDC-1695' into 2.2 2012-03-11 23:31:33 +01:00
Benjamin Eberlei
98ba0c1ab2 [DDC-1695] Fix bug in SQL Walker array hydration with escaped fields. 2012-03-11 23:31:01 +01:00
Benjamin Eberlei
b574be5e3b Merge branch 'DDC-1693' into 2.2 2012-03-11 22:30:05 +01:00
Benjamin Eberlei
79ad9068e1 [DDC-1693] Fix fatal errors in DQL when using Optimistic or None lock modes. Added tests. 2012-03-11 22:29:38 +01:00
Benjamin Eberlei
af403d52fb Bump dev version to 2.2.2 2012-03-03 22:26:27 +01:00
23 changed files with 655 additions and 25 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "doctrine/orm",
"type": "library","version":"2.2.1",
"type": "library","version":"2.2.2",
"description": "Object-Relational-Mapper for PHP",
"keywords": ["orm", "database"],
"homepage": "http://www.doctrine-project.org",

View File

@@ -20,8 +20,9 @@
namespace Doctrine\ORM;
use Doctrine\DBAL\Types\Type,
Doctrine\DBAL\Cache\QueryCacheProfile,
Doctrine\ORM\Query\QueryException,
Doctrine\DBAL\Cache\QueryCacheProfile;
Doctrine\ORM\Internal\Hydration\CacheHydrator;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
@@ -29,7 +30,6 @@ use Doctrine\DBAL\Types\Type,
* @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>
@@ -101,6 +101,11 @@ abstract class AbstractQuery
*/
protected $_expireResultCache = false;
/**
* @param \Doctrine\DBAL\Cache\QueryCacheProfile
*/
protected $_hydrationCacheProfile;
/**
* Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
*
@@ -295,6 +300,68 @@ abstract class AbstractQuery
return $this;
}
/**
* Set a cache profile for hydration caching.
*
* If no result cache driver is set in the QueryCacheProfile, the default
* result cache driver is used from the configuration.
*
* Important: Hydration caching does NOT register entities in the
* UnitOfWork when retrieved from the cache. Never use result cached
* entities for requests that also flush the EntityManager. If you want
* some form of caching with UnitOfWork registration you should use
* {@see AbstractQuery::setResultCacheProfile()}.
*
* @example
* $lifetime = 100;
* $resultKey = "abc";
* $query->setHydrationCacheProfile(new QueryCacheProfile());
* $query->setHydrationCacheProfile(new QueryCacheProfile($lifetime, $resultKey));
*
* @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile
* @return \Doctrine\ORM\AbstractQuery
*/
public function setHydrationCacheProfile(QueryCacheProfile $profile = null)
{
if ( ! $profile->getResultCacheDriver()) {
$resultCacheDriver = $this->_em->getConfiguration()->getHydrationCacheImpl();
$profile = $profile->setResultCacheDriver($resultCacheDriver);
}
$this->_hydrationCacheProfile = $profile;
return $this;
}
/**
* @return \Doctrine\DBAL\Cache\QueryCacheProfile
*/
public function getHydrationCacheProfile()
{
return $this->_hydrationCacheProfile;
}
/**
* Set a cache profile for the result cache.
*
* If no result cache driver is set in the QueryCacheProfile, the default
* result cache driver is used from the configuration.
*
* @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile
* @return \Doctrine\ORM\AbstractQuery
*/
public function setResultCacheProfile(QueryCacheProfile $profile = null)
{
if ( ! $profile->getResultCacheDriver()) {
$resultCacheDriver = $this->_em->getConfiguration()->getResultCacheImpl();
$profile = $profile->setResultCacheDriver($resultCacheDriver);
}
$this->_queryCacheProfile = $profile;
return $this;
}
/**
* Defines a cache driver to be used for caching result sets and implictly enables caching.
*
@@ -640,15 +707,68 @@ abstract class AbstractQuery
$this->setParameters($params);
}
$setCacheEntry = function() {};
if ($this->_hydrationCacheProfile !== null) {
list($cacheKey, $realCacheKey) = $this->getHydrationCacheId();
$queryCacheProfile = $this->getHydrationCacheProfile();
$cache = $queryCacheProfile->getResultCacheDriver();
$result = $cache->fetch($cacheKey);
if (isset($result[$realCacheKey])) {
return $result[$realCacheKey];
}
if ( ! $result) {
$result = array();
}
$setCacheEntry = function($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) {
$result[$realCacheKey] = $data;
$cache->save($cacheKey, $result, $queryCacheProfile->getLifetime());
};
}
$stmt = $this->_doExecute();
if (is_numeric($stmt)) {
$setCacheEntry($stmt);
return $stmt;
}
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$data = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
);
$setCacheEntry($data);
return $data;
}
/**
* Get the result cache id to use to store the result set cache entry.
* Will return the configured id if it exists otherwise a hash will be
* automatically generated for you.
*
* @return array ($key, $hash)
*/
protected function getHydrationCacheId()
{
$params = $this->getParameters();
foreach ($params AS $key => $value) {
$params[$key] = $this->processParameterValue($value);
}
$sql = $this->getSQL();
$queryCacheProfile = $this->getHydrationCacheProfile();
$hints = $this->getHints();
$hints['hydrationMode'] = $this->getHydrationMode();
ksort($hints);
return $queryCacheProfile->generateCacheKeys($sql, $params, $hints);
}
/**

View File

@@ -230,6 +230,28 @@ class Configuration extends \Doctrine\DBAL\Configuration
$this->_attributes['queryCacheImpl'] = $cacheImpl;
}
/**
* Gets the cache driver implementation that is used for the hydration cache (SQL cache).
*
* @return \Doctrine\Common\Cache\Cache
*/
public function getHydrationCacheImpl()
{
return isset($this->_attributes['hydrationCacheImpl'])
? $this->_attributes['hydrationCacheImpl']
: null;
}
/**
* Sets the cache driver implementation that is used for the hydration cache (SQL cache).
*
* @param \Doctrine\Common\Cache\Cache $cacheImpl
*/
public function setHydrationCacheImpl(Cache $cacheImpl)
{
$this->_attributes['hydrationCacheImpl'] = $cacheImpl;
}
/**
* Gets the cache driver implementation that is used for metadata caching.
*

View File

@@ -1209,7 +1209,9 @@ class ClassMetadataInfo implements ClassMetadata
foreach ($mapping['joinColumns'] as $key => &$joinColumn) {
if ($mapping['type'] === self::ONE_TO_ONE && ! $this->isInheritanceTypeSingleTable()) {
if (count($mapping['joinColumns']) == 1) {
$joinColumn['unique'] = true;
if (! isset($mapping['id']) || ! $mapping['id']) {
$joinColumn['unique'] = true;
}
} else {
$uniqueContraintColumns[] = $joinColumn['name'];
}
@@ -1991,7 +1993,7 @@ class ClassMetadataInfo implements ClassMetadata
if ( ! class_exists($className)) {
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
}
if (is_subclass_of($className, $this->name)) {
if (is_subclass_of($className, $this->name) && ! in_array($className, $this->subClasses)) {
$this->subClasses[] = $className;
}
}

View File

@@ -130,6 +130,13 @@ class DatabaseDriver implements Driver
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
}
if ( ! $table->hasPrimaryKey()) {
throw new MappingException(
"Table " . $table->getName() . " has no primary key. Doctrine does not ".
"support reverse engineering from tables that don't have a primary key."
);
}
$pkColumns = $table->getPrimaryKey()->getColumns();
sort($pkColumns);
sort($allForeignKeyColumns);
@@ -185,12 +192,13 @@ class DatabaseDriver implements Driver
$fieldMappings = array();
foreach ($columns as $column) {
$fieldMapping = array();
if ($primaryKeyColumns && in_array($column->getName(), $primaryKeyColumns)) {
$fieldMapping['id'] = true;
} else if (in_array($column->getName(), $allForeignKeyColumns)) {
if (in_array($column->getName(), $allForeignKeyColumns)) {
continue;
} else if ($primaryKeyColumns && in_array($column->getName(), $primaryKeyColumns)) {
$fieldMapping['id'] = true;
}
$fieldMapping['fieldName'] = $this->getFieldNameForColumn($tableName, $column->getName(), false);
$fieldMapping['columnName'] = $column->getName();
$fieldMapping['type'] = strtolower((string) $column->getType());
@@ -291,13 +299,23 @@ class DatabaseDriver implements Driver
$associationMapping['fieldName'] = $this->getFieldNameForColumn($tableName, $localColumn, true);
$associationMapping['targetEntity'] = $this->getClassNameForTable($foreignTable);
if ($primaryKeyColumns && in_array($localColumn, $primaryKeyColumns)) {
$associationMapping['id'] = true;
}
for ($i = 0; $i < count($cols); $i++) {
$associationMapping['joinColumns'][] = array(
'name' => $cols[$i],
'referencedColumnName' => $fkCols[$i],
);
}
$metadata->mapManyToOne($associationMapping);
//Here we need to check if $cols are the same as $primaryKeyColums
if (!array_diff($cols,$primaryKeyColumns)) {
$metadata->mapOneToOne($associationMapping);
} else {
$metadata->mapManyToOne($associationMapping);
}
}
}

View File

@@ -402,9 +402,6 @@ class YamlDriver extends AbstractFileDriver
if (isset($manyToManyElement['mappedBy'])) {
$mapping['mappedBy'] = $manyToManyElement['mappedBy'];
} else if (isset($manyToManyElement['joinTable'])) {
if (isset($manyToManyElement['inversedBy'])) {
$mapping['inversedBy'] = $manyToManyElement['inversedBy'];
}
$joinTableElement = $manyToManyElement['joinTable'];
$joinTable = array(
@@ -434,6 +431,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['joinTable'] = $joinTable;
}
if (isset($manyToManyElement['inversedBy'])) {
$mapping['inversedBy'] = $manyToManyElement['inversedBy'];
}
if (isset($manyToManyElement['cascade'])) {
$mapping['cascade'] = $manyToManyElement['cascade'];
}

View File

@@ -1143,6 +1143,7 @@ class BasicEntityPersister
$placeholder = '?';
if (isset($this->_columnTypes[$column]) &&
isset($this->_class->fieldNames[$column]) &&
isset($this->_class->fieldMappings[$this->_class->fieldNames[$column]]['requireSQLConversion'])) {
$type = Type::getType($this->_columnTypes[$column]);
$placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform);

View File

@@ -0,0 +1,78 @@
<?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\Proxy;
/**
* Special Autoloader for Proxy classes because them not being PSR-0 compatible.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class Autoloader
{
/**
* Resolve proxy class name to a filename based on the following pattern.
*
* 1. Remove Proxy namespace from class name
* 2. Remove namespace seperators from remaining class name.
* 3. Return PHP filename from proxy-dir with the result from 2.
*
* @param string $proxyDir
* @param string $proxyNamespace
* @param string $className
* @return string
*/
static public function resolveFile($proxyDir, $proxyNamespace, $className)
{
if (0 !== strpos($className, $proxyNamespace)) {
throw ProxyException::notProxyClass($className, $proxyNamespace);
}
$className = str_replace('\\', '', substr($className, strlen($proxyNamespace) +1));
return $proxyDir . DIRECTORY_SEPARATOR . $className.'.php';
}
/**
* Register and return autoloader callback for the given proxy dir and
* namespace.
*
* @param string $proxyDir
* @param string $proxyNamespace
* @param Closure $notFoundCallback Invoked when the proxy file is not found.
* @return Closure
*/
static public function register($proxyDir, $proxyNamespace, \Closure $notFoundCallback = null)
{
$proxyNamespace = ltrim($proxyNamespace, "\\");
$autoloader = function($className) use ($proxyDir, $proxyNamespace, $notFoundCallback) {
if (0 === strpos($className, $proxyNamespace)) {
$file = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className);
if ($notFoundCallback && ! file_exists($file)) {
$notFoundCallback($proxyDir, $proxyNamespace, $className);
}
require $file;
}
};
spl_autoload_register($autoloader);
return $autoloader;
}
}

View File

@@ -40,4 +40,12 @@ class ProxyException extends \Doctrine\ORM\ORMException {
return new self("You must configure a proxy namespace. See docs for details");
}
}
public static function notProxyClass($className, $proxyNamespace)
{
return new self(sprintf(
"The class %s is not part of the proxy namespace %s",
$className, $proxyNamespace
));
}
}

View File

@@ -125,22 +125,27 @@ class ProxyFactory
* @param string $toDir The target directory of the proxy classes. If not specified, the
* directory configured on the Configuration of the EntityManager used
* by this factory is used.
* @return int Number of generated proxies.
*/
public function generateProxyClasses(array $classes, $toDir = null)
{
$proxyDir = $toDir ?: $this->_proxyDir;
$proxyDir = rtrim($proxyDir, DIRECTORY_SEPARATOR);
$num = 0;
foreach ($classes as $class) {
/* @var $class ClassMetadata */
if ($class->isMappedSuperclass) {
if ($class->isMappedSuperclass || $class->reflClass->isAbstract()) {
continue;
}
$proxyFileName = $this->getProxyFileName($class->name, $proxyDir);
$this->_generateProxyClass($class, $proxyFileName, self::$_proxyClassTemplate);
$num++;
}
return $num;
}
/**

View File

@@ -562,6 +562,8 @@ class Expr
{
if (is_numeric($literal) && !is_string($literal)) {
return (string) $literal;
} else if (is_bool($literal)) {
return $literal ? "true" : "false";
} else {
return "'" . str_replace("'", "''", $literal) . "'";
}

View File

@@ -440,13 +440,15 @@ class SqlWalker implements TreeWalker
$sql .= ' ' . $this->_platform->getWriteLockSQL();
break;
case LockMode::PESSIMISTIC_OPTIMISTIC:
case LockMode::OPTIMISTIC:
foreach ($this->_selectedClasses AS $selectedClass) {
if ( ! $class->isVersioned) {
if ( ! $selectedClass['class']->isVersioned) {
throw \Doctrine\ORM\OptimisticLockException::lockFailed($selectedClass['class']->name);
}
}
break;
case LockMode::NONE:
break;
default:
throw \Doctrine\ORM\Query\QueryException::invalidLockMode();
@@ -1101,7 +1103,7 @@ class SqlWalker implements TreeWalker
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
$columnName = $class->getQuotedColumnName($fieldName, $this->_platform);
$columnAlias = $this->getSQLColumnAlias($columnName);
$columnAlias = $this->getSQLColumnAlias($class->fieldMappings[$fieldName]['columnName']);
$col = $sqlTableAlias . '.' . $columnName;

View File

@@ -862,6 +862,14 @@ public function <methodName>()
if ($this->_generateAnnotations) {
$lines[] = $this->_spaces . ' *';
if (isset($associationMapping['id']) && $associationMapping['id']) {
$lines[] = $this->_spaces . ' * @' . $this->_annotationsPrefix . 'Id';
if ($generatorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) {
$lines[] = $this->_spaces . ' * @' . $this->_annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")';
}
}
$type = null;
switch ($associationMapping['type']) {

View File

@@ -36,7 +36,7 @@ class Version
/**
* Current Doctrine Version
*/
const VERSION = '2.2.1';
const VERSION = '2.2.2';
/**
* Compares a Doctrine version with the current one.

View File

@@ -0,0 +1,86 @@
<?php
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\OrmFunctionalTestCase;
use Doctrine\Tests\Models\Cms\CmsUser;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\Common\Cache\ArrayCache;
/**
* @group DDC-1766
*/
class HydrationCacheTest extends OrmFunctionalTestCase
{
public function setUp()
{
$this->useModelSet('cms');
parent::setUp();
$user = new CmsUser;
$user->name = "Benjamin";
$user->username = "beberlei";
$user->status = 'active';
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
}
public function testHydrationCache()
{
$cache = new ArrayCache();
$dql = "SELECT u FROM Doctrine\Tests\Models\Cms\CmsUser u";
$users = $this->_em->createQuery($dql)
->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache))
->getResult();
$c = $this->getCurrentQueryCount();
$users = $this->_em->createQuery($dql)
->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache))
->getResult();
$this->assertEquals($c, $this->getCurrentQueryCount(), "Should not execute query. Its cached!");
$users = $this->_em->createQuery($dql)
->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache))
->getArrayResult();
$this->assertEquals($c + 1, $this->getCurrentQueryCount(), "Hydration is part of cache key.");
$users = $this->_em->createQuery($dql)
->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache))
->getArrayResult();
$this->assertEquals($c + 1, $this->getCurrentQueryCount(), "Hydration now cached");
$users = $this->_em->createQuery($dql)
->setHydrationCacheProfile(new QueryCacheProfile(null, 'cachekey', $cache))
->getArrayResult();
$this->assertTrue($cache->contains('cachekey'), 'Explicit cache key');
$users = $this->_em->createQuery($dql)
->setHydrationCacheProfile(new QueryCacheProfile(null, 'cachekey', $cache))
->getArrayResult();
$this->assertEquals($c + 2, $this->getCurrentQueryCount(), "Hydration now cached");
}
public function testHydrationParametersSerialization()
{
$cache = new ArrayCache();
$user = new CmsUser();
$user->id = 1;
$dql = "SELECT u FROM Doctrine\Tests\Models\Cms\CmsUser u WHERE u.id = ?1";
$query = $this->_em->createQuery($dql)
->setParameter(1, $user)
->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache));
$query->getResult();
$c = $this->getCurrentQueryCount();
$query->getResult();
$this->assertEquals($c, $this->getCurrentQueryCount(), "Should not execute query. Its cached!");
}
}

View File

@@ -9,6 +9,9 @@ use Doctrine\Tests\Models\CMS\CmsArticle,
require_once __DIR__ . '/../../../TestInit.php';
/**
* @group locking
*/
class LockTest extends \Doctrine\Tests\OrmFunctionalTestCase {
protected function setUp() {
$this->useModelSet('cms');
@@ -139,7 +142,6 @@ class LockTest extends \Doctrine\Tests\OrmFunctionalTestCase {
/**
* @group DDC-178
* @group locking
*/
public function testLockPessimisticRead() {
$readLockSql = $this->_em->getConnection()->getDatabasePlatform()->getReadLockSql();
@@ -166,4 +168,17 @@ class LockTest extends \Doctrine\Tests\OrmFunctionalTestCase {
$query = array_pop( $this->_sqlLoggerStack->queries );
$this->assertContains($readLockSql, $query['sql']);
}
}
/**
* @group DDC-1693
*/
public function testLockOptimisticNonVersionedThrowsExceptionInDQL()
{
$dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'";
$this->setExpectedException('Doctrine\ORM\OptimisticLockException', 'The optimistic lock on an entity failed.');
$sql = $this->_em->createQuery($dql)->setHint(
\Doctrine\ORM\Query::HINT_LOCK_MODE, \Doctrine\DBAL\LockMode::OPTIMISTIC
)->getSQL();
}
}

View File

@@ -0,0 +1,158 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
/**
* @group DDC-1695
*/
class DDC1695Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function testIssue()
{
if ($this->_em->getConnection()->getDatabasePlatform()->getName() != "sqlite") {
$this->markTestSkipped("Only with sqlite");
}
$dql = "SELECT n.smallText, n.publishDate FROM " . __NAMESPACE__ . "\\DDC1695News n";
$sql = $this->_em->createQuery($dql)->getSQL();
$this->assertEquals(
'SELECT d0_."SmallText" AS SmallText0, d0_."PublishDate" AS PublishDate1 FROM "DDC1695News" d0_',
$sql
);
}
}
/**
* @Table(name="`DDC1695News`")
* @Entity
*/
class DDC1695News
{
/**
* @var integer $idNews
*
* @Column(name="`IdNews`", type="integer", nullable=false)
* @Id
* @GeneratedValue
*/
private $idNews;
/**
* @var bigint $iduser
*
* @Column(name="`IdUser`", type="bigint", nullable=false)
*/
private $idUser;
/**
* @var integer $idLanguage
*
* @Column(name="`IdLanguage`", type="integer", nullable=false)
*/
private $idLanguage;
/**
* @var integer $idCondition
*
* @Column(name="`IdCondition`", type="integer", nullable=true)
*/
private $idCondition;
/**
* @var integer $idHealthProvider
*
* @Column(name="`IdHealthProvider`", type="integer", nullable=true)
*/
private $idHealthProvider;
/**
* @var integer $idSpeciality
*
* @Column(name="`IdSpeciality`", type="integer", nullable=true)
*/
private $idSpeciality;
/**
* @var integer $idMedicineType
*
* @Column(name="`IdMedicineType`", type="integer", nullable=true)
*/
private $idMedicineType;
/**
* @var integer $idTreatment
*
* @Column(name="`IdTreatment`", type="integer", nullable=true)
*/
private $idTreatment;
/**
* @var string $title
*
* @Column(name="`Title`", type="string", nullable=true)
*/
private $title;
/**
* @var string $smallText
*
* @Column(name="`SmallText`", type="string", nullable=true)
*/
private $smallText;
/**
* @var string $longText
*
* @Column(name="`LongText`", type="string", nullable=true)
*/
private $longText;
/**
* @var datetimetz $publishDate
*
* @Column(name="`PublishDate`", type="datetimetz", nullable=true)
*/
private $publishDate;
/**
* @var tsvector $idxNews
*
* @Column(name="`IdxNews`", type="tsvector", nullable=true)
*/
private $idxNews;
/**
* @var boolean $highlight
*
* @Column(name="`Highlight`", type="boolean", nullable=false)
*/
private $highlight;
/**
* @var integer $order
*
* @Column(name="`Order`", type="integer", nullable=false)
*/
private $order;
/**
* @var boolean $deleted
*
* @Column(name="`Deleted`", type="boolean", nullable=false)
*/
private $deleted;
/**
* @var boolean $active
*
* @Column(name="`Active`", type="boolean", nullable=false)
*/
private $active;
/**
* @var boolean $updateToHighlighted
*
* @Column(name="`UpdateToHighlighted`", type="boolean", nullable=true)
*/
private $updateToHighlighted;
}

View File

@@ -0,0 +1,62 @@
<?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\Tests\ORM\Proxy;
use Doctrine\Tests\OrmTestCase;
use Doctrine\ORM\Proxy\Autoloader;
/**
* @group DDC-1698
*/
class AutoloaderTest extends OrmTestCase
{
static public function dataResolveFile()
{
return array(
array('/tmp', 'MyProxy', 'MyProxy\__CG__\RealClass', '/tmp/__CG__RealClass.php'),
array('/tmp', 'MyProxy\Subdir', 'MyProxy\Subdir\__CG__\RealClass', '/tmp/__CG__RealClass.php'),
array('/tmp', 'MyProxy', 'MyProxy\__CG__\Other\RealClass', '/tmp/__CG__OtherRealClass.php'),
);
}
/**
* @dataProvider dataResolveFile
*/
public function testResolveFile($proxyDir, $proxyNamespace, $className, $expectedProxyFile)
{
$actualProxyFile = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className);
$this->assertEquals($expectedProxyFile, $actualProxyFile);
}
public function testAutoload()
{
if (file_exists(sys_get_temp_dir() ."/AutoloaderTestClass.php")) {
unlink(sys_get_temp_dir() ."/AutoloaderTestClass.php");
}
$autoloader = Autoloader::register(sys_get_temp_dir(), 'ProxyAutoloaderTest', function($proxyDir, $proxyNamespace, $className) {
file_put_contents(sys_get_temp_dir() . "/AutoloaderTestClass.php", "<?php namespace ProxyAutoloaderTest; class AutoloaderTestClass {} ");
});
$this->assertTrue(class_exists('ProxyAutoloaderTest\AutoloaderTestClass', true));
unlink(sys_get_temp_dir() ."/AutoloaderTestClass.php");
}
}

View File

@@ -155,6 +155,20 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(1, substr_count($classCode, 'function __sleep'));
}
/**
* @group DDC-1771
*/
public function testSkipAbstractClassesOnGeneration()
{
$cm = new \Doctrine\ORM\Mapping\ClassMetadata(__NAMESPACE__ . '\\AbstractClass');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->assertNotNull($cm->reflClass);
$num = $this->_proxyFactory->generateProxyClasses(array($cm));
$this->assertEquals(0, $num, "No proxies generated.");
}
public function testNoConfigDir_ThrowsException()
{
$this->setExpectedException('Doctrine\ORM\Proxy\ProxyException');
@@ -183,3 +197,8 @@ class SleepClass
return array('id');
}
}
abstract class AbstractClass
{
}

View File

@@ -336,4 +336,13 @@ class ExprTest extends \Doctrine\Tests\OrmTestCase
$orExpr = $this->_expr->orx();
$orExpr->add($this->_expr->quot(5, 2));
}
}
/**
* @group DDC-1683
*/
public function testBooleanLiteral()
{
$this->assertEquals('true', $this->_expr->literal(true));
$this->assertEquals('false', $this->_expr->literal(false));
}
}

View File

@@ -893,6 +893,20 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
);
}
/**
* @group DDC-1693
* @group locking
*/
public function testLockModeNoneQueryHint()
{
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 ".
"FROM cms_users c0_ WHERE c0_.username = 'gblanco'",
array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::NONE)
);
}
/**
* @group DDC-430
*/