Merge branch 'master' into DDC-551
Conflicts: lib/Doctrine/ORM/Configuration.php lib/Doctrine/ORM/Persisters/BasicEntityPersister.php lib/Doctrine/ORM/Persisters/ManyToManyPersister.php
This commit is contained in:
commit
097d573d26
@ -1,3 +1,19 @@
|
||||
# Removed support for onUpdate in @JoinColumn
|
||||
|
||||
The onUpdate foreign key handling makes absolutly no sense in an ORM. Additionally Oracle doesn't even support it. Support for it is removed.
|
||||
|
||||
# Changes in Annotation Handling
|
||||
|
||||
There have been some changes to the annotation handling in Common 2.2 again, that affect how people with old configurations
|
||||
from 2.0 have to configure the annotation driver if they don't use `Configuration::newDefaultAnnotationDriver()`:
|
||||
|
||||
// Register the ORM Annotations in the AnnotationRegistry
|
||||
AnnotationRegistry::registerFile('path/to/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php');
|
||||
|
||||
$reader = new \Doctrine\Common\Annotations\SimpleAnnotationReader();
|
||||
$reader->addNamespace('Doctrine\ORM\Mapping');
|
||||
$reader = new \Doctrine\Common\Annotations\CachedReader($reader, new ArrayCache());
|
||||
|
||||
$driver = new AnnotationDriver($reader, (array)$paths);
|
||||
|
||||
$config->setMetadataDriverImpl($driver);
|
@ -8,6 +8,7 @@ report.dir=reports
|
||||
log.archive.dir=logs
|
||||
project.pirum_dir=
|
||||
project.download_dir=
|
||||
project.xsd_dir=
|
||||
test.phpunit_configuration_file=
|
||||
test.phpunit_generate_coverage=0
|
||||
test.pmd_reports=0
|
||||
|
@ -223,7 +223,12 @@
|
||||
|
||||
<target name="distribute-download">
|
||||
<copy file="dist/DoctrineORM-${version}-full.tar.gz" todir="${project.download_dir}" />
|
||||
<copy file="${dist.dir}/doctrine-orm-${version}.phar" todir="${project.download_dir}" />
|
||||
<!--<copy file="${dist.dir}/doctrine-orm-${version}.phar" todir="${project.download_dir}" />-->
|
||||
</target>
|
||||
|
||||
<target name="distribute-xsd">
|
||||
<php expression="substr('${version}', 0, 3)" returnProperty="minorVersion" /><!-- not too robust -->
|
||||
<copy file="${project.basedir}/doctrine-mapping.xsd" tofile="${project.xsd_dir}/doctrine-mapping-${minorVersion}.xsd" />
|
||||
</target>
|
||||
|
||||
<target name="update-dev-version">
|
||||
@ -235,7 +240,7 @@
|
||||
<exec command="git commit -m 'Bump Dev Version to ${next_version}-DEV'" passthru="true" />
|
||||
</target>
|
||||
|
||||
<target name="release" depends="git-tag,build-packages,package-phar,distribute-download,pirum-release,update-dev-version" />
|
||||
<target name="release" depends="git-tag,build-packages,distribute-download,pirum-release,update-dev-version,distribute-xsd" />
|
||||
|
||||
<!--
|
||||
Builds distributable PEAR packages for the Symfony Dependencies
|
||||
|
20
composer.json
Normal file
20
composer.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "doctrine/orm",
|
||||
"type": "library",
|
||||
"description": "Object-Relational-Mapper for PHP",
|
||||
"keywords": ["orm", "database"],
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"license": "LGPL",
|
||||
"authors": [
|
||||
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
|
||||
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
|
||||
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
|
||||
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"ext-pdo": "*",
|
||||
"doctrine/common": "master-dev",
|
||||
"doctrine/dbal": "master-dev"
|
||||
}
|
||||
}
|
@ -92,7 +92,7 @@
|
||||
<xs:element name="discriminator-map" type="orm:discriminator-map" minOccurs="0"/>
|
||||
<xs:element name="lifecycle-callbacks" type="orm:lifecycle-callbacks" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="named-queries" type="orm:named-queries" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="id" type="orm:id" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="id" type="orm:id" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="field" type="orm:field" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="one-to-one" type="orm:one-to-one" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="one-to-many" type="orm:one-to-many" minOccurs="0" maxOccurs="unbounded" />
|
||||
|
@ -162,6 +162,16 @@ abstract class AbstractQuery
|
||||
{
|
||||
return $this->_params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all defined parameter types.
|
||||
*
|
||||
* @return array The defined query parameter types.
|
||||
*/
|
||||
public function getParameterTypes()
|
||||
{
|
||||
return $this->_paramTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a query parameter.
|
||||
@ -174,6 +184,17 @@ abstract class AbstractQuery
|
||||
return isset($this->_params[$key]) ? $this->_params[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a query parameter type.
|
||||
*
|
||||
* @param mixed $key The key (index or name) of the bound parameter.
|
||||
* @return mixed The parameter type of the bound parameter.
|
||||
*/
|
||||
public function getParameterType($key)
|
||||
{
|
||||
return isset($this->_paramTypes[$key]) ? $this->_paramTypes[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL query that corresponds to this query object.
|
||||
* The returned SQL syntax depends on the connection driver that is used
|
||||
|
@ -528,4 +528,32 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
return isset($this->_attributes['filters'][$name]) ?
|
||||
$this->_attributes['filters'][$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default repository class.
|
||||
*
|
||||
* @since 2.2
|
||||
* @param string $className
|
||||
* @throws ORMException If not is a Doctrine\ORM\EntityRepository
|
||||
*/
|
||||
public function setDefaultRepositoryClassName($className)
|
||||
{
|
||||
if ($className != "Doctrine\ORM\EntityRepository" &&
|
||||
!is_subclass_of($className, 'Doctrine\ORM\EntityRepository')){
|
||||
throw ORMException::invalidEntityRepository($className);
|
||||
}
|
||||
$this->_attributes['defaultRepositoryClassName'] = $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default repository class.
|
||||
*
|
||||
* @since 2.2
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultRepositoryClassName()
|
||||
{
|
||||
return isset($this->_attributes['defaultRepositoryClassName']) ?
|
||||
$this->_attributes['defaultRepositoryClassName'] : 'Doctrine\ORM\EntityRepository';
|
||||
}
|
||||
}
|
||||
|
@ -584,7 +584,8 @@ class EntityManager implements ObjectManager
|
||||
if ($customRepositoryClassName !== null) {
|
||||
$repository = new $customRepositoryClassName($this, $metadata);
|
||||
} else {
|
||||
$repository = new EntityRepository($this, $metadata);
|
||||
$repositoryClass = $this->config->getDefaultRepositoryClassName();
|
||||
$repository = new $repositoryClass($this, $metadata);
|
||||
}
|
||||
|
||||
$this->repositories[$entityName] = $repository;
|
||||
|
110
lib/Doctrine/ORM/Event/EntityEventDelegator.php
Normal file
110
lib/Doctrine/ORM/Event/EntityEventDelegator.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use \Doctrine\Common\EventSubscriber;
|
||||
use \LogicException;
|
||||
|
||||
/**
|
||||
* Delegate events only for certain entities they are registered for.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @since 2.2
|
||||
*/
|
||||
class EntityEventDelegator implements EventSubscriber
|
||||
{
|
||||
/**
|
||||
* Keeps track of all the event listeners.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $listeners = array();
|
||||
|
||||
/**
|
||||
* If frozen no new event listeners can be added.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $frozen = false;
|
||||
|
||||
/**
|
||||
* Adds an event listener that listens on the specified events.
|
||||
*
|
||||
* @param string|array $events The event(s) to listen on.
|
||||
* @param string|array $entities The entities to trigger this listener for
|
||||
* @param object $listener The listener object.
|
||||
*/
|
||||
public function addEventListener($events, $entities, $listener)
|
||||
{
|
||||
if ($this->frozen) {
|
||||
throw new LogicException("Cannot add event listeners after EntityEventDelegator::getSubscribedEvents() " .
|
||||
"is called once. This happens when you register the delegator with the event manager.");
|
||||
}
|
||||
|
||||
// Picks the hash code related to that listener
|
||||
$hash = spl_object_hash($listener);
|
||||
|
||||
foreach ((array) $events as $event) {
|
||||
// Overrides listener if a previous one was associated already
|
||||
// Prevents duplicate listeners on same event (same instance only)
|
||||
$this->listeners[$event][$hash] = array('listener' => $listener, 'entities' => array_flip((array)$entities));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an EventSubscriber. The subscriber is asked for all the events he is
|
||||
* interested in and added as a listener for these events.
|
||||
*
|
||||
* @param Doctrine\Common\EventSubscriber $subscriber The subscriber.
|
||||
*/
|
||||
public function addEventSubscriber(EventSubscriber $subscriber, $entities)
|
||||
{
|
||||
$this->addEventListener($subscriber->getSubscribedEvents(), $entities, $subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of events this subscriber wants to listen to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSubscribedEvents()
|
||||
{
|
||||
$this->frozen = true;
|
||||
return array_keys($this->listeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate the event to an appropriate listener
|
||||
*
|
||||
* @param $eventName
|
||||
* @param $event
|
||||
* @return void
|
||||
*/
|
||||
public function __call($eventName, $args)
|
||||
{
|
||||
$event = $args[0];
|
||||
foreach ($this->listeners[$eventName] AS $listenerData) {
|
||||
$class = get_class($event->getEntity());
|
||||
if (isset($listenerData['entities'][$class])) {
|
||||
$listenerData['listener']->$eventName($event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -90,7 +90,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
if (!isset($this->_entityChangeSet[$field])) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Field '".$field."' is not a valid field of the entity ".
|
||||
"'".get_class($this->getEntity())."' in PreInsertUpdateEventArgs."
|
||||
"'".get_class($this->getEntity())."' in PreUpdateEventArgs."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
167
lib/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php
Normal file
167
lib/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php
Normal file
@ -0,0 +1,167 @@
|
||||
<?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\Mapping\Builder;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
class AssociationBuilder
|
||||
{
|
||||
/**
|
||||
* @var ClassMetadataBuilder
|
||||
*/
|
||||
protected $builder;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $mapping;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $joinColumns;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @param ClassMetadataBuilder $builder
|
||||
* @param array $mapping
|
||||
*/
|
||||
public function __construct(ClassMetadataBuilder $builder, array $mapping, $type)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->mapping = $mapping;
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
public function mappedBy($fieldName)
|
||||
{
|
||||
$this->mapping['mappedBy'] = $fieldName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function inversedBy($fieldName)
|
||||
{
|
||||
$this->mapping['inversedBy'] = $fieldName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function cascadeAll()
|
||||
{
|
||||
$this->mapping['cascade'] = array("ALL");
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function cascadePersist()
|
||||
{
|
||||
$this->mapping['cascade'][] = "persist";
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function cascadeRemove()
|
||||
{
|
||||
$this->mapping['cascade'][] = "remove";
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function cascadeMerge()
|
||||
{
|
||||
$this->mapping['cascade'][] = "merge";
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function cascadeDetach()
|
||||
{
|
||||
$this->mapping['cascade'][] = "detach";
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function cascadeRefresh()
|
||||
{
|
||||
$this->mapping['cascade'][] = "refresh";
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fetchExtraLazy()
|
||||
{
|
||||
$this->mapping['fetch'] = ClassMetadata::FETCH_EXTRA_LAZY;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fetchEager()
|
||||
{
|
||||
$this->mapping['fetch'] = ClassMetadata::FETCH_EAGER;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fetchLazy()
|
||||
{
|
||||
$this->mapping['fetch'] = ClassMetadata::FETCH_LAZY;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Join Columns
|
||||
*
|
||||
* @param string $columnName
|
||||
* @param string $referencedColumnName
|
||||
* @param bool $nullable
|
||||
* @param bool $unique
|
||||
* @param string $onDelete
|
||||
* @param string $columnDef
|
||||
*/
|
||||
public function addJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
|
||||
{
|
||||
$this->joinColumns[] = array(
|
||||
'name' => $columnName,
|
||||
'referencedColumnName' => $referencedColumnName,
|
||||
'nullable' => $nullable,
|
||||
'unique' => $unique,
|
||||
'onDelete' => $onDelete,
|
||||
'columnDefinition' => $columnDef,
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$mapping = $this->mapping;
|
||||
if ($this->joinColumns) {
|
||||
$mapping['joinColumns'] = $this->joinColumns;
|
||||
}
|
||||
$cm = $this->builder->getClassMetadata();
|
||||
if ($this->type == ClassMetadata::MANY_TO_ONE) {
|
||||
$cm->mapManyToOne($mapping);
|
||||
} else if ($this->type == ClassMetadata::ONE_TO_ONE) {
|
||||
$cm->mapOneToOne($mapping);
|
||||
} else {
|
||||
throw new \InvalidArgumentException("Type should be a ToOne Assocation here");
|
||||
}
|
||||
return $this->builder;
|
||||
}
|
||||
}
|
407
lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php
Normal file
407
lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php
Normal file
@ -0,0 +1,407 @@
|
||||
<?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\Mapping\Builder;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* Builder Object for ClassMetadata
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 2.2
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class ClassMetadataBuilder
|
||||
{
|
||||
/**
|
||||
* @var ClassMetadata
|
||||
*/
|
||||
private $cm;
|
||||
|
||||
/**
|
||||
* @param ClassMetadata $cm
|
||||
*/
|
||||
public function __construct(ClassMetadata $cm)
|
||||
{
|
||||
$this->cm = $cm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadata
|
||||
*/
|
||||
public function getClassMetadata()
|
||||
{
|
||||
return $this->cm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the class as mapped superclass.
|
||||
*
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function setMappedSuperClass()
|
||||
{
|
||||
$this->cm->isMappedSuperclass = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom Repository class name
|
||||
*
|
||||
* @param string $repositoryClassName
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function setCustomRepositoryClass($repositoryClassName)
|
||||
{
|
||||
$this->cm->setCustomRepositoryClass($repositoryClassName);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark class read only
|
||||
*
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function setReadOnly()
|
||||
{
|
||||
$this->cm->markReadOnly();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table name
|
||||
*
|
||||
* @param string $name
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function setTable($name)
|
||||
{
|
||||
$this->cm->setPrimaryTable(array('name' => $name));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Index
|
||||
*
|
||||
* @param array $columns
|
||||
* @param string $name
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addIndex(array $columns, $name)
|
||||
{
|
||||
if (!isset($this->cm->table['indexes'])) {
|
||||
$this->cm->table['indexes'] = array();
|
||||
}
|
||||
$this->cm->table['indexes'][$name] = array('columns' => $columns);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Unique Constraint
|
||||
*
|
||||
* @param array $columns
|
||||
* @param string $name
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addUniqueConstraint(array $columns, $name)
|
||||
{
|
||||
if (!isset($this->cm->table['uniqueConstraints'])) {
|
||||
$this->cm->table['uniqueConstraints'] = array();
|
||||
}
|
||||
$this->cm->table['uniqueConstraints'][$name] = array('columns' => $columns);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add named query
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $dqlQuery
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addNamedQuery($name, $dqlQuery)
|
||||
{
|
||||
$this->cm->addNamedQuery(array(
|
||||
'name' => $name,
|
||||
'query' => $dqlQuery,
|
||||
));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set class as root of a joined table inheritance hierachy.
|
||||
*
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function setJoinedTableInheritance()
|
||||
{
|
||||
$this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_JOINED);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set class as root of a single table inheritance hierachy.
|
||||
*
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function setSingleTableInheritance()
|
||||
{
|
||||
$this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the discriminator column details.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
*/
|
||||
public function setDiscriminatorColumn($name, $type = 'string', $length = 255)
|
||||
{
|
||||
$this->cm->setDiscriminatorColumn(array(
|
||||
'name' => $name,
|
||||
'type' => $type,
|
||||
'length' => $length,
|
||||
));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a subclass to this inheritance hierachy.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $class
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addDiscriminatorMapClass($name, $class)
|
||||
{
|
||||
$this->cm->addDiscriminatorMapClass($name, $class);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set deferred explicit change tracking policy.
|
||||
*
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function setChangeTrackingPolicyDeferredExplicit()
|
||||
{
|
||||
$this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set notify change tracking policy.
|
||||
*
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function setChangeTrackingPolicyNotify()
|
||||
{
|
||||
$this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_NOTIFY);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add lifecycle event
|
||||
*
|
||||
* @param string $methodName
|
||||
* @param string $event
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addLifecycleEvent($methodName, $event)
|
||||
{
|
||||
$this->cm->addLifecycleCallback($methodName, $event);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Field
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @param array $mapping
|
||||
*/
|
||||
public function addField($name, $type, array $mapping = array())
|
||||
{
|
||||
$mapping['fieldName'] = $name;
|
||||
$mapping['type'] = $type;
|
||||
$this->cm->mapField($mapping);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a field builder.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function createField($name, $type)
|
||||
{
|
||||
return new FieldBuilder($this, array('fieldName' => $name, 'type' => $type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a simple many to one association, optionally with the inversed by field.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $targetEntity
|
||||
* @param string|null $inversedBy
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addManyToOne($name, $targetEntity, $inversedBy = null)
|
||||
{
|
||||
$builder = $this->createManyToOne($name, $targetEntity);
|
||||
if ($inversedBy) {
|
||||
$builder->setInversedBy($inversedBy);
|
||||
}
|
||||
return $builder->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ManyToOne Assocation Builder.
|
||||
*
|
||||
* Note: This method does not add the association, you have to call build() on the AssociationBuilder.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $targetEntity
|
||||
* @return AssociationBuilder
|
||||
*/
|
||||
public function createManyToOne($name, $targetEntity)
|
||||
{
|
||||
return new AssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::MANY_TO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create OneToOne Assocation Builder
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $targetEntity
|
||||
* @return AssociationBuilder
|
||||
*/
|
||||
public function createOneToOne($name, $targetEntity)
|
||||
{
|
||||
return new AssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::ONE_TO_ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add simple inverse one-to-one assocation.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $targetEntity
|
||||
* @param string $mappedBy
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addInverseOneToOne($name, $targetEntity, $mappedBy)
|
||||
{
|
||||
$builder = $this->createOneToOne($name, $targetEntity);
|
||||
$builder->setMappedBy($mappedBy);
|
||||
return $builder->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add simple owning one-to-one assocation.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $targetEntity
|
||||
* @param string $inversedBy
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addOwningOneToOne($name, $targetEntity, $inversedBy = null)
|
||||
{
|
||||
$builder = $this->createOneToOne($name, $targetEntity);
|
||||
if ($inversedBy) {
|
||||
$builder->setInversedBy($inversedBy);
|
||||
}
|
||||
return $builder->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create ManyToMany Assocation Builder
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $targetEntity
|
||||
* @return ManyToManyAssociationBuilder
|
||||
*/
|
||||
public function createManyToMany($name, $targetEntity)
|
||||
{
|
||||
return new ManyToManyAssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::MANY_TO_MANY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a simple owning many to many assocation.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $targetEntity
|
||||
* @param string|null $inversedBy
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addOwningManyToMany($name, $targetEntity, $inversedBy = null)
|
||||
{
|
||||
$builder = $this->createManyToMany($name, $targetEntity);
|
||||
if ($inversedBy) {
|
||||
$builder->setInversedBy($inversedBy);
|
||||
}
|
||||
return $builder->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a simple inverse many to many assocation.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $targetEntity
|
||||
* @param string $mappedBy
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addInverseManyToMany($name, $targetEntity, $mappedBy)
|
||||
{
|
||||
$builder = $this->createManyToMany($name, $targetEntity);
|
||||
$builder->setMappedBy($mappedBy);
|
||||
return $builder->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a one to many assocation builder
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $targetEntity
|
||||
* @return OneToManyAssociationBuilder
|
||||
*/
|
||||
public function createOneToMany($name, $targetEntity)
|
||||
{
|
||||
return new OneToManyAssociationBuilder($this, array('fieldName' => $name, 'targetEntity' => $targetEntity), ClassMetadata::ONE_TO_MANY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add simple OneToMany assocation.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $targetEntity
|
||||
* @param string $mappedBy
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function addOneToMany($name, $targetEntity, $mappedBy)
|
||||
{
|
||||
$builder = $this->createOneToMany($name, $targetEntity);
|
||||
$builder->setMappedBy($mappedBy);
|
||||
return $builder->build();
|
||||
}
|
||||
}
|
223
lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php
Normal file
223
lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php
Normal file
@ -0,0 +1,223 @@
|
||||
<?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\Mapping\Builder;
|
||||
|
||||
/**
|
||||
* Field Builder
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 2.2
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class FieldBuilder
|
||||
{
|
||||
/**
|
||||
* @var ClassMetadataBuilder
|
||||
*/
|
||||
private $builder;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $mapping;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $generatedValue;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $sequenceDef;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ClassMetadataBuilder $builder
|
||||
* @param array $mapping
|
||||
*/
|
||||
public function __construct(ClassMetadataBuilder $builder, array $mapping)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->mapping = $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set length.
|
||||
*
|
||||
* @param int $length
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function length($length)
|
||||
{
|
||||
$this->mapping['length'] = $length;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set nullable
|
||||
*
|
||||
* @param bool
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function nullable($flag = true)
|
||||
{
|
||||
$this->mapping['nullable'] = (bool)$flag;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Unique
|
||||
*
|
||||
* @param bool
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function unique($flag = true)
|
||||
{
|
||||
$this->mapping['unique'] = (bool)$flag;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set column name
|
||||
*
|
||||
* @param string $name
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function columnName($name)
|
||||
{
|
||||
$this->mapping['columnName'] = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Precision
|
||||
*
|
||||
* @param int $p
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function precision($p)
|
||||
{
|
||||
$this->mapping['precision'] = $p;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set scale.
|
||||
*
|
||||
* @param int $s
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function scale($s)
|
||||
{
|
||||
$this->mapping['scale'] = $s;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set field as primary key.
|
||||
*
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function isPrimaryKey()
|
||||
{
|
||||
$this->mapping['id'] = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $strategy
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function generatedValue($strategy = 'AUTO')
|
||||
{
|
||||
$this->generatedValue = $strategy;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set field versioned
|
||||
*
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function isVersionField()
|
||||
{
|
||||
$this->version = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Sequence Generator
|
||||
*
|
||||
* @param string $sequenceName
|
||||
* @param int $allocationSize
|
||||
* @param int $initialValue
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function setSequenceGenerator($sequenceName, $allocationSize = 1, $initialValue = 1)
|
||||
{
|
||||
$this->sequenceDef = array(
|
||||
'sequenceName' => $sequenceName,
|
||||
'allocationSize' => $allocationSize,
|
||||
'initialValue' => $initialValue,
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set column definition.
|
||||
*
|
||||
* @param string $def
|
||||
* @return FieldBuilder
|
||||
*/
|
||||
public function columnDefinition($def)
|
||||
{
|
||||
$this->mapping['columnDefinition'] = $def;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize this field and attach it to the ClassMetadata.
|
||||
*
|
||||
* Without this call a FieldBuilder has no effect on the ClassMetadata.
|
||||
*
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$cm = $this->builder->getClassMetadata();
|
||||
if ($this->generatedValue) {
|
||||
$cm->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $this->generatedValue));
|
||||
}
|
||||
if ($this->version) {
|
||||
$cm->setVersionMapping($this->mapping);
|
||||
}
|
||||
$cm->mapField($this->mapping);
|
||||
if ($this->sequenceDef) {
|
||||
$cm->setSequenceGeneratorDefinition($this->sequenceDef);
|
||||
}
|
||||
return $this->builder;
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
<?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\Mapping\Builder;
|
||||
|
||||
/**
|
||||
* ManyToMany Association Builder
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 2.0
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
|
||||
{
|
||||
private $joinTableName;
|
||||
|
||||
private $inverseJoinColumns = array();
|
||||
|
||||
public function setJoinTable($name)
|
||||
{
|
||||
$this->joinTableName = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Inverse Join Columns
|
||||
*
|
||||
* @param string $columnName
|
||||
* @param string $referencedColumnName
|
||||
* @param bool $nullable
|
||||
* @param bool $unique
|
||||
* @param string $onDelete
|
||||
* @param string $columnDef
|
||||
*/
|
||||
public function addInverseJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
|
||||
{
|
||||
$this->inverseJoinColumns[] = array(
|
||||
'name' => $columnName,
|
||||
'referencedColumnName' => $referencedColumnName,
|
||||
'nullable' => $nullable,
|
||||
'unique' => $unique,
|
||||
'onDelete' => $onDelete,
|
||||
'columnDefinition' => $columnDef,
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$mapping = $this->mapping;
|
||||
$mapping['joinTable'] = array();
|
||||
if ($this->joinColumns) {
|
||||
$mapping['joinTable']['joinColumns'] = $this->joinColumns;
|
||||
}
|
||||
if ($this->inverseJoinColumns) {
|
||||
$mapping['joinTable']['inverseJoinColumns'] = $this->inverseJoinColumns;
|
||||
}
|
||||
if ($this->joinTableName) {
|
||||
$mapping['joinTable']['name'] = $this->joinTableName;
|
||||
}
|
||||
$cm = $this->builder->getClassMetadata();
|
||||
$cm->mapManyToMany($mapping);
|
||||
return $this->builder;
|
||||
}
|
||||
}
|
@ -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\ORM\Mapping\Builder;
|
||||
|
||||
/**
|
||||
* OneToMany Association Builder
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 2.0
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class OneToManyAssociationBuilder extends AssociationBuilder
|
||||
{
|
||||
/**
|
||||
* @param array $fieldNames
|
||||
* @return OneToManyAssociationBuilder
|
||||
*/
|
||||
public function setOrderBy(array $fieldNames)
|
||||
{
|
||||
$this->mapping['orderBy'] = $fieldNames;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setIndexBy($fieldName)
|
||||
{
|
||||
$this->mapping['indexBy'] = $fieldName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$mapping = $this->mapping;
|
||||
if ($this->joinColumns) {
|
||||
$mapping['joinColumns'] = $this->joinColumns;
|
||||
}
|
||||
$cm = $this->builder->getClassMetadata();
|
||||
$cm->mapOneToMany($mapping);
|
||||
return $this->builder;
|
||||
}
|
||||
}
|
@ -343,4 +343,17 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
}
|
||||
return clone $this->_prototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $callback
|
||||
* @param string $event
|
||||
*/
|
||||
public function addLifecycleCallback($callback, $event)
|
||||
{
|
||||
if ( !$this->reflClass->hasMethod($callback) ||
|
||||
($this->reflClass->getMethod($callback)->getModifiers() & \ReflectionMethod::IS_PUBLIC) == 0) {
|
||||
throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callback);
|
||||
}
|
||||
return parent::addLifecycleCallback($callback, $event);
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
|
||||
private $targetPlatform;
|
||||
|
||||
/**
|
||||
* @var Driver\Driver
|
||||
* @var \Doctrine\ORM\Mapping\Driver\Driver
|
||||
*/
|
||||
private $driver;
|
||||
|
||||
@ -274,6 +274,9 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
|
||||
$class->setDiscriminatorMap($parent->discriminatorMap);
|
||||
$class->setLifecycleCallbacks($parent->lifecycleCallbacks);
|
||||
$class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
|
||||
if ($parent->isMappedSuperclass) {
|
||||
$class->setCustomRepositoryClass($parent->customRepositoryClassName);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke driver
|
||||
@ -448,7 +451,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
|
||||
// <table>_<column>_seq in PostgreSQL for SERIAL columns.
|
||||
// Not pretty but necessary and the simplest solution that currently works.
|
||||
$seqName = $this->targetPlatform instanceof Platforms\PostgreSQLPlatform ?
|
||||
$class->table['name'] . '_' . $class->columnNames[$class->identifier[0]] . '_seq' :
|
||||
$class->getTableName() . '_' . $class->columnNames[$class->identifier[0]] . '_seq' :
|
||||
null;
|
||||
$class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator($seqName));
|
||||
break;
|
||||
@ -478,4 +481,15 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
|
||||
throw new ORMException("Unknown generator type: " . $class->generatorType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this class is mapped by this EntityManager + ClassMetadata configuration
|
||||
*
|
||||
* @param $class
|
||||
* @return bool
|
||||
*/
|
||||
public function isTransient($class)
|
||||
{
|
||||
return $this->driver->isTransient($class);
|
||||
}
|
||||
}
|
||||
|
@ -774,9 +774,13 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
// If targetEntity is unqualified, assume it is in the same namespace as
|
||||
// the sourceEntity.
|
||||
$mapping['sourceEntity'] = $this->name;
|
||||
if (isset($mapping['targetEntity']) && strpos($mapping['targetEntity'], '\\') === false
|
||||
&& strlen($this->namespace) > 0) {
|
||||
$mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity'];
|
||||
|
||||
if (isset($mapping['targetEntity'])) {
|
||||
if (strlen($this->namespace) > 0 && strpos($mapping['targetEntity'], '\\') === false) {
|
||||
$mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity'];
|
||||
}
|
||||
|
||||
$mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\');
|
||||
}
|
||||
|
||||
// Complete id mapping
|
||||
@ -904,9 +908,8 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
$mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']);
|
||||
}
|
||||
|
||||
//TODO: if orphanRemoval, cascade=remove is implicit!
|
||||
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
|
||||
(bool) $mapping['orphanRemoval'] : false;
|
||||
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
|
||||
$mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove'];
|
||||
|
||||
if (isset($mapping['id']) && $mapping['id'] === true && !$mapping['isOwningSide']) {
|
||||
throw MappingException::illegalInverseIdentifierAssocation($this->name, $mapping['fieldName']);
|
||||
@ -931,9 +934,8 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
|
||||
}
|
||||
|
||||
//TODO: if orphanRemoval, cascade=remove is implicit!
|
||||
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
|
||||
(bool) $mapping['orphanRemoval'] : false;
|
||||
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
|
||||
$mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove'];
|
||||
|
||||
if (isset($mapping['orderBy'])) {
|
||||
if ( ! is_array($mapping['orderBy'])) {
|
||||
@ -1268,7 +1270,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
public function getTemporaryIdTableName()
|
||||
{
|
||||
// replace dots with underscores because PostgreSQL creates temporary tables in a special schema
|
||||
return str_replace('.', '_', $this->table['name'] . '_id_tmp');
|
||||
return str_replace('.', '_', $this->getTableName() . '_id_tmp');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1367,9 +1369,11 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
$this->table['name'] = $table['name'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($table['indexes'])) {
|
||||
$this->table['indexes'] = $table['indexes'];
|
||||
}
|
||||
|
||||
if (isset($table['uniqueConstraints'])) {
|
||||
$this->table['uniqueConstraints'] = $table['uniqueConstraints'];
|
||||
}
|
||||
@ -1518,6 +1522,10 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function setCustomRepositoryClass($repositoryClassName)
|
||||
{
|
||||
if ($repositoryClassName !== null && strpos($repositoryClassName, '\\') === false
|
||||
&& strlen($this->namespace) > 0) {
|
||||
$repositoryClassName = $this->namespace . '\\' . $repositoryClassName;
|
||||
}
|
||||
$this->customRepositoryClassName = $repositoryClassName;
|
||||
}
|
||||
|
||||
@ -1560,9 +1568,6 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* Adds a lifecycle callback for entities of this class.
|
||||
*
|
||||
* Note: If the same callback is registered more than once, the old one
|
||||
* will be overridden.
|
||||
*
|
||||
* @param string $callback
|
||||
* @param string $event
|
||||
*/
|
||||
@ -1621,20 +1626,33 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
public function setDiscriminatorMap(array $map)
|
||||
{
|
||||
foreach ($map as $value => $className) {
|
||||
if (strpos($className, '\\') === false && strlen($this->namespace)) {
|
||||
$className = $this->namespace . '\\' . $className;
|
||||
$this->addDiscriminatorMapClass($value, $className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one entry of the discriminator map with a new class and corresponding name.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $className
|
||||
*/
|
||||
public function addDiscriminatorMapClass($name, $className)
|
||||
{
|
||||
if (strlen($this->namespace) > 0 && strpos($className, '\\') === false) {
|
||||
$className = $this->namespace . '\\' . $className;
|
||||
}
|
||||
|
||||
$className = ltrim($className, '\\');
|
||||
$this->discriminatorMap[$name] = $className;
|
||||
|
||||
if ($this->name == $className) {
|
||||
$this->discriminatorValue = $name;
|
||||
} else {
|
||||
if ( ! class_exists($className)) {
|
||||
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
|
||||
}
|
||||
$className = ltrim($className, '\\');
|
||||
$this->discriminatorMap[$value] = $className;
|
||||
if ($this->name == $className) {
|
||||
$this->discriminatorValue = $value;
|
||||
} else {
|
||||
if ( ! class_exists($className)) {
|
||||
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
|
||||
}
|
||||
if (is_subclass_of($className, $this->name)) {
|
||||
$this->subClasses[] = $className;
|
||||
}
|
||||
if (is_subclass_of($className, $this->name)) {
|
||||
$this->subClasses[] = $className;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1869,9 +1887,10 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function getAssociationTargetClass($assocName)
|
||||
{
|
||||
if (!isset($this->associationMappings[$assocName])) {
|
||||
if ( ! isset($this->associationMappings[$assocName])) {
|
||||
throw new \InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association.");
|
||||
}
|
||||
|
||||
return $this->associationMappings[$assocName]['targetEntity'];
|
||||
}
|
||||
|
||||
@ -1895,9 +1914,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function getQuotedColumnName($field, $platform)
|
||||
{
|
||||
return isset($this->fieldMappings[$field]['quoted']) ?
|
||||
$platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) :
|
||||
$this->fieldMappings[$field]['columnName'];
|
||||
return isset($this->fieldMappings[$field]['quoted']) ? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) : $this->fieldMappings[$field]['columnName'];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1909,9 +1926,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function getQuotedTableName($platform)
|
||||
{
|
||||
return isset($this->table['quoted']) ?
|
||||
$platform->quoteIdentifier($this->table['name']) :
|
||||
$this->table['name'];
|
||||
return isset($this->table['quoted']) ? $platform->quoteIdentifier($this->table['name']) : $this->table['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1922,8 +1937,6 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function getQuotedJoinTableName(array $assoc, $platform)
|
||||
{
|
||||
return isset($assoc['joinTable']['quoted'])
|
||||
? $platform->quoteIdentifier($assoc['joinTable']['name'])
|
||||
: $assoc['joinTable']['name'];
|
||||
return isset($assoc['joinTable']['quoted']) ? $platform->quoteIdentifier($assoc['joinTable']['name']) : $assoc['joinTable']['name'];
|
||||
}
|
||||
}
|
||||
|
@ -147,12 +147,15 @@ class AnnotationDriver implements Driver
|
||||
// Evaluate Entity annotation
|
||||
if (isset($classAnnotations['Doctrine\ORM\Mapping\Entity'])) {
|
||||
$entityAnnot = $classAnnotations['Doctrine\ORM\Mapping\Entity'];
|
||||
$metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
|
||||
|
||||
if ($entityAnnot->repositoryClass !== null) {
|
||||
$metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
|
||||
}
|
||||
if ($entityAnnot->readOnly) {
|
||||
$metadata->markReadOnly();
|
||||
}
|
||||
} else if (isset($classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'])) {
|
||||
$mappedSuperclassAnnot = $classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'];
|
||||
$metadata->setCustomRepositoryClass($mappedSuperclassAnnot->repositoryClass);
|
||||
$metadata->isMappedSuperclass = true;
|
||||
} else {
|
||||
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
|
||||
|
@ -19,7 +19,8 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use Doctrine\Common\Annotations\Annotation;
|
||||
interface Annotation {}
|
||||
|
||||
|
||||
/* Annotations */
|
||||
|
||||
@ -27,8 +28,10 @@ use Doctrine\Common\Annotations\Annotation;
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class Entity extends Annotation {
|
||||
final class Entity implements Annotation {
|
||||
/** @var string */
|
||||
public $repositoryClass;
|
||||
/** @var boolean */
|
||||
public $readOnly = false;
|
||||
}
|
||||
|
||||
@ -36,42 +39,56 @@ final class Entity extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class MappedSuperclass extends Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class InheritanceType extends Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class DiscriminatorColumn extends Annotation {
|
||||
public $name;
|
||||
public $fieldName; // field name used in non-object hydration (array/scalar)
|
||||
public $type;
|
||||
public $length;
|
||||
final class MappedSuperclass implements Annotation {
|
||||
/** @var string */
|
||||
public $repositoryClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class DiscriminatorMap extends Annotation {}
|
||||
final class InheritanceType implements Annotation {
|
||||
/** @var string */
|
||||
public $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class DiscriminatorColumn implements Annotation {
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var string */
|
||||
public $type;
|
||||
/** @var integer */
|
||||
public $length;
|
||||
/** @var mixed */
|
||||
public $fieldName; // field name used in non-object hydration (array/scalar)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class DiscriminatorMap implements Annotation {
|
||||
/** @var array<string> */
|
||||
public $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class Id extends Annotation {}
|
||||
final class Id implements Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class GeneratedValue extends Annotation {
|
||||
final class GeneratedValue implements Annotation {
|
||||
/** @var string */
|
||||
public $strategy = 'AUTO';
|
||||
}
|
||||
|
||||
@ -79,43 +96,60 @@ final class GeneratedValue extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class Version extends Annotation {}
|
||||
final class Version implements Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target({"PROPERTY","ANNOTATION"})
|
||||
*/
|
||||
final class JoinColumn extends Annotation {
|
||||
final class JoinColumn implements Annotation {
|
||||
/** @var string */
|
||||
public $name;
|
||||
public $fieldName; // field name used in non-object hydration (array/scalar)
|
||||
/** @var string */
|
||||
public $referencedColumnName = 'id';
|
||||
/** @var boolean */
|
||||
public $unique = false;
|
||||
/** @var boolean */
|
||||
public $nullable = true;
|
||||
/** @var mixed */
|
||||
public $onDelete;
|
||||
/** @var string */
|
||||
public $columnDefinition;
|
||||
/** @var string */
|
||||
public $fieldName; // field name used in non-object hydration (array/scalar)
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class JoinColumns extends Annotation {}
|
||||
final class JoinColumns implements Annotation {
|
||||
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
|
||||
public $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class Column extends Annotation {
|
||||
public $type = 'string';
|
||||
public $length;
|
||||
// The precision for a decimal (exact numeric) column (Applies only for decimal column)
|
||||
public $precision = 0;
|
||||
// The scale for a decimal (exact numeric) column (Applies only for decimal column)
|
||||
public $scale = 0;
|
||||
public $unique = false;
|
||||
public $nullable = false;
|
||||
final class Column implements Annotation {
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var mixed */
|
||||
public $type = 'string';
|
||||
/** @var integer */
|
||||
public $length;
|
||||
/** @var integer */
|
||||
public $precision = 0; // The precision for a decimal (exact numeric) column (Applies only for decimal column)
|
||||
/** @var integer */
|
||||
public $scale = 0; // The scale for a decimal (exact numeric) column (Applies only for decimal column)
|
||||
/** @var boolean */
|
||||
public $unique = false;
|
||||
/** @var boolean */
|
||||
public $nullable = false;
|
||||
/** @var array */
|
||||
public $options = array();
|
||||
/** @var string */
|
||||
public $columnDefinition;
|
||||
}
|
||||
|
||||
@ -123,12 +157,18 @@ final class Column extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class OneToOne extends Annotation {
|
||||
final class OneToOne implements Annotation {
|
||||
/** @var string */
|
||||
public $targetEntity;
|
||||
/** @var string */
|
||||
public $mappedBy;
|
||||
/** @var string */
|
||||
public $inversedBy;
|
||||
/** @var array<string> */
|
||||
public $cascade;
|
||||
/** @var string */
|
||||
public $fetch = 'LAZY';
|
||||
/** @var boolean */
|
||||
public $orphanRemoval = false;
|
||||
}
|
||||
|
||||
@ -136,12 +176,18 @@ final class OneToOne extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class OneToMany extends Annotation {
|
||||
final class OneToMany implements Annotation {
|
||||
/** @var string */
|
||||
public $mappedBy;
|
||||
/** @var string */
|
||||
public $targetEntity;
|
||||
/** @var array<string> */
|
||||
public $cascade;
|
||||
/** @var string */
|
||||
public $fetch = 'LAZY';
|
||||
/** @var boolean */
|
||||
public $orphanRemoval = false;
|
||||
/** @var string */
|
||||
public $indexBy;
|
||||
}
|
||||
|
||||
@ -149,10 +195,14 @@ final class OneToMany extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class ManyToOne extends Annotation {
|
||||
final class ManyToOne implements Annotation {
|
||||
/** @var string */
|
||||
public $targetEntity;
|
||||
/** @var array<string> */
|
||||
public $cascade;
|
||||
/** @var string */
|
||||
public $fetch = 'LAZY';
|
||||
/** @var string */
|
||||
public $inversedBy;
|
||||
}
|
||||
|
||||
@ -160,12 +210,18 @@ final class ManyToOne extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class ManyToMany extends Annotation {
|
||||
final class ManyToMany implements Annotation {
|
||||
/** @var string */
|
||||
public $targetEntity;
|
||||
/** @var string */
|
||||
public $mappedBy;
|
||||
/** @var string */
|
||||
public $inversedBy;
|
||||
/** @var array<string> */
|
||||
public $cascade;
|
||||
/** @var string */
|
||||
public $fetch = 'LAZY';
|
||||
/** @var string */
|
||||
public $indexBy;
|
||||
}
|
||||
|
||||
@ -174,7 +230,8 @@ final class ManyToMany extends Annotation {
|
||||
* @Target("ALL")
|
||||
* @todo check available targets
|
||||
*/
|
||||
final class ElementCollection extends Annotation {
|
||||
final class ElementCollection implements Annotation {
|
||||
/** @var string */
|
||||
public $tableName;
|
||||
}
|
||||
|
||||
@ -182,10 +239,14 @@ final class ElementCollection extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class Table extends Annotation {
|
||||
final class Table implements Annotation {
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var string */
|
||||
public $schema;
|
||||
/** @var array<Doctrine\ORM\Mapping\Index> */
|
||||
public $indexes;
|
||||
/** @var array<Doctrine\ORM\Mapping\UniqueConstraint> */
|
||||
public $uniqueConstraints;
|
||||
}
|
||||
|
||||
@ -193,8 +254,10 @@ final class Table extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("ANNOTATION")
|
||||
*/
|
||||
final class UniqueConstraint extends Annotation {
|
||||
final class UniqueConstraint implements Annotation {
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var array<string> */
|
||||
public $columns;
|
||||
}
|
||||
|
||||
@ -202,8 +265,10 @@ final class UniqueConstraint extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("ANNOTATION")
|
||||
*/
|
||||
final class Index extends Annotation {
|
||||
final class Index implements Annotation {
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var array<string> */
|
||||
public $columns;
|
||||
}
|
||||
|
||||
@ -211,10 +276,14 @@ final class Index extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class JoinTable extends Annotation {
|
||||
final class JoinTable implements Annotation {
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var string */
|
||||
public $schema;
|
||||
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
|
||||
public $joinColumns = array();
|
||||
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
|
||||
public $inverseJoinColumns = array();
|
||||
}
|
||||
|
||||
@ -222,9 +291,12 @@ final class JoinTable extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class SequenceGenerator extends Annotation {
|
||||
final class SequenceGenerator implements Annotation {
|
||||
/** @var string */
|
||||
public $sequenceName;
|
||||
/** @var integer */
|
||||
public $allocationSize = 1;
|
||||
/** @var integer */
|
||||
public $initialValue = 1;
|
||||
}
|
||||
|
||||
@ -232,26 +304,37 @@ final class SequenceGenerator extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class ChangeTrackingPolicy extends Annotation {}
|
||||
final class ChangeTrackingPolicy implements Annotation {
|
||||
/** @var string */
|
||||
public $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
final class OrderBy extends Annotation {}
|
||||
final class OrderBy implements Annotation {
|
||||
/** @var array<string> */
|
||||
public $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class NamedQueries extends Annotation {}
|
||||
final class NamedQueries implements Annotation {
|
||||
/** @var array<Doctrine\ORM\Mapping\NamedQuery> */
|
||||
public $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("ANNOTATION")
|
||||
*/
|
||||
final class NamedQuery extends Annotation {
|
||||
final class NamedQuery implements Annotation {
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var string */
|
||||
public $query;
|
||||
}
|
||||
|
||||
@ -261,46 +344,46 @@ final class NamedQuery extends Annotation {
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
final class HasLifecycleCallbacks extends Annotation {}
|
||||
final class HasLifecycleCallbacks implements Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
final class PrePersist extends Annotation {}
|
||||
final class PrePersist implements Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
final class PostPersist extends Annotation {}
|
||||
final class PostPersist implements Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
final class PreUpdate extends Annotation {}
|
||||
final class PreUpdate implements Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
final class PostUpdate extends Annotation {}
|
||||
final class PostUpdate implements Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
final class PreRemove extends Annotation {}
|
||||
final class PreRemove implements Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
final class PostRemove extends Annotation {}
|
||||
final class PostRemove implements Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
final class PostLoad extends Annotation {}
|
||||
final class PostLoad implements Annotation {}
|
||||
|
176
lib/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php
Normal file
176
lib/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php
Normal file
@ -0,0 +1,176 @@
|
||||
<?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\Mapping\Driver;
|
||||
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
|
||||
/**
|
||||
* XmlDriver that additionally looks for mapping information in a global file.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @license MIT
|
||||
*/
|
||||
class SimplifiedXmlDriver extends XmlDriver
|
||||
{
|
||||
protected $_prefixes = array();
|
||||
protected $_globalBasename;
|
||||
protected $_classCache;
|
||||
protected $_fileExtension = '.orm.xml';
|
||||
|
||||
public function __construct($prefixes)
|
||||
{
|
||||
$this->addNamespacePrefixes($prefixes);
|
||||
}
|
||||
|
||||
public function setGlobalBasename($file)
|
||||
{
|
||||
$this->_globalBasename = $file;
|
||||
}
|
||||
|
||||
public function getGlobalBasename()
|
||||
{
|
||||
return $this->_globalBasename;
|
||||
}
|
||||
|
||||
public function addNamespacePrefixes($prefixes)
|
||||
{
|
||||
$this->_prefixes = array_merge($this->_prefixes, $prefixes);
|
||||
$this->addPaths(array_flip($prefixes));
|
||||
}
|
||||
|
||||
public function getNamespacePrefixes()
|
||||
{
|
||||
return $this->_prefixes;
|
||||
}
|
||||
|
||||
public function isTransient($className)
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
// The mapping is defined in the global mapping file
|
||||
if (isset($this->_classCache[$className])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->_findMappingFile($className);
|
||||
|
||||
return false;
|
||||
} catch (MappingException $e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAllClassNames()
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
$classes = array();
|
||||
|
||||
if ($this->_paths) {
|
||||
foreach ((array) $this->_paths as $path) {
|
||||
if (!is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($path),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
$fileName = $file->getBasename($this->_fileExtension);
|
||||
|
||||
if ($fileName == $file->getBasename() || $fileName == $this->_globalBasename) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: All files found here means classes are not transient!
|
||||
if (isset($this->_prefixes[$path])) {
|
||||
$classes[] = $this->_prefixes[$path].'\\'.str_replace('.', '\\', $fileName);
|
||||
} else {
|
||||
$classes[] = str_replace('.', '\\', $fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($classes, array_keys($this->_classCache));
|
||||
}
|
||||
|
||||
public function getElement($className)
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
if (!isset($this->_classCache[$className])) {
|
||||
$this->_classCache[$className] = parent::getElement($className);
|
||||
}
|
||||
|
||||
return $this->_classCache[$className];
|
||||
}
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
$this->_classCache = array();
|
||||
if (null !== $this->_globalBasename) {
|
||||
foreach ($this->_paths as $path) {
|
||||
if (is_file($file = $path.'/'.$this->_globalBasename.$this->_fileExtension)) {
|
||||
$this->_classCache = array_merge($this->_classCache, $this->_loadMappingFile($file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function _findMappingFile($className)
|
||||
{
|
||||
$defaultFileName = str_replace('\\', '.', $className).$this->_fileExtension;
|
||||
foreach ($this->_paths as $path) {
|
||||
if (!isset($this->_prefixes[$path])) {
|
||||
if (is_file($path.DIRECTORY_SEPARATOR.$defaultFileName)) {
|
||||
return $path.DIRECTORY_SEPARATOR.$defaultFileName;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$prefix = $this->_prefixes[$path];
|
||||
|
||||
if (0 !== strpos($className, $prefix.'\\')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', '.').$this->_fileExtension;
|
||||
if (is_file($filename)) {
|
||||
return $filename;
|
||||
}
|
||||
|
||||
throw MappingException::mappingFileNotFound($className, $filename);
|
||||
}
|
||||
|
||||
throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1).$this->_fileExtension);
|
||||
}
|
||||
}
|
182
lib/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php
Normal file
182
lib/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php
Normal file
@ -0,0 +1,182 @@
|
||||
<?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\Mapping\Driver;
|
||||
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
|
||||
/**
|
||||
* YamlDriver that additionally looks for mapping information in a global file.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @license MIT
|
||||
*/
|
||||
class SimplifiedYamlDriver extends YamlDriver
|
||||
{
|
||||
protected $_prefixes = array();
|
||||
protected $_globalBasename;
|
||||
protected $_classCache;
|
||||
protected $_fileExtension = '.orm.yml';
|
||||
|
||||
public function __construct($prefixes)
|
||||
{
|
||||
$this->addNamespacePrefixes($prefixes);
|
||||
}
|
||||
|
||||
public function setGlobalBasename($file)
|
||||
{
|
||||
$this->_globalBasename = $file;
|
||||
}
|
||||
|
||||
public function getGlobalBasename()
|
||||
{
|
||||
return $this->_globalBasename;
|
||||
}
|
||||
|
||||
public function addNamespacePrefixes($prefixes)
|
||||
{
|
||||
$this->_prefixes = array_merge($this->_prefixes, $prefixes);
|
||||
$this->addPaths(array_flip($prefixes));
|
||||
}
|
||||
|
||||
public function addNamespacePrefix($prefix, $path)
|
||||
{
|
||||
$this->_prefixes[$path] = $prefix;
|
||||
}
|
||||
|
||||
|
||||
public function getNamespacePrefixes()
|
||||
{
|
||||
return $this->_prefixes;
|
||||
}
|
||||
|
||||
public function isTransient($className)
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
// The mapping is defined in the global mapping file
|
||||
if (isset($this->_classCache[$className])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->_findMappingFile($className);
|
||||
|
||||
return false;
|
||||
} catch (MappingException $e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAllClassNames()
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
$classes = array();
|
||||
|
||||
if ($this->_paths) {
|
||||
foreach ((array) $this->_paths as $path) {
|
||||
if (!is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($path),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
$fileName = $file->getBasename($this->_fileExtension);
|
||||
|
||||
if ($fileName == $file->getBasename() || $fileName == $this->_globalBasename) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: All files found here means classes are not transient!
|
||||
if (isset($this->_prefixes[$path])) {
|
||||
$classes[] = $this->_prefixes[$path].'\\'.str_replace('.', '\\', $fileName);
|
||||
} else {
|
||||
$classes[] = str_replace('.', '\\', $fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($classes, array_keys($this->_classCache));
|
||||
}
|
||||
|
||||
public function getElement($className)
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
if (!isset($this->_classCache[$className])) {
|
||||
$this->_classCache[$className] = parent::getElement($className);
|
||||
}
|
||||
|
||||
return $this->_classCache[$className];
|
||||
}
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
$this->_classCache = array();
|
||||
if (null !== $this->_globalBasename) {
|
||||
foreach ($this->_paths as $path) {
|
||||
if (is_file($file = $path.'/'.$this->_globalBasename.$this->_fileExtension)) {
|
||||
$this->_classCache = array_merge($this->_classCache, $this->_loadMappingFile($file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function _findMappingFile($className)
|
||||
{
|
||||
$defaultFileName = str_replace('\\', '.', $className).$this->_fileExtension;
|
||||
foreach ($this->_paths as $path) {
|
||||
if (!isset($this->_prefixes[$path])) {
|
||||
if (is_file($path.DIRECTORY_SEPARATOR.$defaultFileName)) {
|
||||
return $path.DIRECTORY_SEPARATOR.$defaultFileName;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$prefix = $this->_prefixes[$path];
|
||||
|
||||
if (0 !== strpos($className, $prefix.'\\')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', '.').$this->_fileExtension;
|
||||
if (is_file($filename)) {
|
||||
return $filename;
|
||||
}
|
||||
|
||||
throw MappingException::mappingFileNotFound($className, $filename);
|
||||
}
|
||||
|
||||
throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1).$this->_fileExtension);
|
||||
}
|
||||
}
|
@ -52,13 +52,16 @@ class XmlDriver extends AbstractFileDriver
|
||||
$xmlRoot = $this->getElement($className);
|
||||
|
||||
if ($xmlRoot->getName() == 'entity') {
|
||||
$metadata->setCustomRepositoryClass(
|
||||
isset($xmlRoot['repository-class']) ? (string)$xmlRoot['repository-class'] : null
|
||||
);
|
||||
if (isset($xmlRoot['repository-class'])) {
|
||||
$metadata->setCustomRepositoryClass((string)$xmlRoot['repository-class']);
|
||||
}
|
||||
if (isset($xmlRoot['read-only']) && $xmlRoot['read-only'] == "true") {
|
||||
$metadata->markReadOnly();
|
||||
}
|
||||
} else if ($xmlRoot->getName() == 'mapped-superclass') {
|
||||
$metadata->setCustomRepositoryClass(
|
||||
isset($xmlRoot['repository-class']) ? (string)$xmlRoot['repository-class'] : null
|
||||
);
|
||||
$metadata->isMappedSuperclass = true;
|
||||
} else {
|
||||
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
|
||||
|
@ -46,13 +46,16 @@ class YamlDriver extends AbstractFileDriver
|
||||
$element = $this->getElement($className);
|
||||
|
||||
if ($element['type'] == 'entity') {
|
||||
$metadata->setCustomRepositoryClass(
|
||||
isset($element['repositoryClass']) ? $element['repositoryClass'] : null
|
||||
);
|
||||
if (isset($element['repositoryClass'])) {
|
||||
$metadata->setCustomRepositoryClass($element['repositoryClass']);
|
||||
}
|
||||
if (isset($element['readOnly']) && $element['readOnly'] == true) {
|
||||
$metadata->markReadOnly();
|
||||
}
|
||||
} else if ($element['type'] == 'mappedSuperclass') {
|
||||
$metadata->setCustomRepositoryClass(
|
||||
isset($element['repositoryClass']) ? $element['repositoryClass'] : null
|
||||
);
|
||||
$metadata->isMappedSuperclass = true;
|
||||
} else {
|
||||
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
|
||||
|
@ -293,4 +293,9 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
"to avoid this exception from occuring."
|
||||
);
|
||||
}
|
||||
|
||||
public static function lifecycleCallbackMethodNotFound($className, $methodName)
|
||||
{
|
||||
return new self("Entity '" . $className . "' has no method '" . $methodName . "' to be registered as lifecycle callback.");
|
||||
}
|
||||
}
|
@ -130,4 +130,10 @@ class ORMException extends Exception
|
||||
"Unknown Entity namespace alias '$entityNamespaceAlias'."
|
||||
);
|
||||
}
|
||||
|
||||
public static function invalidEntityRepository($className)
|
||||
{
|
||||
return new self("Invalid repository class '".$className."'. ".
|
||||
"it must be a Doctrine\ORM\EntityRepository.");
|
||||
}
|
||||
}
|
||||
|
@ -65,9 +65,11 @@ abstract class AbstractCollectionPersister
|
||||
public function delete(PersistentCollection $coll)
|
||||
{
|
||||
$mapping = $coll->getMapping();
|
||||
|
||||
if ( ! $mapping['isOwningSide']) {
|
||||
return; // ignore inverse side
|
||||
}
|
||||
|
||||
$sql = $this->_getDeleteSQL($coll);
|
||||
$this->_conn->executeUpdate($sql, $this->_getDeleteSQLParameters($coll));
|
||||
}
|
||||
@ -96,9 +98,11 @@ abstract class AbstractCollectionPersister
|
||||
public function update(PersistentCollection $coll)
|
||||
{
|
||||
$mapping = $coll->getMapping();
|
||||
|
||||
if ( ! $mapping['isOwningSide']) {
|
||||
return; // ignore inverse side
|
||||
}
|
||||
|
||||
$this->deleteRows($coll);
|
||||
//$this->updateRows($coll);
|
||||
$this->insertRows($coll);
|
||||
@ -108,6 +112,7 @@ abstract class AbstractCollectionPersister
|
||||
{
|
||||
$deleteDiff = $coll->getDeleteDiff();
|
||||
$sql = $this->_getDeleteRowSQL($coll);
|
||||
|
||||
foreach ($deleteDiff as $element) {
|
||||
$this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element));
|
||||
}
|
||||
@ -120,6 +125,7 @@ abstract class AbstractCollectionPersister
|
||||
{
|
||||
$insertDiff = $coll->getInsertDiff();
|
||||
$sql = $this->_getInsertRowSQL($coll);
|
||||
|
||||
foreach ($insertDiff as $element) {
|
||||
$this->_conn->executeUpdate($sql, $this->_getInsertRowSQLParameters($coll, $element));
|
||||
}
|
||||
|
@ -39,10 +39,12 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
protected function _prepareInsertData($entity)
|
||||
{
|
||||
$data = parent::_prepareInsertData($entity);
|
||||
|
||||
// Populate the discriminator column
|
||||
$discColumn = $this->_class->discriminatorColumn;
|
||||
$this->_columnTypes[$discColumn['name']] = $discColumn['type'];
|
||||
$data[$this->_getDiscriminatorColumnTableName()][$discColumn['name']] = $this->_class->discriminatorValue;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@ -63,7 +65,7 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
|
||||
$this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name);
|
||||
|
||||
return "$sql AS $columnAlias";
|
||||
return $sql . ' AS ' . $columnAlias;
|
||||
}
|
||||
|
||||
protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className)
|
||||
@ -72,6 +74,6 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$this->_rsm->addMetaResult('r', $resultColumnName, $joinColumnName);
|
||||
|
||||
return $tableAlias . ".$joinColumnName AS $columnAlias";
|
||||
return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias;
|
||||
}
|
||||
}
|
@ -222,7 +222,7 @@ class BasicEntityPersister
|
||||
$isPostInsertId = $idGen->isPostInsertGenerator();
|
||||
|
||||
$stmt = $this->_conn->prepare($this->_getInsertSQL());
|
||||
$tableName = $this->_class->table['name'];
|
||||
$tableName = $this->_class->getTableName();
|
||||
|
||||
foreach ($this->_queuedInserts as $entity) {
|
||||
$insertData = $this->_prepareInsertData($entity);
|
||||
@ -278,11 +278,14 @@ class BasicEntityPersister
|
||||
protected function fetchVersionValue($versionedClass, $id)
|
||||
{
|
||||
$versionField = $versionedClass->versionField;
|
||||
$identifier = $versionedClass->getIdentifierColumnNames();
|
||||
$versionFieldColumnName = $versionedClass->getColumnName($versionField);
|
||||
$identifier = $versionedClass->getIdentifierColumnNames();
|
||||
|
||||
$versionFieldColumnName = $versionedClass->getQuotedColumnName($versionField, $this->_platform);
|
||||
|
||||
//FIXME: Order with composite keys might not be correct
|
||||
$sql = "SELECT " . $versionFieldColumnName . " FROM " . $versionedClass->getQuotedTableName($this->_platform)
|
||||
. " WHERE " . implode(' = ? AND ', $identifier) . " = ?";
|
||||
$sql = 'SELECT ' . $versionFieldColumnName
|
||||
. ' FROM ' . $versionedClass->getQuotedTableName($this->_platform)
|
||||
. ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?';
|
||||
$value = $this->_conn->fetchColumn($sql, array_values((array)$id));
|
||||
|
||||
return Type::getType($versionedClass->fieldMappings[$versionField]['type'])->convertToPHPValue($value, $this->_platform);
|
||||
@ -305,7 +308,8 @@ class BasicEntityPersister
|
||||
public function update($entity)
|
||||
{
|
||||
$updateData = $this->_prepareUpdateData($entity);
|
||||
$tableName = $this->_class->table['name'];
|
||||
$tableName = $this->_class->getTableName();
|
||||
|
||||
if (isset($updateData[$tableName]) && $updateData[$tableName]) {
|
||||
$this->_updateTable(
|
||||
$entity, $this->_class->getQuotedTableName($this->_platform),
|
||||
@ -333,17 +337,17 @@ class BasicEntityPersister
|
||||
$set = $params = $types = array();
|
||||
|
||||
foreach ($updateData as $columnName => $value) {
|
||||
if (isset($this->_class->fieldNames[$columnName])) {
|
||||
$set[] = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform) . ' = ?';
|
||||
} else {
|
||||
$set[] = $columnName . ' = ?';
|
||||
}
|
||||
$set[] = (isset($this->_class->fieldNames[$columnName]))
|
||||
? $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform) . ' = ?'
|
||||
: $columnName . ' = ?';
|
||||
|
||||
$params[] = $value;
|
||||
$types[] = $this->_columnTypes[$columnName];
|
||||
}
|
||||
|
||||
$where = array();
|
||||
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity);
|
||||
|
||||
foreach ($this->_class->identifier as $idField) {
|
||||
if (isset($this->_class->associationMappings[$idField])) {
|
||||
$targetMapping = $this->_em->getClassMetadata($this->_class->associationMappings[$idField]['targetEntity']);
|
||||
@ -361,18 +365,21 @@ class BasicEntityPersister
|
||||
$versionField = $this->_class->versionField;
|
||||
$versionFieldType = $this->_class->fieldMappings[$versionField]['type'];
|
||||
$versionColumn = $this->_class->getQuotedColumnName($versionField, $this->_platform);
|
||||
|
||||
if ($versionFieldType == Type::INTEGER) {
|
||||
$set[] = $versionColumn . ' = ' . $versionColumn . ' + 1';
|
||||
} else if ($versionFieldType == Type::DATETIME) {
|
||||
$set[] = $versionColumn . ' = CURRENT_TIMESTAMP';
|
||||
}
|
||||
|
||||
$where[] = $versionColumn;
|
||||
$params[] = $this->_class->reflFields[$versionField]->getValue($entity);
|
||||
$types[] = $this->_class->fieldMappings[$versionField]['type'];
|
||||
}
|
||||
|
||||
$sql = "UPDATE $quotedTableName SET " . implode(', ', $set)
|
||||
. ' WHERE ' . implode(' = ? AND ', $where) . ' = ?';
|
||||
$sql = 'UPDATE ' . $quotedTableName
|
||||
. ' SET ' . implode(', ', $set)
|
||||
. ' WHERE ' . implode(' = ? AND ', $where) . ' = ?';
|
||||
|
||||
$result = $this->_conn->executeUpdate($sql, $params, $types);
|
||||
|
||||
@ -398,21 +405,29 @@ class BasicEntityPersister
|
||||
$relatedClass = $this->_em->getClassMetadata($mapping['targetEntity']);
|
||||
$mapping = $relatedClass->associationMappings[$mapping['mappedBy']];
|
||||
$keys = array_keys($mapping['relationToTargetKeyColumns']);
|
||||
|
||||
if ($selfReferential) {
|
||||
$otherKeys = array_keys($mapping['relationToSourceKeyColumns']);
|
||||
}
|
||||
} else {
|
||||
$keys = array_keys($mapping['relationToSourceKeyColumns']);
|
||||
|
||||
if ($selfReferential) {
|
||||
$otherKeys = array_keys($mapping['relationToTargetKeyColumns']);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset($mapping['isOnDeleteCascade'])) {
|
||||
$this->_conn->delete($mapping['joinTable']['name'], array_combine($keys, $identifier));
|
||||
$this->_conn->delete(
|
||||
$this->_class->getQuotedJoinTableName($mapping, $this->_platform),
|
||||
array_combine($keys, $identifier)
|
||||
);
|
||||
|
||||
if ($selfReferential) {
|
||||
$this->_conn->delete($mapping['joinTable']['name'], array_combine($otherKeys, $identifier));
|
||||
$this->_conn->delete(
|
||||
$this->_class->getQuotedJoinTableName($mapping, $this->_platform),
|
||||
array_combine($otherKeys, $identifier)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -463,7 +478,7 @@ class BasicEntityPersister
|
||||
$result = array();
|
||||
$uow = $this->_em->getUnitOfWork();
|
||||
|
||||
if ($versioned = $this->_class->isVersioned) {
|
||||
if (($versioned = $this->_class->isVersioned) != false) {
|
||||
$versionField = $this->_class->versionField;
|
||||
}
|
||||
|
||||
@ -477,6 +492,7 @@ class BasicEntityPersister
|
||||
|
||||
if (isset($this->_class->associationMappings[$field])) {
|
||||
$assoc = $this->_class->associationMappings[$field];
|
||||
|
||||
// Only owning side of x-1 associations can have a FK column.
|
||||
if ( ! $assoc['isOwningSide'] || ! ($assoc['type'] & ClassMetadata::TO_ONE)) {
|
||||
continue;
|
||||
@ -484,6 +500,7 @@ class BasicEntityPersister
|
||||
|
||||
if ($newVal !== null) {
|
||||
$oid = spl_object_hash($newVal);
|
||||
|
||||
if (isset($this->_queuedInserts[$oid]) || $uow->isScheduledForInsert($newVal)) {
|
||||
// The associated entity $newVal is not yet persisted, so we must
|
||||
// set $newVal = null, in order to insert a null value and schedule an
|
||||
@ -510,6 +527,7 @@ class BasicEntityPersister
|
||||
} else {
|
||||
$result[$owningTable][$sourceColumn] = $newValId[$targetClass->fieldNames[$targetColumn]];
|
||||
}
|
||||
|
||||
$this->_columnTypes[$sourceColumn] = $targetClass->getTypeOfColumn($targetColumn);
|
||||
}
|
||||
} else {
|
||||
@ -518,6 +536,7 @@ class BasicEntityPersister
|
||||
$result[$this->getOwningTable($field)][$columnName] = $newVal;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -548,7 +567,7 @@ class BasicEntityPersister
|
||||
*/
|
||||
public function getOwningTable($fieldName)
|
||||
{
|
||||
return $this->_class->table['name'];
|
||||
return $this->_class->getTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -574,12 +593,9 @@ class BasicEntityPersister
|
||||
$hints[Query::HINT_REFRESH_ENTITY] = $entity;
|
||||
}
|
||||
|
||||
if ($this->_selectJoinSql) {
|
||||
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
|
||||
} else {
|
||||
$hydrator = $this->_em->newHydrator(Query::HYDRATE_SIMPLEOBJECT);
|
||||
}
|
||||
$hydrator = $this->_em->newHydrator($this->_selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
|
||||
$entities = $hydrator->hydrateAll($stmt, $this->_rsm, $hints);
|
||||
|
||||
return $entities ? $entities[0] : null;
|
||||
}
|
||||
|
||||
@ -596,7 +612,7 @@ class BasicEntityPersister
|
||||
*/
|
||||
public function loadOneToOneEntity(array $assoc, $sourceEntity, array $identifier = array())
|
||||
{
|
||||
if ($foundEntity = $this->_em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) {
|
||||
if (($foundEntity = $this->_em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) != false) {
|
||||
return $foundEntity;
|
||||
}
|
||||
|
||||
@ -608,14 +624,17 @@ class BasicEntityPersister
|
||||
// Mark inverse side as fetched in the hints, otherwise the UoW would
|
||||
// try to load it in a separate query (remember: to-one inverse sides can not be lazy).
|
||||
$hints = array();
|
||||
|
||||
if ($isInverseSingleValued) {
|
||||
$hints['fetched'][$targetClass->name][$assoc['inversedBy']] = true;
|
||||
|
||||
if ($targetClass->subClasses) {
|
||||
foreach ($targetClass->subClasses as $targetSubclassName) {
|
||||
$hints['fetched'][$targetSubclassName][$assoc['inversedBy']] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* cascade read-only status
|
||||
if ($this->_em->getUnitOfWork()->isReadOnly($sourceEntity)) {
|
||||
$hints[Query::HINT_READ_ONLY] = true;
|
||||
@ -631,19 +650,21 @@ class BasicEntityPersister
|
||||
} else {
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
|
||||
$owningAssoc = $targetClass->getAssociationMapping($assoc['mappedBy']);
|
||||
|
||||
// TRICKY: since the association is specular source and target are flipped
|
||||
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
// unset the old value and set the new sql aliased value here. By definition
|
||||
// unset($identifier[$targetKeyColumn] works here with how UnitOfWork::createEntity() calls this method.
|
||||
$identifier[$this->_getSQLTableAlias($targetClass->name) . "." . $targetKeyColumn] =
|
||||
$sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
unset($identifier[$targetKeyColumn]);
|
||||
} else {
|
||||
if ( ! isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
|
||||
// unset the old value and set the new sql aliased value here. By definition
|
||||
// unset($identifier[$targetKeyColumn] works here with how UnitOfWork::createEntity() calls this method.
|
||||
$identifier[$this->_getSQLTableAlias($targetClass->name) . "." . $targetKeyColumn] =
|
||||
$sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
|
||||
unset($identifier[$targetKeyColumn]);
|
||||
}
|
||||
|
||||
$targetEntity = $this->load($identifier, null, $assoc);
|
||||
@ -675,7 +696,9 @@ class BasicEntityPersister
|
||||
if (isset($this->_class->lifecycleCallbacks[Events::postLoad])) {
|
||||
$this->_class->invokeLifecycleCallbacks(Events::postLoad, $entity);
|
||||
}
|
||||
|
||||
$evm = $this->_em->getEventManager();
|
||||
|
||||
if ($evm->hasListeners(Events::postLoad)) {
|
||||
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
|
||||
}
|
||||
@ -697,11 +720,8 @@ class BasicEntityPersister
|
||||
list($params, $types) = $this->expandParameters($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params, $types);
|
||||
|
||||
if ($this->_selectJoinSql) {
|
||||
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
|
||||
} else {
|
||||
$hydrator = $this->_em->newHydrator(Query::HYDRATE_SIMPLEOBJECT);
|
||||
}
|
||||
$hydrator = $this->_em->newHydrator(($this->_selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
|
||||
|
||||
return $hydrator->hydrateAll($stmt, $this->_rsm, array('deferEagerLoads' => true));
|
||||
}
|
||||
|
||||
@ -717,6 +737,7 @@ class BasicEntityPersister
|
||||
public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||
{
|
||||
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit);
|
||||
|
||||
return $this->loadArrayFromStatement($assoc, $stmt);
|
||||
}
|
||||
|
||||
@ -725,6 +746,7 @@ class BasicEntityPersister
|
||||
*
|
||||
* @param array $assoc
|
||||
* @param Doctrine\DBAL\Statement $stmt
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function loadArrayFromStatement($assoc, $stmt)
|
||||
@ -739,6 +761,7 @@ class BasicEntityPersister
|
||||
}
|
||||
|
||||
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
|
||||
|
||||
return $hydrator->hydrateAll($stmt, $rsm, $hints);
|
||||
}
|
||||
|
||||
@ -748,6 +771,8 @@ class BasicEntityPersister
|
||||
* @param array $assoc
|
||||
* @param Doctrine\DBAL\Statement $stmt
|
||||
* @param PersistentCollection $coll
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function loadCollectionFromStatement($assoc, $stmt, $coll)
|
||||
{
|
||||
@ -761,7 +786,8 @@ class BasicEntityPersister
|
||||
}
|
||||
|
||||
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
|
||||
$hydrator->hydrateAll($stmt, $rsm, $hints);
|
||||
|
||||
return $hydrator->hydrateAll($stmt, $rsm, $hints);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -777,6 +803,7 @@ class BasicEntityPersister
|
||||
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
|
||||
{
|
||||
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity);
|
||||
|
||||
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
|
||||
}
|
||||
|
||||
@ -784,12 +811,15 @@ class BasicEntityPersister
|
||||
{
|
||||
$criteria = array();
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
|
||||
|
||||
if ($assoc['isOwningSide']) {
|
||||
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($assoc, $this->_platform);
|
||||
|
||||
foreach ($assoc['relationToSourceKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
|
||||
if ($sourceClass->containsForeignIdentifier) {
|
||||
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
|
||||
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
|
||||
|
||||
if (isset($sourceClass->associationMappings[$field])) {
|
||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
||||
@ -807,15 +837,18 @@ class BasicEntityPersister
|
||||
} else {
|
||||
$owningAssoc = $this->_em->getClassMetadata($assoc['targetEntity'])->associationMappings[$assoc['mappedBy']];
|
||||
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($owningAssoc, $this->_platform);
|
||||
|
||||
// TRICKY: since the association is inverted source and target are flipped
|
||||
foreach ($owningAssoc['relationToTargetKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
|
||||
if ($sourceClass->containsForeignIdentifier) {
|
||||
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
|
||||
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
|
||||
|
||||
if (isset($sourceClass->associationMappings[$field])) {
|
||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
||||
}
|
||||
|
||||
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $value;
|
||||
} else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
@ -829,6 +862,7 @@ class BasicEntityPersister
|
||||
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, 0, $limit, $offset);
|
||||
list($params, $types) = $this->expandParameters($criteria);
|
||||
|
||||
return $this->_conn->executeQuery($sql, $params, $types);
|
||||
}
|
||||
|
||||
@ -847,15 +881,14 @@ class BasicEntityPersister
|
||||
*/
|
||||
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0, $limit = null, $offset = null, array $orderBy = null)
|
||||
{
|
||||
$joinSql = $assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY ?
|
||||
$this->_getSelectManyToManyJoinSQL($assoc) : '';
|
||||
|
||||
$joinSql = ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) ? $this->_getSelectManyToManyJoinSQL($assoc) : '';
|
||||
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
|
||||
|
||||
$orderBy = ($assoc !== null && isset($assoc['orderBy'])) ? $assoc['orderBy'] : $orderBy;
|
||||
$orderBy = ($assoc !== null && isset($assoc['orderBy'])) ? $assoc['orderBy'] : $orderBy;
|
||||
$orderBySql = $orderBy ? $this->_getOrderBySQL($orderBy, $this->_getSQLTableAlias($this->_class->name)) : '';
|
||||
|
||||
$lockSql = '';
|
||||
|
||||
if ($lockMode == LockMode::PESSIMISTIC_READ) {
|
||||
$lockSql = ' ' . $this->_platform->getReadLockSql();
|
||||
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
|
||||
@ -890,6 +923,7 @@ class BasicEntityPersister
|
||||
protected final function _getOrderBySQL(array $orderBy, $baseTableAlias)
|
||||
{
|
||||
$orderBySql = '';
|
||||
|
||||
foreach ($orderBy as $fieldName => $orientation) {
|
||||
if ( ! isset($this->_class->fieldMappings[$fieldName])) {
|
||||
throw ORMException::unrecognizedField($fieldName);
|
||||
@ -900,6 +934,7 @@ class BasicEntityPersister
|
||||
: $baseTableAlias;
|
||||
|
||||
$columnName = $this->_class->getQuotedColumnName($fieldName, $this->_platform);
|
||||
|
||||
$orderBySql .= $orderBySql ? ', ' : ' ORDER BY ';
|
||||
$orderBySql .= $tableAlias . '.' . $columnName . ' ' . $orientation;
|
||||
}
|
||||
@ -932,20 +967,25 @@ class BasicEntityPersister
|
||||
// Add regular columns to select list
|
||||
foreach ($this->_class->fieldNames as $field) {
|
||||
if ($columnList) $columnList .= ', ';
|
||||
|
||||
$columnList .= $this->_getSelectColumnSQL($field, $this->_class);
|
||||
}
|
||||
|
||||
$this->_selectJoinSql = '';
|
||||
$eagerAliasCounter = 0;
|
||||
|
||||
foreach ($this->_class->associationMappings as $assocField => $assoc) {
|
||||
$assocColumnSQL = $this->_getSelectColumnAssociationSQL($assocField, $assoc, $this->_class);
|
||||
|
||||
if ($assocColumnSQL) {
|
||||
if ($columnList) $columnList .= ', ';
|
||||
|
||||
$columnList .= $assocColumnSQL;
|
||||
}
|
||||
|
||||
if ($assoc['type'] & ClassMetadata::TO_ONE && ($assoc['fetch'] == ClassMetadata::FETCH_EAGER || !$assoc['isOwningSide'])) {
|
||||
$eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']);
|
||||
|
||||
if ($eagerEntity->inheritanceType != ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||
continue; // now this is why you shouldn't use inheritance
|
||||
}
|
||||
@ -955,41 +995,48 @@ class BasicEntityPersister
|
||||
|
||||
foreach ($eagerEntity->fieldNames AS $field) {
|
||||
if ($columnList) $columnList .= ', ';
|
||||
|
||||
$columnList .= $this->_getSelectColumnSQL($field, $eagerEntity, $assocAlias);
|
||||
}
|
||||
|
||||
foreach ($eagerEntity->associationMappings as $assoc2Field => $assoc2) {
|
||||
$assoc2ColumnSQL = $this->_getSelectColumnAssociationSQL($assoc2Field, $assoc2, $eagerEntity, $assocAlias);
|
||||
|
||||
if ($assoc2ColumnSQL) {
|
||||
if ($columnList) $columnList .= ', ';
|
||||
$columnList .= $assoc2ColumnSQL;
|
||||
}
|
||||
}
|
||||
|
||||
$this->_selectJoinSql .= ' LEFT JOIN'; // TODO: Inner join when all join columns are NOT nullable.
|
||||
$first = true;
|
||||
|
||||
if ($assoc['isOwningSide']) {
|
||||
$this->_selectJoinSql .= ' ' . $eagerEntity->table['name'] . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON ';
|
||||
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON ';
|
||||
|
||||
foreach ($assoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
|
||||
if (!$first) {
|
||||
if ( ! $first) {
|
||||
$this->_selectJoinSql .= ' AND ';
|
||||
}
|
||||
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.'.$sourceCol.' = ' .
|
||||
$this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.'.$targetCol.' ';
|
||||
|
||||
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
|
||||
. $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.' . $targetCol . ' ';
|
||||
$first = false;
|
||||
}
|
||||
} else {
|
||||
$eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']);
|
||||
$owningAssoc = $eagerEntity->getAssociationMapping($assoc['mappedBy']);
|
||||
|
||||
$this->_selectJoinSql .= ' ' . $eagerEntity->table['name'] . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON ';
|
||||
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) . ' ON ';
|
||||
|
||||
foreach ($owningAssoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
|
||||
if (!$first) {
|
||||
if ( ! $first) {
|
||||
$this->_selectJoinSql .= ' AND ';
|
||||
}
|
||||
$this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.'.$sourceCol.' = ' .
|
||||
$this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol . ' ';
|
||||
|
||||
$this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = '
|
||||
. $this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol . ' ';
|
||||
$first = false;
|
||||
}
|
||||
}
|
||||
@ -1001,19 +1048,32 @@ class BasicEntityPersister
|
||||
return $this->_selectColumnListSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL join fragment used when selecting entities from an association.
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $assoc
|
||||
* @param ClassMetadata $class
|
||||
* @param string $alias
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _getSelectColumnAssociationSQL($field, $assoc, ClassMetadata $class, $alias = 'r')
|
||||
{
|
||||
$columnList = '';
|
||||
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
if ($columnList) $columnList .= ', ';
|
||||
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) ) . ".$srcColumn AS $columnAlias";
|
||||
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
|
||||
. '.' . $srcColumn . ' AS ' . $columnAlias;
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$this->_rsm->addMetaResult($alias, $this->_platform->getSQLResultCasing($columnAlias), $srcColumn, isset($assoc['id']) && $assoc['id'] === true);
|
||||
}
|
||||
}
|
||||
|
||||
return $columnList;
|
||||
}
|
||||
|
||||
@ -1035,23 +1095,22 @@ class BasicEntityPersister
|
||||
}
|
||||
|
||||
$joinTableName = $this->_class->getQuotedJoinTableName($owningAssoc, $this->_platform);
|
||||
|
||||
$joinSql = '';
|
||||
|
||||
foreach ($joinClauses as $joinTableColumn => $sourceColumn) {
|
||||
if ($joinSql != '') $joinSql .= ' AND ';
|
||||
|
||||
if ($this->_class->containsForeignIdentifier && !isset($this->_class->fieldNames[$sourceColumn])) {
|
||||
if ($this->_class->containsForeignIdentifier && ! isset($this->_class->fieldNames[$sourceColumn])) {
|
||||
$quotedColumn = $sourceColumn; // join columns cannot be quoted
|
||||
} else {
|
||||
$quotedColumn = $this->_class->getQuotedColumnName($this->_class->fieldNames[$sourceColumn], $this->_platform);
|
||||
}
|
||||
|
||||
$joinSql .= $this->_getSQLTableAlias($this->_class->name) .
|
||||
'.' . $quotedColumn . ' = '
|
||||
. $joinTableName . '.' . $joinTableColumn;
|
||||
$joinSql .= $this->_getSQLTableAlias($this->_class->name) . '.' . $quotedColumn . ' = '
|
||||
. $joinTableName . '.' . $joinTableColumn;
|
||||
}
|
||||
|
||||
return " INNER JOIN $joinTableName ON $joinSql";
|
||||
return ' INNER JOIN ' . $joinTableName . ' ON ' . $joinSql;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1064,21 +1123,23 @@ class BasicEntityPersister
|
||||
if ($this->_insertSql === null) {
|
||||
$insertSql = '';
|
||||
$columns = $this->_getInsertColumnList();
|
||||
|
||||
if (empty($columns)) {
|
||||
$insertSql = $this->_platform->getEmptyIdentityInsertSQL(
|
||||
$this->_class->getQuotedTableName($this->_platform),
|
||||
$this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform)
|
||||
$this->_class->getQuotedTableName($this->_platform),
|
||||
$this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform)
|
||||
);
|
||||
} else {
|
||||
$columns = array_unique($columns);
|
||||
$values = array_fill(0, count($columns), '?');
|
||||
|
||||
$insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform)
|
||||
. ' (' . implode(', ', $columns) . ') '
|
||||
. 'VALUES (' . implode(', ', $values) . ')';
|
||||
. ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', $values) . ')';
|
||||
}
|
||||
|
||||
$this->_insertSql = $insertSql;
|
||||
}
|
||||
|
||||
return $this->_insertSql;
|
||||
}
|
||||
|
||||
@ -1093,19 +1154,21 @@ class BasicEntityPersister
|
||||
protected function _getInsertColumnList()
|
||||
{
|
||||
$columns = array();
|
||||
|
||||
foreach ($this->_class->reflFields as $name => $field) {
|
||||
if ($this->_class->isVersioned && $this->_class->versionField == $name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($this->_class->associationMappings[$name])) {
|
||||
$assoc = $this->_class->associationMappings[$name];
|
||||
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) {
|
||||
$columns[] = $sourceCol;
|
||||
}
|
||||
}
|
||||
} else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY ||
|
||||
$this->_class->identifier[0] != $name) {
|
||||
} else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $this->_class->identifier[0] != $name) {
|
||||
$columns[] = $this->_class->getQuotedColumnName($name, $this->_platform);
|
||||
}
|
||||
}
|
||||
@ -1124,11 +1187,13 @@ class BasicEntityPersister
|
||||
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
|
||||
{
|
||||
$columnName = $class->columnNames[$field];
|
||||
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
|
||||
. '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
|
||||
|
||||
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
|
||||
|
||||
return "$sql AS $columnAlias";
|
||||
return $sql . ' AS ' . $columnAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1141,15 +1206,17 @@ class BasicEntityPersister
|
||||
protected function _getSQLTableAlias($className, $assocName = '')
|
||||
{
|
||||
if ($assocName) {
|
||||
$className .= '#'.$assocName;
|
||||
$className .= '#' . $assocName;
|
||||
}
|
||||
|
||||
if (isset($this->_sqlTableAliases[$className])) {
|
||||
return $this->_sqlTableAliases[$className];
|
||||
}
|
||||
|
||||
$tableAlias = 't' . $this->_sqlAliasCounter++;
|
||||
|
||||
$this->_sqlTableAliases[$className] = $tableAlias;
|
||||
|
||||
return $tableAlias;
|
||||
}
|
||||
|
||||
@ -1173,7 +1240,9 @@ class BasicEntityPersister
|
||||
$sql = 'SELECT 1 '
|
||||
. $this->_platform->appendLockHint($this->getLockTablesSql(), $lockMode)
|
||||
. ($conditionSql ? ' WHERE ' . $conditionSql : '') . ' ' . $lockSql;
|
||||
|
||||
list($params, $types) = $this->expandParameters($criteria);
|
||||
|
||||
$stmt = $this->_conn->executeQuery($sql, $params, $types);
|
||||
}
|
||||
|
||||
@ -1185,7 +1254,7 @@ class BasicEntityPersister
|
||||
protected function getLockTablesSql()
|
||||
{
|
||||
return 'FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->_getSQLTableAlias($this->_class->name);
|
||||
. $this->_getSQLTableAlias($this->_class->name);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1202,28 +1271,26 @@ class BasicEntityPersister
|
||||
protected function _getSelectConditionSQL(array $criteria, $assoc = null)
|
||||
{
|
||||
$conditionSql = '';
|
||||
|
||||
foreach ($criteria as $field => $value) {
|
||||
$conditionSql .= $conditionSql ? ' AND ' : '';
|
||||
|
||||
if (isset($this->_class->columnNames[$field])) {
|
||||
if (isset($this->_class->fieldMappings[$field]['inherited'])) {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->fieldMappings[$field]['inherited']) . '.';
|
||||
} else {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
|
||||
}
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
$className = (isset($this->_class->fieldMappings[$field]['inherited']))
|
||||
? $this->_class->fieldMappings[$field]['inherited']
|
||||
: $this->_class->name;
|
||||
|
||||
$conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
} else if (isset($this->_class->associationMappings[$field])) {
|
||||
if (!$this->_class->associationMappings[$field]['isOwningSide']) {
|
||||
if ( ! $this->_class->associationMappings[$field]['isOwningSide']) {
|
||||
throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field);
|
||||
}
|
||||
|
||||
if (isset($this->_class->associationMappings[$field]['inherited'])) {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->associationMappings[$field]['inherited']) . '.';
|
||||
} else {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
|
||||
}
|
||||
|
||||
$conditionSql .= $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
|
||||
$className = (isset($this->_class->associationMappings[$field]['inherited']))
|
||||
? $this->_class->associationMappings[$field]['inherited']
|
||||
: $this->_class->name;
|
||||
|
||||
$conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
|
||||
} else if ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false) {
|
||||
// very careless developers could potentially open up this normally hidden api for userland attacks,
|
||||
// therefore checking for spaces and function calls which are not allowed.
|
||||
@ -1251,6 +1318,7 @@ class BasicEntityPersister
|
||||
public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||
{
|
||||
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit);
|
||||
|
||||
return $this->loadArrayFromStatement($assoc, $stmt);
|
||||
}
|
||||
|
||||
@ -1266,7 +1334,8 @@ class BasicEntityPersister
|
||||
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
|
||||
{
|
||||
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity);
|
||||
$this->loadCollectionFromStatement($assoc, $stmt, $coll);
|
||||
|
||||
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1284,18 +1353,18 @@ class BasicEntityPersister
|
||||
$owningAssoc = $this->_class->associationMappings[$assoc['mappedBy']];
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
|
||||
|
||||
$tableAlias = isset($owningAssoc['inherited']) ?
|
||||
$this->_getSQLTableAlias($owningAssoc['inherited'])
|
||||
: $this->_getSQLTableAlias($this->_class->name);
|
||||
$tableAlias = $this->_getSQLTableAlias(isset($owningAssoc['inherited']) ? $owningAssoc['inherited'] : $this->_class->name);
|
||||
|
||||
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
|
||||
if ($sourceClass->containsForeignIdentifier) {
|
||||
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
|
||||
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
|
||||
|
||||
if (isset($sourceClass->associationMappings[$field])) {
|
||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
||||
}
|
||||
|
||||
$criteria[$tableAlias . "." . $targetKeyColumn] = $value;
|
||||
} else {
|
||||
$criteria[$tableAlias . "." . $targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
@ -1424,23 +1493,25 @@ class BasicEntityPersister
|
||||
public function exists($entity, array $extraConditions = array())
|
||||
{
|
||||
$criteria = $this->_class->getIdentifierValues($entity);
|
||||
|
||||
if ($extraConditions) {
|
||||
$criteria = array_merge($criteria, $extraConditions);
|
||||
}
|
||||
|
||||
$alias = $this->_getSQLTableAlias($this->_class->name);
|
||||
|
||||
|
||||
$sql = 'SELECT 1 FROM ' . $this->_class->getQuotedTableName($this->_platform)
|
||||
. ' ' . $alias
|
||||
. ' WHERE ' . $this->_getSelectConditionSQL($criteria);
|
||||
$sql = 'SELECT 1'
|
||||
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $alias
|
||||
. ' WHERE ' . $this->_getSelectConditionSQL($criteria);
|
||||
|
||||
$filterSql = $this->generateFilterConditionSQL($this->_class, $alias);
|
||||
if('' !== $filterSql) {
|
||||
$sql .= ' AND ' . $filterSql;
|
||||
}
|
||||
|
||||
return (bool) $this->_conn->fetchColumn($sql, array_values($criteria));
|
||||
|
||||
list($params, $types) = $this->expandParameters($criteria);
|
||||
|
||||
return (bool) $this->_conn->fetchColumn($sql, $params);
|
||||
}
|
||||
|
||||
private function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
|
||||
|
@ -22,6 +22,7 @@ namespace Doctrine\ORM\Persisters;
|
||||
use Doctrine\ORM\ORMException,
|
||||
Doctrine\ORM\Mapping\ClassMetadata,
|
||||
Doctrine\DBAL\LockMode,
|
||||
Doctrine\DBAL\Types\Type,
|
||||
Doctrine\ORM\Query\ResultSetMapping;
|
||||
|
||||
/**
|
||||
@ -55,11 +56,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
*/
|
||||
protected function _getDiscriminatorColumnTableName()
|
||||
{
|
||||
if ($this->_class->name == $this->_class->rootEntityName) {
|
||||
return $this->_class->table['name'];
|
||||
} else {
|
||||
return $this->_em->getClassMetadata($this->_class->rootEntityName)->table['name'];
|
||||
}
|
||||
$class = ($this->_class->name !== $this->_class->rootEntityName)
|
||||
? $this->_em->getClassMetadata($this->_class->rootEntityName)
|
||||
: $this->_class;
|
||||
|
||||
return $class->getTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,8 +73,10 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
{
|
||||
if (isset($this->_class->fieldMappings[$this->_class->versionField]['inherited'])) {
|
||||
$definingClassName = $this->_class->fieldMappings[$this->_class->versionField]['inherited'];
|
||||
|
||||
return $this->_em->getClassMetadata($definingClassName);
|
||||
}
|
||||
|
||||
return $this->_class;
|
||||
}
|
||||
|
||||
@ -86,19 +89,24 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
*/
|
||||
public function getOwningTable($fieldName)
|
||||
{
|
||||
if (!isset($this->_owningTableMap[$fieldName])) {
|
||||
if (isset($this->_class->associationMappings[$fieldName]['inherited'])) {
|
||||
$cm = $this->_em->getClassMetadata($this->_class->associationMappings[$fieldName]['inherited']);
|
||||
} else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) {
|
||||
$cm = $this->_em->getClassMetadata($this->_class->fieldMappings[$fieldName]['inherited']);
|
||||
} else {
|
||||
$cm = $this->_class;
|
||||
}
|
||||
$this->_owningTableMap[$fieldName] = $cm->table['name'];
|
||||
$this->_quotedTableMap[$cm->table['name']] = $cm->getQuotedTableName($this->_platform);
|
||||
if (isset($this->_owningTableMap[$fieldName])) {
|
||||
return $this->_owningTableMap[$fieldName];
|
||||
}
|
||||
|
||||
if (isset($this->_class->associationMappings[$fieldName]['inherited'])) {
|
||||
$cm = $this->_em->getClassMetadata($this->_class->associationMappings[$fieldName]['inherited']);
|
||||
} else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) {
|
||||
$cm = $this->_em->getClassMetadata($this->_class->fieldMappings[$fieldName]['inherited']);
|
||||
} else {
|
||||
$cm = $this->_class;
|
||||
}
|
||||
|
||||
return $this->_owningTableMap[$fieldName];
|
||||
$tableName = $cm->getTableName();
|
||||
|
||||
$this->_owningTableMap[$fieldName] = $tableName;
|
||||
$this->_quotedTableMap[$tableName] = $cm->getQuotedTableName($this->_platform);
|
||||
|
||||
return $tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,20 +123,22 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$isPostInsertId = $idGen->isPostInsertGenerator();
|
||||
|
||||
// Prepare statement for the root table
|
||||
$rootClass = $this->_class->name == $this->_class->rootEntityName ?
|
||||
$this->_class : $this->_em->getClassMetadata($this->_class->rootEntityName);
|
||||
$rootClass = ($this->_class->name !== $this->_class->rootEntityName) ? $this->_em->getClassMetadata($this->_class->rootEntityName) : $this->_class;
|
||||
$rootPersister = $this->_em->getUnitOfWork()->getEntityPersister($rootClass->name);
|
||||
$rootTableName = $rootClass->table['name'];
|
||||
$rootTableName = $rootClass->getTableName();
|
||||
$rootTableStmt = $this->_conn->prepare($rootPersister->_getInsertSQL());
|
||||
|
||||
// Prepare statements for sub tables.
|
||||
$subTableStmts = array();
|
||||
|
||||
if ($rootClass !== $this->_class) {
|
||||
$subTableStmts[$this->_class->table['name']] = $this->_conn->prepare($this->_getInsertSQL());
|
||||
$subTableStmts[$this->_class->getTableName()] = $this->_conn->prepare($this->_getInsertSQL());
|
||||
}
|
||||
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$parentTableName = $parentClass->table['name'];
|
||||
$parentTableName = $parentClass->getTableName();
|
||||
|
||||
if ($parentClass !== $rootClass) {
|
||||
$parentPersister = $this->_em->getUnitOfWork()->getEntityPersister($parentClassName);
|
||||
$subTableStmts[$parentTableName] = $this->_conn->prepare($parentPersister->_getInsertSQL());
|
||||
@ -143,9 +153,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// Execute insert on root table
|
||||
$paramIndex = 1;
|
||||
|
||||
foreach ($insertData[$rootTableName] as $columnName => $value) {
|
||||
$rootTableStmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]);
|
||||
}
|
||||
|
||||
$rootTableStmt->execute();
|
||||
|
||||
if ($isPostInsertId) {
|
||||
@ -160,17 +172,23 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
foreach ($subTableStmts as $tableName => $stmt) {
|
||||
$data = isset($insertData[$tableName]) ? $insertData[$tableName] : array();
|
||||
$paramIndex = 1;
|
||||
foreach ((array) $id as $idVal) {
|
||||
$stmt->bindValue($paramIndex++, $idVal);
|
||||
|
||||
foreach ((array) $id as $idName => $idVal) {
|
||||
$type = isset($this->_columnTypes[$idName]) ? $this->_columnTypes[$idName] : Type::STRING;
|
||||
|
||||
$stmt->bindValue($paramIndex++, $idVal, $type);
|
||||
}
|
||||
|
||||
foreach ($data as $columnName => $value) {
|
||||
$stmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]);
|
||||
}
|
||||
|
||||
$stmt->execute();
|
||||
}
|
||||
}
|
||||
|
||||
$rootTableStmt->closeCursor();
|
||||
|
||||
foreach ($subTableStmts as $stmt) {
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
@ -191,15 +209,18 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
{
|
||||
$updateData = $this->_prepareUpdateData($entity);
|
||||
|
||||
if ($isVersioned = $this->_class->isVersioned) {
|
||||
if (($isVersioned = $this->_class->isVersioned) != false) {
|
||||
$versionedClass = $this->_getVersionedClassMetadata();
|
||||
$versionedTable = $versionedClass->table['name'];
|
||||
$versionedTable = $versionedClass->getTableName();
|
||||
}
|
||||
|
||||
if ($updateData) {
|
||||
foreach ($updateData as $tableName => $data) {
|
||||
$this->_updateTable($entity, $this->_quotedTableMap[$tableName], $data, $isVersioned && $versionedTable == $tableName);
|
||||
$this->_updateTable(
|
||||
$entity, $this->_quotedTableMap[$tableName], $data, $isVersioned && $versionedTable == $tableName
|
||||
);
|
||||
}
|
||||
|
||||
// Make sure the table with the version column is updated even if no columns on that
|
||||
// table were affected.
|
||||
if ($isVersioned && ! isset($updateData[$versionedTable])) {
|
||||
@ -224,13 +245,17 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
// If the database platform supports FKs, just
|
||||
// delete the row from the root table. Cascades do the rest.
|
||||
if ($this->_platform->supportsForeignKeyConstraints()) {
|
||||
$this->_conn->delete($this->_em->getClassMetadata($this->_class->rootEntityName)
|
||||
->getQuotedTableName($this->_platform), $id);
|
||||
$this->_conn->delete(
|
||||
$this->_em->getClassMetadata($this->_class->rootEntityName)->getQuotedTableName($this->_platform), $id
|
||||
);
|
||||
} else {
|
||||
// Delete from all tables individually, starting from this class' table up to the root table.
|
||||
$this->_conn->delete($this->_class->getQuotedTableName($this->_platform), $id);
|
||||
|
||||
foreach ($this->_class->parentClasses as $parentClass) {
|
||||
$this->_conn->delete($this->_em->getClassMetadata($parentClass)->getQuotedTableName($this->_platform), $id);
|
||||
$this->_conn->delete(
|
||||
$this->_em->getClassMetadata($parentClass)->getQuotedTableName($this->_platform), $id
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -251,23 +276,27 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// Add regular columns
|
||||
$columnList = '';
|
||||
|
||||
foreach ($this->_class->fieldMappings as $fieldName => $mapping) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
$columnList .= $this->_getSelectColumnSQL($fieldName,
|
||||
isset($mapping['inherited']) ?
|
||||
$this->_em->getClassMetadata($mapping['inherited']) :
|
||||
$this->_class);
|
||||
|
||||
$columnList .= $this->_getSelectColumnSQL(
|
||||
$fieldName,
|
||||
isset($mapping['inherited']) ? $this->_em->getClassMetadata($mapping['inherited']) : $this->_class
|
||||
);
|
||||
}
|
||||
|
||||
// Add foreign key columns
|
||||
foreach ($this->_class->associationMappings as $assoc2) {
|
||||
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE) {
|
||||
$tableAlias = isset($assoc2['inherited']) ?
|
||||
$this->_getSQLTableAlias($assoc2['inherited'])
|
||||
: $baseTableAlias;
|
||||
$tableAlias = isset($assoc2['inherited']) ? $this->_getSQLTableAlias($assoc2['inherited']) : $baseTableAlias;
|
||||
|
||||
foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
$columnList .= $this->getSelectJoinColumnSQL($tableAlias, $srcColumn,
|
||||
|
||||
$columnList .= $this->getSelectJoinColumnSQL(
|
||||
$tableAlias,
|
||||
$srcColumn,
|
||||
isset($assoc2['inherited']) ? $assoc2['inherited'] : $this->_class->name
|
||||
);
|
||||
}
|
||||
@ -276,27 +305,27 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#_processSQLResult).
|
||||
$discrColumn = $this->_class->discriminatorColumn['name'];
|
||||
if ($this->_class->rootEntityName == $this->_class->name) {
|
||||
$columnList .= ", $baseTableAlias.$discrColumn";
|
||||
} else {
|
||||
$columnList .= ', ' . $this->_getSQLTableAlias($this->_class->rootEntityName)
|
||||
. ".$discrColumn";
|
||||
}
|
||||
$tableAlias = ($this->_class->rootEntityName == $this->_class->name) ? $baseTableAlias : $this->_getSQLTableAlias($this->_class->rootEntityName);
|
||||
$columnList .= ', ' . $tableAlias . '.' . $discrColumn;
|
||||
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($discrColumn);
|
||||
|
||||
$this->_rsm->setDiscriminatorColumn('r', $resultColumnName);
|
||||
$this->_rsm->addMetaResult('r', $resultColumnName, $discrColumn);
|
||||
}
|
||||
|
||||
// INNER JOIN parent tables
|
||||
$joinSql = '';
|
||||
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$tableAlias = $this->_getSQLTableAlias($parentClassName);
|
||||
$joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
|
||||
foreach ($idColumns as $idColumn) {
|
||||
if ($first) $first = false; else $joinSql .= ' AND ';
|
||||
|
||||
$joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
|
||||
}
|
||||
}
|
||||
@ -309,19 +338,20 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
if ($this->_selectColumnListSql === null) {
|
||||
// Add subclass columns
|
||||
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
|
||||
if (isset($mapping['inherited'])) {
|
||||
continue;
|
||||
}
|
||||
if (isset($mapping['inherited'])) continue;
|
||||
|
||||
$columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass);
|
||||
}
|
||||
|
||||
// Add join columns (foreign keys)
|
||||
foreach ($subClass->associationMappings as $assoc2) {
|
||||
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE
|
||||
&& ! isset($assoc2['inherited'])) {
|
||||
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE && ! isset($assoc2['inherited'])) {
|
||||
foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
$columnList .= $this->getSelectJoinColumnSQL($tableAlias, $srcColumn,
|
||||
|
||||
$columnList .= $this->getSelectJoinColumnSQL(
|
||||
$tableAlias,
|
||||
$srcColumn,
|
||||
isset($assoc2['inherited']) ? $assoc2['inherited'] : $subClass->name
|
||||
);
|
||||
}
|
||||
@ -332,14 +362,15 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
// Add LEFT JOIN
|
||||
$joinSql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
|
||||
foreach ($idColumns as $idColumn) {
|
||||
if ($first) $first = false; else $joinSql .= ' AND ';
|
||||
|
||||
$joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
|
||||
}
|
||||
}
|
||||
|
||||
$joinSql .= $assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY ?
|
||||
$this->_getSelectManyToManyJoinSQL($assoc) : '';
|
||||
$joinSql .= ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) ? $this->_getSelectManyToManyJoinSQL($assoc) : '';
|
||||
|
||||
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
|
||||
|
||||
@ -351,6 +382,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
|
||||
$lockSql = '';
|
||||
|
||||
if ($lockMode == LockMode::PESSIMISTIC_READ) {
|
||||
$lockSql = ' ' . $this->_platform->getReadLockSql();
|
||||
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
|
||||
@ -376,13 +408,16 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// INNER JOIN parent tables
|
||||
$joinSql = '';
|
||||
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$tableAlias = $this->_getSQLTableAlias($parentClassName);
|
||||
$joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
|
||||
foreach ($idColumns as $idColumn) {
|
||||
if ($first) $first = false; else $joinSql .= ' AND ';
|
||||
|
||||
$joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
|
||||
}
|
||||
}
|
||||
|
@ -40,9 +40,10 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
protected function _getDeleteRowSQL(PersistentCollection $coll)
|
||||
{
|
||||
$mapping = $coll->getMapping();
|
||||
$joinTable = $mapping['joinTable'];
|
||||
$columns = $mapping['joinTableColumns'];
|
||||
return 'DELETE FROM ' . $joinTable['name'] . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
|
||||
$class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
|
||||
|
||||
return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
|
||||
. ' WHERE ' . implode(' = ? AND ', $mapping['joinTableColumns']) . ' = ?';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,10 +76,11 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
protected function _getInsertRowSQL(PersistentCollection $coll)
|
||||
{
|
||||
$mapping = $coll->getMapping();
|
||||
$joinTable = $mapping['joinTable'];
|
||||
$columns = $mapping['joinTableColumns'];
|
||||
return 'INSERT INTO ' . $joinTable['name'] . ' (' . implode(', ', $columns) . ')'
|
||||
. ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
|
||||
$class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
|
||||
|
||||
return 'INSERT INTO ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
|
||||
. ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,8 +105,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
*/
|
||||
private function _collectJoinTableColumnParameters(PersistentCollection $coll, $element)
|
||||
{
|
||||
$params = array();
|
||||
$mapping = $coll->getMapping();
|
||||
$params = array();
|
||||
$mapping = $coll->getMapping();
|
||||
$isComposite = count($mapping['joinTableColumns']) > 2;
|
||||
|
||||
$identifier1 = $this->_uow->getEntityIdentifier($coll->getOwner());
|
||||
@ -149,14 +151,19 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
*/
|
||||
protected function _getDeleteSQL(PersistentCollection $coll)
|
||||
{
|
||||
$mapping = $coll->getMapping();
|
||||
$mapping = $coll->getMapping();
|
||||
$class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
|
||||
$joinTable = $mapping['joinTable'];
|
||||
$whereClause = '';
|
||||
|
||||
foreach ($mapping['relationToSourceKeyColumns'] as $relationColumn => $srcColumn) {
|
||||
if ($whereClause !== '') $whereClause .= ' AND ';
|
||||
$whereClause .= "$relationColumn = ?";
|
||||
|
||||
$whereClause .= $relationColumn . ' = ?';
|
||||
}
|
||||
return 'DELETE FROM ' . $joinTable['name'] . ' WHERE ' . $whereClause;
|
||||
|
||||
return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
|
||||
. ' WHERE ' . $whereClause;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,8 +178,10 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
$params = array();
|
||||
$mapping = $coll->getMapping();
|
||||
$identifier = $this->_uow->getEntityIdentifier($coll->getOwner());
|
||||
|
||||
if (count($mapping['relationToSourceKeyColumns']) > 1) {
|
||||
$sourceClass = $this->_em->getClassMetadata(get_class($mapping->getOwner()));
|
||||
|
||||
foreach ($mapping['relationToSourceKeyColumns'] as $relColumn => $srcColumn) {
|
||||
$params[] = $identifier[$sourceClass->fieldNames[$srcColumn]];
|
||||
}
|
||||
@ -188,21 +197,20 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
*/
|
||||
public function count(PersistentCollection $coll)
|
||||
{
|
||||
$params = array();
|
||||
$params = array();
|
||||
$mapping = $coll->getMapping();
|
||||
$class = $this->_em->getClassMetadata($mapping['sourceEntity']);
|
||||
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
|
||||
$class = $this->_em->getClassMetadata($mapping['sourceEntity']);
|
||||
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
|
||||
|
||||
if ($mapping['isOwningSide']) {
|
||||
$joinTable = $mapping['joinTable'];
|
||||
$joinColumns = $mapping['relationToSourceKeyColumns'];
|
||||
} else {
|
||||
$mapping = $this->_em->getClassMetadata($mapping['targetEntity'])->associationMappings[$mapping['mappedBy']];
|
||||
$joinTable = $mapping['joinTable'];
|
||||
$joinColumns = $mapping['relationToTargetKeyColumns'];
|
||||
}
|
||||
|
||||
$whereClause = '';
|
||||
|
||||
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
|
||||
if (isset($joinColumns[$joinTableColumn])) {
|
||||
if ($whereClause !== '') {
|
||||
@ -210,18 +218,16 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
}
|
||||
$whereClause .= "t.$joinTableColumn = ?";
|
||||
|
||||
if ($class->containsForeignIdentifier) {
|
||||
$params[] = $id[$class->getFieldForColumn($joinColumns[$joinTableColumn])];
|
||||
} else {
|
||||
$params[] = $id[$class->fieldNames[$joinColumns[$joinTableColumn]]];
|
||||
}
|
||||
$params[] = ($class->containsForeignIdentifier)
|
||||
? $id[$class->getFieldForColumn($joinColumns[$joinTableColumn])]
|
||||
: $id[$class->fieldNames[$joinColumns[$joinTableColumn]]];
|
||||
}
|
||||
}
|
||||
|
||||
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
|
||||
|
||||
$sql = 'SELECT count(*)'
|
||||
. ' FROM ' . $joinTable['name'] . ' t'
|
||||
|
||||
$sql = 'SELECT COUNT(*)'
|
||||
. ' FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) . ' t'
|
||||
. $joinTargetEntitySQL
|
||||
. ' WHERE ' . $whereClause
|
||||
. $filterSql;
|
||||
@ -238,9 +244,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
public function slice(PersistentCollection $coll, $offset, $length = null)
|
||||
{
|
||||
$mapping = $coll->getMapping();
|
||||
return $this->_em->getUnitOfWork()
|
||||
->getEntityPersister($mapping['targetEntity'])
|
||||
->getManyToManyCollection($mapping, $coll->getOwner(), $offset, $length);
|
||||
|
||||
return $this->_em->getUnitOfWork()->getEntityPersister($mapping['targetEntity'])->getManyToManyCollection($mapping, $coll->getOwner(), $offset, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -259,7 +264,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
$params = array();
|
||||
$mapping = $coll->getMapping();
|
||||
|
||||
if (!$mapping['isOwningSide']) {
|
||||
if ( ! $mapping['isOwningSide']) {
|
||||
$sourceClass = $this->_em->getClassMetadata($mapping['targetEntity']);
|
||||
$targetClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
|
||||
$sourceId = $uow->getEntityIdentifier($element);
|
||||
@ -272,44 +277,42 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
$sourceId = $uow->getEntityIdentifier($coll->getOwner());
|
||||
$targetId = $uow->getEntityIdentifier($element);
|
||||
}
|
||||
$joinTable = $mapping['joinTable'];
|
||||
|
||||
|
||||
$whereClause = '';
|
||||
|
||||
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
|
||||
if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) {
|
||||
if ($whereClause !== '') {
|
||||
$whereClause .= ' AND ';
|
||||
}
|
||||
$whereClause .= "$joinTableColumn = ?";
|
||||
|
||||
$whereClause .= $joinTableColumn . ' = ?';
|
||||
|
||||
if ($targetClass->containsForeignIdentifier) {
|
||||
$params[] = $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])];
|
||||
} else {
|
||||
$params[] = $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
|
||||
}
|
||||
$params[] = ($targetClass->containsForeignIdentifier)
|
||||
? $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]
|
||||
: $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
|
||||
} else if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) {
|
||||
if ($whereClause !== '') {
|
||||
$whereClause .= ' AND ';
|
||||
}
|
||||
$whereClause .= "$joinTableColumn = ?";
|
||||
|
||||
$whereClause .= $joinTableColumn . ' = ?';
|
||||
|
||||
if ($sourceClass->containsForeignIdentifier) {
|
||||
$params[] = $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])];
|
||||
} else {
|
||||
$params[] = $sourceId[$sourceClass->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
|
||||
}
|
||||
$params[] = ($sourceClass->containsForeignIdentifier)
|
||||
? $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])]
|
||||
: $sourceId[$sourceClass->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
|
||||
}
|
||||
}
|
||||
|
||||
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
|
||||
|
||||
|
||||
$sql = 'SELECT 1'
|
||||
. ' FROM ' . $joinTable['name'] . ' t'
|
||||
. ' FROM ' . $sourceClass->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) . ' t'
|
||||
. $joinTargetEntitySQL
|
||||
. ' WHERE ' . $whereClause
|
||||
. ' WHERE ' . $whereClause
|
||||
. $filterSql;
|
||||
|
||||
return (bool)$this->_conn->fetchColumn($sql, $params);
|
||||
return (bool) $this->_conn->fetchColumn($sql, $params);
|
||||
}
|
||||
|
||||
public function getFilterSql($mapping)
|
||||
|
@ -35,38 +35,49 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
/** {@inheritdoc} */
|
||||
protected function _getDiscriminatorColumnTableName()
|
||||
{
|
||||
return $this->_class->table['name'];
|
||||
return $this->_class->getTableName();
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function _getSelectColumnListSQL()
|
||||
{
|
||||
if ($this->_selectColumnListSql !== null) {
|
||||
return $this->_selectColumnListSql;
|
||||
}
|
||||
|
||||
$columnList = parent::_getSelectColumnListSQL();
|
||||
|
||||
// Append discriminator column
|
||||
$discrColumn = $this->_class->discriminatorColumn['name'];
|
||||
$columnList .= ", $discrColumn";
|
||||
$rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName);
|
||||
$columnList .= ', ' . $discrColumn;
|
||||
|
||||
$rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName);
|
||||
$tableAlias = $this->_getSQLTableAlias($rootClass->name);
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($discrColumn);
|
||||
|
||||
$this->_rsm->setDiscriminatorColumn('r', $resultColumnName);
|
||||
$this->_rsm->addMetaResult('r', $resultColumnName, $discrColumn);
|
||||
|
||||
// Append subclass columns
|
||||
foreach ($this->_class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
|
||||
// Regular columns
|
||||
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
|
||||
if ( ! isset($mapping['inherited'])) {
|
||||
$columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass);
|
||||
}
|
||||
}
|
||||
|
||||
// Foreign key columns
|
||||
foreach ($subClass->associationMappings as $assoc) {
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE && ! isset($assoc['inherited'])) {
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
$columnList .= $this->getSelectJoinColumnSQL($tableAlias, $srcColumn,
|
||||
|
||||
$columnList .= $this->getSelectJoinColumnSQL(
|
||||
$tableAlias,
|
||||
$srcColumn,
|
||||
isset($assoc['inherited']) ? $assoc['inherited'] : $this->_class->name
|
||||
);
|
||||
}
|
||||
@ -74,13 +85,15 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
}
|
||||
|
||||
return $columnList;
|
||||
$this->_selectColumnListSql = $columnList;
|
||||
return $this->_selectColumnListSql;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function _getInsertColumnList()
|
||||
{
|
||||
$columns = parent::_getInsertColumnList();
|
||||
|
||||
// Add discriminator column to the INSERT SQL
|
||||
$columns[] = $this->_class->discriminatorColumn['name'];
|
||||
|
||||
@ -100,18 +113,21 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// Append discriminator condition
|
||||
if ($conditionSql) $conditionSql .= ' AND ';
|
||||
|
||||
$values = array();
|
||||
|
||||
if ($this->_class->discriminatorValue !== null) { // discriminators can be 0
|
||||
$values[] = $this->_conn->quote($this->_class->discriminatorValue);
|
||||
}
|
||||
|
||||
$discrValues = array_flip($this->_class->discriminatorMap);
|
||||
|
||||
foreach ($this->_class->subClasses as $subclassName) {
|
||||
$values[] = $this->_conn->quote($discrValues[$subclassName]);
|
||||
}
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.'
|
||||
. $this->_class->discriminatorColumn['name']
|
||||
. ' IN (' . implode(', ', $values) . ')';
|
||||
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.' . $this->_class->discriminatorColumn['name']
|
||||
. ' IN (' . implode(', ', $values) . ')';
|
||||
|
||||
return $conditionSql;
|
||||
}
|
||||
|
@ -207,8 +207,9 @@ final class Query extends AbstractQuery
|
||||
|
||||
// Check query cache.
|
||||
if ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver())) {
|
||||
$hash = $this->_getQueryCacheId();
|
||||
$hash = $this->_getQueryCacheId();
|
||||
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
|
||||
|
||||
if ($cached === false) {
|
||||
// Cache miss.
|
||||
$parser = new Parser($this);
|
||||
@ -222,6 +223,7 @@ final class Query extends AbstractQuery
|
||||
$parser = new Parser($this);
|
||||
$this->_parserResult = $parser->parse();
|
||||
}
|
||||
|
||||
$this->_state = self::STATE_CLEAN;
|
||||
|
||||
return $this->_parserResult;
|
||||
@ -241,50 +243,85 @@ final class Query extends AbstractQuery
|
||||
throw QueryException::invalidParameterNumber();
|
||||
}
|
||||
|
||||
$sqlParams = $types = array();
|
||||
|
||||
foreach ($this->_params as $key => $value) {
|
||||
if ( ! isset($paramMappings[$key])) {
|
||||
throw QueryException::unknownParameter($key);
|
||||
}
|
||||
if (isset($this->_paramTypes[$key])) {
|
||||
foreach ($paramMappings[$key] as $position) {
|
||||
$types[$position] = $this->_paramTypes[$key];
|
||||
}
|
||||
}
|
||||
|
||||
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value))) {
|
||||
if ($this->_em->getUnitOfWork()->getEntityState($value) == UnitOfWork::STATE_MANAGED) {
|
||||
$idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
} else {
|
||||
$class = $this->_em->getClassMetadata(get_class($value));
|
||||
$idValues = $class->getIdentifierValues($value);
|
||||
}
|
||||
$sqlPositions = $paramMappings[$key];
|
||||
$cSqlPos = count($sqlPositions);
|
||||
$cIdValues = count($idValues);
|
||||
$idValues = array_values($idValues);
|
||||
for ($i = 0; $i < $cSqlPos; $i++) {
|
||||
$sqlParams[$sqlPositions[$i]] = $idValues[ ($i % $cIdValues) ];
|
||||
}
|
||||
} else {
|
||||
foreach ($paramMappings[$key] as $position) {
|
||||
$sqlParams[$position] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($sqlParams) {
|
||||
ksort($sqlParams);
|
||||
$sqlParams = array_values($sqlParams);
|
||||
}
|
||||
|
||||
list($sqlParams, $types) = $this->processParameterMappings($paramMappings);
|
||||
|
||||
if ($this->_resultSetMapping === null) {
|
||||
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
|
||||
}
|
||||
|
||||
return $executor->execute($this->_em->getConnection(), $sqlParams, $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes query parameter mappings
|
||||
*
|
||||
* @param array $paramMappings
|
||||
* @return array
|
||||
*/
|
||||
private function processParameterMappings($paramMappings)
|
||||
{
|
||||
$sqlParams = $types = array();
|
||||
|
||||
foreach ($this->_params as $key => $value) {
|
||||
if ( ! isset($paramMappings[$key])) {
|
||||
throw QueryException::unknownParameter($key);
|
||||
}
|
||||
|
||||
if (isset($this->_paramTypes[$key])) {
|
||||
foreach ($paramMappings[$key] as $position) {
|
||||
$types[$position] = $this->_paramTypes[$key];
|
||||
}
|
||||
}
|
||||
|
||||
$sqlPositions = $paramMappings[$key];
|
||||
$value = array_values($this->processParameterValue($value));
|
||||
$countValue = count($value);
|
||||
|
||||
for ($i = 0, $l = count($sqlPositions); $i < $l; $i++) {
|
||||
$sqlParams[$sqlPositions[$i]] = $value[($i % $countValue)];
|
||||
}
|
||||
}
|
||||
|
||||
if ($sqlParams) {
|
||||
ksort($sqlParams);
|
||||
$sqlParams = array_values($sqlParams);
|
||||
}
|
||||
|
||||
return array($sqlParams, $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an individual parameter value
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
private function processParameterValue($value)
|
||||
{
|
||||
switch (true) {
|
||||
case is_array($value):
|
||||
for ($i = 0, $l = count($value); $i < $l; $i++) {
|
||||
$paramValue = $this->processParameterValue($value[$i]);
|
||||
|
||||
// TODO: What about Entities that have composite primary key?
|
||||
$value[$i] = is_array($paramValue) ? $paramValue[key($paramValue)] : $paramValue;
|
||||
}
|
||||
|
||||
return array($value);
|
||||
|
||||
case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value)):
|
||||
if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) {
|
||||
return array_values($this->_em->getUnitOfWork()->getEntityIdentifier($value));
|
||||
}
|
||||
|
||||
$class = $this->_em->getClassMetadata(get_class($value));
|
||||
|
||||
return array_values($class->getIdentifierValues($value));
|
||||
|
||||
default:
|
||||
return array($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a cache driver to be used for caching queries.
|
||||
|
68
lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php
Normal file
68
lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
|
||||
/**
|
||||
* "IDENTITY" "(" SingleValuedAssociationPathExpression ")"
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.2
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class IdentityFunction extends FunctionNode
|
||||
{
|
||||
public $pathExpression;
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
{
|
||||
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
|
||||
$dqlAlias = $this->pathExpression->identificationVariable;
|
||||
$assocField = $this->pathExpression->field;
|
||||
|
||||
$qComp = $sqlWalker->getQueryComponent($dqlAlias);
|
||||
$class = $qComp['metadata'];
|
||||
$assoc = $class->associationMappings[$assocField];
|
||||
|
||||
$tableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
return $tableAlias . '.' . reset($assoc['targetToSourceKeyColumns']);;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->pathExpression = $parser->SingleValuedAssociationPathExpression();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ class SizeFunction extends FunctionNode
|
||||
|
||||
if ($assoc['type'] == \Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_MANY) {
|
||||
$targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc['targetEntity']);
|
||||
$targetTableAlias = $sqlWalker->getSQLTableAlias($targetClass->table['name']);
|
||||
$sourceTableAlias = $sqlWalker->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
$targetTableAlias = $sqlWalker->getSQLTableAlias($targetClass->getTableName());
|
||||
$sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
$sql .= $targetClass->getQuotedTableName($platform) . ' ' . $targetTableAlias . ' WHERE ';
|
||||
|
||||
@ -77,7 +77,7 @@ class SizeFunction extends FunctionNode
|
||||
|
||||
// SQL table aliases
|
||||
$joinTableAlias = $sqlWalker->getSQLTableAlias($joinTable['name']);
|
||||
$sourceTableAlias = $sqlWalker->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
$sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
// join to target table
|
||||
$sql .= $targetClass->getQuotedJoinTableName($owningAssoc, $platform) . ' ' . $joinTableAlias . ' WHERE ';
|
||||
|
@ -23,7 +23,7 @@ namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SelectExpression ::= IdentificationVariable ["." "*"] | StateFieldPathExpression |
|
||||
* (AggregateExpression | "(" Subselect ")") [["AS"] FieldAliasIdentificationVariable]
|
||||
* (AggregateExpression | "(" Subselect ")") [["AS"] ["HIDDEN"] FieldAliasIdentificationVariable]
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
@ -37,11 +37,13 @@ class SelectExpression extends Node
|
||||
{
|
||||
public $expression;
|
||||
public $fieldIdentificationVariable;
|
||||
public $hiddenAliasResultVariable;
|
||||
|
||||
public function __construct($expression, $fieldIdentificationVariable)
|
||||
public function __construct($expression, $fieldIdentificationVariable, $hiddenAliasResultVariable = false)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
$this->fieldIdentificationVariable = $fieldIdentificationVariable;
|
||||
$this->hiddenAliasResultVariable = $hiddenAliasResultVariable;
|
||||
}
|
||||
|
||||
public function dispatch($sqlWalker)
|
||||
|
@ -63,7 +63,7 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
||||
$idColumnList = implode(', ', $idColumnNames);
|
||||
|
||||
// 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause()
|
||||
$sqlWalker->setSQLTableAlias($primaryClass->table['name'], 't0', $primaryDqlAlias);
|
||||
$sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $primaryDqlAlias);
|
||||
|
||||
$this->_insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')'
|
||||
. ' SELECT t0.' . implode(', t0.', $idColumnNames);
|
||||
@ -98,7 +98,7 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
||||
}
|
||||
$this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' ('
|
||||
. $platform->getColumnDeclarationListSQL($columnDefinitions) . ')';
|
||||
$this->_dropTempTableSql = 'DROP TABLE ' . $tempTable;
|
||||
$this->_dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,7 +64,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
||||
$idColumnList = implode(', ', $idColumnNames);
|
||||
|
||||
// 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause()
|
||||
$sqlWalker->setSQLTableAlias($primaryClass->table['name'], 't0', $updateClause->aliasIdentificationVariable);
|
||||
$sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $updateClause->aliasIdentificationVariable);
|
||||
|
||||
$this->_insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')'
|
||||
. ' SELECT t0.' . implode(', t0.', $idColumnNames);
|
||||
@ -106,7 +106,8 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
||||
//FIXME (URGENT): With query cache the parameter is out of date. Move to execute() stage.
|
||||
if ($newValue instanceof AST\InputParameter) {
|
||||
$paramKey = $newValue->name;
|
||||
$this->_sqlParameters[$i][] = $sqlWalker->getQuery()->getParameter($paramKey);
|
||||
$this->_sqlParameters[$i]['parameters'][] = $sqlWalker->getQuery()->getParameter($paramKey);
|
||||
$this->_sqlParameters[$i]['types'][] = $sqlWalker->getQuery()->getParameterType($paramKey);
|
||||
|
||||
++$this->_numParametersInUpdateClause;
|
||||
}
|
||||
@ -136,7 +137,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
||||
$this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' ('
|
||||
. $platform->getColumnDeclarationListSQL($columnDefinitions) . ')';
|
||||
|
||||
$this->_dropTempTableSql = 'DROP TABLE ' . $tempTable;
|
||||
$this->_dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,11 +155,23 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
||||
$conn->executeUpdate($this->_createTempTableSql);
|
||||
|
||||
// Insert identifiers. Parameters from the update clause are cut off.
|
||||
$numUpdated = $conn->executeUpdate($this->_insertSql, array_slice($params, $this->_numParametersInUpdateClause), $types);
|
||||
$numUpdated = $conn->executeUpdate(
|
||||
$this->_insertSql,
|
||||
array_slice($params, $this->_numParametersInUpdateClause),
|
||||
array_slice($types, $this->_numParametersInUpdateClause)
|
||||
);
|
||||
|
||||
// Execute UPDATE statements
|
||||
for ($i=0, $count=count($this->_sqlStatements); $i<$count; ++$i) {
|
||||
$conn->executeUpdate($this->_sqlStatements[$i], isset($this->_sqlParameters[$i]) ? $this->_sqlParameters[$i] : array());
|
||||
$parameters = array();
|
||||
$types = array();
|
||||
|
||||
if (isset($this->_sqlParameters[$i])) {
|
||||
$parameters = isset($this->_sqlParameters[$i]['parameters']) ? $this->_sqlParameters[$i]['parameters'] : array();
|
||||
$types = isset($this->_sqlParameters[$i]['types']) ? $this->_sqlParameters[$i]['types'] : array();
|
||||
}
|
||||
|
||||
$conn->executeUpdate($this->_sqlStatements[$i], $parameters, $types);
|
||||
}
|
||||
|
||||
// Drop temporary table
|
||||
|
@ -34,27 +34,55 @@ namespace Doctrine\ORM\Query\Expr;
|
||||
*/
|
||||
class From
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $_from;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $_alias;
|
||||
|
||||
public function __construct($from, $alias)
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $_indexBy;
|
||||
|
||||
/**
|
||||
* @param string $from The class name.
|
||||
* @param string $alias The alias of the class.
|
||||
* @param string $indexBy The index for the from.
|
||||
*/
|
||||
public function __construct($from, $alias, $indexBy = null)
|
||||
{
|
||||
$this->_from = $from;
|
||||
$this->_alias = $alias;
|
||||
$this->_from = $from;
|
||||
$this->_alias = $alias;
|
||||
$this->_indexBy = $indexBy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFrom()
|
||||
{
|
||||
return $this->_from;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAlias()
|
||||
{
|
||||
return $this->_alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->_from . ' ' . $this->_alias;
|
||||
return $this->_from . ' ' . $this->_alias .
|
||||
($this->_indexBy ? ' INDEX BY ' . $this->_indexBy : '');
|
||||
}
|
||||
}
|
@ -76,39 +76,40 @@ class Lexer extends \Doctrine\Common\Lexer
|
||||
const T_FROM = 122;
|
||||
const T_GROUP = 123;
|
||||
const T_HAVING = 124;
|
||||
const T_IN = 125;
|
||||
const T_INDEX = 126;
|
||||
const T_INNER = 127;
|
||||
const T_INSTANCE = 128;
|
||||
const T_IS = 129;
|
||||
const T_JOIN = 130;
|
||||
const T_LEADING = 131;
|
||||
const T_LEFT = 132;
|
||||
const T_LIKE = 133;
|
||||
const T_MAX = 134;
|
||||
const T_MEMBER = 135;
|
||||
const T_MIN = 136;
|
||||
const T_NOT = 137;
|
||||
const T_NULL = 138;
|
||||
const T_NULLIF = 139;
|
||||
const T_OF = 140;
|
||||
const T_OR = 141;
|
||||
const T_ORDER = 142;
|
||||
const T_OUTER = 143;
|
||||
const T_SELECT = 144;
|
||||
const T_SET = 145;
|
||||
const T_SIZE = 146;
|
||||
const T_SOME = 147;
|
||||
const T_SUM = 148;
|
||||
const T_THEN = 149;
|
||||
const T_TRAILING = 150;
|
||||
const T_TRUE = 151;
|
||||
const T_UPDATE = 152;
|
||||
const T_WHEN = 153;
|
||||
const T_WHERE = 154;
|
||||
const T_WITH = 155;
|
||||
const T_PARTIAL = 156;
|
||||
const T_MOD = 157;
|
||||
const T_HIDDEN = 125;
|
||||
const T_IN = 126;
|
||||
const T_INDEX = 127;
|
||||
const T_INNER = 128;
|
||||
const T_INSTANCE = 129;
|
||||
const T_IS = 130;
|
||||
const T_JOIN = 131;
|
||||
const T_LEADING = 132;
|
||||
const T_LEFT = 133;
|
||||
const T_LIKE = 134;
|
||||
const T_MAX = 135;
|
||||
const T_MEMBER = 136;
|
||||
const T_MIN = 137;
|
||||
const T_NOT = 138;
|
||||
const T_NULL = 139;
|
||||
const T_NULLIF = 140;
|
||||
const T_OF = 141;
|
||||
const T_OR = 142;
|
||||
const T_ORDER = 143;
|
||||
const T_OUTER = 144;
|
||||
const T_SELECT = 145;
|
||||
const T_SET = 146;
|
||||
const T_SIZE = 147;
|
||||
const T_SOME = 148;
|
||||
const T_SUM = 149;
|
||||
const T_THEN = 150;
|
||||
const T_TRAILING = 151;
|
||||
const T_TRUE = 152;
|
||||
const T_UPDATE = 153;
|
||||
const T_WHEN = 154;
|
||||
const T_WHERE = 155;
|
||||
const T_WITH = 156;
|
||||
const T_PARTIAL = 157;
|
||||
const T_MOD = 158;
|
||||
|
||||
/**
|
||||
* Creates a new query scanner object.
|
||||
|
@ -40,7 +40,8 @@ class Parser
|
||||
'substring' => 'Doctrine\ORM\Query\AST\Functions\SubstringFunction',
|
||||
'trim' => 'Doctrine\ORM\Query\AST\Functions\TrimFunction',
|
||||
'lower' => 'Doctrine\ORM\Query\AST\Functions\LowerFunction',
|
||||
'upper' => 'Doctrine\ORM\Query\AST\Functions\UpperFunction'
|
||||
'upper' => 'Doctrine\ORM\Query\AST\Functions\UpperFunction',
|
||||
'identity' => 'Doctrine\ORM\Query\AST\Functions\IdentityFunction',
|
||||
);
|
||||
|
||||
/** READ-ONLY: Maps BUILT-IN numeric function names to AST class names. */
|
||||
@ -1695,6 +1696,7 @@ class Parser
|
||||
return $this->CoalesceExpression();
|
||||
|
||||
case Lexer::T_CASE:
|
||||
$this->_lexer->resetPeek();
|
||||
$peek = $this->_lexer->peek();
|
||||
|
||||
return ($peek['type'] === Lexer::T_WHEN)
|
||||
@ -1829,7 +1831,7 @@ class Parser
|
||||
/**
|
||||
* SelectExpression ::=
|
||||
* IdentificationVariable | StateFieldPathExpression |
|
||||
* (AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable]
|
||||
* (AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] ["HIDDEN"] AliasResultVariable]
|
||||
*
|
||||
* @return Doctrine\ORM\Query\AST\SelectExpression
|
||||
*/
|
||||
@ -1837,6 +1839,7 @@ class Parser
|
||||
{
|
||||
$expression = null;
|
||||
$identVariable = null;
|
||||
$hiddenAliasResultVariable = false;
|
||||
$fieldAliasIdentificationVariable = null;
|
||||
$peek = $this->_lexer->glimpse();
|
||||
|
||||
@ -1898,6 +1901,12 @@ class Parser
|
||||
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
|
||||
$this->match(Lexer::T_AS);
|
||||
}
|
||||
|
||||
if ($this->_lexer->isNextToken(Lexer::T_HIDDEN)) {
|
||||
$this->match(Lexer::T_HIDDEN);
|
||||
|
||||
$hiddenAliasResultVariable = true;
|
||||
}
|
||||
|
||||
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$token = $this->_lexer->lookahead;
|
||||
@ -1912,10 +1921,12 @@ class Parser
|
||||
}
|
||||
}
|
||||
|
||||
$expr = new AST\SelectExpression($expression, $fieldAliasIdentificationVariable);
|
||||
if (!$supportsAlias) {
|
||||
$expr = new AST\SelectExpression($expression, $fieldAliasIdentificationVariable, $hiddenAliasResultVariable);
|
||||
|
||||
if ( ! $supportsAlias) {
|
||||
$this->_identVariableExpressions[$identVariable] = $expr;
|
||||
}
|
||||
|
||||
return $expr;
|
||||
}
|
||||
|
||||
@ -2381,7 +2392,7 @@ class Parser
|
||||
/**
|
||||
* ArithmeticPrimary ::= SingleValuedPathExpression | Literal | "(" SimpleArithmeticExpression ")"
|
||||
* | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings
|
||||
* | FunctionsReturningDatetime | IdentificationVariable | CaseExpression
|
||||
* | FunctionsReturningDatetime | IdentificationVariable | ResultVariable | CaseExpression
|
||||
*/
|
||||
public function ArithmeticPrimary()
|
||||
{
|
||||
@ -2410,7 +2421,11 @@ class Parser
|
||||
if ($peek['value'] == '.') {
|
||||
return $this->SingleValuedPathExpression();
|
||||
}
|
||||
|
||||
|
||||
if (isset($this->_queryComponents[$this->_lexer->lookahead['value']]['resultVariable'])) {
|
||||
return $this->ResultVariable();
|
||||
}
|
||||
|
||||
return $this->StateFieldPathExpression();
|
||||
|
||||
case Lexer::T_INPUT_PARAMETER:
|
||||
|
@ -244,24 +244,23 @@ class SqlWalker implements TreeWalker
|
||||
{
|
||||
$sql = '';
|
||||
|
||||
$baseTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
$baseTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
// INNER JOIN parent class tables
|
||||
foreach ($class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$tableAlias = $this->getSQLTableAlias($parentClass->table['name'], $dqlAlias);
|
||||
$tableAlias = $this->getSQLTableAlias($parentClass->getTableName(), $dqlAlias);
|
||||
|
||||
// If this is a joined association we must use left joins to preserve the correct result.
|
||||
$sql .= isset($this->_queryComponents[$dqlAlias]['relation']) ? ' LEFT ' : ' INNER ';
|
||||
$sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform)
|
||||
. ' ' . $tableAlias . ' ON ';
|
||||
$sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
|
||||
foreach ($class->identifier as $idField) {
|
||||
if ($first) $first = false; else $sql .= ' AND ';
|
||||
|
||||
$columnName = $class->getQuotedColumnName($idField, $this->_platform);
|
||||
$sql .= $baseTableAlias . '.' . $columnName
|
||||
. ' = '
|
||||
. $tableAlias . '.' . $columnName;
|
||||
$sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,17 +268,15 @@ class SqlWalker implements TreeWalker
|
||||
if ( ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
|
||||
foreach ($class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
$tableAlias = $this->getSQLTableAlias($subClass->table['name'], $dqlAlias);
|
||||
$sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform)
|
||||
. ' ' . $tableAlias . ' ON ';
|
||||
$tableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias);
|
||||
$sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
|
||||
foreach ($class->identifier as $idField) {
|
||||
if ($first) $first = false; else $sql .= ' AND ';
|
||||
|
||||
$columnName = $class->getQuotedColumnName($idField, $this->_platform);
|
||||
$sql .= $baseTableAlias . '.' . $columnName
|
||||
. ' = '
|
||||
. $tableAlias . '.' . $columnName;
|
||||
$sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -290,24 +287,26 @@ class SqlWalker implements TreeWalker
|
||||
private function _generateOrderedCollectionOrderByItems()
|
||||
{
|
||||
$sql = '';
|
||||
|
||||
foreach ($this->_selectedClasses AS $dqlAlias => $class) {
|
||||
$qComp = $this->_queryComponents[$dqlAlias];
|
||||
|
||||
if (isset($qComp['relation']['orderBy'])) {
|
||||
foreach ($qComp['relation']['orderBy'] AS $fieldName => $orientation) {
|
||||
if ($qComp['metadata']->isInheritanceTypeJoined()) {
|
||||
$tableName = $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName);
|
||||
} else {
|
||||
$tableName = $qComp['metadata']->table['name'];
|
||||
}
|
||||
$tableName = ($qComp['metadata']->isInheritanceTypeJoined())
|
||||
? $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName)
|
||||
: $qComp['metadata']->getTableName();
|
||||
|
||||
if ($sql != '') {
|
||||
$sql .= ', ';
|
||||
}
|
||||
$sql .= $this->getSQLTableAlias($tableName, $dqlAlias) . '.' .
|
||||
$qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform) . " $orientation";
|
||||
|
||||
$sql .= $this->getSQLTableAlias($tableName, $dqlAlias) . '.'
|
||||
. $qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform) . ' ' . $orientation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
@ -328,6 +327,7 @@ class SqlWalker implements TreeWalker
|
||||
if ($class->isInheritanceTypeSingleTable()) {
|
||||
$conn = $this->_em->getConnection();
|
||||
$values = array();
|
||||
|
||||
if ($class->discriminatorValue !== null) { // discrimnators can be 0
|
||||
$values[] = $conn->quote($class->discriminatorValue);
|
||||
}
|
||||
@ -342,7 +342,7 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
|
||||
$sql .= ($sql != '' ? ' AND ' : '')
|
||||
. (($this->_useSqlTableAliases) ? $this->getSQLTableAlias($class->table['name'], $dqlAlias) . '.' : '')
|
||||
. (($this->_useSqlTableAliases) ? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.' : '')
|
||||
. $class->discriminatorColumn['name'] . ' IN (' . implode(', ', $values) . ')';
|
||||
}
|
||||
}
|
||||
@ -373,7 +373,7 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
public function walkSelectStatement(AST\SelectStatement $AST)
|
||||
{
|
||||
$sql = $this->walkSelectClause($AST->selectClause);
|
||||
$sql = $this->walkSelectClause($AST->selectClause);
|
||||
$sql .= $this->walkFromClause($AST->fromClause);
|
||||
$sql .= $this->walkWhereClause($AST->whereClause);
|
||||
$sql .= $AST->groupByClause ? $this->walkGroupByClause($AST->groupByClause) : '';
|
||||
@ -382,19 +382,18 @@ class SqlWalker implements TreeWalker
|
||||
if (($orderByClause = $AST->orderByClause) !== null) {
|
||||
$sql .= $AST->orderByClause ? $this->walkOrderByClause($AST->orderByClause) : '';
|
||||
} else if (($orderBySql = $this->_generateOrderedCollectionOrderByItems()) !== '') {
|
||||
$sql .= ' ORDER BY '.$orderBySql;
|
||||
$sql .= ' ORDER BY ' . $orderBySql;
|
||||
}
|
||||
|
||||
|
||||
$sql = $this->_platform->modifyLimitQuery(
|
||||
$sql, $this->_query->getMaxResults(), $this->_query->getFirstResult()
|
||||
);
|
||||
|
||||
if (($lockMode = $this->_query->getHint(Query::HINT_LOCK_MODE)) !== false) {
|
||||
if ($lockMode == LockMode::PESSIMISTIC_READ) {
|
||||
$sql .= " " . $this->_platform->getReadLockSQL();
|
||||
$sql .= ' ' . $this->_platform->getReadLockSQL();
|
||||
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
|
||||
$sql .= " " . $this->_platform->getWriteLockSQL();
|
||||
$sql .= ' ' . $this->_platform->getWriteLockSQL();
|
||||
} else if ($lockMode == LockMode::OPTIMISTIC) {
|
||||
foreach ($this->_selectedClasses AS $class) {
|
||||
if ( ! $class->isVersioned) {
|
||||
@ -416,10 +415,8 @@ class SqlWalker implements TreeWalker
|
||||
public function walkUpdateStatement(AST\UpdateStatement $AST)
|
||||
{
|
||||
$this->_useSqlTableAliases = false;
|
||||
$sql = $this->walkUpdateClause($AST->updateClause);
|
||||
$sql .= $this->walkWhereClause($AST->whereClause);
|
||||
|
||||
return $sql;
|
||||
|
||||
return $this->walkUpdateClause($AST->updateClause) . $this->walkWhereClause($AST->whereClause);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -431,10 +428,8 @@ class SqlWalker implements TreeWalker
|
||||
public function walkDeleteStatement(AST\DeleteStatement $AST)
|
||||
{
|
||||
$this->_useSqlTableAliases = false;
|
||||
$sql = $this->walkDeleteClause($AST->deleteClause);
|
||||
$sql .= $this->walkWhereClause($AST->whereClause);
|
||||
|
||||
return $sql;
|
||||
|
||||
return $this->walkDeleteClause($AST->deleteClause) . $this->walkWhereClause($AST->whereClause);
|
||||
}
|
||||
|
||||
|
||||
@ -456,7 +451,7 @@ class SqlWalker implements TreeWalker
|
||||
$class = $this->_em->getClassMetadata($class->fieldMappings[$fieldName]['inherited']);
|
||||
}
|
||||
|
||||
return $this->getSQLTableAlias($class->table['name'], $identificationVariable);
|
||||
return $this->getSQLTableAlias($class->getTableName(), $identificationVariable);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -505,7 +500,7 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
|
||||
if ($this->_useSqlTableAliases) {
|
||||
$sql .= $this->getSQLTableAlias($class->table['name'], $dqlAlias) . '.';
|
||||
$sql .= $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.';
|
||||
}
|
||||
|
||||
$sql .= reset($assoc['targetToSourceKeyColumns']);
|
||||
@ -550,7 +545,7 @@ class SqlWalker implements TreeWalker
|
||||
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) {
|
||||
// Add discriminator columns to SQL
|
||||
$rootClass = $this->_em->getClassMetadata($class->rootEntityName);
|
||||
$tblAlias = $this->getSQLTableAlias($rootClass->table['name'], $dqlAlias);
|
||||
$tblAlias = $this->getSQLTableAlias($rootClass->getTableName(), $dqlAlias);
|
||||
$discrColumn = $rootClass->discriminatorColumn;
|
||||
$columnAlias = $this->getSQLColumnAlias($discrColumn['name']);
|
||||
|
||||
@ -567,9 +562,9 @@ class SqlWalker implements TreeWalker
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
|
||||
if (isset($assoc['inherited'])) {
|
||||
$owningClass = $this->_em->getClassMetadata($assoc['inherited']);
|
||||
$sqlTableAlias = $this->getSQLTableAlias($owningClass->table['name'], $dqlAlias);
|
||||
$sqlTableAlias = $this->getSQLTableAlias($owningClass->getTableName(), $dqlAlias);
|
||||
} else {
|
||||
$sqlTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
$sqlTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
}
|
||||
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
@ -586,7 +581,8 @@ class SqlWalker implements TreeWalker
|
||||
} else {
|
||||
// Add foreign key columns to SQL, if necessary
|
||||
if ($addMetaColumns) {
|
||||
$sqlTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
$sqlTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
foreach ($class->associationMappings as $assoc) {
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
@ -628,7 +624,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
$class = $this->_em->getClassMetadata($rangeDecl->abstractSchemaName);
|
||||
$sql .= $class->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
. $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
if ($class->isInheritanceTypeJoined()) {
|
||||
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
|
||||
@ -739,13 +735,15 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
|
||||
$joinAssocPathExpr = $join->joinAssociationPathExpression;
|
||||
$joinedDqlAlias = $join->aliasIdentificationVariable;
|
||||
$relation = $this->_queryComponents[$joinedDqlAlias]['relation'];
|
||||
$targetClass = $this->_em->getClassMetadata($relation['targetEntity']);
|
||||
$sourceClass = $this->_em->getClassMetadata($relation['sourceEntity']);
|
||||
$joinedDqlAlias = $join->aliasIdentificationVariable;
|
||||
|
||||
$relation = $this->_queryComponents[$joinedDqlAlias]['relation'];
|
||||
$targetClass = $this->_em->getClassMetadata($relation['targetEntity']);
|
||||
$sourceClass = $this->_em->getClassMetadata($relation['sourceEntity']);
|
||||
$targetTableName = $targetClass->getQuotedTableName($this->_platform);
|
||||
$targetTableAlias = $this->getSQLTableAlias($targetClass->table['name'], $joinedDqlAlias);
|
||||
$sourceTableAlias = $this->getSQLTableAlias($sourceClass->table['name'], $joinAssocPathExpr->identificationVariable);
|
||||
|
||||
$targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName(), $joinedDqlAlias);
|
||||
$sourceTableAlias = $this->getSQLTableAlias($sourceClass->getTableName(), $joinAssocPathExpr->identificationVariable);
|
||||
|
||||
// Ensure we got the owning side, since it has all mapping info
|
||||
$assoc = ( ! $relation['isOwningSide']) ? $targetClass->associationMappings[$relation['mappedBy']] : $relation;
|
||||
@ -833,8 +831,7 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
|
||||
// Join target table
|
||||
$sql .= ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER)
|
||||
? ' LEFT JOIN ' : ' INNER JOIN ';
|
||||
$sql .= ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) ? ' LEFT JOIN ' : ' INNER JOIN ';
|
||||
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
|
||||
|
||||
$first = true;
|
||||
@ -1006,8 +1003,9 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
public function walkSelectExpression($selectExpression)
|
||||
{
|
||||
$sql = '';
|
||||
$expr = $selectExpression->expression;
|
||||
$sql = '';
|
||||
$expr = $selectExpression->expression;
|
||||
$hidden = $selectExpression->hiddenAliasResultVariable;
|
||||
|
||||
if ($expr instanceof AST\PathExpression) {
|
||||
if ($expr->type !== AST\PathExpression::TYPE_STATE_FIELD) {
|
||||
@ -1037,7 +1035,10 @@ class SqlWalker implements TreeWalker
|
||||
$columnAlias = $this->getSQLColumnAlias($columnName);
|
||||
$sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias;
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
}
|
||||
} else if ($expr instanceof AST\AggregateExpression) {
|
||||
if ( ! $selectExpression->fieldIdentificationVariable) {
|
||||
$resultAlias = $this->_scalarResultCounter++;
|
||||
@ -1050,7 +1051,10 @@ class SqlWalker implements TreeWalker
|
||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
}
|
||||
} else if ($expr instanceof AST\Subselect) {
|
||||
if ( ! $selectExpression->fieldIdentificationVariable) {
|
||||
$resultAlias = $this->_scalarResultCounter++;
|
||||
@ -1063,7 +1067,10 @@ class SqlWalker implements TreeWalker
|
||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
}
|
||||
} else if ($expr instanceof AST\Functions\FunctionNode) {
|
||||
if ( ! $selectExpression->fieldIdentificationVariable) {
|
||||
$resultAlias = $this->_scalarResultCounter++;
|
||||
@ -1076,7 +1083,10 @@ class SqlWalker implements TreeWalker
|
||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
}
|
||||
} else if (
|
||||
$expr instanceof AST\SimpleArithmeticExpression ||
|
||||
$expr instanceof AST\ArithmeticTerm ||
|
||||
@ -1101,7 +1111,10 @@ class SqlWalker implements TreeWalker
|
||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
}
|
||||
} else if (
|
||||
$expr instanceof AST\NullIfExpression ||
|
||||
$expr instanceof AST\CoalesceExpression ||
|
||||
@ -1121,7 +1134,10 @@ class SqlWalker implements TreeWalker
|
||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
}
|
||||
} else {
|
||||
// IdentificationVariable or PartialObjectExpression
|
||||
if ($expr instanceof AST\PartialObjectExpression) {
|
||||
@ -1146,11 +1162,9 @@ class SqlWalker implements TreeWalker
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($mapping['inherited'])) {
|
||||
$tableName = $this->_em->getClassMetadata($mapping['inherited'])->table['name'];
|
||||
} else {
|
||||
$tableName = $class->table['name'];
|
||||
}
|
||||
$tableName = (isset($mapping['inherited']))
|
||||
? $this->_em->getClassMetadata($mapping['inherited'])->getTableName()
|
||||
: $class->getTableName();
|
||||
|
||||
if ($beginning) $beginning = false; else $sql .= ', ';
|
||||
|
||||
@ -1170,7 +1184,7 @@ class SqlWalker implements TreeWalker
|
||||
if ($class->isInheritanceTypeSingleTable() || ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
|
||||
foreach ($class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
$sqlTableAlias = $this->getSQLTableAlias($subClass->table['name'], $dqlAlias);
|
||||
$sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias);
|
||||
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
|
||||
if (isset($mapping['inherited']) || $partialFieldSet && !in_array($fieldName, $partialFieldSet)) {
|
||||
continue;
|
||||
@ -1263,7 +1277,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
$class = $this->_em->getClassMetadata($rangeDecl->abstractSchemaName);
|
||||
$sql .= $class->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
. $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
$this->_rootAliases[] = $dqlAlias;
|
||||
|
||||
@ -1348,6 +1362,22 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
||||
$sql .= $this->walkSimpleArithmeticExpression($expr) . ' AS ' . $columnAlias;
|
||||
$this->_scalarResultAliasMap[$alias] = $columnAlias;
|
||||
} else if (
|
||||
$expr instanceof AST\NullIfExpression ||
|
||||
$expr instanceof AST\CoalesceExpression ||
|
||||
$expr instanceof AST\GeneralCaseExpression ||
|
||||
$expr instanceof AST\SimpleCaseExpression
|
||||
) {
|
||||
if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
|
||||
$alias = $this->_scalarResultCounter++;
|
||||
} else {
|
||||
$alias = $simpleSelectExpression->fieldIdentificationVariable;
|
||||
}
|
||||
|
||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
||||
$sql .= $this->walkCaseExpression($expr) . ' AS ' . $columnAlias;
|
||||
|
||||
$this->_scalarResultAliasMap[$alias] = $columnAlias;
|
||||
} else {
|
||||
// IdentificationVariable
|
||||
@ -1637,15 +1667,13 @@ class SqlWalker implements TreeWalker
|
||||
$assoc = $class->associationMappings[$fieldName];
|
||||
|
||||
if ($assoc['type'] == ClassMetadata::ONE_TO_MANY) {
|
||||
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
|
||||
$targetTableAlias = $this->getSQLTableAlias($targetClass->table['name']);
|
||||
$sourceTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
|
||||
$targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName());
|
||||
$sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
$sql .= $targetClass->getQuotedTableName($this->_platform)
|
||||
. ' ' . $targetTableAlias . ' WHERE ';
|
||||
$sql .= $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' WHERE ';
|
||||
|
||||
$owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']];
|
||||
|
||||
$first = true;
|
||||
|
||||
foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) {
|
||||
@ -1673,15 +1701,13 @@ class SqlWalker implements TreeWalker
|
||||
$joinTable = $owningAssoc['joinTable'];
|
||||
|
||||
// SQL table aliases
|
||||
$joinTableAlias = $this->getSQLTableAlias($joinTable['name']);
|
||||
$targetTableAlias = $this->getSQLTableAlias($targetClass->table['name']);
|
||||
$sourceTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
$joinTableAlias = $this->getSQLTableAlias($joinTable['name']);
|
||||
$targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName());
|
||||
$sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
// join to target table
|
||||
$sql .= $targetClass->getQuotedJoinTableName($owningAssoc, $this->_platform)
|
||||
. ' ' . $joinTableAlias . ' INNER JOIN '
|
||||
. $targetClass->getQuotedTableName($this->_platform)
|
||||
. ' ' . $targetTableAlias . ' ON ';
|
||||
$sql .= $targetClass->getQuotedJoinTableName($owningAssoc, $this->_platform) . ' ' . $joinTableAlias
|
||||
. ' INNER JOIN ' . $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' ON ';
|
||||
|
||||
// join conditions
|
||||
$joinColumns = $assoc['isOwningSide']
|
||||
@ -1693,25 +1719,19 @@ class SqlWalker implements TreeWalker
|
||||
if ($first) $first = false; else $sql .= ' AND ';
|
||||
|
||||
$sql .= $joinTableAlias . '.' . $joinColumn['name'] . ' = '
|
||||
. $targetTableAlias . '.' . $targetClass->getQuotedColumnName(
|
||||
$targetClass->fieldNames[$joinColumn['referencedColumnName']],
|
||||
$this->_platform);
|
||||
. $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->fieldNames[$joinColumn['referencedColumnName']], $this->_platform);
|
||||
}
|
||||
|
||||
$sql .= ' WHERE ';
|
||||
|
||||
$joinColumns = $assoc['isOwningSide']
|
||||
? $joinTable['joinColumns']
|
||||
: $joinTable['inverseJoinColumns'];
|
||||
|
||||
$joinColumns = $assoc['isOwningSide'] ? $joinTable['joinColumns'] : $joinTable['inverseJoinColumns'];
|
||||
$first = true;
|
||||
|
||||
foreach ($joinColumns as $joinColumn) {
|
||||
if ($first) $first = false; else $sql .= ' AND ';
|
||||
|
||||
$sql .= $joinTableAlias . '.' . $joinColumn['name'] . ' = '
|
||||
. $sourceTableAlias . '.' . $class->getQuotedColumnName(
|
||||
$class->fieldNames[$joinColumn['referencedColumnName']],
|
||||
$this->_platform);
|
||||
. $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$joinColumn['referencedColumnName']], $this->_platform);
|
||||
}
|
||||
|
||||
$sql .= ' AND ';
|
||||
@ -1808,7 +1828,7 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
|
||||
if ($this->_useSqlTableAliases) {
|
||||
$sql .= $this->getSQLTableAlias($discrClass->table['name'], $dqlAlias) . '.';
|
||||
$sql .= $this->getSQLTableAlias($discrClass->getTableName(), $dqlAlias) . '.';
|
||||
}
|
||||
|
||||
$sql .= $class->discriminatorColumn['name'] . ($instanceOfExpr->not ? ' NOT IN ' : ' IN ');
|
||||
@ -2019,6 +2039,12 @@ class SqlWalker implements TreeWalker
|
||||
public function walkArithmeticTerm($term)
|
||||
{
|
||||
if (is_string($term)) {
|
||||
if (isset($this->_queryComponents[$term])) {
|
||||
$columnName = $this->_queryComponents[$term]['token']['value'];
|
||||
|
||||
return $this->_scalarResultAliasMap[$columnName];
|
||||
}
|
||||
|
||||
return $term;
|
||||
}
|
||||
|
||||
|
@ -595,11 +595,12 @@ class QueryBuilder
|
||||
*
|
||||
* @param string $from The class name.
|
||||
* @param string $alias The alias of the class.
|
||||
* @param string $indexBy The index for the from.
|
||||
* @return QueryBuilder This QueryBuilder instance.
|
||||
*/
|
||||
public function from($from, $alias)
|
||||
public function from($from, $alias, $indexBy = null)
|
||||
{
|
||||
return $this->add('from', new Expr\From($from, $alias), true);
|
||||
return $this->add('from', new Expr\From($from, $alias, $indexBy), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -23,7 +21,8 @@ namespace Doctrine\ORM\Tools\Console\Command\ClearCache;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument,
|
||||
Symfony\Component\Console\Input\InputOption,
|
||||
Symfony\Component\Console;
|
||||
Symfony\Component\Console,
|
||||
Doctrine\Common\Cache;
|
||||
|
||||
/**
|
||||
* Command to clear the metadata cache of the various cache drivers.
|
||||
@ -31,7 +30,6 @@ use Symfony\Component\Console\Input\InputArgument,
|
||||
* @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>
|
||||
@ -47,9 +45,30 @@ class MetadataCommand extends Console\Command\Command
|
||||
$this
|
||||
->setName('orm:clear-cache:metadata')
|
||||
->setDescription('Clear all metadata cache of the various cache drivers.')
|
||||
->setDefinition(array())
|
||||
->setHelp(<<<EOT
|
||||
Clear all metadata cache of the various cache drivers.
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'flush', null, InputOption::VALUE_NONE,
|
||||
'If defined, cache entries will be flushed instead of deleted/invalidated.'
|
||||
)
|
||||
));
|
||||
|
||||
$fullName = $this->getName();
|
||||
$this->setHelp(<<<EOT
|
||||
The <info>$fullName</info> command is meant to clear the metadata cache of associated Entity Manager.
|
||||
It is possible to invalidate all cache entries at once - called delete -, or flushes the cache provider
|
||||
instance completely.
|
||||
|
||||
The execution type differ on how you execute the command.
|
||||
If you want to invalidate the entries (and not delete from cache instance), this command would do the work:
|
||||
|
||||
<info>$fullName</info>
|
||||
|
||||
Alternatively, if you want to flush the cache provider using this command:
|
||||
|
||||
<info>$fullName --flush</info>
|
||||
|
||||
Finally, be aware that if <info>--flush</info> option is passed, not all cache providers are able to flush entries,
|
||||
because of a limitation of its execution nature.
|
||||
EOT
|
||||
);
|
||||
}
|
||||
@ -65,21 +84,21 @@ EOT
|
||||
if ( ! $cacheDriver) {
|
||||
throw new \InvalidArgumentException('No Metadata cache driver is configured on given EntityManager.');
|
||||
}
|
||||
|
||||
if ($cacheDriver instanceof \Doctrine\Common\Cache\ApcCache) {
|
||||
|
||||
if ($cacheDriver instanceof Cache\ApcCache) {
|
||||
throw new \LogicException("Cannot clear APC Cache from Console, its shared in the Webserver memory and not accessible from the CLI.");
|
||||
}
|
||||
|
||||
$output->write('Clearing ALL Metadata cache entries' . PHP_EOL);
|
||||
|
||||
$cacheIds = $cacheDriver->deleteAll();
|
||||
|
||||
if ($cacheIds) {
|
||||
foreach ($cacheIds as $cacheId) {
|
||||
$output->write(' - ' . $cacheId . PHP_EOL);
|
||||
}
|
||||
} else {
|
||||
$output->write('No entries to be deleted.' . PHP_EOL);
|
||||
$result = $cacheDriver->deleteAll();
|
||||
$message = ($result) ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.';
|
||||
|
||||
if (true === $input->getOption('flush')) {
|
||||
$result = $cacheDriver->flushAll();
|
||||
$message = ($result) ? 'Successfully flushed cache entries.' : $message;
|
||||
}
|
||||
|
||||
$output->write($message . PHP_EOL);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -23,7 +21,8 @@ namespace Doctrine\ORM\Tools\Console\Command\ClearCache;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument,
|
||||
Symfony\Component\Console\Input\InputOption,
|
||||
Symfony\Component\Console;
|
||||
Symfony\Component\Console,
|
||||
Doctrine\Common\Cache;
|
||||
|
||||
/**
|
||||
* Command to clear the query cache of the various cache drivers.
|
||||
@ -31,7 +30,6 @@ use Symfony\Component\Console\Input\InputArgument,
|
||||
* @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>
|
||||
@ -47,9 +45,30 @@ class QueryCommand extends Console\Command\Command
|
||||
$this
|
||||
->setName('orm:clear-cache:query')
|
||||
->setDescription('Clear all query cache of the various cache drivers.')
|
||||
->setDefinition(array())
|
||||
->setHelp(<<<EOT
|
||||
Clear all query cache of the various cache drivers.
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'flush', null, InputOption::VALUE_NONE,
|
||||
'If defined, cache entries will be flushed instead of deleted/invalidated.'
|
||||
)
|
||||
));
|
||||
|
||||
$fullName = $this->getName();
|
||||
$this->setHelp(<<<EOT
|
||||
The <info>$fullName</info> command is meant to clear the query cache of associated Entity Manager.
|
||||
It is possible to invalidate all cache entries at once - called delete -, or flushes the cache provider
|
||||
instance completely.
|
||||
|
||||
The execution type differ on how you execute the command.
|
||||
If you want to invalidate the entries (and not delete from cache instance), this command would do the work:
|
||||
|
||||
<info>$fullName</info>
|
||||
|
||||
Alternatively, if you want to flush the cache provider using this command:
|
||||
|
||||
<info>$fullName --flush</info>
|
||||
|
||||
Finally, be aware that if <info>--flush</info> option is passed, not all cache providers are able to flush entries,
|
||||
because of a limitation of its execution nature.
|
||||
EOT
|
||||
);
|
||||
}
|
||||
@ -65,21 +84,21 @@ EOT
|
||||
if ( ! $cacheDriver) {
|
||||
throw new \InvalidArgumentException('No Query cache driver is configured on given EntityManager.');
|
||||
}
|
||||
|
||||
if ($cacheDriver instanceof \Doctrine\Common\Cache\ApcCache) {
|
||||
|
||||
if ($cacheDriver instanceof Cache\ApcCache) {
|
||||
throw new \LogicException("Cannot clear APC Cache from Console, its shared in the Webserver memory and not accessible from the CLI.");
|
||||
}
|
||||
|
||||
$output->write('Clearing ALL Query cache entries' . PHP_EOL);
|
||||
|
||||
$cacheIds = $cacheDriver->deleteAll();
|
||||
|
||||
if ($cacheIds) {
|
||||
foreach ($cacheIds as $cacheId) {
|
||||
$output->write(' - ' . $cacheId . PHP_EOL);
|
||||
}
|
||||
} else {
|
||||
$output->write('No entries to be deleted.' . PHP_EOL);
|
||||
$result = $cacheDriver->deleteAll();
|
||||
$message = ($result) ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.';
|
||||
|
||||
if (true === $input->getOption('flush')) {
|
||||
$result = $cacheDriver->flushAll();
|
||||
$message = ($result) ? 'Successfully flushed cache entries.' : $message;
|
||||
}
|
||||
|
||||
$output->write($message . PHP_EOL);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -23,7 +21,8 @@ namespace Doctrine\ORM\Tools\Console\Command\ClearCache;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument,
|
||||
Symfony\Component\Console\Input\InputOption,
|
||||
Symfony\Component\Console;
|
||||
Symfony\Component\Console,
|
||||
Doctrine\Common\Cache;
|
||||
|
||||
/**
|
||||
* Command to clear the result cache of the various cache drivers.
|
||||
@ -31,7 +30,6 @@ use Symfony\Component\Console\Input\InputArgument,
|
||||
* @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>
|
||||
@ -46,28 +44,31 @@ class ResultCommand extends Console\Command\Command
|
||||
{
|
||||
$this
|
||||
->setName('orm:clear-cache:result')
|
||||
->setDescription('Clear result cache of the various cache drivers.')
|
||||
->setDescription('Clear all result cache of the various cache drivers.')
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'id', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'ID(s) of the cache entry to delete (accepts * wildcards).', array()
|
||||
),
|
||||
new InputOption(
|
||||
'regex', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Delete cache entries that match the given regular expression(s).', array()
|
||||
),
|
||||
new InputOption(
|
||||
'prefix', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Delete cache entries that have the given prefix(es).', array()
|
||||
),
|
||||
new InputOption(
|
||||
'suffix', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Delete cache entries that have the given suffix(es).', array()
|
||||
),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
Clear result cache of the various cache drivers.
|
||||
If none of the options are defined, all cache entries will be removed.
|
||||
'flush', null, InputOption::VALUE_NONE,
|
||||
'If defined, cache entries will be flushed instead of deleted/invalidated.'
|
||||
)
|
||||
));
|
||||
|
||||
$fullName = $this->getName();
|
||||
$this->setHelp(<<<EOT
|
||||
The <info>$fullName</info> command is meant to clear the result cache of associated Entity Manager.
|
||||
It is possible to invalidate all cache entries at once - called delete -, or flushes the cache provider
|
||||
instance completely.
|
||||
|
||||
The execution type differ on how you execute the command.
|
||||
If you want to invalidate the entries (and not delete from cache instance), this command would do the work:
|
||||
|
||||
<info>$fullName</info>
|
||||
|
||||
Alternatively, if you want to flush the cache provider using this command:
|
||||
|
||||
<info>$fullName --flush</info>
|
||||
|
||||
Finally, be aware that if <info>--flush</info> option is passed, not all cache providers are able to flush entries,
|
||||
because of a limitation of its execution nature.
|
||||
EOT
|
||||
);
|
||||
}
|
||||
@ -83,86 +84,21 @@ EOT
|
||||
if ( ! $cacheDriver) {
|
||||
throw new \InvalidArgumentException('No Result cache driver is configured on given EntityManager.');
|
||||
}
|
||||
|
||||
if ($cacheDriver instanceof \Doctrine\Common\Cache\ApcCache) {
|
||||
|
||||
if ($cacheDriver instanceof Cache\ApcCache) {
|
||||
throw new \LogicException("Cannot clear APC Cache from Console, its shared in the Webserver memory and not accessible from the CLI.");
|
||||
}
|
||||
|
||||
$outputed = false;
|
||||
$output->write('Clearing ALL Result cache entries' . PHP_EOL);
|
||||
|
||||
// Removing based on --id
|
||||
if (($ids = $input->getOption('id')) !== null && $ids) {
|
||||
foreach ($ids as $id) {
|
||||
$output->write($outputed ? PHP_EOL : '');
|
||||
$output->write(sprintf('Clearing Result cache entries that match the id "<info>%s</info>"', $id) . PHP_EOL);
|
||||
|
||||
$deleted = $cacheDriver->delete($id);
|
||||
|
||||
if (is_array($deleted)) {
|
||||
$this->_printDeleted($output, $deleted);
|
||||
} else if (is_bool($deleted) && $deleted) {
|
||||
$this->_printDeleted($output, array($id));
|
||||
}
|
||||
|
||||
$outputed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Removing based on --regex
|
||||
if (($regexps = $input->getOption('regex')) !== null && $regexps) {
|
||||
foreach($regexps as $regex) {
|
||||
$output->write($outputed ? PHP_EOL : '');
|
||||
$output->write(sprintf('Clearing Result cache entries that match the regular expression "<info>%s</info>"', $regex) . PHP_EOL);
|
||||
|
||||
$this->_printDeleted($output, $cacheDriver->deleteByRegex('/' . $regex. '/'));
|
||||
|
||||
$outputed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Removing based on --prefix
|
||||
if (($prefixes = $input->getOption('prefix')) !== null & $prefixes) {
|
||||
foreach ($prefixes as $prefix) {
|
||||
$output->write($outputed ? PHP_EOL : '');
|
||||
$output->write(sprintf('Clearing Result cache entries that have the prefix "<info>%s</info>"', $prefix) . PHP_EOL);
|
||||
|
||||
$this->_printDeleted($output, $cacheDriver->deleteByPrefix($prefix));
|
||||
|
||||
$outputed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Removing based on --suffix
|
||||
if (($suffixes = $input->getOption('suffix')) !== null && $suffixes) {
|
||||
foreach ($suffixes as $suffix) {
|
||||
$output->write($outputed ? PHP_EOL : '');
|
||||
$output->write(sprintf('Clearing Result cache entries that have the suffix "<info>%s</info>"', $suffix) . PHP_EOL);
|
||||
|
||||
$this->_printDeleted($output, $cacheDriver->deleteBySuffix($suffix));
|
||||
|
||||
$outputed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Removing ALL entries
|
||||
if ( ! $ids && ! $regexps && ! $prefixes && ! $suffixes) {
|
||||
$output->write($outputed ? PHP_EOL : '');
|
||||
$output->write('Clearing ALL Result cache entries' . PHP_EOL);
|
||||
|
||||
$this->_printDeleted($output, $cacheDriver->deleteAll());
|
||||
|
||||
$outputed = true;
|
||||
$result = $cacheDriver->deleteAll();
|
||||
$message = ($result) ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.';
|
||||
|
||||
if (true === $input->getOption('flush')) {
|
||||
$result = $cacheDriver->flushAll();
|
||||
$message = ($result) ? 'Successfully flushed cache entries.' : $message;
|
||||
}
|
||||
|
||||
$output->write($message . PHP_EOL);
|
||||
}
|
||||
|
||||
private function _printDeleted(Console\Output\OutputInterface $output, array $items)
|
||||
{
|
||||
if ($items) {
|
||||
foreach ($items as $item) {
|
||||
$output->write(' - ' . $item . PHP_EOL);
|
||||
}
|
||||
} else {
|
||||
$output->write('No entries to be deleted.' . PHP_EOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -137,7 +137,7 @@ EOT
|
||||
|
||||
if ( ! file_exists($destPath)) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("Mapping destination directory '<info>%s</info>' does not exist.", $destPath)
|
||||
sprintf("Mapping destination directory '<info>%s</info>' does not exist.", $input->getArgument('dest-path'))
|
||||
);
|
||||
} else if ( ! is_writable($destPath)) {
|
||||
throw new \InvalidArgumentException(
|
||||
|
@ -123,7 +123,7 @@ EOT
|
||||
|
||||
if ( ! file_exists($destPath)) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("Entities destination directory '<info>%s</info>' does not exist.", $destPath)
|
||||
sprintf("Entities destination directory '<info>%s</info>' does not exist.", $input->getArgument('dest-path'))
|
||||
);
|
||||
} else if ( ! is_writable($destPath)) {
|
||||
throw new \InvalidArgumentException(
|
||||
|
@ -87,7 +87,7 @@ EOT
|
||||
|
||||
if ( ! file_exists($destPath)) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("Proxies destination directory '<info>%s</info>' does not exist.", $destPath)
|
||||
sprintf("Proxies destination directory '<info>%s</info>' does not exist.", $em->getConfiguration()->getProxyDir())
|
||||
);
|
||||
} else if ( ! is_writable($destPath)) {
|
||||
throw new \InvalidArgumentException(
|
||||
|
@ -79,7 +79,7 @@ EOT
|
||||
|
||||
if ( ! file_exists($destPath)) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("Entities destination directory '<info>%s</info>' does not exist.", $destPath)
|
||||
sprintf("Entities destination directory '<info>%s</info>' does not exist.", $input->getArgument('dest-path'))
|
||||
);
|
||||
} else if ( ! is_writable($destPath)) {
|
||||
throw new \InvalidArgumentException(
|
||||
|
@ -46,7 +46,7 @@ class ValidateSchemaCommand extends Console\Command\Command
|
||||
{
|
||||
$this
|
||||
->setName('orm:validate-schema')
|
||||
->setDescription('Validate that the mapping files.')
|
||||
->setDescription('Validate the mapping files.')
|
||||
->setHelp(<<<EOT
|
||||
'Validate that the mapping files are correct and in sync with the database.'
|
||||
EOT
|
||||
|
@ -101,6 +101,7 @@ class ConvertDoctrine1Schema
|
||||
{
|
||||
if (isset($model['tableName']) && $model['tableName']) {
|
||||
$e = explode('.', $model['tableName']);
|
||||
|
||||
if (count($e) > 1) {
|
||||
$metadata->table['schema'] = $e[0];
|
||||
$metadata->table['name'] = $e[1];
|
||||
|
@ -150,7 +150,7 @@ public function <methodName>()
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (version_compare(\Doctrine\Common\Version::VERSION, '3.0.0-DEV', '>=')) {
|
||||
if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) {
|
||||
$this->_annotationsPrefix = 'ORM\\';
|
||||
}
|
||||
}
|
||||
@ -399,14 +399,17 @@ public function <methodName>()
|
||||
}
|
||||
|
||||
$collections = array();
|
||||
|
||||
foreach ($metadata->associationMappings AS $mapping) {
|
||||
if ($mapping['type'] & ClassMetadataInfo::TO_MANY) {
|
||||
$collections[] = '$this->'.$mapping['fieldName'].' = new \Doctrine\Common\Collections\ArrayCollection();';
|
||||
}
|
||||
}
|
||||
|
||||
if ($collections) {
|
||||
return $this->_prefixCodeWithSpaces(str_replace("<collections>", implode("\n", $collections), self::$_constructorMethodTemplate));
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -570,7 +573,12 @@ public function <methodName>()
|
||||
private function _generateTableAnnotation($metadata)
|
||||
{
|
||||
$table = array();
|
||||
if ($metadata->table['name']) {
|
||||
|
||||
if (isset($metadata->table['schema'])) {
|
||||
$table[] = 'schema="' . $metadata->table['schema'] . '"';
|
||||
}
|
||||
|
||||
if (isset($metadata->table['name'])) {
|
||||
$table[] = 'name="' . $metadata->table['name'] . '"';
|
||||
}
|
||||
|
||||
|
@ -49,11 +49,13 @@ class YamlExporter extends AbstractExporter
|
||||
public function exportClassMetadata(ClassMetadataInfo $metadata)
|
||||
{
|
||||
$array = array();
|
||||
|
||||
if ($metadata->isMappedSuperclass) {
|
||||
$array['type'] = 'mappedSuperclass';
|
||||
} else {
|
||||
$array['type'] = 'entity';
|
||||
}
|
||||
|
||||
$array['table'] = $metadata->table['name'];
|
||||
|
||||
if (isset($metadata->table['schema'])) {
|
||||
@ -81,6 +83,10 @@ class YamlExporter extends AbstractExporter
|
||||
$array['indexes'] = $metadata->table['indexes'];
|
||||
}
|
||||
|
||||
if ($metadata->customRepositoryClassName) {
|
||||
$array['repositoryClass'] = $metadata->customRepositoryClassName;
|
||||
}
|
||||
|
||||
if (isset($metadata->table['uniqueConstraints'])) {
|
||||
$array['uniqueConstraints'] = $metadata->table['uniqueConstraints'];
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ class Setup
|
||||
require_once $directory . "/Doctrine/Common/ClassLoader.php";
|
||||
}
|
||||
|
||||
$loader = new ClassLoader("Doctrine");
|
||||
$loader = new ClassLoader("Doctrine", $directory);
|
||||
$loader->register();
|
||||
|
||||
$loader = new ClassLoader("Symfony\Component", $directory . "/Doctrine");
|
||||
@ -115,13 +115,13 @@ class Setup
|
||||
*/
|
||||
static public function createAnnotationMetadataConfiguration(array $paths, $isDevMode = false, $proxyDir = null, Cache $cache = null)
|
||||
{
|
||||
$config = self::createConfiguration($isDevMode, $cache, $proxyDir);
|
||||
$config = self::createConfiguration($isDevMode, $proxyDir, $cache);
|
||||
$config->setMetadataDriverImpl($config->newDefaultAnnotationDriver($paths));
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a configuration with an annotation metadata driver.
|
||||
* Create a configuration with a xml metadata driver.
|
||||
*
|
||||
* @param array $paths
|
||||
* @param boolean $isDevMode
|
||||
@ -131,13 +131,13 @@ class Setup
|
||||
*/
|
||||
static public function createXMLMetadataConfiguration(array $paths, $isDevMode = false, $proxyDir = null, Cache $cache = null)
|
||||
{
|
||||
$config = self::createConfiguration($isDevMode, $cache, $proxyDir);
|
||||
$config = self::createConfiguration($isDevMode, $proxyDir, $cache);
|
||||
$config->setMetadataDriverImpl(new XmlDriver($paths));
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a configuration with an annotation metadata driver.
|
||||
* Create a configuration with a yaml metadata driver.
|
||||
*
|
||||
* @param array $paths
|
||||
* @param boolean $isDevMode
|
||||
@ -147,7 +147,7 @@ class Setup
|
||||
*/
|
||||
static public function createYAMLMetadataConfiguration(array $paths, $isDevMode = false, $proxyDir = null, Cache $cache = null)
|
||||
{
|
||||
$config = self::createConfiguration($isDevMode, $cache, $proxyDir);
|
||||
$config = self::createConfiguration($isDevMode, $proxyDir, $cache);
|
||||
$config->setMetadataDriverImpl(new YamlDriver($paths));
|
||||
return $config;
|
||||
}
|
||||
@ -162,6 +162,7 @@ class Setup
|
||||
*/
|
||||
static public function createConfiguration($isDevMode = false, $proxyDir = null, Cache $cache = null)
|
||||
{
|
||||
$proxyDir = $proxyDir ?: sys_get_temp_dir();
|
||||
if ($isDevMode === false && $cache === null) {
|
||||
if (extension_loaded('apc')) {
|
||||
$cache = new \Doctrine\Common\Cache\ApcCache;
|
||||
@ -175,16 +176,16 @@ class Setup
|
||||
} else {
|
||||
$cache = new ArrayCache;
|
||||
}
|
||||
$cache->setNamespace("dc2_"); // to avoid collisions
|
||||
} else if ($cache === null) {
|
||||
$cache = new ArrayCache;
|
||||
}
|
||||
$cache->setNamespace("dc2_" . md5($proxyDir) . "_"); // to avoid collisions
|
||||
|
||||
$config = new Configuration();
|
||||
$config->setMetadataCacheImpl($cache);
|
||||
$config->setQueryCacheImpl($cache);
|
||||
$config->setResultCacheImpl($cache);
|
||||
$config->setProxyDir( $proxyDir ?: sys_get_temp_dir() );
|
||||
$config->setProxyDir( $proxyDir );
|
||||
$config->setProxyNamespace('DoctrineProxies');
|
||||
$config->setAutoGenerateProxyClasses($isDevMode);
|
||||
|
||||
|
@ -834,6 +834,8 @@ class UnitOfWork implements PropertyChangedListener
|
||||
|
||||
// See if there are any new classes in the changeset, that are not in the
|
||||
// commit order graph yet (dont have a node).
|
||||
|
||||
// TODO: Can we know the know the possible $newNodes based on something more efficient? IdentityMap?
|
||||
$newNodes = array();
|
||||
foreach ($entityChangeSet as $oid => $entity) {
|
||||
$className = get_class($entity);
|
||||
@ -845,7 +847,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
|
||||
// Calculate dependencies for new nodes
|
||||
foreach ($newNodes as $class) {
|
||||
while ($class = array_pop($newNodes)) {
|
||||
foreach ($class->associationMappings as $assoc) {
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
|
||||
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||
@ -860,6 +862,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$targetSubClass = $this->em->getClassMetadata($subClassName);
|
||||
if ( ! $calc->hasClass($subClassName)) {
|
||||
$calc->addClass($targetSubClass);
|
||||
$newNodes[] = $targetSubClass;
|
||||
}
|
||||
$calc->addDependency($targetSubClass, $class);
|
||||
}
|
||||
@ -1102,6 +1105,22 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!$class->idGenerator->isPostInsertGenerator()) {
|
||||
// if we have a pre insert generator we can't be sure that having an id
|
||||
// really means that the entity exists. We have to verify this through
|
||||
// the last resort: a db lookup
|
||||
|
||||
// Last try before db lookup: check the identity map.
|
||||
if ($this->tryGetById($id, $class->rootEntityName)) {
|
||||
return self::STATE_DETACHED;
|
||||
} else {
|
||||
// db lookup
|
||||
if ($this->getEntityPersister(get_class($entity))->exists($entity)) {
|
||||
return self::STATE_DETACHED;
|
||||
} else {
|
||||
return self::STATE_NEW;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return self::STATE_DETACHED;
|
||||
}
|
||||
@ -1368,6 +1387,10 @@ class UnitOfWork implements PropertyChangedListener
|
||||
if ($this->getEntityState($entity, self::STATE_DETACHED) == self::STATE_MANAGED) {
|
||||
$managedCopy = $entity;
|
||||
} else {
|
||||
if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
|
||||
$entity->__load();
|
||||
}
|
||||
|
||||
// Try to look the entity up in the identity map.
|
||||
$id = $class->getIdentifierValues($entity);
|
||||
|
||||
@ -1406,7 +1429,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$entityVersion = $class->reflFields[$class->versionField]->getValue($entity);
|
||||
// Throw exception if versions dont match.
|
||||
if ($managedCopyVersion != $entityVersion) {
|
||||
throw OptimisticLockException::lockFailedVersionMissmatch($entityVersion, $managedCopyVersion);
|
||||
throw OptimisticLockException::lockFailedVersionMissmatch($entity, $entityVersion, $managedCopyVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1742,7 +1765,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
*/
|
||||
public function lock($entity, $lockMode, $lockVersion = null)
|
||||
{
|
||||
if ($this->getEntityState($entity) != self::STATE_MANAGED) {
|
||||
if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) {
|
||||
throw new InvalidArgumentException("Entity is not MANAGED.");
|
||||
}
|
||||
|
||||
@ -2164,9 +2187,11 @@ class UnitOfWork implements PropertyChangedListener
|
||||
public function tryGetById($id, $rootClassName)
|
||||
{
|
||||
$idHash = implode(' ', (array) $id);
|
||||
|
||||
if (isset($this->identityMap[$rootClassName][$idHash])) {
|
||||
return $this->identityMap[$rootClassName][$idHash];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
2
lib/vendor/doctrine-common
vendored
2
lib/vendor/doctrine-common
vendored
@ -1 +1 @@
|
||||
Subproject commit 74a2c924cd08b30785877808b1fb519b4b2e60b1
|
||||
Subproject commit ef431a14852d7e8f2d0ea789487509ab266e5ce2
|
2
lib/vendor/doctrine-dbal
vendored
2
lib/vendor/doctrine-dbal
vendored
@ -1 +1 @@
|
||||
Subproject commit be3790059cc43b674a55548eb42d5d25846ea6a9
|
||||
Subproject commit f91395b6f469b5076f52fefd64574c443b076485
|
48
tests/Doctrine/Tests/Models/CMS/CmsEmail.php
Normal file
48
tests/Doctrine/Tests/Models/CMS/CmsEmail.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\Models\CMS;
|
||||
|
||||
/**
|
||||
* CmsEmail
|
||||
*
|
||||
* @Entity
|
||||
* @Table(name="cms_emails")
|
||||
*/
|
||||
class CmsEmail
|
||||
{
|
||||
/**
|
||||
* @Column(type="integer")
|
||||
* @Id @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @Column(length=250)
|
||||
*/
|
||||
public $email;
|
||||
|
||||
/**
|
||||
* @OneToOne(targetEntity="CmsUser", mappedBy="email")
|
||||
*/
|
||||
public $user;
|
||||
|
||||
public function getId() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getEmail() {
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail($email) {
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
public function getUser() {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function setUser(CmsUser $user) {
|
||||
$this->user = $user;
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@ class CmsUser
|
||||
*/
|
||||
public $name;
|
||||
/**
|
||||
* @OneToMany(targetEntity="CmsPhonenumber", mappedBy="user", cascade={"persist", "remove", "merge"}, orphanRemoval=true)
|
||||
* @OneToMany(targetEntity="CmsPhonenumber", mappedBy="user", cascade={"persist", "merge"}, orphanRemoval=true)
|
||||
*/
|
||||
public $phonenumbers;
|
||||
/**
|
||||
@ -42,6 +42,11 @@ class CmsUser
|
||||
* @OneToOne(targetEntity="CmsAddress", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
|
||||
*/
|
||||
public $address;
|
||||
/**
|
||||
* @OneToOne(targetEntity="CmsEmail", inversedBy="user", cascade={"persist"}, orphanRemoval=true)
|
||||
* @JoinColumn(referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
public $email;
|
||||
/**
|
||||
* @ManyToMany(targetEntity="CmsGroup", inversedBy="users", cascade={"persist", "merge"})
|
||||
* @JoinTable(name="cms_users_groups",
|
||||
@ -119,4 +124,16 @@ class CmsUser
|
||||
$address->setUser($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function getEmail() { return $this->email; }
|
||||
|
||||
public function setEmail(CmsEmail $email = null) {
|
||||
if ($this->email !== $email) {
|
||||
$this->email = $email;
|
||||
|
||||
if ($email) {
|
||||
$email->setUser($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ class CompanyCar
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @Column(type="string", length="50")
|
||||
* @Column(type="string", length=50)
|
||||
*/
|
||||
private $brand;
|
||||
|
||||
|
@ -17,6 +17,11 @@ class CompanyEmployee extends CompanyPerson
|
||||
* @Column(type="string", length=255)
|
||||
*/
|
||||
private $department;
|
||||
|
||||
/**
|
||||
* @Column(type="datetime", nullable=true)
|
||||
*/
|
||||
private $startDate;
|
||||
|
||||
public function getSalary() {
|
||||
return $this->salary;
|
||||
@ -33,4 +38,12 @@ class CompanyEmployee extends CompanyPerson
|
||||
public function setDepartment($dep) {
|
||||
$this->department = $dep;
|
||||
}
|
||||
|
||||
public function getStartDate() {
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
public function setStartDate($date) {
|
||||
$this->startDate = $date;
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ namespace Doctrine\Tests\Models\Company;
|
||||
class CompanyManager extends CompanyEmployee
|
||||
{
|
||||
/**
|
||||
* @Column(type="string", length="250")
|
||||
* @Column(type="string", length=250)
|
||||
*/
|
||||
private $title;
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
<?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\Models\DDC753;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class DDC753CustomRepository extends EntityRepository
|
||||
{
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCustomRepository()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<?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\Models\DDC753;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class DDC753DefaultRepository extends EntityRepository
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDefaultRepository()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?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\Models\DDC753;
|
||||
|
||||
/**
|
||||
* @Entity(repositoryClass = "Doctrine\Tests\Models\DDC753\DDC753CustomRepository")
|
||||
*/
|
||||
class DDC753EntityWithCustomRepository
|
||||
{
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/** @column(type="string") */
|
||||
protected $name;
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?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\Models\DDC753;
|
||||
|
||||
/**
|
||||
* @Entity()
|
||||
*/
|
||||
class DDC753EntityWithDefaultCustomRepository
|
||||
{
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/** @column(type="string") */
|
||||
protected $name;
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?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\Models\DDC753;
|
||||
|
||||
/**
|
||||
* @Entity(repositoryClass = "\stdClass")
|
||||
*/
|
||||
class DDC753EntityWithInvalidRepository
|
||||
{
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/** @column(type="string") */
|
||||
protected $name;
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?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\Models\DDC753;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class DDC753InvalidRepository
|
||||
{
|
||||
|
||||
}
|
40
tests/Doctrine/Tests/Models/DDC869/DDC869ChequePayment.php
Normal file
40
tests/Doctrine/Tests/Models/DDC869/DDC869ChequePayment.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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\Models\DDC869;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC869ChequePayment extends DDC869Payment
|
||||
{
|
||||
|
||||
/** @column(type="string") */
|
||||
protected $serialNumber;
|
||||
|
||||
public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata)
|
||||
{
|
||||
$metadata->mapField(array(
|
||||
'fieldName' => 'serialNumber',
|
||||
'type' => 'string',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?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\Models\DDC869;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC869CreditCardPayment extends DDC869Payment
|
||||
{
|
||||
|
||||
/** @column(type="string") */
|
||||
protected $creditCardNumber;
|
||||
|
||||
public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata)
|
||||
{
|
||||
$metadata->mapField(array(
|
||||
'fieldName' => 'creditCardNumber',
|
||||
'type' => 'string',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
57
tests/Doctrine/Tests/Models/DDC869/DDC869Payment.php
Normal file
57
tests/Doctrine/Tests/Models/DDC869/DDC869Payment.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?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\Models\DDC869;
|
||||
|
||||
/**
|
||||
* @MappedSuperclass(repositoryClass = "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository")
|
||||
*/
|
||||
class DDC869Payment
|
||||
{
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/** @column(type="float") */
|
||||
protected $value;
|
||||
|
||||
|
||||
public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata)
|
||||
{
|
||||
$metadata->mapField(array(
|
||||
'id' => true,
|
||||
'fieldName' => 'id',
|
||||
'type' => 'integer',
|
||||
'columnName' => 'id',
|
||||
));
|
||||
$metadata->mapField(array(
|
||||
'fieldName' => 'value',
|
||||
'type' => 'float',
|
||||
));
|
||||
$metadata->isMappedSuperclass = true;
|
||||
$metadata->setCustomRepositoryClass("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository");
|
||||
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadataInfo::GENERATOR_TYPE_AUTO);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?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\Models\DDC869;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class DDC869PaymentRepository extends EntityRepository
|
||||
{
|
||||
|
||||
/**
|
||||
* Very complex method
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isTrue()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ class ECommerceProduct
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @Column(type="string", length=50, nullable="true")
|
||||
* @Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
private $name;
|
||||
|
||||
|
91
tests/Doctrine/Tests/ORM/Event/EntityEventDelegateeTest.php
Normal file
91
tests/Doctrine/Tests/ORM/Event/EntityEventDelegateeTest.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Event;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* @group DDC-1415
|
||||
*/
|
||||
class EntityEventDelegatorTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\Event\EntityEventDelegator
|
||||
*/
|
||||
private $delegator;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->delegator = new \Doctrine\ORM\Event\EntityEventDelegator();
|
||||
}
|
||||
|
||||
public function testGetSubscribedEventsWhenEmpty()
|
||||
{
|
||||
$this->assertEquals(array(), $this->delegator->getSubscribedEvents());
|
||||
}
|
||||
|
||||
public function testAddListener()
|
||||
{
|
||||
$this->delegator->addEventListener('postLoad', 'stdClass', new DelegateeEventListener());
|
||||
$this->assertEquals(array('postLoad'), $this->delegator->getSubscribedEvents());
|
||||
}
|
||||
|
||||
public function testAddSubscriber()
|
||||
{
|
||||
$this->delegator->addEventSubscriber(new DelegateeEventListener(), 'stdClass');
|
||||
$this->assertEquals(array('postLoad'), $this->delegator->getSubscribedEvents());
|
||||
}
|
||||
|
||||
public function testAddListenerAfterFrozenThrowsException()
|
||||
{
|
||||
$this->delegator->getSubscribedEvents(); // freezes
|
||||
|
||||
$this->setExpectedException("LogicException", "Cannot add event listeners aft");
|
||||
$this->delegator->addEventListener('postLoad', 'stdClass', new DelegateeEventListener());
|
||||
}
|
||||
|
||||
public function testDelegateEvent()
|
||||
{
|
||||
$delegatee = new DelegateeEventListener();
|
||||
$this->delegator->addEventListener('postLoad', 'stdClass', $delegatee);
|
||||
|
||||
$event = new \Doctrine\ORM\Event\LifecycleEventArgs(new \stdClass(), $this->_getTestEntityManager());
|
||||
$this->delegator->postLoad($event);
|
||||
$this->delegator->postLoad($event);
|
||||
|
||||
$this->assertEquals(2, $delegatee->postLoad);
|
||||
}
|
||||
|
||||
public function testDelegatePickEntity()
|
||||
{
|
||||
$delegatee = new DelegateeEventListener();
|
||||
$this->delegator->addEventListener('postLoad', 'stdClass', $delegatee);
|
||||
|
||||
$event1 = new \Doctrine\ORM\Event\LifecycleEventArgs(new \stdClass(), $this->_getTestEntityManager());
|
||||
$event2 = new \Doctrine\ORM\Event\LifecycleEventArgs(new \Doctrine\Tests\Models\CMS\CmsUser(), $this->_getTestEntityManager());
|
||||
$this->delegator->postLoad($event1);
|
||||
$this->delegator->postLoad($event2);
|
||||
|
||||
$this->assertEquals(1, $delegatee->postLoad);
|
||||
}
|
||||
}
|
||||
|
||||
class DelegateeEventListener implements \Doctrine\Common\EventSubscriber
|
||||
{
|
||||
public $postLoad = 0;
|
||||
|
||||
public function postLoad($args)
|
||||
{
|
||||
$this->postLoad++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of events this subscriber wants to listen to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getSubscribedEvents()
|
||||
{
|
||||
return array('postLoad');
|
||||
}
|
||||
}
|
@ -150,15 +150,15 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$user->username = 'gblanco';
|
||||
$user->status = 'developer';
|
||||
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user));
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user), "State should be UnitOfWork::STATE_NEW");
|
||||
|
||||
$this->_em->persist($user);
|
||||
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($user));
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($user), "State should be UnitOfWork::STATE_MANAGED");
|
||||
|
||||
$this->_em->remove($user);
|
||||
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user));
|
||||
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user), "State should be UnitOfWork::STATE_NEW");
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
@ -166,10 +166,10 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->_em->remove($user);
|
||||
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_REMOVED, $this->_em->getUnitOfWork()->getEntityState($user));
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_REMOVED, $this->_em->getUnitOfWork()->getEntityState($user), "State should be UnitOfWork::STATE_REMOVED");
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user));
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user), "State should be UnitOfWork::STATE_NEW");
|
||||
|
||||
$this->assertNull($this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $id));
|
||||
}
|
||||
|
@ -291,8 +291,21 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->assertTrue(count($this->_em->createQuery(
|
||||
'SELECT count(p.id) FROM Doctrine\Tests\Models\Company\CompanyEmployee p WHERE p.salary = 1')
|
||||
->getResult()) > 0);
|
||||
->getResult()) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1341
|
||||
*/
|
||||
public function testBulkUpdateNonScalarParameterDDC1341()
|
||||
{
|
||||
$dql = 'UPDATE Doctrine\Tests\Models\Company\CompanyEmployee AS p SET p.startDate = ?0 WHERE p.department = ?1';
|
||||
$query = $this->_em->createQuery($dql)
|
||||
->setParameter(0, new \DateTime())
|
||||
->setParameter(1, 'IT');
|
||||
|
||||
$result = $query->execute();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,7 +59,7 @@ class CustomTreeWalkersTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'select u from Doctrine\Tests\Models\CMS\CmsUser u',
|
||||
"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"
|
||||
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ WHERE c0_.id = 1"
|
||||
);
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ class CustomTreeWalkersTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'select u from Doctrine\Tests\Models\CMS\CmsUser u where u.name = :name or u.name = :otherName',
|
||||
"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"
|
||||
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ WHERE (c0_.name = ? OR c0_.name = ?) AND c0_.id = 1"
|
||||
);
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ class CustomTreeWalkersTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'select u from Doctrine\Tests\Models\CMS\CmsUser u where u.name = :name',
|
||||
"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"
|
||||
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ WHERE c0_.name = ? AND c0_.id = 1"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Functional;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
||||
use Doctrine\Tests\Models\CMS\CmsAddress;
|
||||
use Doctrine\Tests\Models\CMS\CmsArticle;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
@ -192,5 +193,26 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertFalse($this->_em->contains($user));
|
||||
$this->assertFalse($this->_em->getUnitOfWork()->isInIdentityMap($user));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1340
|
||||
*/
|
||||
public function testMergeArticleWrongVersion()
|
||||
{
|
||||
$article = new CmsArticle();
|
||||
$article->topic = "test";
|
||||
$article->text = "test";
|
||||
|
||||
$this->_em->persist($article);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->detach($article);
|
||||
|
||||
$sql = "UPDATE cms_articles SET version = version+1 WHERE id = " . $article->id;
|
||||
$this->_em->getConnection()->executeUpdate($sql);
|
||||
|
||||
$this->setExpectedException('Doctrine\ORM\OptimisticLockException', 'The optimistic lock failed, version 1 was expected, but is actually 2');
|
||||
$this->_em->merge($article);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,5 +433,43 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertSame($usersAsc[0], $usersDesc[1]);
|
||||
$this->assertSame($usersAsc[1], $usersDesc[0]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-753
|
||||
*/
|
||||
public function testDefaultRepositoryClassName()
|
||||
{
|
||||
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository");
|
||||
$this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753DefaultRepository");
|
||||
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\Tests\Models\DDC753\DDC753DefaultRepository");
|
||||
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithDefaultCustomRepository');
|
||||
$this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753DefaultRepository", $repos);
|
||||
$this->assertTrue($repos->isDefaultRepository());
|
||||
|
||||
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithCustomRepository');
|
||||
$this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753CustomRepository", $repos);
|
||||
$this->assertTrue($repos->isCustomRepository());
|
||||
|
||||
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\Tests\Models\DDC753\DDC753DefaultRepository");
|
||||
$this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\ORM\EntityRepository");
|
||||
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-753
|
||||
* @expectedException Doctrine\ORM\ORMException
|
||||
* @expectedExceptionMessage Invalid repository class 'Doctrine\Tests\Models\DDC753\DDC753InvalidRepository'. it must be a Doctrine\ORM\EntityRepository.
|
||||
*/
|
||||
public function testSetDefaultRepositoryInvalidClassError()
|
||||
{
|
||||
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository");
|
||||
$this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753InvalidRepository");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Tests\Models\CMS\CmsUser,
|
||||
Doctrine\Tests\Models\CMS\CmsAddress,
|
||||
Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
/**
|
||||
* Tests a bidirectional one-to-many association mapping with orphan removal.
|
||||
*/
|
||||
class OneToManyOrphanRemovalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testOrphanRemoval()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->status = 'dev';
|
||||
$user->username = 'romanb';
|
||||
$user->name = 'Roman B.';
|
||||
|
||||
$phone = new CmsPhonenumber;
|
||||
$phone->phonenumber = '123456';
|
||||
|
||||
$user->addPhonenumber($phone);
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$userId = $user->getId();
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$userProxy = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $userId);
|
||||
|
||||
$this->_em->remove($userProxy);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(0, count($result), 'CmsUser should be removed by EntityManager');
|
||||
|
||||
$query = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p');
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(0, count($result), 'CmsPhonenumber should be removed by orphanRemoval');
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Tests\Models\CMS\CmsUser,
|
||||
Doctrine\Tests\Models\CMS\CmsEmail,
|
||||
Doctrine\Tests\Models\CMS\CmsAddress,
|
||||
Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
/**
|
||||
* Tests a bidirectional one-to-one association mapping with orphan removal.
|
||||
*/
|
||||
class OneToOneOrphanRemovalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testOrphanRemoval()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->status = 'dev';
|
||||
$user->username = 'romanb';
|
||||
$user->name = 'Roman B.';
|
||||
|
||||
$address = new CmsAddress;
|
||||
$address->country = 'de';
|
||||
$address->zip = 1234;
|
||||
$address->city = 'Berlin';
|
||||
|
||||
$user->setAddress($address);
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$userId = $user->getId();
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$userProxy = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $userId);
|
||||
|
||||
$this->_em->remove($userProxy);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(0, count($result), 'CmsUser should be removed by EntityManager');
|
||||
|
||||
$query = $this->_em->createQuery('SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a');
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(0, count($result), 'CmsAddress should be removed by orphanRemoval');
|
||||
}
|
||||
|
||||
public function testOrphanRemovalWhenUnlink()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->status = 'dev';
|
||||
$user->username = 'beberlei';
|
||||
$user->name = 'Bejamin Eberlei';
|
||||
|
||||
$email = new CmsEmail;
|
||||
$email->email = 'beberlei@domain.com';
|
||||
|
||||
$user->setEmail($email);
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$userId = $user->getId();
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId);
|
||||
|
||||
$user->setEmail(null);
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery('SELECT e FROM Doctrine\Tests\Models\CMS\CmsEmail e');
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(0, count($result), 'CmsEmail should be removed by orphanRemoval');
|
||||
}
|
||||
}
|
@ -14,10 +14,27 @@ require_once __DIR__ . '/../../TestInit.php';
|
||||
*/
|
||||
class QueryCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
/**
|
||||
* @var \ReflectionProperty
|
||||
*/
|
||||
private $cacheDataReflection;
|
||||
|
||||
protected function setUp() {
|
||||
$this->cacheDataReflection = new \ReflectionProperty("Doctrine\Common\Cache\ArrayCache", "data");
|
||||
$this->cacheDataReflection->setAccessible(true);
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArrayCache $cache
|
||||
* @return integer
|
||||
*/
|
||||
private function getCacheSize(ArrayCache $cache)
|
||||
{
|
||||
return sizeof($this->cacheDataReflection->getValue($cache));
|
||||
}
|
||||
|
||||
|
||||
public function testQueryCache_DependsOnHints()
|
||||
{
|
||||
@ -27,12 +44,12 @@ class QueryCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$query->setQueryCacheDriver($cache);
|
||||
|
||||
$query->getResult();
|
||||
$this->assertEquals(1, count($cache->getIds()));
|
||||
$this->assertEquals(1, $this->getCacheSize($cache));
|
||||
|
||||
$query->setHint('foo', 'bar');
|
||||
|
||||
$query->getResult();
|
||||
$this->assertEquals(2, count($cache->getIds()));
|
||||
$this->assertEquals(2, $this->getCacheSize($cache));
|
||||
|
||||
return $query;
|
||||
}
|
||||
@ -44,13 +61,13 @@ class QueryCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testQueryCache_DependsOnFirstResult($query)
|
||||
{
|
||||
$cache = $query->getQueryCacheDriver();
|
||||
$cacheCount = count($cache->getIds());
|
||||
$cacheCount = $this->getCacheSize($cache);
|
||||
|
||||
$query->setFirstResult(10);
|
||||
$query->setMaxResults(9999);
|
||||
|
||||
$query->getResult();
|
||||
$this->assertEquals($cacheCount + 1, count($cache->getIds()));
|
||||
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,12 +77,12 @@ class QueryCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testQueryCache_DependsOnMaxResults($query)
|
||||
{
|
||||
$cache = $query->getQueryCacheDriver();
|
||||
$cacheCount = count($cache->getIds());
|
||||
$cacheCount = $this->getCacheSize($cache);
|
||||
|
||||
$query->setMaxResults(10);
|
||||
|
||||
$query->getResult();
|
||||
$this->assertEquals($cacheCount + 1, count($cache->getIds()));
|
||||
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,10 +92,10 @@ class QueryCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testQueryCache_DependsOnHydrationMode($query)
|
||||
{
|
||||
$cache = $query->getQueryCacheDriver();
|
||||
$cacheCount = count($cache->getIds());
|
||||
$cacheCount = $this->getCacheSize($cache);
|
||||
|
||||
$query->getArrayResult();
|
||||
$this->assertEquals($cacheCount + 1, count($cache->getIds()));
|
||||
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
|
||||
}
|
||||
|
||||
public function testQueryCache_NoHitSaveParserResult()
|
||||
@ -87,13 +104,13 @@ class QueryCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
|
||||
|
||||
$cache = $this->getMock('Doctrine\Common\Cache\AbstractCache', array('_doFetch', '_doContains', '_doSave', '_doDelete', 'getIds'));
|
||||
$cache = $this->getMock('Doctrine\Common\Cache\ArrayCache', array('doFetch', 'doSave'));
|
||||
$cache->expects($this->at(0))
|
||||
->method('_doFetch')
|
||||
->method('doFetch')
|
||||
->with($this->isType('string'))
|
||||
->will($this->returnValue(false));
|
||||
$cache->expects($this->at(1))
|
||||
->method('_doSave')
|
||||
->method('doSave')
|
||||
->with($this->isType('string'), $this->isInstanceOf('Doctrine\ORM\Query\ParserResult'), $this->equalTo(null));
|
||||
|
||||
$query->setQueryCacheDriver($cache);
|
||||
@ -117,13 +134,14 @@ class QueryCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
->method('getSqlExecutor')
|
||||
->will($this->returnValue($sqlExecMock));
|
||||
|
||||
$cache = $this->getMock('Doctrine\Common\Cache\AbstractCache', array('_doFetch', '_doContains', '_doSave', '_doDelete', 'getIds'));
|
||||
$cache = $this->getMock('Doctrine\Common\Cache\CacheProvider',
|
||||
array('doFetch', 'doContains', 'doSave', 'doDelete', 'doFlush'));
|
||||
$cache->expects($this->once())
|
||||
->method('_doFetch')
|
||||
->method('doFetch')
|
||||
->with($this->isType('string'))
|
||||
->will($this->returnValue($parserResultMock));
|
||||
$cache->expects($this->never())
|
||||
->method('_doSave');
|
||||
->method('doSave');
|
||||
|
||||
$query->setQueryCacheDriver($cache);
|
||||
|
||||
|
@ -501,4 +501,66 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->assertEquals(0, count($users));
|
||||
}
|
||||
|
||||
public function testQueryWithArrayOfEntitiesAsParameter()
|
||||
{
|
||||
$userA = new CmsUser;
|
||||
$userA->name = 'Benjamin';
|
||||
$userA->username = 'beberlei';
|
||||
$userA->status = 'developer';
|
||||
$this->_em->persist($userA);
|
||||
|
||||
$userB = new CmsUser;
|
||||
$userB->name = 'Roman';
|
||||
$userB->username = 'romanb';
|
||||
$userB->status = 'developer';
|
||||
$this->_em->persist($userB);
|
||||
|
||||
$userC = new CmsUser;
|
||||
$userC->name = 'Jonathan';
|
||||
$userC->username = 'jwage';
|
||||
$userC->status = 'developer';
|
||||
$this->_em->persist($userC);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u IN (?0) OR u.username = ?1");
|
||||
$query->setParameter(0, array($userA, $userC));
|
||||
$query->setParameter(1, 'beberlei');
|
||||
|
||||
$users = $query->execute();
|
||||
|
||||
$this->assertEquals(2, count($users));
|
||||
}
|
||||
|
||||
public function testQueryWithHiddenAsSelectExpression()
|
||||
{
|
||||
$userA = new CmsUser;
|
||||
$userA->name = 'Benjamin';
|
||||
$userA->username = 'beberlei';
|
||||
$userA->status = 'developer';
|
||||
$this->_em->persist($userA);
|
||||
|
||||
$userB = new CmsUser;
|
||||
$userB->name = 'Roman';
|
||||
$userB->username = 'romanb';
|
||||
$userB->status = 'developer';
|
||||
$this->_em->persist($userB);
|
||||
|
||||
$userC = new CmsUser;
|
||||
$userC->name = 'Jonathan';
|
||||
$userC->username = 'jwage';
|
||||
$userC->status = 'developer';
|
||||
$this->_em->persist($userC);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery("SELECT u, (SELECT COUNT(u2.id) FROM Doctrine\Tests\Models\CMS\CmsUser u2) AS HIDDEN total FROM Doctrine\Tests\Models\CMS\CmsUser u");
|
||||
$users = $query->execute();
|
||||
|
||||
$this->assertEquals(3, count($users));
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]);
|
||||
}
|
||||
}
|
@ -15,10 +15,26 @@ require_once __DIR__ . '/../../TestInit.php';
|
||||
*/
|
||||
class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
/**
|
||||
* @var \ReflectionProperty
|
||||
*/
|
||||
private $cacheDataReflection;
|
||||
|
||||
protected function setUp() {
|
||||
$this->cacheDataReflection = new \ReflectionProperty("Doctrine\Common\Cache\ArrayCache", "data");
|
||||
$this->cacheDataReflection->setAccessible(true);
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArrayCache $cache
|
||||
* @return integer
|
||||
*/
|
||||
private function getCacheSize(ArrayCache $cache)
|
||||
{
|
||||
return sizeof($this->cacheDataReflection->getValue($cache));
|
||||
}
|
||||
|
||||
public function testResultCache()
|
||||
{
|
||||
@ -125,9 +141,9 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$cache = new ArrayCache();
|
||||
$query->setResultCacheDriver($cache)->useResultCache(true);
|
||||
|
||||
$this->assertEquals(0, count($cache->getIds()));
|
||||
$this->assertEquals(0, $this->getCacheSize($cache));
|
||||
$query->getResult();
|
||||
$this->assertEquals(1, count($cache->getIds()));
|
||||
$this->assertEquals(1, $this->getCacheSize($cache));
|
||||
|
||||
return $query;
|
||||
}
|
||||
@ -139,12 +155,12 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testResultCacheDependsOnQueryHints($query)
|
||||
{
|
||||
$cache = $query->getResultCacheDriver();
|
||||
$cacheCount = count($cache->getIds());
|
||||
$cacheCount = $this->getCacheSize($cache);
|
||||
|
||||
$query->setHint('foo', 'bar');
|
||||
$query->getResult();
|
||||
|
||||
$this->assertEquals($cacheCount + 1, count($cache->getIds()));
|
||||
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,12 +170,12 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testResultCacheDependsOnParameters($query)
|
||||
{
|
||||
$cache = $query->getResultCacheDriver();
|
||||
$cacheCount = count($cache->getIds());
|
||||
$cacheCount = $this->getCacheSize($cache);
|
||||
|
||||
$query->setParameter(1, 50);
|
||||
$query->getResult();
|
||||
|
||||
$this->assertEquals($cacheCount + 1, count($cache->getIds()));
|
||||
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,12 +185,12 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testResultCacheDependsOnHydrationMode($query)
|
||||
{
|
||||
$cache = $query->getResultCacheDriver();
|
||||
$cacheCount = count($cache->getIds());
|
||||
$cacheCount = $this->getCacheSize($cache);
|
||||
|
||||
$this->assertNotEquals(\Doctrine\ORM\Query::HYDRATE_ARRAY, $query->getHydrationMode());
|
||||
$query->getArrayResult();
|
||||
|
||||
$this->assertEquals($cacheCount + 1, count($cache->getIds()));
|
||||
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -253,24 +253,27 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
public function testQueryCache_DependsOnFilters()
|
||||
{
|
||||
$cacheDataReflection = new \ReflectionProperty("Doctrine\Common\Cache\ArrayCache", "data");
|
||||
$cacheDataReflection->setAccessible(true);
|
||||
|
||||
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
|
||||
|
||||
$cache = new ArrayCache();
|
||||
$query->setQueryCacheDriver($cache);
|
||||
|
||||
$query->getResult();
|
||||
$this->assertEquals(1, count($cache->getIds()));
|
||||
$this->assertEquals(1, sizeof($cacheDataReflection->getValue($cache)));
|
||||
|
||||
$conf = $this->_em->getConfiguration();
|
||||
$conf->addFilter("locale", "\Doctrine\Tests\ORM\Functional\MyLocaleFilter");
|
||||
$this->_em->getFilters()->enable("locale");
|
||||
|
||||
$query->getResult();
|
||||
$this->assertEquals(2, count($cache->getIds()));
|
||||
$this->assertEquals(2, sizeof($cacheDataReflection->getValue($cache)));
|
||||
|
||||
// Another time doesn't add another cache entry
|
||||
$query->getResult();
|
||||
$this->assertEquals(2, count($cache->getIds()));
|
||||
$this->assertEquals(2, sizeof($cacheDataReflection->getValue($cache)));
|
||||
}
|
||||
|
||||
public function testQueryGeneration_DependsOnFilters()
|
||||
|
99
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1113Test.php
Normal file
99
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1113Test.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-1113
|
||||
* @group DDC-1306
|
||||
*/
|
||||
class DDC1113Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1113Engine'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1113Vehicle'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1113Car'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1113Bus'),
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$car = new DDC1113Car();
|
||||
$car->engine = new DDC1113Engine();
|
||||
|
||||
$bus = new DDC1113Bus();
|
||||
$bus->engine = new DDC1113Engine();
|
||||
|
||||
$this->_em->persist($car);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->persist($bus);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->remove($bus);
|
||||
$this->_em->remove($car);
|
||||
$this->_em->flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorMap({"car" = "DDC1113Car", "bus" = "DDC1113Bus"})
|
||||
*/
|
||||
class DDC1113Vehicle
|
||||
{
|
||||
|
||||
/** @Id @GeneratedValue @Column(type="integer") */
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC1113Vehicle")
|
||||
*/
|
||||
public $parent;
|
||||
|
||||
/** @OneToOne(targetEntity="DDC1113Engine", cascade={"persist", "remove"}) */
|
||||
public $engine;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1113Car extends DDC1113Vehicle
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1113Bus extends DDC1113Vehicle
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1113Engine
|
||||
{
|
||||
|
||||
/** @Id @GeneratedValue @Column(type="integer") */
|
||||
public $id;
|
||||
|
||||
}
|
||||
|
54
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1306Test.php
Normal file
54
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1306Test.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\Models\CMS\CmsGroup;
|
||||
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-1306
|
||||
*/
|
||||
class DDC1306Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$phone = new CmsPhonenumber();
|
||||
$phone->phonenumber = "1234";
|
||||
|
||||
// puts user and phone into commit order calculator
|
||||
$this->_em->persist($phone);
|
||||
$this->_em->flush();
|
||||
|
||||
$address = new \Doctrine\Tests\Models\CMS\CmsAddress();
|
||||
$address->city = "bonn";
|
||||
$address->country = "Germany";
|
||||
$address->street = "somestreet!";
|
||||
$address->zip = 12345;
|
||||
|
||||
$this->_em->persist($address);
|
||||
|
||||
$user = new CmsUser();
|
||||
$user->username = "beberlei";
|
||||
$user->name = "benjamin";
|
||||
$user->status = "active";
|
||||
$user->setAddress($address);
|
||||
|
||||
// puts user and address into commit order calculator, but does not calculate user dependencies new
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->remove($user->getAddress());
|
||||
$this->_em->remove($user);
|
||||
$this->_em->flush();
|
||||
}
|
||||
}
|
214
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1335Test.php
Normal file
214
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1335Test.php
Normal file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use DateTime;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-1135
|
||||
*/
|
||||
class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1135User'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1135Phone'),
|
||||
));
|
||||
$this->loadFixture();
|
||||
} catch(\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testDql()
|
||||
{
|
||||
$dql = 'SELECT u FROM ' . __NAMESPACE__ . '\DDC1135User u INDEX BY u.id';
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(sizeof($result), 3);
|
||||
$this->assertArrayHasKey(1, $result);
|
||||
$this->assertArrayHasKey(2, $result);
|
||||
$this->assertArrayHasKey(3, $result);
|
||||
|
||||
$dql = 'SELECT u, p FROM '.__NAMESPACE__ . '\DDC1135User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id';
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(sizeof($result), 3);
|
||||
$this->assertArrayHasKey('foo@foo.com', $result);
|
||||
$this->assertArrayHasKey('bar@bar.com', $result);
|
||||
$this->assertArrayHasKey('foobar@foobar.com', $result);
|
||||
|
||||
$this->assertEquals(sizeof($result['foo@foo.com']->phones), 3);
|
||||
$this->assertEquals(sizeof($result['bar@bar.com']->phones), 3);
|
||||
$this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3);
|
||||
|
||||
$this->assertArrayHasKey(1, $result['foo@foo.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(2, $result['foo@foo.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(3, $result['foo@foo.com']->phones->toArray());
|
||||
|
||||
$this->assertArrayHasKey(4, $result['bar@bar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(5, $result['bar@bar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(6, $result['bar@bar.com']->phones->toArray());
|
||||
|
||||
$this->assertArrayHasKey(7, $result['foobar@foobar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(8, $result['foobar@foobar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(9, $result['foobar@foobar.com']->phones->toArray());
|
||||
}
|
||||
|
||||
public function testTicket()
|
||||
{
|
||||
$builder = $this->_em->createQueryBuilder();
|
||||
$builder->select('u')->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.id');
|
||||
|
||||
$dql = $builder->getQuery()->getDQL();
|
||||
$result = $builder->getQuery()->getResult();
|
||||
|
||||
$this->assertEquals(sizeof($result), 3);
|
||||
$this->assertArrayHasKey(1, $result);
|
||||
$this->assertArrayHasKey(2, $result);
|
||||
$this->assertArrayHasKey(3, $result);
|
||||
$this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1135User u INDEX BY u.id', $dql);
|
||||
}
|
||||
|
||||
public function testIndexByUnique()
|
||||
{
|
||||
$builder = $this->_em->createQueryBuilder();
|
||||
$builder->select('u')->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.email');
|
||||
|
||||
$dql = $builder->getQuery()->getDQL();
|
||||
$result = $builder->getQuery()->getResult();
|
||||
|
||||
$this->assertEquals(sizeof($result), 3);
|
||||
$this->assertArrayHasKey('foo@foo.com', $result);
|
||||
$this->assertArrayHasKey('bar@bar.com', $result);
|
||||
$this->assertArrayHasKey('foobar@foobar.com', $result);
|
||||
$this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1135User u INDEX BY u.email', $dql);
|
||||
}
|
||||
|
||||
public function testIndexWithJoin()
|
||||
{
|
||||
$builder = $this->_em->createQueryBuilder();
|
||||
$builder->select('u','p')
|
||||
->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.email')
|
||||
->join('u.phones', 'p', null, null, 'p.id');
|
||||
|
||||
$dql = $builder->getQuery()->getDQL();
|
||||
$result = $builder->getQuery()->getResult();
|
||||
|
||||
$this->assertEquals(sizeof($result), 3);
|
||||
$this->assertArrayHasKey('foo@foo.com', $result);
|
||||
$this->assertArrayHasKey('bar@bar.com', $result);
|
||||
$this->assertArrayHasKey('foobar@foobar.com', $result);
|
||||
|
||||
$this->assertEquals(sizeof($result['foo@foo.com']->phones), 3);
|
||||
$this->assertEquals(sizeof($result['bar@bar.com']->phones), 3);
|
||||
$this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3);
|
||||
|
||||
$this->assertArrayHasKey(1, $result['foo@foo.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(2, $result['foo@foo.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(3, $result['foo@foo.com']->phones->toArray());
|
||||
|
||||
$this->assertArrayHasKey(4, $result['bar@bar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(5, $result['bar@bar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(6, $result['bar@bar.com']->phones->toArray());
|
||||
|
||||
$this->assertArrayHasKey(7, $result['foobar@foobar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(8, $result['foobar@foobar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(9, $result['foobar@foobar.com']->phones->toArray());
|
||||
|
||||
$this->assertEquals('SELECT u, p FROM '.__NAMESPACE__ . '\DDC1135User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id', $dql);
|
||||
}
|
||||
|
||||
private function loadFixture()
|
||||
{
|
||||
$p1 = array('11 xxxx-xxxx','11 yyyy-yyyy','11 zzzz-zzzz');
|
||||
$p2 = array('22 xxxx-xxxx','22 yyyy-yyyy','22 zzzz-zzzz');
|
||||
$p3 = array('33 xxxx-xxxx','33 yyyy-yyyy','33 zzzz-zzzz');
|
||||
|
||||
$u1 = new DDC1135User("foo@foo.com", "Foo",$p1);
|
||||
$u2 = new DDC1135User("bar@bar.com", "Bar",$p2);
|
||||
$u3 = new DDC1135User("foobar@foobar.com", "Foo Bar",$p3);
|
||||
|
||||
$this->_em->persist($u1);
|
||||
$this->_em->persist($u2);
|
||||
$this->_em->persist($u3);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1135User
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @Column(type="string", unique=true)
|
||||
*/
|
||||
public $email;
|
||||
|
||||
/**
|
||||
* @Column(type="string")
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity="DDC1135Phone", mappedBy="user", cascade={"persist", "remove"})
|
||||
*/
|
||||
public $phones;
|
||||
|
||||
public function __construct($email, $name, array $numbers = array())
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->email = $email;
|
||||
$this->phones = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
|
||||
foreach ($numbers as $number) {
|
||||
$this->phones->add(new DDC1135Phone($this,$number));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1135Phone
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(name="id", type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @Column(name="number", type="string", nullable = false)
|
||||
*/
|
||||
public $number;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC1135User", inversedBy="phones")
|
||||
* @JoinColumn(name="user_id", referencedColumnName="id", nullable = false)
|
||||
*/
|
||||
public $user;
|
||||
|
||||
public function __construct($user, $number)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->number = $number;
|
||||
}
|
||||
}
|
127
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1392Test.php
Normal file
127
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1392Test.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-1392
|
||||
*/
|
||||
class DDC1392Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1392File'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1392Picture'),
|
||||
));
|
||||
} catch (\Exception $ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public function testFailingCase()
|
||||
{
|
||||
$file = new DDC1392File;
|
||||
|
||||
$picture = new DDC1392Picture;
|
||||
$picture->setFile($file);
|
||||
|
||||
$em = $this->_em;
|
||||
$em->persist($picture);
|
||||
$em->flush();
|
||||
$em->clear();
|
||||
|
||||
$fileId = $file->getFileId();
|
||||
$pictureId = $picture->getPictureId();
|
||||
|
||||
$this->assertTrue($fileId > 0);
|
||||
|
||||
$picture = $em->find(__NAMESPACE__ . '\DDC1392Picture', $pictureId);
|
||||
$this->assertEquals(UnitOfWork::STATE_MANAGED, $em->getUnitOfWork()->getEntityState($picture->getFile()), "Lazy Proxy should be marked MANAGED.");
|
||||
|
||||
$file = $picture->getFile();
|
||||
|
||||
// With this activated there will be no problem
|
||||
//$file->__load();
|
||||
|
||||
$picture->setFile(null);
|
||||
|
||||
$em->clear();
|
||||
|
||||
$em->merge($file);
|
||||
|
||||
$em->flush();
|
||||
|
||||
$q = $this->_em->createQuery("SELECT COUNT(e) FROM " . __NAMESPACE__ . '\DDC1392File e');
|
||||
$result = $q->getSingleScalarResult();
|
||||
|
||||
self::assertEquals(1, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1392Picture
|
||||
{
|
||||
/**
|
||||
* @Column(name="picture_id", type="integer")
|
||||
* @Id @GeneratedValue
|
||||
*/
|
||||
private $pictureId;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC1392File", cascade={"persist", "remove"})
|
||||
* @JoinColumn(name="file_id", referencedColumnName="file_id")
|
||||
*/
|
||||
private $file;
|
||||
|
||||
/**
|
||||
* Get pictureId
|
||||
*/
|
||||
public function getPictureId()
|
||||
{
|
||||
return $this->pictureId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file
|
||||
*/
|
||||
public function setFile($value = null)
|
||||
{
|
||||
$this->file = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1392File
|
||||
{
|
||||
/**
|
||||
* @Column(name="file_id", type="integer")
|
||||
* @Id
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
public $fileId;
|
||||
|
||||
/**
|
||||
* Get fileId
|
||||
*/
|
||||
public function getFileId()
|
||||
{
|
||||
return $this->fileId;
|
||||
}
|
||||
}
|
@ -92,12 +92,12 @@ abstract class DDC258Super
|
||||
class DDC258Class1 extends DDC258Super
|
||||
{
|
||||
/**
|
||||
* @Column(name="title", type="string", length="150")
|
||||
* @Column(name="title", type="string", length=150)
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* @Column(name="content", type="string", length="500")
|
||||
* @Column(name="content", type="string", length=500)
|
||||
*/
|
||||
public $description;
|
||||
}
|
||||
@ -108,12 +108,12 @@ class DDC258Class1 extends DDC258Super
|
||||
class DDC258Class2 extends DDC258Super
|
||||
{
|
||||
/**
|
||||
* @Column(name="title", type="string", length="150")
|
||||
* @Column(name="title", type="string", length=150)
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* @Column(name="content", type="string", length="500")
|
||||
* @Column(name="content", type="string", length=500)
|
||||
*/
|
||||
public $description;
|
||||
|
||||
@ -131,12 +131,12 @@ class DDC258Class2 extends DDC258Super
|
||||
class DDC258Class3 extends DDC258Super
|
||||
{
|
||||
/**
|
||||
* @Column(name="title", type="string", length="150")
|
||||
* @Column(name="title", type="string", length=150)
|
||||
*/
|
||||
public $apples;
|
||||
|
||||
/**
|
||||
* @Column(name="content", type="string", length="500")
|
||||
* @Column(name="content", type="string", length=500)
|
||||
*/
|
||||
public $bananas;
|
||||
}
|
@ -111,7 +111,7 @@ class DDC522Cart {
|
||||
class DDC522ForeignKeyTest {
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
/** @Column(type="integer", name="cart_id", nullable="true") */
|
||||
/** @Column(type="integer", name="cart_id", nullable=true) */
|
||||
public $cartId;
|
||||
/**
|
||||
* @OneToOne(targetEntity="DDC522Cart")
|
||||
|
@ -49,14 +49,14 @@ class DDC698Role
|
||||
protected $roleID;
|
||||
|
||||
/**
|
||||
* @Column(name="name", type="string", length="45")
|
||||
* @Column(name="name", type="string", length=45)
|
||||
*
|
||||
*
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @Column(name="shortName", type="string", length="45")
|
||||
* @Column(name="shortName", type="string", length=45)
|
||||
*
|
||||
*
|
||||
*/
|
||||
@ -91,7 +91,7 @@ class DDC698Privilege
|
||||
protected $privilegeID;
|
||||
|
||||
/**
|
||||
* @Column(name="name", type="string", length="45")
|
||||
* @Column(name="name", type="string", length=45)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
@ -111,12 +111,12 @@ abstract class DDC837Super
|
||||
class DDC837Class1 extends DDC837Super
|
||||
{
|
||||
/**
|
||||
* @Column(name="title", type="string", length="150")
|
||||
* @Column(name="title", type="string", length=150)
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* @Column(name="content", type="string", length="500")
|
||||
* @Column(name="content", type="string", length=500)
|
||||
*/
|
||||
public $description;
|
||||
|
||||
@ -132,12 +132,12 @@ class DDC837Class1 extends DDC837Super
|
||||
class DDC837Class2 extends DDC837Super
|
||||
{
|
||||
/**
|
||||
* @Column(name="title", type="string", length="150")
|
||||
* @Column(name="title", type="string", length=150)
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* @Column(name="content", type="string", length="500")
|
||||
* @Column(name="content", type="string", length=500)
|
||||
*/
|
||||
public $description;
|
||||
|
||||
@ -160,12 +160,12 @@ class DDC837Class2 extends DDC837Super
|
||||
class DDC837Class3 extends DDC837Super
|
||||
{
|
||||
/**
|
||||
* @Column(name="title", type="string", length="150")
|
||||
* @Column(name="title", type="string", length=150)
|
||||
*/
|
||||
public $apples;
|
||||
|
||||
/**
|
||||
* @Column(name="content", type="string", length="500")
|
||||
* @Column(name="content", type="string", length=500)
|
||||
*/
|
||||
public $bananas;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ class DDC992Role
|
||||
*/
|
||||
public $roleID;
|
||||
/**
|
||||
* @Column (name="name", type="string", length="45")
|
||||
* @Column (name="name", type="string", length=45)
|
||||
*/
|
||||
public $name;
|
||||
/**
|
||||
|
@ -182,7 +182,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertTrue(isset($class->associationMappings['phonenumbers']));
|
||||
$this->assertFalse($class->associationMappings['phonenumbers']['isOwningSide']);
|
||||
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadePersist']);
|
||||
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRemove']);
|
||||
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadeRemove']);
|
||||
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']);
|
||||
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']);
|
||||
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeMerge']);
|
||||
@ -291,6 +291,42 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
||||
$class->discriminatorColumn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-869
|
||||
*/
|
||||
public function testMappedSuperclassWithRepository()
|
||||
{
|
||||
$driver = $this->_loadDriver();
|
||||
$em = $this->_getTestEntityManager();
|
||||
$factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory();
|
||||
|
||||
$em->getConfiguration()->setMetadataDriverImpl($driver);
|
||||
$factory->setEntityManager($em);
|
||||
|
||||
|
||||
$class = $factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869CreditCardPayment');
|
||||
|
||||
$this->assertTrue(isset($class->fieldMappings['id']));
|
||||
$this->assertTrue(isset($class->fieldMappings['value']));
|
||||
$this->assertTrue(isset($class->fieldMappings['creditCardNumber']));
|
||||
$this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository");
|
||||
$this->assertInstanceOf("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository",
|
||||
$em->getRepository("Doctrine\Tests\Models\DDC869\DDC869CreditCardPayment"));
|
||||
$this->assertTrue($em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment")->isTrue());
|
||||
|
||||
|
||||
|
||||
$class = $factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869ChequePayment');
|
||||
|
||||
$this->assertTrue(isset($class->fieldMappings['id']));
|
||||
$this->assertTrue(isset($class->fieldMappings['value']));
|
||||
$this->assertTrue(isset($class->fieldMappings['serialNumber']));
|
||||
$this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository");
|
||||
$this->assertInstanceOf("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository",
|
||||
$em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment"));
|
||||
$this->assertTrue($em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment")->isTrue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,6 +52,35 @@ class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
|
||||
|
||||
$this->assertTrue(isset($class->associationMappings['mappedRelated1']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-869
|
||||
*/
|
||||
public function testGetMetadataForSubclassWithMappedSuperclassWhithRepository()
|
||||
{
|
||||
$class = $this->_factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869CreditCardPayment');
|
||||
|
||||
$this->assertTrue(isset($class->fieldMappings['id']));
|
||||
$this->assertTrue(isset($class->fieldMappings['value']));
|
||||
$this->assertTrue(isset($class->fieldMappings['creditCardNumber']));
|
||||
$this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository");
|
||||
|
||||
|
||||
$class = $this->_factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869ChequePayment');
|
||||
|
||||
$this->assertTrue(isset($class->fieldMappings['id']));
|
||||
$this->assertTrue(isset($class->fieldMappings['value']));
|
||||
$this->assertTrue(isset($class->fieldMappings['serialNumber']));
|
||||
$this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository");
|
||||
|
||||
|
||||
// override repositoryClass
|
||||
$class = $this->_factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\SubclassWithRepository');
|
||||
|
||||
$this->assertTrue(isset($class->fieldMappings['id']));
|
||||
$this->assertTrue(isset($class->fieldMappings['value']));
|
||||
$this->assertEquals($class->customRepositoryClassName, "Doctrine\ORM\EntityRepository");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-388
|
||||
@ -191,7 +220,7 @@ abstract class HierachyBase
|
||||
{
|
||||
/**
|
||||
* @Column(type="integer") @Id @GeneratedValue(strategy="SEQUENCE")
|
||||
* @SequenceGenerator(sequenceName="foo", initialValue="10")
|
||||
* @SequenceGenerator(sequenceName="foo", initialValue=10)
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
@ -257,7 +286,7 @@ abstract class SuperclassBase
|
||||
{
|
||||
/**
|
||||
* @Column(type="integer") @Id @GeneratedValue(strategy="SEQUENCE")
|
||||
* @SequenceGenerator(sequenceName="foo", initialValue="10")
|
||||
* @SequenceGenerator(sequenceName="foo", initialValue=10)
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
@ -277,4 +306,12 @@ abstract class MediumSuperclassBase extends SuperclassBase
|
||||
class MediumSuperclassEntity extends MediumSuperclassBase
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity(repositoryClass = "Doctrine\ORM\EntityRepository")
|
||||
*/
|
||||
class SubclassWithRepository extends \Doctrine\Tests\Models\DDC869\DDC869Payment
|
||||
{
|
||||
|
||||
}
|
426
tests/Doctrine/Tests/ORM/Mapping/ClassMetadataBuilderTest.php
Normal file
426
tests/Doctrine/Tests/ORM/Mapping/ClassMetadataBuilderTest.php
Normal file
@ -0,0 +1,426 @@
|
||||
<?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\Mapping;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
|
||||
|
||||
/**
|
||||
* @group DDC-659
|
||||
*/
|
||||
class ClassMetadataBuilderTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
/**
|
||||
* @var ClassMetadata
|
||||
*/
|
||||
private $cm;
|
||||
/**
|
||||
* @var ClassMetadataBuilder
|
||||
*/
|
||||
private $builder;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$this->builder = new ClassMetadataBuilder($this->cm);
|
||||
}
|
||||
|
||||
public function testSetMappedSuperClass()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->setMappedSuperClass());
|
||||
$this->assertTrue($this->cm->isMappedSuperclass);
|
||||
}
|
||||
|
||||
public function testSetCustomRepositoryClass()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->setCustomRepositoryClass('Doctrine\Tests\Models\CMS\CmsGroup'));
|
||||
$this->assertEquals('Doctrine\Tests\Models\CMS\CmsGroup', $this->cm->customRepositoryClassName);
|
||||
}
|
||||
|
||||
public function testSetReadOnly()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->setReadOnly());
|
||||
$this->assertTrue($this->cm->isReadOnly);
|
||||
}
|
||||
|
||||
public function testSetTable()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->setTable('users'));
|
||||
$this->assertEquals('users', $this->cm->table['name']);
|
||||
}
|
||||
|
||||
public function testAddIndex()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->addIndex(array('username', 'name'), 'users_idx'));
|
||||
$this->assertEquals(array('users_idx' => array('columns' => array('username', 'name'))), $this->cm->table['indexes']);
|
||||
}
|
||||
|
||||
public function testAddUniqueConstraint()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->addUniqueConstraint(array('username', 'name'), 'users_idx'));
|
||||
$this->assertEquals(array('users_idx' => array('columns' => array('username', 'name'))), $this->cm->table['uniqueConstraints']);
|
||||
}
|
||||
|
||||
public function testSetPrimaryTableRelated()
|
||||
{
|
||||
$this->builder->addUniqueConstraint(array('username', 'name'), 'users_idx');
|
||||
$this->builder->addIndex(array('username', 'name'), 'users_idx');
|
||||
$this->builder->setTable('users');
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'name' => 'users',
|
||||
'indexes' => array('users_idx' => array('columns' => array('username', 'name'))),
|
||||
'uniqueConstraints' => array('users_idx' => array('columns' => array('username', 'name'))),
|
||||
),
|
||||
$this->cm->table
|
||||
);
|
||||
}
|
||||
|
||||
public function testSetInheritanceJoined()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->setJoinedTableInheritance());
|
||||
$this->assertEquals(ClassMetadata::INHERITANCE_TYPE_JOINED, $this->cm->inheritanceType);
|
||||
}
|
||||
|
||||
public function testSetInheritanceSingleTable()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->setSingleTableInheritance());
|
||||
$this->assertEquals(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE, $this->cm->inheritanceType);
|
||||
}
|
||||
|
||||
public function testSetDiscriminatorColumn()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->setDiscriminatorColumn('discr', 'string', '124'));
|
||||
$this->assertEquals(array('fieldName' => 'discr', 'name' => 'discr', 'type' => 'string', 'length' => '124'), $this->cm->discriminatorColumn);
|
||||
}
|
||||
|
||||
public function testAddDiscriminatorMapClass()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->addDiscriminatorMapClass('test', 'Doctrine\Tests\Models\CMS\CmsUser'));
|
||||
$this->assertIsFluent($this->builder->addDiscriminatorMapClass('test2', 'Doctrine\Tests\Models\CMS\CmsGroup'));
|
||||
|
||||
$this->assertEquals(array('test' => 'Doctrine\Tests\Models\CMS\CmsUser', 'test2' => 'Doctrine\Tests\Models\CMS\CmsGroup'), $this->cm->discriminatorMap);
|
||||
$this->assertEquals('test', $this->cm->discriminatorValue);
|
||||
}
|
||||
|
||||
public function testChangeTrackingPolicyExplicit()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->setChangeTrackingPolicyDeferredExplicit());
|
||||
$this->assertEquals(ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT, $this->cm->changeTrackingPolicy);
|
||||
}
|
||||
|
||||
public function testChangeTrackingPolicyNotify()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->setChangeTrackingPolicyNotify());
|
||||
$this->assertEquals(ClassMetadata::CHANGETRACKING_NOTIFY, $this->cm->changeTrackingPolicy);
|
||||
}
|
||||
|
||||
public function testAddField()
|
||||
{
|
||||
$this->assertIsFluent($this->builder->addField('name', 'string'));
|
||||
$this->assertEquals(array('columnName' => 'name', 'fieldName' => 'name', 'type' => 'string'), $this->cm->fieldMappings['name']);
|
||||
}
|
||||
|
||||
public function testCreateField()
|
||||
{
|
||||
$fieldBuilder = ($this->builder->createField('name', 'string'));
|
||||
$this->assertInstanceOf('Doctrine\ORM\Mapping\Builder\FieldBuilder', $fieldBuilder);
|
||||
|
||||
$this->assertFalse(isset($this->cm->fieldMappings['name']));
|
||||
$this->assertIsFluent($fieldBuilder->build());
|
||||
$this->assertEquals(array('columnName' => 'name', 'fieldName' => 'name', 'type' => 'string'), $this->cm->fieldMappings['name']);
|
||||
}
|
||||
|
||||
public function testCreateVersionedField()
|
||||
{
|
||||
$this->builder->createField('name', 'integer')->columnName('username')->length(124)->nullable()->columnDefinition('foobar')->unique()->isVersionField()->build();
|
||||
$this->assertEquals(array(
|
||||
'columnDefinition' => 'foobar',
|
||||
'columnName' => 'username',
|
||||
'default' => 1,
|
||||
'fieldName' => 'name',
|
||||
'length' => 124,
|
||||
'type' => 'integer',
|
||||
'nullable' => true,
|
||||
'unique' => true,
|
||||
), $this->cm->fieldMappings['name']);
|
||||
}
|
||||
|
||||
public function testCreatePrimaryField()
|
||||
{
|
||||
$this->builder->createField('id', 'integer')->isPrimaryKey()->generatedValue()->build();
|
||||
|
||||
$this->assertEquals(array('id'), $this->cm->identifier);
|
||||
$this->assertEquals(array('columnName' => 'id', 'fieldName' => 'id', 'id' => true, 'type' => 'integer'), $this->cm->fieldMappings['id']);
|
||||
}
|
||||
|
||||
public function testAddLifecycleEvent()
|
||||
{
|
||||
$this->builder->addLifecycleEvent('getStatus', 'postLoad');
|
||||
|
||||
$this->assertEquals(array('postLoad' => array('getStatus')), $this->cm->lifecycleCallbacks);
|
||||
}
|
||||
|
||||
public function testCreateManyToOne()
|
||||
{
|
||||
$this->assertIsFluent(
|
||||
$this->builder->createManyToOne('groups', 'Doctrine\Tests\Models\CMS\CmsGroup')
|
||||
->addJoinColumn('group_id', 'id', true, false, 'CASCADE')
|
||||
->cascadeAll()
|
||||
->fetchExtraLazy()
|
||||
->build()
|
||||
);
|
||||
|
||||
$this->assertEquals(array('groups' => array (
|
||||
'fieldName' => 'groups',
|
||||
'targetEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsGroup',
|
||||
'cascade' => array (
|
||||
0 => 'remove',
|
||||
1 => 'persist',
|
||||
2 => 'refresh',
|
||||
3 => 'merge',
|
||||
4 => 'detach',
|
||||
),
|
||||
'fetch' => 4,
|
||||
'joinColumns' => array (
|
||||
0 =>
|
||||
array (
|
||||
'name' => 'group_id',
|
||||
'referencedColumnName' => 'id',
|
||||
'nullable' => true,
|
||||
'unique' => false,
|
||||
'onDelete' => 'CASCADE',
|
||||
'columnDefinition' => NULL,
|
||||
),
|
||||
),
|
||||
'type' => 2,
|
||||
'mappedBy' => NULL,
|
||||
'inversedBy' => NULL,
|
||||
'isOwningSide' => true,
|
||||
'sourceEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser',
|
||||
'isCascadeRemove' => true,
|
||||
'isCascadePersist' => true,
|
||||
'isCascadeRefresh' => true,
|
||||
'isCascadeMerge' => true,
|
||||
'isCascadeDetach' => true,
|
||||
'sourceToTargetKeyColumns' =>
|
||||
array (
|
||||
'group_id' => 'id',
|
||||
),
|
||||
'joinColumnFieldNames' =>
|
||||
array (
|
||||
'group_id' => 'group_id',
|
||||
),
|
||||
'targetToSourceKeyColumns' =>
|
||||
array (
|
||||
'id' => 'group_id',
|
||||
),
|
||||
'orphanRemoval' => false,
|
||||
),
|
||||
), $this->cm->associationMappings);
|
||||
}
|
||||
|
||||
public function testCreateOneToOne()
|
||||
{
|
||||
$this->assertIsFluent(
|
||||
$this->builder->createOneToOne('groups', 'Doctrine\Tests\Models\CMS\CmsGroup')
|
||||
->addJoinColumn('group_id', 'id', true, false, 'CASCADE')
|
||||
->cascadeAll()
|
||||
->fetchExtraLazy()
|
||||
->build()
|
||||
);
|
||||
|
||||
$this->assertEquals(array('groups' => array (
|
||||
'fieldName' => 'groups',
|
||||
'targetEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsGroup',
|
||||
'cascade' => array (
|
||||
0 => 'remove',
|
||||
1 => 'persist',
|
||||
2 => 'refresh',
|
||||
3 => 'merge',
|
||||
4 => 'detach',
|
||||
),
|
||||
'fetch' => 4,
|
||||
'joinColumns' => array (
|
||||
0 =>
|
||||
array (
|
||||
'name' => 'group_id',
|
||||
'referencedColumnName' => 'id',
|
||||
'nullable' => true,
|
||||
'unique' => true,
|
||||
'onDelete' => 'CASCADE',
|
||||
'columnDefinition' => NULL,
|
||||
),
|
||||
),
|
||||
'type' => 1,
|
||||
'mappedBy' => NULL,
|
||||
'inversedBy' => NULL,
|
||||
'isOwningSide' => true,
|
||||
'sourceEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser',
|
||||
'isCascadeRemove' => true,
|
||||
'isCascadePersist' => true,
|
||||
'isCascadeRefresh' => true,
|
||||
'isCascadeMerge' => true,
|
||||
'isCascadeDetach' => true,
|
||||
'sourceToTargetKeyColumns' =>
|
||||
array (
|
||||
'group_id' => 'id',
|
||||
),
|
||||
'joinColumnFieldNames' =>
|
||||
array (
|
||||
'group_id' => 'group_id',
|
||||
),
|
||||
'targetToSourceKeyColumns' =>
|
||||
array (
|
||||
'id' => 'group_id',
|
||||
),
|
||||
'orphanRemoval' => false,
|
||||
),
|
||||
), $this->cm->associationMappings);
|
||||
}
|
||||
|
||||
public function testCreateManyToMany()
|
||||
{
|
||||
$this->assertIsFluent(
|
||||
$this->builder->createManyToMany('groups', 'Doctrine\Tests\Models\CMS\CmsGroup')
|
||||
->setJoinTable('groups_users')
|
||||
->addJoinColumn('group_id', 'id', true, false, 'CASCADE')
|
||||
->addInverseJoinColumn('user_id', 'id')
|
||||
->cascadeAll()
|
||||
->fetchExtraLazy()
|
||||
->build()
|
||||
);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'groups' =>
|
||||
array(
|
||||
'fieldName' => 'groups',
|
||||
'targetEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsGroup',
|
||||
'cascade' =>
|
||||
array(
|
||||
0 => 'remove',
|
||||
1 => 'persist',
|
||||
2 => 'refresh',
|
||||
3 => 'merge',
|
||||
4 => 'detach',
|
||||
),
|
||||
'fetch' => 4,
|
||||
'joinTable' =>
|
||||
array(
|
||||
'joinColumns' =>
|
||||
array(
|
||||
0 =>
|
||||
array(
|
||||
'name' => 'group_id',
|
||||
'referencedColumnName' => 'id',
|
||||
'nullable' => true,
|
||||
'unique' => false,
|
||||
'onDelete' => 'CASCADE',
|
||||
'columnDefinition' => NULL,
|
||||
),
|
||||
),
|
||||
'inverseJoinColumns' =>
|
||||
array(
|
||||
0 =>
|
||||
array(
|
||||
'name' => 'user_id',
|
||||
'referencedColumnName' => 'id',
|
||||
'nullable' => true,
|
||||
'unique' => false,
|
||||
'onDelete' => NULL,
|
||||
'columnDefinition' => NULL,
|
||||
),
|
||||
),
|
||||
'name' => 'groups_users',
|
||||
),
|
||||
'type' => 8,
|
||||
'mappedBy' => NULL,
|
||||
'inversedBy' => NULL,
|
||||
'isOwningSide' => true,
|
||||
'sourceEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser',
|
||||
'isCascadeRemove' => true,
|
||||
'isCascadePersist' => true,
|
||||
'isCascadeRefresh' => true,
|
||||
'isCascadeMerge' => true,
|
||||
'isCascadeDetach' => true,
|
||||
'isOnDeleteCascade' => true,
|
||||
'relationToSourceKeyColumns' =>
|
||||
array(
|
||||
'group_id' => 'id',
|
||||
),
|
||||
'joinTableColumns' =>
|
||||
array(
|
||||
0 => 'group_id',
|
||||
1 => 'user_id',
|
||||
),
|
||||
'relationToTargetKeyColumns' =>
|
||||
array(
|
||||
'user_id' => 'id',
|
||||
),
|
||||
),
|
||||
), $this->cm->associationMappings);
|
||||
}
|
||||
|
||||
public function testCreateOneToMany()
|
||||
{
|
||||
$this->assertIsFluent(
|
||||
$this->builder->createOneToMany('groups', 'Doctrine\Tests\Models\CMS\CmsGroup')
|
||||
->mappedBy('test')
|
||||
->setOrderBy(array('test'))
|
||||
->setIndexBy('test')
|
||||
->build()
|
||||
);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'groups' =>
|
||||
array(
|
||||
'fieldName' => 'groups',
|
||||
'targetEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsGroup',
|
||||
'mappedBy' => 'test',
|
||||
'orderBy' =>
|
||||
array(
|
||||
0 => 'test',
|
||||
),
|
||||
'indexBy' => 'test',
|
||||
'type' => 4,
|
||||
'inversedBy' => NULL,
|
||||
'isOwningSide' => false,
|
||||
'sourceEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser',
|
||||
'fetch' => 2,
|
||||
'cascade' =>
|
||||
array(
|
||||
),
|
||||
'isCascadeRemove' => false,
|
||||
'isCascadePersist' => false,
|
||||
'isCascadeRefresh' => false,
|
||||
'isCascadeMerge' => false,
|
||||
'isCascadeDetach' => false,
|
||||
'orphanRemoval' => false,
|
||||
),
|
||||
), $this->cm->associationMappings);
|
||||
}
|
||||
|
||||
public function assertIsFluent($ret)
|
||||
{
|
||||
$this->assertSame($this->builder, $ret, "Return Value has to be same instance as used builder");
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertEquals('UserParent', $cm->rootEntityName);
|
||||
$this->assertEquals(array('Doctrine\Tests\Models\CMS\One', 'Doctrine\Tests\Models\CMS\Two', 'Doctrine\Tests\Models\CMS\Three'), $cm->subClasses);
|
||||
$this->assertEquals(array('UserParent'), $cm->parentClasses);
|
||||
$this->assertEquals('UserRepository', $cm->customRepositoryClassName);
|
||||
$this->assertEquals('Doctrine\Tests\Models\CMS\UserRepository', $cm->customRepositoryClassName);
|
||||
$this->assertEquals(array('name' => 'disc', 'type' => 'integer', 'fieldName' => 'disc'), $cm->discriminatorColumn);
|
||||
$this->assertTrue($cm->associationMappings['phonenumbers']['type'] == ClassMetadata::ONE_TO_ONE);
|
||||
$this->assertEquals(1, count($cm->associationMappings));
|
||||
@ -471,4 +471,15 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
|
||||
$cm = new ClassMetadata('DOCTRINE\TESTS\MODELS\CMS\CMSUSER');
|
||||
$this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $cm->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-659
|
||||
*/
|
||||
public function testLifecycleCallbackNotFound()
|
||||
{
|
||||
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$this->setExpectedException("Doctrine\ORM\Mapping\MappingException", "Entity 'Doctrine\Tests\Models\CMS\CmsUser' has no method 'notfound' to be registered as lifecycle callback.");
|
||||
$cm->addLifecycleCallback('notfound', 'postLoad');
|
||||
}
|
||||
}
|
||||
|
113
tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php
Normal file
113
tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?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\Mapping\Symfony;
|
||||
|
||||
/**
|
||||
* @group DDC-1418
|
||||
*/
|
||||
abstract class AbstractDriverTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testFindMappingFile()
|
||||
{
|
||||
$driver = $this->getDriver(array(
|
||||
'MyNamespace\MySubnamespace\EntityFoo' => 'foo',
|
||||
'MyNamespace\MySubnamespace\Entity' => $this->dir,
|
||||
));
|
||||
|
||||
touch($filename = $this->dir.'/Foo'.$this->getFileExtension());
|
||||
$this->assertEquals($filename, $this->invoke($driver, '_findMappingFile', array('MyNamespace\MySubnamespace\Entity\Foo')));
|
||||
}
|
||||
|
||||
public function testFindMappingFileInSubnamespace()
|
||||
{
|
||||
$driver = $this->getDriver(array(
|
||||
'MyNamespace\MySubnamespace\Entity' => $this->dir,
|
||||
));
|
||||
|
||||
touch($filename = $this->dir.'/Foo.Bar'.$this->getFileExtension());
|
||||
$this->assertEquals($filename, $this->invoke($driver, '_findMappingFile', array('MyNamespace\MySubnamespace\Entity\Foo\Bar')));
|
||||
}
|
||||
|
||||
public function testFindMappingFileNamespacedFoundFileNotFound()
|
||||
{
|
||||
$this->setExpectedException(
|
||||
'Doctrine\ORM\Mapping\MappingException',
|
||||
"No mapping file found named '".$this->dir."/Foo".$this->getFileExtension()."' for class 'MyNamespace\MySubnamespace\Entity\Foo'."
|
||||
);
|
||||
|
||||
$driver = $this->getDriver(array(
|
||||
'MyNamespace\MySubnamespace\Entity' => $this->dir,
|
||||
));
|
||||
|
||||
$this->invoke($driver, '_findMappingFile', array('MyNamespace\MySubnamespace\Entity\Foo'));
|
||||
}
|
||||
|
||||
public function testFindMappingNamespaceNotFound()
|
||||
{
|
||||
$this->setExpectedException(
|
||||
'Doctrine\ORM\Mapping\MappingException',
|
||||
"No mapping file found named 'Foo".$this->getFileExtension()."' for class 'MyOtherNamespace\MySubnamespace\Entity\Foo'."
|
||||
);
|
||||
|
||||
$driver = $this->getDriver(array(
|
||||
'MyNamespace\MySubnamespace\Entity' => $this->dir,
|
||||
));
|
||||
|
||||
$this->invoke($driver, '_findMappingFile', array('MyOtherNamespace\MySubnamespace\Entity\Foo'));
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->dir = sys_get_temp_dir().'/abstract_driver_test';
|
||||
@mkdir($this->dir, 0777, true);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->dir), \RecursiveIteratorIterator::CHILD_FIRST);
|
||||
|
||||
foreach ($iterator as $path) {
|
||||
if ($path->isDir()) {
|
||||
@rmdir($path);
|
||||
} else {
|
||||
@unlink($path);
|
||||
}
|
||||
}
|
||||
|
||||
@rmdir($this->dir);
|
||||
}
|
||||
|
||||
abstract protected function getFileExtension();
|
||||
abstract protected function getDriver(array $paths = array());
|
||||
|
||||
private function setField($obj, $field, $value)
|
||||
{
|
||||
$ref = new \ReflectionProperty($obj, $field);
|
||||
$ref->setAccessible(true);
|
||||
$ref->setValue($obj, $value);
|
||||
}
|
||||
|
||||
private function invoke($obj, $method, array $args = array()) {
|
||||
$ref = new \ReflectionMethod($obj, $method);
|
||||
$ref->setAccessible(true);
|
||||
|
||||
return $ref->invokeArgs($obj, $args);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user