2008-05-26 00:10:41 +04:00
|
|
|
<?php
|
2008-02-11 20:08:22 +03:00
|
|
|
/*
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* This software consists of voluntary contributions made by many individuals
|
|
|
|
* and is licensed under the LGPL. For more information, see
|
|
|
|
* <http://www.phpdoctrine.org>.
|
|
|
|
*/
|
2008-02-04 00:29:57 +03:00
|
|
|
|
2008-12-18 17:08:11 +03:00
|
|
|
#namespace Doctrine\ORM\Mapping;
|
|
|
|
|
|
|
|
#use Doctrine\DBAL\Platforms\AbstractPlatform;
|
2008-07-21 00:13:24 +04:00
|
|
|
|
2008-02-04 00:29:57 +03:00
|
|
|
/**
|
2008-02-11 20:08:22 +03:00
|
|
|
* The metadata factory is used to create ClassMetadata objects that contain all the
|
2008-12-18 17:08:11 +03:00
|
|
|
* metadata mapping informations of a class which describes how a class should be mapped
|
|
|
|
* to a relational database.
|
2008-02-04 00:29:57 +03:00
|
|
|
*
|
2008-05-26 00:10:41 +04:00
|
|
|
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
|
|
|
* @author Roman Borschel <roman@code-factory.org>
|
|
|
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
|
|
|
* @version $Revision$
|
2009-01-05 20:25:56 +03:00
|
|
|
* @link www.doctrine-project.org
|
2008-05-26 00:10:41 +04:00
|
|
|
* @since 2.0
|
2008-02-04 00:29:57 +03:00
|
|
|
*/
|
2009-01-05 20:25:56 +03:00
|
|
|
class Doctrine_ORM_Mapping_ClassMetadataFactory
|
2008-02-04 00:29:57 +03:00
|
|
|
{
|
2008-12-18 17:08:11 +03:00
|
|
|
/** The targeted database platform. */
|
|
|
|
private $_targetPlatform;
|
2009-01-05 20:25:56 +03:00
|
|
|
private $_driver;
|
2009-01-06 20:22:23 +03:00
|
|
|
private $_cacheDriver;
|
2008-02-04 00:29:57 +03:00
|
|
|
|
2008-02-11 20:08:22 +03:00
|
|
|
/**
|
|
|
|
* Constructor.
|
2008-12-18 17:08:11 +03:00
|
|
|
* Creates a new factory instance that uses the given metadata driver implementation.
|
2008-02-11 20:08:22 +03:00
|
|
|
*
|
|
|
|
* @param $driver The metadata driver to use.
|
|
|
|
*/
|
2008-12-18 17:08:11 +03:00
|
|
|
public function __construct($driver, Doctrine_DBAL_Platforms_AbstractPlatform $targetPlatform)
|
2008-02-04 00:29:57 +03:00
|
|
|
{
|
2009-01-05 20:25:56 +03:00
|
|
|
$this->_driver = $driver;
|
2008-12-18 17:08:11 +03:00
|
|
|
$this->_targetPlatform = $targetPlatform;
|
2008-02-04 00:29:57 +03:00
|
|
|
}
|
2009-01-05 20:25:56 +03:00
|
|
|
|
2009-01-06 20:22:23 +03:00
|
|
|
public function setCacheDriver($cacheDriver)
|
|
|
|
{
|
|
|
|
$this->_cacheDriver = $cacheDriver;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCacheDriver()
|
|
|
|
{
|
|
|
|
return $this->_cacheDriver;
|
|
|
|
}
|
|
|
|
|
2009-01-05 20:25:56 +03:00
|
|
|
/**
|
|
|
|
* Returns the metadata object for a class.
|
|
|
|
*
|
|
|
|
* @param string $className The name of the class.
|
2009-01-06 20:22:23 +03:00
|
|
|
* @return Doctrine\ORM\Mapping\ClassMetadata
|
2009-01-05 20:25:56 +03:00
|
|
|
*/
|
|
|
|
public function getMetadataFor($className)
|
|
|
|
{
|
|
|
|
if ( ! isset($this->_loadedMetadata[$className])) {
|
2009-01-06 20:22:23 +03:00
|
|
|
if ($this->_cacheDriver) {
|
|
|
|
if ($this->_cacheDriver->contains("$className\$CLASSMETADATA")) {
|
|
|
|
$this->_loadedMetadata[$className] = $this->_cacheDriver->get("$className\$CLASSMETADATA");
|
|
|
|
} else {
|
|
|
|
$this->_loadMetadata($className);
|
|
|
|
$this->_cacheDriver->put("$className\$CLASSMETADATA", $this->_loadedMetadata[$className]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$this->_loadMetadata($className);
|
|
|
|
}
|
2009-01-05 20:25:56 +03:00
|
|
|
}
|
|
|
|
return $this->_loadedMetadata[$className];
|
|
|
|
}
|
2008-02-04 00:29:57 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads the metadata of the class in question and all it's ancestors whose metadata
|
|
|
|
* is still not loaded.
|
|
|
|
*
|
|
|
|
* @param string $name The name of the class for which the metadata should get loaded.
|
|
|
|
* @param array $tables The metadata collection to which the loaded metadata is added.
|
|
|
|
*/
|
2008-12-18 17:08:11 +03:00
|
|
|
protected function _loadMetadata($name)
|
2008-02-04 00:29:57 +03:00
|
|
|
{
|
|
|
|
$parentClass = $name;
|
|
|
|
$parentClasses = array();
|
|
|
|
$loadedParentClass = false;
|
|
|
|
while ($parentClass = get_parent_class($parentClass)) {
|
2008-12-18 17:08:11 +03:00
|
|
|
if (isset($this->_loadedMetadata[$parentClass])) {
|
2008-02-04 00:29:57 +03:00
|
|
|
$loadedParentClass = $parentClass;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
$parentClasses[] = $parentClass;
|
|
|
|
}
|
|
|
|
$parentClasses = array_reverse($parentClasses);
|
|
|
|
$parentClasses[] = $name;
|
|
|
|
|
|
|
|
if ($loadedParentClass) {
|
2008-12-18 17:08:11 +03:00
|
|
|
$class = $this->_loadedMetadata[$loadedParentClass];
|
2008-02-04 00:29:57 +03:00
|
|
|
} else {
|
|
|
|
$rootClassOfHierarchy = count($parentClasses) > 0 ? array_shift($parentClasses) : $name;
|
2009-01-06 20:22:23 +03:00
|
|
|
$class = $this->_newClassMetadataInstance($rootClassOfHierarchy);
|
2008-12-18 17:08:11 +03:00
|
|
|
$this->_loadClassMetadata($class, $rootClassOfHierarchy);
|
|
|
|
$this->_loadedMetadata[$rootClassOfHierarchy] = $class;
|
2008-02-04 00:29:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (count($parentClasses) == 0) {
|
|
|
|
return $class;
|
|
|
|
}
|
|
|
|
|
|
|
|
// load metadata of subclasses
|
|
|
|
// -> child1 -> child2 -> $name
|
|
|
|
|
2008-08-22 13:05:14 +04:00
|
|
|
// Move down the hierarchy of parent classes, starting from the topmost class
|
2008-02-04 00:29:57 +03:00
|
|
|
$parent = $class;
|
|
|
|
foreach ($parentClasses as $subclassName) {
|
2009-01-06 20:22:23 +03:00
|
|
|
$subClass = $this->_newClassMetadataInstance($subclassName);
|
2009-01-05 23:18:56 +03:00
|
|
|
$subClass->setInheritanceType($parent->getInheritanceType());
|
|
|
|
$subClass->setDiscriminatorMap($parent->getDiscriminatorMap());
|
|
|
|
$subClass->setDiscriminatorColumn($parent->getDiscriminatorColumn());
|
2009-01-06 21:30:51 +03:00
|
|
|
$subClass->setIdGeneratorType($parent->getIdGeneratorType());
|
2008-02-04 00:29:57 +03:00
|
|
|
$this->_addInheritedFields($subClass, $parent);
|
|
|
|
$this->_addInheritedRelations($subClass, $parent);
|
2008-12-18 17:08:11 +03:00
|
|
|
$this->_loadClassMetadata($subClass, $subclassName);
|
2008-08-22 13:05:14 +04:00
|
|
|
if ($parent->isInheritanceTypeSingleTable()) {
|
2008-02-04 00:29:57 +03:00
|
|
|
$subClass->setTableName($parent->getTableName());
|
|
|
|
}
|
2008-12-18 17:08:11 +03:00
|
|
|
$this->_loadedMetadata[$subclassName] = $subClass;
|
2008-02-04 00:29:57 +03:00
|
|
|
$parent = $subClass;
|
|
|
|
}
|
|
|
|
}
|
2009-01-06 20:22:23 +03:00
|
|
|
|
|
|
|
protected function _newClassMetadataInstance($className)
|
|
|
|
{
|
|
|
|
return new Doctrine_ORM_Mapping_ClassMetadata($className);
|
|
|
|
}
|
2008-02-04 00:29:57 +03:00
|
|
|
|
2008-08-16 23:40:59 +04:00
|
|
|
/**
|
|
|
|
* Adds inherited fields to the subclass mapping.
|
|
|
|
*
|
2009-01-06 20:22:23 +03:00
|
|
|
* @param Doctrine\ORM\Mapping\ClassMetadata $subClass
|
|
|
|
* @param Doctrine\ORM\Mapping\ClassMetadata $parentClass
|
2008-08-16 23:40:59 +04:00
|
|
|
*/
|
2008-12-18 17:08:11 +03:00
|
|
|
private function _addInheritedFields($subClass, $parentClass)
|
2008-02-04 00:29:57 +03:00
|
|
|
{
|
2008-07-21 00:13:24 +04:00
|
|
|
foreach ($parentClass->getFieldMappings() as $fieldName => $mapping) {
|
2008-08-22 13:05:14 +04:00
|
|
|
if ( ! isset($mapping['inherited'])) {
|
|
|
|
$mapping['inherited'] = $parentClass->getClassName();
|
|
|
|
}
|
2009-01-06 20:22:23 +03:00
|
|
|
$subClass->mapField($mapping);
|
2008-02-04 00:29:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-16 23:40:59 +04:00
|
|
|
/**
|
|
|
|
* Adds inherited associations to the subclass mapping.
|
|
|
|
*
|
2009-01-06 20:22:23 +03:00
|
|
|
* @param Doctrine\ORM\Mapping\ClassMetadata $subClass
|
|
|
|
* @param Doctrine\ORM\Mapping\ClassMetadata $parentClass
|
2008-08-16 23:40:59 +04:00
|
|
|
*/
|
2008-12-18 17:08:11 +03:00
|
|
|
private function _addInheritedRelations($subClass, $parentClass)
|
2008-05-26 00:10:41 +04:00
|
|
|
{
|
2009-01-06 20:22:23 +03:00
|
|
|
foreach ($parentClass->getAssociationMappings() as $mapping) {
|
|
|
|
$subClass->addAssociationMapping($mapping);
|
2008-02-04 00:29:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-03-26 14:10:45 +03:00
|
|
|
* Loads the metadata of a specified class.
|
|
|
|
*
|
|
|
|
* @param Doctrine_ClassMetadata $class The container for the metadata.
|
|
|
|
* @param string $name The name of the class for which the metadata will be loaded.
|
2008-02-04 00:29:57 +03:00
|
|
|
*/
|
2008-12-18 17:08:11 +03:00
|
|
|
private function _loadClassMetadata(Doctrine_ORM_Mapping_ClassMetadata $class, $name)
|
2008-02-04 00:29:57 +03:00
|
|
|
{
|
|
|
|
if ( ! class_exists($name) || empty($name)) {
|
|
|
|
throw new Doctrine_Exception("Couldn't find class " . $name . ".");
|
|
|
|
}
|
|
|
|
|
|
|
|
$names = array();
|
|
|
|
$className = $name;
|
|
|
|
// get parent classes
|
2008-07-21 00:13:24 +04:00
|
|
|
//TODO: Skip Entity types MappedSuperclass/Transient
|
2008-02-04 00:29:57 +03:00
|
|
|
do {
|
2008-12-18 17:08:11 +03:00
|
|
|
if ($className == $name) {
|
2008-02-04 00:29:57 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$names[] = $className;
|
|
|
|
} while ($className = get_parent_class($className));
|
|
|
|
|
|
|
|
// save parents
|
2008-02-11 20:08:22 +03:00
|
|
|
$class->setParentClasses($names);
|
2008-02-04 00:29:57 +03:00
|
|
|
|
2008-08-16 23:40:59 +04:00
|
|
|
// load user-specified mapping metadata through the driver
|
2008-02-04 00:29:57 +03:00
|
|
|
$this->_driver->loadMetadataForClass($name, $class);
|
2008-12-18 17:08:11 +03:00
|
|
|
|
|
|
|
// Complete Id generator mapping. If AUTO is specified we choose the generator
|
|
|
|
// most appropriate for the target platform.
|
|
|
|
if ($class->getIdGeneratorType() == Doctrine_ORM_Mapping_ClassMetadata::GENERATOR_TYPE_AUTO) {
|
|
|
|
if ($this->_targetPlatform->prefersSequences()) {
|
|
|
|
$class->setIdGeneratorType(Doctrine_ORM_Mapping_ClassMetadata::GENERATOR_TYPE_SEQUENCE);
|
|
|
|
} else if ($this->_targetPlatform->prefersIdentityColumns()) {
|
|
|
|
$class->setIdGeneratorType(Doctrine_ORM_Mapping_ClassMetadata::GENERATOR_TYPE_IDENTITY);
|
|
|
|
} else {
|
|
|
|
$class->setIdGeneratorType(Doctrine_ORM_Mapping_ClassMetadata::GENERATOR_TYPE_TABLE);
|
|
|
|
}
|
|
|
|
}
|
2008-02-04 00:29:57 +03:00
|
|
|
|
|
|
|
return $class;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|