Merged Master into IBM DB2 branch
This commit is contained in:
commit
604ed962e5
@ -1,6 +1,75 @@
|
||||
|
||||
# Upgrade from 2.0-ALPHA4 to 2.0-BETA1
|
||||
|
||||
## EntityRepository deprecates access to protected variables
|
||||
|
||||
Instead of accessing protected variables for the EntityManager in
|
||||
a custom EntityRepository it is now required to use the getter methods
|
||||
for all the three instance variables:
|
||||
|
||||
* `$this->_em` now accessible through `$this->getEntityManager()`
|
||||
* `$this->_class` now accessible through `$this->getClassMetadata()`
|
||||
* `$this->_entityName` now accessible through `$this->getEntityName()`
|
||||
|
||||
Important: For Beta 2 the protected visibility of these three properties will be
|
||||
changed to private!
|
||||
|
||||
## Console migrated to Symfony Console
|
||||
|
||||
The Doctrine CLI has been replaced by Symfony Console Configuration
|
||||
|
||||
Instead of having to specify:
|
||||
|
||||
[php]
|
||||
$cliConfig = new CliConfiguration();
|
||||
$cliConfig->setAttribute('em', $entityManager);
|
||||
|
||||
You now have to configure the script like:
|
||||
|
||||
[php]
|
||||
$helperSet = new \Symfony\Components\Console\Helper\HelperSet(array(
|
||||
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
|
||||
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
|
||||
));
|
||||
|
||||
## Console: No need for Mapping Paths anymore
|
||||
|
||||
In previous versions you had to specify the --from and --from-path options
|
||||
to show where your mapping paths are from the console. However this information
|
||||
is already known from the Mapping Driver configuration, so the requirement
|
||||
for this options were dropped.
|
||||
|
||||
Instead for each console command all the entities are loaded and to
|
||||
restrict the operation to one or more sub-groups you can use the --filter flag.
|
||||
|
||||
## AnnotationDriver is not a default mapping driver anymore
|
||||
|
||||
In conjunction with the recent changes to Console we realized that the
|
||||
annotations driver being a default metadata driver lead to lots of glue
|
||||
code in the console components to detect where entities lie and how to load
|
||||
them for batch updates like SchemaTool and other commands. However the
|
||||
annotations driver being a default driver does not really help that much
|
||||
anyways.
|
||||
|
||||
Therefore we decided to break backwards compability in this issue and drop
|
||||
the support for Annotations as Default Driver and require our users to
|
||||
specify the driver explicitly (which allows us to ask for the path to all
|
||||
entities).
|
||||
|
||||
If you are using the annotations metadata driver as default driver, you
|
||||
have to add the following lines to your bootstrap code:
|
||||
|
||||
$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities"));
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
|
||||
You have to specify the path to your entities as either string of a single
|
||||
path or array of multiple paths
|
||||
to your entities. This information will be used by all console commands to
|
||||
access all entities.
|
||||
|
||||
Xml and Yaml Drivers work as before!
|
||||
|
||||
|
||||
## New inversedBy attribute
|
||||
|
||||
It is now *mandatory* that the owning side of a bidirectional association specifies the
|
||||
@ -44,9 +113,22 @@ The "default" option for database column defaults has been removed. If desired,
|
||||
be implemented by using the columnDefinition attribute of the @Column annotation (or the approriate XML and YAML equivalents).
|
||||
Prefer PHP default values, if possible.
|
||||
|
||||
## Partial Objects
|
||||
## Selecting Partial Objects
|
||||
|
||||
xxx
|
||||
Querying for partial objects now has a new syntax. The old syntax to query for partial objects
|
||||
now has a different meaning. This is best illustrated by an example. If you previously
|
||||
had a DQL query like this:
|
||||
|
||||
[sql]
|
||||
SELECT u.id, u.name FROM User u
|
||||
|
||||
Since BETA1, simple state field path expressions in the select clause are used to select
|
||||
object fields as plain scalar values (something that was not possible before).
|
||||
To achieve the same result as previously (that is, a partial object with only id and name populated)
|
||||
you need to use the following, explicit syntax:
|
||||
|
||||
[sql]
|
||||
SELECT PARTIAL u.{id,name} FROM User u
|
||||
|
||||
## XML Mapping Driver
|
||||
|
||||
@ -77,3 +159,9 @@ by using the API on the `PreUpdateEventArgs` instance passed to the preUpdate li
|
||||
to the state of the entitys properties won't affect the database UPDATE statement anymore. This gives drastic
|
||||
performance benefits for the preUpdate event.
|
||||
|
||||
## Collection API
|
||||
|
||||
The Collection interface in the Common package has been updated with some missing methods
|
||||
that were present only on the default implementation, ArrayCollection. Custom collection
|
||||
implementations need to be updated to adhere to the updated interface.
|
||||
|
||||
|
@ -2,12 +2,15 @@
|
||||
|
||||
require_once 'Doctrine/Common/ClassLoader.php';
|
||||
|
||||
$classLoader = new \Doctrine\Common\ClassLoader('Doctrine');
|
||||
$classLoader = new \Doctrine\Common\ClassLoader('Doctrine', __DIR__ . '/../lib');
|
||||
$classLoader->register();
|
||||
|
||||
$classLoader = new \Doctrine\Common\ClassLoader('Symfony', __DIR__ . '/../lib/vendor');
|
||||
$classLoader->register();
|
||||
|
||||
$configFile = getcwd() . DIRECTORY_SEPARATOR . 'cli-config.php';
|
||||
|
||||
$configuration = null;
|
||||
$helperSet = null;
|
||||
if (file_exists($configFile)) {
|
||||
if ( ! is_readable($configFile)) {
|
||||
trigger_error(
|
||||
@ -17,15 +20,38 @@ if (file_exists($configFile)) {
|
||||
|
||||
require $configFile;
|
||||
|
||||
foreach ($GLOBALS as $configCandidate) {
|
||||
if ($configCandidate instanceof \Doctrine\Common\CLI\Configuration) {
|
||||
$configuration = $configCandidate;
|
||||
foreach ($GLOBALS as $helperSetCandidate) {
|
||||
if ($helperSetCandidate instanceof \Symfony\Components\Console\Helper\HelperSet) {
|
||||
$helperSet = $helperSetCandidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$configuration = ($configuration) ?: new \Doctrine\Common\CLI\Configuration();
|
||||
$helperSet = ($helperSet) ?: new \Symfony\Components\Console\Helper\HelperSet();
|
||||
|
||||
$cli = new \Doctrine\Common\CLI\CLIController($configuration);
|
||||
$cli->run($_SERVER['argv']);
|
||||
$cli = new \Symfony\Components\Console\Application('Doctrine Command Line Interface', Doctrine\Common\Version::VERSION);
|
||||
$cli->setCatchExceptions(true);
|
||||
$cli->setHelperSet($helperSet);
|
||||
$cli->addCommands(array(
|
||||
// DBAL Commands
|
||||
new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(),
|
||||
new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(),
|
||||
|
||||
// ORM Commands
|
||||
new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\RunDqlCommand(),
|
||||
|
||||
));
|
||||
$cli->run();
|
14
build.xml
14
build.xml
@ -142,16 +142,16 @@
|
||||
|
||||
<nativephpunit testfile="./tests/Doctrine/Tests/ORM/Performance/AllTests.php" testdirectory="./tests" haltonfailure="false" haltonerror="false" />
|
||||
<tstamp/>
|
||||
<svnlastrevision svnpath="${svn.path}" workingcopy="." propertyname="svn.lastrevision"/>
|
||||
<copy file="${build.dir}/logs/testsuites.xml" tofile="${log.archive.dir}/${svn.lastrevision}/log.xml" overwrite="true"/>
|
||||
<!--<svnlastrevision svnpath="${svn.path}" workingcopy="." propertyname="svn.lastrevision"/>-->
|
||||
<copy file="${build.dir}/logs/testsuites.xml" tofile="${log.archive.dir}/latest/log.xml" overwrite="true"/>
|
||||
|
||||
<if><equals arg1="${test.pmd_reports}" arg2="1" />
|
||||
<then>
|
||||
<exec command="${test.pdepend_exec} --jdepend-xml=${build.dir}/logs/jdepend.xml ./lib/Doctrine" />
|
||||
<exec command="${test.phpmd_exec} ./lib/Doctrine xml codesize --reportfile ${build.dir}/logs/phpmd.xml" />
|
||||
|
||||
<copy file="${build.dir}/logs/jdepend.xml" tofile="${log.archive.dir}/${svn.lastrevision}/jdepend.xml" overwrite="true"/>
|
||||
<copy file="${build.dir}/logs/phpmd.xml" tofile="${log.archive.dir}/${svn.lastrevision}/phpmd.xml" overwrite="true"/>
|
||||
<copy file="${build.dir}/logs/jdepend.xml" tofile="${log.archive.dir}/latest/jdepend.xml" overwrite="true"/>
|
||||
<copy file="${build.dir}/logs/phpmd.xml" tofile="${log.archive.dir}/latest/phpmd.xml" overwrite="true"/>
|
||||
</then>
|
||||
</if>
|
||||
</target>
|
||||
@ -163,7 +163,7 @@
|
||||
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/common/DoctrineCommon-${version}">
|
||||
<name>DoctrineCommon</name>
|
||||
<summary>Common Doctrine code</summary>
|
||||
<channel>pear.phpdoctrine.org</channel>
|
||||
<channel>pear.doctrine-project.org</channel>
|
||||
<description>The Doctrine Common package contains shared code between the other packages.</description>
|
||||
<lead user="jwage" name="Jonathan H. Wage" email="jonwage@gmail.com" />
|
||||
<lead user="guilhermeblanco" name="Guilherme Blanco" email="guilhermeblanco@gmail.com" />
|
||||
@ -182,7 +182,7 @@
|
||||
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/dbal/DoctrineDBAL-${version}">
|
||||
<name>DoctrineDBAL</name>
|
||||
<summary>Doctrine Database Abstraction Layer</summary>
|
||||
<channel>pear.phpdoctrine.org</channel>
|
||||
<channel>pear.doctrine-project.org</channel>
|
||||
<description>The Doctrine DBAL package is the database abstraction layer used to power the ORM package.</description>
|
||||
<lead user="jwage" name="Jonathan H. Wage" email="jonwage@gmail.com" />
|
||||
<lead user="guilhermeblanco" name="Guilherme Blanco" email="guilhermeblanco@gmail.com" />
|
||||
@ -201,7 +201,7 @@
|
||||
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/orm/DoctrineORM-${version}">
|
||||
<name>DoctrineORM</name>
|
||||
<summary>Doctrine Object Relationl Mapper</summary>
|
||||
<channel>pear.phpdoctrine.org</channel>
|
||||
<channel>pear.doctrine-project.org</channel>
|
||||
<description>The Doctrine ORM package is the primary package containing the object relational mapper.</description>
|
||||
<lead user="jwage" name="Jonathan H. Wage" email="jonwage@gmail.com" />
|
||||
<lead user="guilhermeblanco" name="Guilherme Blanco" email="guilhermeblanco@gmail.com" />
|
||||
|
@ -173,12 +173,19 @@
|
||||
<xs:complexType name="id">
|
||||
<xs:sequence>
|
||||
<xs:element name="generator" type="orm:generator" minOccurs="0" />
|
||||
<xs:element name="sequence-generator" type="orm:sequence-generator" minOccurs="0" maxOccurs="1" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="column" type="xs:NMTOKEN" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="sequence-generator">
|
||||
<xs:attribute name="sequence-name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="allocation-size" type="xs:integer" use="optional" default="1" />
|
||||
<xs:attribute name="initial-value" type="xs:integer" use="optional" default="1" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="inverse-join-columns">
|
||||
<xs:sequence>
|
||||
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />
|
||||
@ -217,7 +224,7 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="order-by-field">
|
||||
<xs:attribute name="field" type="XS:NMTOKEN" use="required" />
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="direction" type="orm:order-by-direction" default="ASC" />
|
||||
</xs:complexType>
|
||||
|
||||
@ -237,6 +244,7 @@
|
||||
<xs:attribute name="target-entity" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
||||
</xs:complexType>
|
||||
|
||||
@ -246,7 +254,7 @@
|
||||
<xs:element name="order-by" type="orm:order-by" minOccurs="0" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="target-entity" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
||||
@ -264,6 +272,7 @@
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
||||
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="one-to-one">
|
||||
@ -274,9 +283,10 @@
|
||||
<xs:element name="join-columns" type="orm:join-columns"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="target-entity" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
||||
</xs:complexType>
|
||||
|
@ -27,7 +27,8 @@ namespace Doctrine\Common\Annotations;
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -53,13 +54,28 @@ class Annotation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler for unknown property accessor in Annotation class.
|
||||
*
|
||||
* @param string $name Unknown property name
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
throw new \BadMethodCallException("Unknown annotation property '$name' on annotation '".get_class($this)."'.");
|
||||
throw new \BadMethodCallException(
|
||||
sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler for unknown property mutator in Annotation class.
|
||||
*
|
||||
* @param string $name Unkown property name
|
||||
* @param mixed $value Property value
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
throw new \BadMethodCallException("Unknown annotation property '$name' on annotation '".get_class($this)."'.");
|
||||
throw new \BadMethodCallException(
|
||||
sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
|
||||
);
|
||||
}
|
||||
}
|
@ -27,20 +27,32 @@ namespace Doctrine\Common\Annotations;
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class AnnotationException extends \Doctrine\Common\CommonException
|
||||
class AnnotationException extends \Exception
|
||||
{
|
||||
/**
|
||||
* Creates a new AnnotationException describing a Syntax error.
|
||||
*
|
||||
* @param string $message Exception message
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function syntaxError($message)
|
||||
{
|
||||
return new self('[Syntax Error] ' . $message);
|
||||
}
|
||||
|
||||
|
||||
public static function semanticalError($message)
|
||||
/**
|
||||
* Creates a new AnnotationException describing a Semantical error.
|
||||
*
|
||||
* @param string $message Exception message
|
||||
* @return AnnotationException
|
||||
*/
|
||||
public static function semanticalError($message)
|
||||
{
|
||||
return new self('[Semantical Error] ' . $message);
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -29,10 +27,7 @@ use \ReflectionClass,
|
||||
/**
|
||||
* A reader for docblock annotations.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
@ -46,7 +41,7 @@ class AnnotationReader
|
||||
* @var string
|
||||
* @static
|
||||
*/
|
||||
private static $CACHE_SALT = "@<Annot>";
|
||||
private static $CACHE_SALT = '@<Annot>';
|
||||
|
||||
/**
|
||||
* Annotations Parser
|
||||
@ -56,15 +51,14 @@ class AnnotationReader
|
||||
private $_parser;
|
||||
|
||||
/**
|
||||
* Cache machanism to store processed Annotations
|
||||
* Cache mechanism to store processed Annotations
|
||||
*
|
||||
* @var Doctrine\Common\Cache\Cache
|
||||
*/
|
||||
private $_cache;
|
||||
|
||||
/**
|
||||
* Constructor. Initializes a new AnnotationReader that uses the given
|
||||
* Cache provider.
|
||||
* Constructor. Initializes a new AnnotationReader that uses the given Cache provider.
|
||||
*
|
||||
* @param Cache $cache The cache provider to use. If none is provided, ArrayCache is used.
|
||||
*/
|
||||
@ -112,7 +106,7 @@ class AnnotationReader
|
||||
return $data;
|
||||
}
|
||||
|
||||
$annotations = $this->_parser->parse($class->getDocComment(), "class ".$class->getName());
|
||||
$annotations = $this->_parser->parse($class->getDocComment(), 'class ' . $class->getName());
|
||||
$this->_cache->save($cacheKey, $annotations, null);
|
||||
|
||||
return $annotations;
|
||||
@ -128,6 +122,7 @@ class AnnotationReader
|
||||
public function getClassAnnotation(ReflectionClass $class, $annotation)
|
||||
{
|
||||
$annotations = $this->getClassAnnotations($class);
|
||||
|
||||
return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
|
||||
}
|
||||
|
||||
@ -148,7 +143,7 @@ class AnnotationReader
|
||||
return $data;
|
||||
}
|
||||
|
||||
$context = "property ".$property->getDeclaringClass()->getName()."::\$".$property->getName();
|
||||
$context = 'property ' . $property->getDeclaringClass()->getName() . "::\$" . $property->getName();
|
||||
$annotations = $this->_parser->parse($property->getDocComment(), $context);
|
||||
$this->_cache->save($cacheKey, $annotations, null);
|
||||
|
||||
@ -165,6 +160,7 @@ class AnnotationReader
|
||||
public function getPropertyAnnotation(ReflectionProperty $property, $annotation)
|
||||
{
|
||||
$annotations = $this->getPropertyAnnotations($property);
|
||||
|
||||
return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
|
||||
}
|
||||
|
||||
@ -185,7 +181,7 @@ class AnnotationReader
|
||||
return $data;
|
||||
}
|
||||
|
||||
$context = "method ".$method->getDeclaringClass()->getName()."::".$method->getName()."()";
|
||||
$context = 'method ' . $method->getDeclaringClass()->getName() . '::' . $method->getName() . '()';
|
||||
$annotations = $this->_parser->parse($method->getDocComment(), $context);
|
||||
$this->_cache->save($cacheKey, $annotations, null);
|
||||
|
||||
@ -202,6 +198,7 @@ class AnnotationReader
|
||||
public function getMethodAnnotation(ReflectionMethod $method, $annotation)
|
||||
{
|
||||
$annotations = $this->getMethodAnnotations($method);
|
||||
|
||||
return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
|
||||
}
|
||||
}
|
@ -27,7 +27,8 @@ namespace Doctrine\Common\Annotations;
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -80,7 +81,7 @@ class Lexer extends \Doctrine\Common\Lexer
|
||||
$newVal = $this->_getNumeric($value);
|
||||
|
||||
// Checking numeric value
|
||||
if ($newVal !== false){
|
||||
if ($newVal !== false) {
|
||||
$value = $newVal;
|
||||
|
||||
return (strpos($value, '.') !== false || stripos($value, 'e') !== false)
|
||||
@ -93,16 +94,34 @@ class Lexer extends \Doctrine\Common\Lexer
|
||||
return self::T_STRING;
|
||||
} else {
|
||||
switch (strtolower($value)) {
|
||||
case '@': return self::T_AT;
|
||||
case ',': return self::T_COMMA;
|
||||
case '(': return self::T_OPEN_PARENTHESIS;
|
||||
case ')': return self::T_CLOSE_PARENTHESIS;
|
||||
case '{': return self::T_OPEN_CURLY_BRACES;
|
||||
case '@':
|
||||
return self::T_AT;
|
||||
|
||||
case ',':
|
||||
return self::T_COMMA;
|
||||
|
||||
case '(':
|
||||
return self::T_OPEN_PARENTHESIS;
|
||||
|
||||
case ')':
|
||||
return self::T_CLOSE_PARENTHESIS;
|
||||
|
||||
case '{':
|
||||
return self::T_OPEN_CURLY_BRACES;
|
||||
|
||||
case '}': return self::T_CLOSE_CURLY_BRACES;
|
||||
case '=': return self::T_EQUALS;
|
||||
case '\\': return self::T_NAMESPACE_SEPARATOR;
|
||||
case 'true': return self::T_TRUE;
|
||||
case 'false': return self::T_FALSE;
|
||||
case '=':
|
||||
return self::T_EQUALS;
|
||||
|
||||
case '\\':
|
||||
return self::T_NAMESPACE_SEPARATOR;
|
||||
|
||||
case 'true':
|
||||
return self::T_TRUE;
|
||||
|
||||
case 'false':
|
||||
return self::T_FALSE;
|
||||
|
||||
default:
|
||||
if (ctype_alpha($value[0]) || $value[0] === '_') {
|
||||
return self::T_IDENTIFIER;
|
||||
@ -126,6 +145,7 @@ class Lexer extends \Doctrine\Common\Lexer
|
||||
if ( ! is_scalar($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checking for valid numeric numbers: 1.234, -1.234e-2
|
||||
if (is_numeric($value)) {
|
||||
return $value;
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -24,14 +22,11 @@ namespace Doctrine\Common\Annotations;
|
||||
/**
|
||||
* A simple parser for docblock annotations.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class Parser
|
||||
{
|
||||
@ -173,9 +168,10 @@ class Parser
|
||||
$message .= "'{$token['value']}' at position {$token['position']}";
|
||||
}
|
||||
|
||||
if(strlen($this->_context)) {
|
||||
$message .= ' in '.$this->_context;
|
||||
if (strlen($this->_context)) {
|
||||
$message .= ' in ' . $this->_context;
|
||||
}
|
||||
|
||||
$message .= '.';
|
||||
|
||||
throw AnnotationException::syntaxError($message);
|
||||
@ -236,7 +232,7 @@ class Parser
|
||||
$nameParts[] = $this->_lexer->token['value'];
|
||||
}
|
||||
|
||||
// Effectively pick the name of class (append default NS if none, grab from NS alias, etc)
|
||||
// Effectively pick the name of the class (append default NS if none, grab from NS alias, etc)
|
||||
if (count($nameParts) == 1) {
|
||||
if (strpos($nameParts[0], ':')) {
|
||||
list ($alias, $simpleName) = explode(':', $nameParts[0]);
|
||||
@ -250,7 +246,7 @@ class Parser
|
||||
|
||||
// Is it really an annotation class?
|
||||
if (
|
||||
(! $this->_isNestedAnnotation && $this->_lexer->lookahead != null &&
|
||||
( ! $this->_isNestedAnnotation && $this->_lexer->lookahead != null &&
|
||||
! $this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS) &&
|
||||
! $this->_lexer->isNextToken(Lexer::T_AT)) ||
|
||||
! class_exists($name, false)
|
||||
@ -411,6 +407,7 @@ class Parser
|
||||
|
||||
foreach ($values as $value) {
|
||||
list ($key, $val) = $value;
|
||||
|
||||
if ($key !== null) {
|
||||
$array[$key] = $val;
|
||||
} else {
|
||||
|
@ -1,234 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI;
|
||||
|
||||
use Doctrine\Common\Util\Inflector;
|
||||
|
||||
/**
|
||||
* Abstract CLI Namespace class
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
abstract class AbstractNamespace
|
||||
{
|
||||
/**
|
||||
* @var Configuration CLI Configuration instance
|
||||
*/
|
||||
private $_configuration = null;
|
||||
|
||||
/**
|
||||
* @var AbstractPrinter CLI Printer instance
|
||||
*/
|
||||
private $_printer = null;
|
||||
|
||||
/**
|
||||
* @var AbstractNamespace CLI Namespace instance
|
||||
*/
|
||||
private $_parentNamespace = null;
|
||||
|
||||
/**
|
||||
* @var array Available namespaces
|
||||
*/
|
||||
private $_namespaces = array();
|
||||
|
||||
/**
|
||||
* Add a single namespace to CLI.
|
||||
* Example of inclusion support to a single namespace:
|
||||
*
|
||||
* [php]
|
||||
* $cliOrmNamespace->addNamespace('my-custom-namespace');
|
||||
*
|
||||
* @param string $name CLI Namespace name
|
||||
*
|
||||
* @return CliController This object instance
|
||||
*/
|
||||
public function addNamespace($name)
|
||||
{
|
||||
$name = self::formatName($name);
|
||||
|
||||
if ($this->hasNamespace($name)) {
|
||||
throw CLIException::cannotOverrideNamespace($name);
|
||||
}
|
||||
|
||||
return $this->overrideNamespace($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides a namespace to CLI.
|
||||
* Example of inclusion support to a single namespace:
|
||||
*
|
||||
* [php]
|
||||
* $cli->overrideNamespace('orm');
|
||||
*
|
||||
* @param string $name CLI Namespace name
|
||||
*
|
||||
* @return AbstractNamespace Newly created CLI Namespace
|
||||
*/
|
||||
public function overrideNamespace($name)
|
||||
{
|
||||
$taskNamespace = new TaskNamespace($name);
|
||||
|
||||
$taskNamespace->setParentNamespace($this);
|
||||
$taskNamespace->setPrinter($this->_printer);
|
||||
$taskNamespace->setConfiguration($this->_configuration);
|
||||
|
||||
$this->_namespaces[$taskNamespace->getName()] = $taskNamespace;
|
||||
|
||||
return $taskNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve CLI Namespace.
|
||||
* Example of usage:
|
||||
*
|
||||
* [php]
|
||||
* $cliOrmNamespace = $cli->getNamespace('ORM');
|
||||
*
|
||||
* @param string $name CLI Namespace name
|
||||
*
|
||||
* @return TaskNamespace CLI Namespace
|
||||
*/
|
||||
public function getNamespace($name)
|
||||
{
|
||||
$name = self::formatName($name);
|
||||
|
||||
return isset($this->_namespaces[$name])
|
||||
? $this->_namespaces[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check existance of a CLI Namespace
|
||||
*
|
||||
* @param string CLI Namespace name
|
||||
*
|
||||
* @return boolean TRUE if namespace if defined, false otherwise
|
||||
*/
|
||||
public function hasNamespace($name)
|
||||
{
|
||||
return ($this->getNamespace($name) !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the parent CLI Namespace
|
||||
*
|
||||
* @return AbstractNamespace
|
||||
*/
|
||||
public function setParentNamespace(AbstractNamespace $namespace)
|
||||
{
|
||||
$this->_parentNamespace = $namespace;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves currently parent CLI Namespace
|
||||
*
|
||||
* @return AbstractNamespace
|
||||
*/
|
||||
public function getParentNamespace()
|
||||
{
|
||||
return $this->_parentNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all defined CLI Tasks
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAvailableTasks()
|
||||
{
|
||||
$tasks = array();
|
||||
|
||||
foreach ($this->_namespaces as $namespace) {
|
||||
$tasks = array_merge($tasks, $namespace->getAvailableTasks());
|
||||
}
|
||||
|
||||
return $tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the CLI Output Printer
|
||||
*
|
||||
* @param AbstractPrinter $printer CLI Output Printer
|
||||
*
|
||||
* @return AbstractNamespace
|
||||
*/
|
||||
public function setPrinter(Printers\AbstractPrinter $printer = null)
|
||||
{
|
||||
$this->_printer = $printer ?: new Printers\AnsiColorPrinter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves currently used CLI Output Printer
|
||||
*
|
||||
* @return AbstractPrinter
|
||||
*/
|
||||
public function getPrinter()
|
||||
{
|
||||
return $this->_printer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the CLI Configuration
|
||||
*
|
||||
* #param Configuration $configuration CLI Configuration
|
||||
*
|
||||
* @return AbstractNamespace
|
||||
*/
|
||||
public function setConfiguration(Configuration $config)
|
||||
{
|
||||
$this->_configuration = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves currently used CLI Configuration
|
||||
*
|
||||
* @return Configuration
|
||||
*/
|
||||
public function getConfiguration()
|
||||
{
|
||||
return $this->_configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the CLI Namespace name into a camel-cased name
|
||||
*
|
||||
* @param string $name CLI Namespace name
|
||||
*
|
||||
* @return string Formatted CLI Namespace name
|
||||
*/
|
||||
public static function formatName($name)
|
||||
{
|
||||
return Inflector::classify($name);
|
||||
}
|
||||
}
|
@ -1,306 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI;
|
||||
|
||||
/**
|
||||
* Generic CLI Controller of Tasks execution
|
||||
*
|
||||
* To include a new Task support, create a task:
|
||||
*
|
||||
* [php]
|
||||
* class MyProject\Tools\CLI\Tasks\MyTask extends Doctrine\ORM\Tools\CLI\Tasks\AbstractTask
|
||||
* {
|
||||
* public function run();
|
||||
* public function basicHelp();
|
||||
* public function extendedHelp();
|
||||
* public function validate();
|
||||
* }
|
||||
*
|
||||
* And then, load the namespace assoaicated an include the support to it in your command-line script:
|
||||
*
|
||||
* [php]
|
||||
* $cli = new Doctrine\Common\CLI\CLIController();
|
||||
* $cliNS = $cli->getNamespace('custom');
|
||||
* $cliNS->addTask('myTask', 'MyProject\Tools\CLI\Tasks\MyTask');
|
||||
*
|
||||
* To execute, just type any classify-able name:
|
||||
*
|
||||
* $ cli.php custom:my-task
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class CLIController extends AbstractNamespace
|
||||
{
|
||||
/**
|
||||
* The CLI processor of tasks
|
||||
*
|
||||
* @param Configuration $config
|
||||
* @param AbstractPrinter $printer CLI Output printer
|
||||
*/
|
||||
public function __construct(Configuration $config, Printers\AbstractPrinter $printer = null)
|
||||
{
|
||||
$this->setPrinter($printer);
|
||||
$this->setConfiguration($config);
|
||||
|
||||
// Include core namespaces of tasks
|
||||
$ns = 'Doctrine\Common\CLI\Tasks';
|
||||
$this->addNamespace('Core')
|
||||
->addTask('help', $ns . '\HelpTask')
|
||||
->addTask('version', $ns . '\VersionTask');
|
||||
|
||||
$ns = 'Doctrine\ORM\Tools\CLI\Tasks';
|
||||
$this->addNamespace('Orm')
|
||||
->addTask('clear-cache', $ns . '\ClearCacheTask')
|
||||
->addTask('convert-mapping', $ns . '\ConvertMappingTask')
|
||||
->addTask('ensure-production-settings', $ns . '\EnsureProductionSettingsTask')
|
||||
->addTask('generate-proxies', $ns . '\GenerateProxiesTask')
|
||||
->addTask('run-dql', $ns . '\RunDqlTask')
|
||||
->addTask('schema-tool', $ns . '\SchemaToolTask')
|
||||
->addTask('version', $ns . '\VersionTask')
|
||||
->addTask('convert-d1-schema', $ns . '\ConvertDoctrine1SchemaTask')
|
||||
->addTask('generate-entities', $ns . '\GenerateEntitiesTask')
|
||||
->addTask('generate-repositories', $ns . '\GenerateRepositoriesTask');
|
||||
|
||||
$ns = 'Doctrine\DBAL\Tools\CLI\Tasks';
|
||||
$this->addNamespace('Dbal')
|
||||
->addTask('run-sql', $ns . '\RunSqlTask')
|
||||
->addTask('version', $ns . '\VersionTask');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single task to CLI Core Namespace. This method acts as a delegate.
|
||||
* Example of inclusion support to a single task:
|
||||
*
|
||||
* [php]
|
||||
* $cli->addTask('my-custom-task', 'MyProject\CLI\Tasks\MyCustomTask');
|
||||
*
|
||||
* @param string $name CLI Task name
|
||||
* @param string $class CLI Task class (FQCN - Fully Qualified Class Name)
|
||||
*
|
||||
* @return CLIController This object instance
|
||||
*/
|
||||
public function addTask($name, $class)
|
||||
{
|
||||
$this->getNamespace('Core')->addTask($name, $class);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processor of CLI Tasks. Handles multiple task calls, instantiate
|
||||
* respective classes and run them.
|
||||
*
|
||||
* @param array $args CLI Arguments
|
||||
*/
|
||||
public function run($args = array())
|
||||
{
|
||||
// Remove script file argument
|
||||
$scriptFile = array_shift($args);
|
||||
|
||||
// If not arguments are defined, include "help"
|
||||
if (empty($args)) {
|
||||
array_unshift($args, 'Core:Help');
|
||||
}
|
||||
|
||||
// Process all sent arguments
|
||||
$args = $this->_processArguments($args);
|
||||
|
||||
try {
|
||||
$this->getPrinter()->writeln('Doctrine Command Line Interface' . PHP_EOL, 'HEADER');
|
||||
|
||||
// Handle possible multiple tasks on a single command
|
||||
foreach($args as $taskData) {
|
||||
$taskName = $taskData['name'];
|
||||
$taskArguments = $taskData['args'];
|
||||
|
||||
$this->runTask($taskName, $taskArguments);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
$message = $taskName . ' => ' . $e->getMessage();
|
||||
|
||||
if (isset($taskArguments['trace']) && $taskArguments['trace']) {
|
||||
$message .= PHP_EOL . PHP_EOL . $e->getTraceAsString();
|
||||
}
|
||||
|
||||
$this->getPrinter()->writeln($message, 'ERROR');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a given CLI Task
|
||||
*
|
||||
* @param atring $name CLI Task name
|
||||
* @param array $args CLI Arguments
|
||||
*/
|
||||
public function runTask($name, $args = array())
|
||||
{
|
||||
// Retrieve namespace name, task name and arguments
|
||||
$taskPath = explode(':', $name);
|
||||
|
||||
// Find the correct namespace where the task is defined
|
||||
$taskName = array_pop($taskPath);
|
||||
$taskNamespace = $this->_retrieveTaskNamespace($taskPath);
|
||||
|
||||
$taskNamespace->runTask($taskName, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes arguments and returns a structured hierachy.
|
||||
* Example:
|
||||
*
|
||||
* cli.php foo -abc --option=value bar --option -a=value --optArr=value1,value2
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* array(
|
||||
* 0 => array(
|
||||
* 'name' => 'foo',
|
||||
* 'args' => array(
|
||||
* 'a' => true,
|
||||
* 'b' => true,
|
||||
* 'c' => true,
|
||||
* 'option' => 'value',
|
||||
* ),
|
||||
* ),
|
||||
* 1 => array(
|
||||
* 'name' => 'bar',
|
||||
* 'args' => array(
|
||||
* 'option' => true,
|
||||
* 'a' => 'value',
|
||||
* 'optArr' => array(
|
||||
* 'value1', 'value2'
|
||||
* ),
|
||||
* ),
|
||||
* ),
|
||||
* )
|
||||
*
|
||||
* Based on implementation of Patrick Fisher <patrick@pwfisher.com> available at:
|
||||
* http://pwfisher.com/nucleus/index.php?itemid=45
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _processArguments($args = array())
|
||||
{
|
||||
$flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE;
|
||||
$regex = '/\s*[,]?\s*"([^"]*)"|\s*[,]?\s*([^,]*)/i';
|
||||
$preparedArgs = array();
|
||||
$out = & $preparedArgs;
|
||||
|
||||
foreach ($args as $arg){
|
||||
// --foo --bar=baz
|
||||
if (substr($arg, 0, 2) == '--'){
|
||||
$eqPos = strpos($arg, '=');
|
||||
|
||||
// --foo
|
||||
if ($eqPos === false){
|
||||
$key = substr($arg, 2);
|
||||
$out[$key] = isset($out[$key]) ? $out[$key] : true;
|
||||
// --bar=baz
|
||||
} else {
|
||||
$key = substr($arg, 2, $eqPos - 2);
|
||||
$value = substr($arg, $eqPos + 1);
|
||||
$value = (strpos($value, ' ') !== false) ? $value : array_values(array_filter(
|
||||
explode(',', $value), function ($v) { return trim($v) != ''; }
|
||||
));
|
||||
$out[$key] = ( ! is_array($value) || empty($value) || (is_array($value) && count($value) > 1))
|
||||
? $value : $value[0];
|
||||
}
|
||||
// -k=value -abc
|
||||
} else if (substr($arg, 0, 1) == '-'){
|
||||
// -k=value
|
||||
if (substr($arg, 2, 1) == '='){
|
||||
$key = substr($arg, 1, 1);
|
||||
$value = substr($arg, 3);
|
||||
$value = (strpos($value, ' ') !== false) ? $value : array_values(array_filter(
|
||||
explode(',', $value), function ($v) { return trim($v) != ''; }
|
||||
));
|
||||
$out[$key] = ( ! is_array($value) || (is_array($value) && count($value) > 1))
|
||||
? $value : $value[0];
|
||||
// -abc
|
||||
} else {
|
||||
$chars = str_split(substr($arg, 1));
|
||||
|
||||
foreach ($chars as $char){
|
||||
$key = $char;
|
||||
$out[$key] = isset($out[$key]) ? $out[$key] : true;
|
||||
}
|
||||
}
|
||||
// plain-arg
|
||||
} else {
|
||||
$key = count($preparedArgs);
|
||||
$preparedArgs[$key] = array(
|
||||
'name' => $arg,
|
||||
'args' => array()
|
||||
);
|
||||
$out = & $preparedArgs[$key]['args'];
|
||||
}
|
||||
}
|
||||
|
||||
return $preparedArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the correct namespace given a namespace path
|
||||
*
|
||||
* @param array $namespacePath CLI Namespace path
|
||||
*
|
||||
* @return AbstractNamespace
|
||||
*/
|
||||
private function _retrieveTaskNamespace($namespacePath)
|
||||
{
|
||||
$taskNamespace = $this;
|
||||
$currentNamespacePath = '';
|
||||
|
||||
// Consider possible missing namespace (ie. "help") and forward to "core"
|
||||
if (count($namespacePath) == 0) {
|
||||
$namespacePath = array('Core');
|
||||
}
|
||||
|
||||
// Loop through each namespace
|
||||
foreach ($namespacePath as $namespaceName) {
|
||||
$taskNamespace = $taskNamespace->getNamespace($namespaceName);
|
||||
|
||||
// If the given namespace returned "null", throw exception
|
||||
if ($taskNamespace === null) {
|
||||
throw CLIException::namespaceDoesNotExist($namespaceName, $currentNamespacePath);
|
||||
}
|
||||
|
||||
$currentNamespacePath = (( ! empty($currentNamespacePath)) ? ':' : '')
|
||||
. $taskNamespace->getName();
|
||||
}
|
||||
|
||||
return $taskNamespace;
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI;
|
||||
|
||||
/**
|
||||
* CLI Configuration class
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class Configuration
|
||||
{
|
||||
/**
|
||||
* @var array Configuration attributes
|
||||
*/
|
||||
private $_attributes = array();
|
||||
|
||||
/**
|
||||
* Defines a new configuration attribute
|
||||
*
|
||||
* @param string $name Attribute name
|
||||
* @param mixed $value Attribute value
|
||||
*
|
||||
* @return Configuration This object instance
|
||||
*/
|
||||
public function setAttribute($name, $value = null)
|
||||
{
|
||||
$this->_attributes[$name] = $value;
|
||||
|
||||
if ($value === null) {
|
||||
unset($this->_attributes[$name]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a configuration attribute
|
||||
*
|
||||
* @param string $name Attribute name
|
||||
*
|
||||
* @return mixed Attribute value
|
||||
*/
|
||||
public function getAttribute($name)
|
||||
{
|
||||
return isset($this->_attributes[$name])
|
||||
? $this->_attributes[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if configuration attribute is defined
|
||||
*
|
||||
* @param string $name Attribute name
|
||||
*
|
||||
* @return boolean TRUE if attribute exists, FALSE otherwise
|
||||
*/
|
||||
public function hasAttribute($name)
|
||||
{
|
||||
return isset($this->_attributes[$name]);
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI;
|
||||
|
||||
/**
|
||||
* CLI Option definition
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class Option
|
||||
{
|
||||
/** @var string Option name */
|
||||
private $_name;
|
||||
|
||||
/** @var string Option default value */
|
||||
private $_defaultValue;
|
||||
|
||||
/** @var string Option description */
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* Constructs a CLI Option
|
||||
*
|
||||
* @param string Option name
|
||||
* @param integer Option type
|
||||
* @param string Option description
|
||||
*/
|
||||
public function __construct($name, $defaultValue, $description)
|
||||
{
|
||||
$this->_name = $name;
|
||||
$this->_defaultValue = $defaultValue;
|
||||
$this->_description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Option name
|
||||
*
|
||||
* @return string Option name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Option default value
|
||||
*
|
||||
* @return mixed Option default value
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
return $this->_defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Option description
|
||||
*
|
||||
* @return string Option description
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->_description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the Option instance into a string representation
|
||||
*
|
||||
* @return string CLI Option representation in string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$defaultValue = ( ! is_null($this->_defaultValue))
|
||||
? '=' . (is_array($this->_defaultValue) ? implode(',', $this->_defaultValue) : $this->_defaultValue)
|
||||
: '';
|
||||
|
||||
return '--' . $this->_name . $defaultValue;
|
||||
}
|
||||
}
|
@ -1,482 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI;
|
||||
|
||||
use Doctrine\Common\CLI\Printers\AbstractPrinter;
|
||||
|
||||
/**
|
||||
* CLI Option Group definition
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class OptionGroup
|
||||
{
|
||||
/* CLI Option Group CARDINALITY */
|
||||
/**
|
||||
* Defines the cardinality 0..N to CLI Option Group.
|
||||
* This means options in this group are optional and you can
|
||||
* define more than one CLI Option on a single command.
|
||||
*/
|
||||
const CARDINALITY_0_N = 0; // [...] [...] [...]
|
||||
|
||||
/**
|
||||
* Defines the cardinality 0..1 to CLI Option Group.
|
||||
* This means all options in this group are optional and you can
|
||||
* define only one CLI Option on a single command.
|
||||
*/
|
||||
const CARDINALITY_0_1 = 1; // [...|...|...]
|
||||
|
||||
/**
|
||||
* Defines the cardinality 1..1 to CLI Option Group.
|
||||
* This means all options in this group are required and you must
|
||||
* define only one CLI Option on a single command.
|
||||
*/
|
||||
const CARDINALITY_1_1 = 2; // (...|...|...)
|
||||
|
||||
/**
|
||||
* Defines the cardinality 1..N to CLI Option Group.
|
||||
* This means all options in this group are required and you must
|
||||
* define at least one CLI Option on a single command.
|
||||
*/
|
||||
const CARDINALITY_1_N = 3; // (... ... ...)
|
||||
|
||||
/**
|
||||
* Defines the cardinality N..N to CLI Option Group.
|
||||
* This means all options in this group are required and you must
|
||||
* define all CLI Options on a single command.
|
||||
*/
|
||||
const CARDINALITY_N_N = 4; // ... ... ...
|
||||
|
||||
/**
|
||||
* Defines the cardinality M..N to CLI Option Group.
|
||||
* This means all options in this group are either required or
|
||||
* optional and you can CLI Options on a single command.
|
||||
* This is the option to skip CLI Option validation.
|
||||
*/
|
||||
const CARDINALITY_M_N = 5; // ... ... ...
|
||||
|
||||
|
||||
/** @var integer Option Group cardinality */
|
||||
private $_cadinality;
|
||||
|
||||
/** @var array Option Group list of CLI Options */
|
||||
private $_options;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new CLI Option Group
|
||||
*
|
||||
* @param integer Option Group cardinality
|
||||
* @param array CLI Option Group options
|
||||
*/
|
||||
public function __construct($cardinality, $options = array())
|
||||
{
|
||||
$this->_cardinality = $cardinality;
|
||||
$this->_options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Option Group cardinality
|
||||
*
|
||||
* @return integer Option Group cardinality
|
||||
*/
|
||||
public function getCardinality()
|
||||
{
|
||||
return $this->_cardinality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Option Group options
|
||||
*
|
||||
* @return array Option Group options
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans the CLI Options inside this CLI Option Group
|
||||
*
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->_options = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes a new CLI Option to the Option Group
|
||||
*
|
||||
* @param Option|OptionGroup CLI Option or CLI Option Group
|
||||
* @return OptionGroup This object instance
|
||||
*/
|
||||
public function addOption($option)
|
||||
{
|
||||
if ($option instanceof Option || $option instanceof OptionGroup) {
|
||||
$this->_options[] = $option;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the CLI Option Group into a single line representation
|
||||
*
|
||||
* @param AbstractPrinter CLI Printer
|
||||
* @return string Single line string representation of CLI Option Group
|
||||
*/
|
||||
public function formatPlain(AbstractPrinter $printer)
|
||||
{
|
||||
$numOptions = count($this->_options);
|
||||
|
||||
if ($numOptions == 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$style = $this->_getGroupOptionStyle();
|
||||
$shouldDisplayExtras = (
|
||||
$numOptions > 1 ||
|
||||
$this->_cardinality == self::CARDINALITY_0_1 ||
|
||||
$this->_cardinality == self::CARDINALITY_0_N
|
||||
);
|
||||
|
||||
$str = ($shouldDisplayExtras) ? $printer->format($this->_startGroupDeclaration(), $style) : '';
|
||||
|
||||
// Loop through all CLI Options defined in OptionGroup
|
||||
for ($i = 0; $i < $numOptions; $i++) {
|
||||
$option = $this->_options[$i];
|
||||
|
||||
// Check for possible recursive OptionGroup
|
||||
if ($option instanceof OptionGroup) {
|
||||
// Simple increase nesting level by calling format recursively
|
||||
$str .= $option->formatPlain($printer);
|
||||
} else {
|
||||
// Expose the option formatted
|
||||
$str .= $printer->format((string) $option, $style);
|
||||
}
|
||||
|
||||
// Possibly append content if needed
|
||||
if ($i < $numOptions - 1) {
|
||||
$str .= $printer->format($this->_separatorGroupDeclaration(), $style);
|
||||
}
|
||||
}
|
||||
|
||||
$str .= ($shouldDisplayExtras) ? $printer->format($this->_endGroupDeclaration(), $style) : '';
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Defines the start Option Group declaration string
|
||||
*
|
||||
* @return string Start Option Group declaration string
|
||||
*/
|
||||
private function _startGroupDeclaration()
|
||||
{
|
||||
$str = '';
|
||||
|
||||
// Inspect cardinality of OptionGroup
|
||||
switch ($this->_cardinality) {
|
||||
case self::CARDINALITY_0_1:
|
||||
case self::CARDINALITY_0_N:
|
||||
$str .= '[';
|
||||
break;
|
||||
|
||||
case self::CARDINALITY_1_1:
|
||||
case self::CARDINALITY_1_N:
|
||||
$str .= '(';
|
||||
break;
|
||||
|
||||
case self::CARDINALITY_N_N:
|
||||
case self::CARDINALITY_M_N:
|
||||
default:
|
||||
// Does nothing
|
||||
break;
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Defines the separator Option Group declaration string
|
||||
*
|
||||
* @return string Separator Option Group declaration string
|
||||
*/
|
||||
private function _separatorGroupDeclaration()
|
||||
{
|
||||
$str = '';
|
||||
|
||||
// Inspect cardinality of OptionGroup
|
||||
switch ($this->_cardinality) {
|
||||
case self::CARDINALITY_0_1:
|
||||
case self::CARDINALITY_1_1:
|
||||
$str .= ' | ';
|
||||
break;
|
||||
|
||||
case self::CARDINALITY_1_N:
|
||||
case self::CARDINALITY_N_N:
|
||||
case self::CARDINALITY_M_N:
|
||||
$str .= ' ';
|
||||
break;
|
||||
|
||||
case self::CARDINALITY_0_N:
|
||||
$str .= '] [';
|
||||
break;
|
||||
|
||||
default:
|
||||
// Does nothing
|
||||
break;
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Defines the end Option Group declaration string
|
||||
*
|
||||
* @return string End Option Group declaration string
|
||||
*/
|
||||
private function _endGroupDeclaration()
|
||||
{
|
||||
$str = '';
|
||||
|
||||
// Inspect cardinality of OptionGroup
|
||||
switch ($this->_cardinality) {
|
||||
case self::CARDINALITY_0_1:
|
||||
case self::CARDINALITY_0_N:
|
||||
$str .= ']';
|
||||
break;
|
||||
|
||||
case self::CARDINALITY_1_1:
|
||||
case self::CARDINALITY_1_N:
|
||||
$str .= ')';
|
||||
break;
|
||||
|
||||
case self::CARDINALITY_N_N:
|
||||
case self::CARDINALITY_M_N:
|
||||
default:
|
||||
// Does nothing
|
||||
break;
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Retrieve the Option Group style based on defined cardinality
|
||||
*
|
||||
* @return string CLI Style string representation
|
||||
*/
|
||||
private function _getGroupOptionStyle()
|
||||
{
|
||||
$style = 'NONE';
|
||||
|
||||
// Inspect cardinality of OptionGroup
|
||||
switch ($this->_cardinality) {
|
||||
case self::CARDINALITY_0_1:
|
||||
case self::CARDINALITY_0_N:
|
||||
$style = 'OPT_ARG';
|
||||
break;
|
||||
|
||||
case self::CARDINALITY_1_1:
|
||||
case self::CARDINALITY_1_N:
|
||||
case self::CARDINALITY_N_N:
|
||||
case self::CARDINALITY_M_N:
|
||||
$style = 'REQ_ARG';
|
||||
break;
|
||||
|
||||
default:
|
||||
// Does nothing
|
||||
break;
|
||||
}
|
||||
|
||||
return $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the CLI Option Group into a multi-line list with respective description
|
||||
*
|
||||
* @param AbstractPrinter CLI Printer
|
||||
* @return string Multi-line string representation of CLI Option Group
|
||||
*/
|
||||
public function formatWithDescription(AbstractPrinter $printer)
|
||||
{
|
||||
$numOptions = count($this->_options);
|
||||
|
||||
if ($numOptions == 0) {
|
||||
return 'No available options' . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
|
||||
$str = '';
|
||||
|
||||
// Get list of required and optional and max length options
|
||||
list(
|
||||
$requiredOptions, $optionalOptions, $maxOptionLength
|
||||
) = $this->_getOrganizedOptions(
|
||||
$this->_options, $this->_cardinality, 0
|
||||
);
|
||||
|
||||
// Array-unique options
|
||||
$requiredOptions = array_unique($requiredOptions);
|
||||
$optionalOptions = array_unique($optionalOptions);
|
||||
|
||||
// TODO Sort options alphabetically
|
||||
|
||||
// Displaying required options
|
||||
for ($i = 0, $l = count($requiredOptions); $i < $l; $i++) {
|
||||
$str .= $this->_displayOptionWithDescription(
|
||||
$printer, $requiredOptions[$i], 'REQ_ARG', $maxOptionLength
|
||||
);
|
||||
|
||||
// Include extra line breaks between options
|
||||
$str .= PHP_EOL . PHP_EOL;
|
||||
}
|
||||
|
||||
// Displaying optional options
|
||||
for ($i = 0, $l = count($optionalOptions); $i < $l; $i++) {
|
||||
$str .= $this->_displayOptionWithDescription(
|
||||
$printer, $optionalOptions[$i], 'OPT_ARG', $maxOptionLength
|
||||
);
|
||||
|
||||
// Include extra line breaks between options
|
||||
$str .= PHP_EOL . PHP_EOL;
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Organize the Options into arrays of required and optional options.
|
||||
* Also define the maximum length of CLI Options.
|
||||
*
|
||||
* @param array Array of CLI Option or CLI Option Group
|
||||
* @param integer Current CLI OptionGroup cardinality
|
||||
* @param integer Maximum length of CLI Options
|
||||
* @return array Array containing 3 indexes: required options, optional
|
||||
* options and maximum length of CLI Options
|
||||
*/
|
||||
private function _getOrganizedOptions($options, $cardinality, $maxColumn)
|
||||
{
|
||||
// Calculate maximum length and also organize the
|
||||
// options into required and optional ones
|
||||
$numOptions = count($options);
|
||||
$requiredOptions = array();
|
||||
$optionalOptions = array();
|
||||
|
||||
for ($i = 0; $i < $numOptions; $i++) {
|
||||
$option = $options[$i];
|
||||
|
||||
// Check for possible recursive OptionGroup
|
||||
if ($option instanceof OptionGroup) {
|
||||
// Initialize OptionGroup options
|
||||
$groupRequiredOptions = array();
|
||||
$groupOptionalOptions = array();
|
||||
|
||||
// Get nested information
|
||||
list(
|
||||
$groupRequiredOptions, $groupOptionalOptions, $maxGroupColumn
|
||||
) = $this->_getOrganizedOptions(
|
||||
$option->getOptions(), $option->getCardinality(), $maxColumn
|
||||
);
|
||||
|
||||
// Merge nested required and optional options
|
||||
$requiredOptions = array_merge($requiredOptions, $groupRequiredOptions);
|
||||
$optionalOptions = array_merge($optionalOptions, $groupOptionalOptions);
|
||||
|
||||
// If OptionGroup length is bigger than the current maximum, update
|
||||
if ($maxColumn < $maxGroupColumn) {
|
||||
$maxColumn = $maxGroupColumn;
|
||||
}
|
||||
} else {
|
||||
// Cardinality defines between optional or required options
|
||||
switch ($cardinality) {
|
||||
case self::CARDINALITY_0_1:
|
||||
case self::CARDINALITY_0_N:
|
||||
$optionalOptions[] = $option;
|
||||
break;
|
||||
|
||||
case self::CARDINALITY_1_1:
|
||||
case self::CARDINALITY_1_N:
|
||||
case self::CARDINALITY_N_N:
|
||||
case self::CARDINALITY_M_N:
|
||||
$requiredOptions[] = $option;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Does nothing
|
||||
break;
|
||||
}
|
||||
|
||||
// Build Option string
|
||||
$optionStr = (string) $option;
|
||||
|
||||
// + 2 = aditional spaces after option
|
||||
$length = strlen($optionStr) + 2;
|
||||
|
||||
if ($maxColumn < $length) {
|
||||
$maxColumn = $length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($requiredOptions, $optionalOptions, $maxColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Formats the CLI Option and also include the description
|
||||
*
|
||||
* @param AbstractPrinter CLI Printer
|
||||
* @param Option CLI Option to be formatted
|
||||
* @param string CLI Style string representation
|
||||
* @param integer Maximum CLI Option length
|
||||
* @return string Formats the current CLI Option line(s)
|
||||
*/
|
||||
private function _displayOptionWithDescription($printer, $option, $style, $maxOptionLength)
|
||||
{
|
||||
// Expose the option formatted
|
||||
$optionStr = (string) $option;
|
||||
|
||||
// Format Option string
|
||||
$str = $printer->format($optionStr, $style);
|
||||
|
||||
// Include missing spaces
|
||||
$str .= str_repeat(' ', $maxOptionLength - strlen($optionStr));
|
||||
|
||||
// Calculate and display description
|
||||
$str .= str_replace(
|
||||
PHP_EOL, PHP_EOL . str_repeat(' ', $maxOptionLength), $option->getDescription()
|
||||
);
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
@ -1,190 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI\Printers;
|
||||
|
||||
use Doctrine\Common\CLI\Style;
|
||||
|
||||
/**
|
||||
* CLI Output Printer.
|
||||
* Abstract class responsable to provide basic methods to support output
|
||||
* styling and excerpt limited by output margin.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
abstract class AbstractPrinter
|
||||
{
|
||||
/**
|
||||
* @var resource Output Stream
|
||||
*/
|
||||
protected $_stream;
|
||||
|
||||
/**
|
||||
* @var integer Maximum column size
|
||||
*/
|
||||
protected $_maxColumnSize;
|
||||
|
||||
/**
|
||||
* @var array Array of Styles
|
||||
*/
|
||||
protected $_styles;
|
||||
|
||||
/**
|
||||
* Creates an instance of Printer
|
||||
*
|
||||
* @param resource $stream Output Stream
|
||||
*/
|
||||
public function __construct($stream = STDOUT)
|
||||
{
|
||||
$this->_stream = $stream;
|
||||
$this->_maxColumnSize = 80;
|
||||
|
||||
$this->_initStyles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes Printer Styles
|
||||
*
|
||||
*/
|
||||
protected function _initStyles()
|
||||
{
|
||||
// Defines base styles
|
||||
$this->addStyles(array(
|
||||
'ERROR' => new Style(),
|
||||
'INFO' => new Style(),
|
||||
'COMMENT' => new Style(),
|
||||
'HEADER' => new Style(),
|
||||
'NONE' => new Style(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a collection of styles to the Printer.
|
||||
* To include them, just call the method with the following structure:
|
||||
*
|
||||
* [php]
|
||||
* $printer->addStyles(array(
|
||||
* 'ERROR' => new Style('BLACK', 'DEFAULT', array('BOLD' => true)),
|
||||
* ...
|
||||
* ));
|
||||
*
|
||||
* @param array $tasks CLI Tasks to be included
|
||||
*/
|
||||
public function addStyles($styles)
|
||||
{
|
||||
foreach ($styles as $name => $style) {
|
||||
$this->addStyle($name, $style);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single Style to Printer.
|
||||
* Example of inclusion to support a new Style:
|
||||
*
|
||||
* [php]
|
||||
* $printer->addStyle('ERROR', new Style('BLACK', 'DEFAULT', array('BOLD' => true)));
|
||||
*
|
||||
* @param string $name Style name
|
||||
* @param Style $style Style instance
|
||||
*/
|
||||
public function addStyle($name, Style $style)
|
||||
{
|
||||
$this->_styles[strtoupper($name)] = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a defined Style.
|
||||
*
|
||||
* @return Style
|
||||
*/
|
||||
public function getStyle($name)
|
||||
{
|
||||
if (is_string($name)) {
|
||||
$name = strtoupper($name);
|
||||
return isset($this->_styles[$name]) ? $this->_styles[$name] : null;
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum column size (defines the CLI margin).
|
||||
*
|
||||
* @param integer $maxColumnSize The maximum column size for a message
|
||||
*/
|
||||
public function setMaxColumnSize($maxColumnSize)
|
||||
{
|
||||
$this->_maxColumnSize = $maxColumnSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes to the output stream.
|
||||
*
|
||||
* @param string $message Message to be outputted
|
||||
*/
|
||||
public function output($message)
|
||||
{
|
||||
fwrite($this->_stream, $message);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats message applying the defined style and writes to the output stream.
|
||||
*
|
||||
* @param string $message Message to be outputted
|
||||
* @param mixed $style Optional style to be applied in message
|
||||
*/
|
||||
public function write($message, $style = 'NONE')
|
||||
{
|
||||
$this->output($this->format($message, $style));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a line to the output stream, formatting it by applying the defined style.
|
||||
*
|
||||
* @param string $message Message to be outputted
|
||||
* @param mixed $style Optional style to be applied in message
|
||||
*/
|
||||
public function writeln($message, $style = 'NONE')
|
||||
{
|
||||
$this->output($this->format($message, $style) . PHP_EOL);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given message with the defined style.
|
||||
*
|
||||
* @param string $message Message to be formatted
|
||||
* @param mixed $style Style to be applied in message
|
||||
* @return string Formatted message
|
||||
*/
|
||||
abstract public function format($message, $style);
|
||||
}
|
@ -1,214 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI\Printers;
|
||||
|
||||
use Doctrine\Common\CLI\Style;
|
||||
|
||||
/**
|
||||
* CLI Output Printer for ANSI Color terminal
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class AnsiColorPrinter extends AbstractPrinter
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function _initStyles()
|
||||
{
|
||||
$this->addStyles(array(
|
||||
'HEADER' => new Style('DEFAULT', 'DEFAULT', array('BOLD' => true)),
|
||||
'ERROR' => new Style('WHITE', 'RED', array('BOLD' => true)),
|
||||
'WARNING' => new Style('DEFAULT', 'YELLOW'),
|
||||
'KEYWORD' => new Style('BLUE', 'DEFAULT', array('BOLD' => true)),
|
||||
'REQ_ARG' => new Style('MAGENTA', 'DEFAULT', array('BOLD' => true)),
|
||||
'OPT_ARG' => new Style('CYAN', 'DEFAULT', array('BOLD' => true)),
|
||||
'INFO' => new Style('GREEN', 'DEFAULT', array('BOLD' => true)),
|
||||
'COMMENT' => new Style('DEFAULT', 'MAGENTA'),
|
||||
'NONE' => new Style(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function format($message, $style = 'NONE')
|
||||
{
|
||||
if ( ! $this->_supportsColor()) {
|
||||
return $message;
|
||||
}
|
||||
|
||||
$style = $this->getStyle($style);
|
||||
$str = $this->_getForegroundString($style)
|
||||
. $this->_getBackgroundString($style);
|
||||
$styleSet = ($str != '');
|
||||
|
||||
return $str . $message . ($styleSet ? chr(27) . '[0m' : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ANSI string representation of requested color name
|
||||
*
|
||||
* @param Style $style Style
|
||||
* @return string
|
||||
*/
|
||||
protected function _getBackgroundString(Style $style)
|
||||
{
|
||||
$background = $style->getBackground();
|
||||
|
||||
if (empty($background)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$esc = chr(27);
|
||||
|
||||
switch (strtoupper($background)) {
|
||||
case 'BLACK':
|
||||
return $esc . '[40m';
|
||||
case 'RED':
|
||||
return $esc . '[41m';
|
||||
case 'GREEN':
|
||||
return $esc . '[42m';
|
||||
case 'YELLOW':
|
||||
return $esc . '[43m';
|
||||
case 'BLUE':
|
||||
return $esc . '[44m';
|
||||
case 'MAGENTA':
|
||||
return $esc . '[45m';
|
||||
case 'CYAN':
|
||||
return $esc . '[46m';
|
||||
case 'WHITE':
|
||||
return $esc . '[47m';
|
||||
case 'DEFAULT':
|
||||
default:
|
||||
return $esc . '[48m';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ANSI string representation of requested color name
|
||||
*
|
||||
* @param Style $style Style
|
||||
* @return string
|
||||
*/
|
||||
protected function _getForegroundString(Style $style)
|
||||
{
|
||||
$foreground = $style->getForeground();
|
||||
|
||||
if (empty($foreground)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$str = chr(27) . '[' . $this->_getOptionsString($style);
|
||||
|
||||
switch (strtoupper($foreground)) {
|
||||
case 'BLACK':
|
||||
return $str . '30m';
|
||||
case 'RED':
|
||||
return $str . '31m';
|
||||
case 'GREEN':
|
||||
return $str . '32m';
|
||||
case 'YELLOW':
|
||||
return $str . '33m';
|
||||
case 'BLUE':
|
||||
return $str . '34m';
|
||||
case 'MAGENTA':
|
||||
return $str . '35m';
|
||||
case 'CYAN':
|
||||
return $str . '36m';
|
||||
case 'WHITE':
|
||||
return $str . '37m';
|
||||
case 'DEFAULT_FGU':
|
||||
return $str . '38m';
|
||||
case 'DEFAULT':
|
||||
default:
|
||||
return $str . '39m';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ANSI string representation of requested options
|
||||
*
|
||||
* @param Style $style Style
|
||||
* @return string
|
||||
*/
|
||||
protected function _getOptionsString(Style $style)
|
||||
{
|
||||
$options = $style->getOptions();
|
||||
|
||||
if (empty($options)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$str = '';
|
||||
|
||||
foreach ($options as $name => $value) {
|
||||
if ($value) {
|
||||
$name = strtoupper($name);
|
||||
|
||||
switch ($name) {
|
||||
case 'BOLD':
|
||||
$str .= '1;';
|
||||
break;
|
||||
case 'HALF':
|
||||
$str .= '2;';
|
||||
break;
|
||||
case 'UNDERLINE':
|
||||
$str .= '4;';
|
||||
break;
|
||||
case 'BLINK':
|
||||
$str .= '5;';
|
||||
break;
|
||||
case 'REVERSE':
|
||||
$str .= '7;';
|
||||
break;
|
||||
case 'CONCEAL':
|
||||
$str .= '8;';
|
||||
break;
|
||||
default:
|
||||
// Ignore unknown option
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current Output Stream supports ANSI Colors
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function _supportsColor()
|
||||
{
|
||||
return DIRECTORY_SEPARATOR != '\\' &&
|
||||
function_exists('posix_isatty') &&
|
||||
@posix_isatty($this->_stream);
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI\Printers;
|
||||
|
||||
use Doctrine\Common\CLI\Style;
|
||||
|
||||
/**
|
||||
* CLI Output Printer for Normal terminal
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class NormalPrinter extends AbstractPrinter
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function format($message, $style)
|
||||
{
|
||||
return $message;
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI;
|
||||
|
||||
/**
|
||||
* CLI Output Style
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class Style
|
||||
{
|
||||
/**
|
||||
* @var string Background color
|
||||
*/
|
||||
private $_background;
|
||||
|
||||
/**
|
||||
* @var string Foreground color
|
||||
*/
|
||||
private $_foreground;
|
||||
|
||||
/**
|
||||
* @var array Formatting options
|
||||
*/
|
||||
private $_options = array();
|
||||
|
||||
/**
|
||||
* @param string $foreground Foreground color name
|
||||
* @param string $background Background color name
|
||||
* @param array $options Formatting options
|
||||
*/
|
||||
public function __construct($foreground = null, $background = null, $options = array())
|
||||
{
|
||||
$this->_foreground = strtoupper($foreground);
|
||||
$this->_background = strtoupper($background);
|
||||
$this->_options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the foreground color name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getForeground()
|
||||
{
|
||||
return $this->_foreground;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the background color name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBackground()
|
||||
{
|
||||
return $this->_background;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the formatting options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->_options;
|
||||
}
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI;
|
||||
|
||||
use Doctrine\Common\CLI\Printers\AbstractPrinter,
|
||||
Doctrine\Common\CLI\OptionGroup,
|
||||
Doctrine\Common\CLI\Option;
|
||||
|
||||
/**
|
||||
* CLI Task documentation
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class TaskDocumentation
|
||||
{
|
||||
/** @var AbstractPrinter CLI Printer */
|
||||
private $_printer;
|
||||
|
||||
/** @var AbstractNamespace CLI Namespace */
|
||||
private $_namespace;
|
||||
|
||||
/** @var string CLI Task name */
|
||||
private $_name;
|
||||
|
||||
/** @var string CLI Task description */
|
||||
private $_description;
|
||||
|
||||
/** @var array CLI Task Option Group */
|
||||
private $_optionGroup;
|
||||
|
||||
/**
|
||||
* Constructs a new CLI Task Documentation
|
||||
*
|
||||
* @param AbstractNamespace CLI Namespace
|
||||
*/
|
||||
public function __construct(AbstractNamespace $namespace)
|
||||
{
|
||||
$this->_namespace = $namespace;
|
||||
$this->_printer = $namespace->getPrinter();
|
||||
$this->_optionGroup = new OptionGroup(OptionGroup::CARDINALITY_M_N);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Namespace
|
||||
*
|
||||
* @return AbstractNamespace
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return $this->_namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the CLI Task name
|
||||
*
|
||||
* @param string Task name
|
||||
* @return TaskDocumentation This object instance
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->_name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Task name
|
||||
*
|
||||
* @return string Task name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the full CLI Task name
|
||||
*
|
||||
* @return string Task full name
|
||||
*/
|
||||
public function getFullName()
|
||||
{
|
||||
return $this->getNamespace()->getFullName() . ':' . $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the CLI Task description
|
||||
*
|
||||
* @param string Task description
|
||||
* @return TaskDocumentation This object instance
|
||||
*/
|
||||
public function setDescription($description)
|
||||
{
|
||||
$this->_description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Task description
|
||||
*
|
||||
* @var string Task description
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->_description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Task Option Group
|
||||
*
|
||||
* @return OptionGroup CLI Task Option Group
|
||||
*/
|
||||
public function getOptionGroup()
|
||||
{
|
||||
return $this->_optionGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes a new CLI Option Group to the CLI Task documentation
|
||||
*
|
||||
* @param OptionGroup CLI Option Group
|
||||
* @return TaskDocumentation This object instance
|
||||
*/
|
||||
public function addOption($option)
|
||||
{
|
||||
if ($option instanceof OptionGroup) {
|
||||
$this->_optionGroup->addOption($option);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the synopsis of associated CLI Task
|
||||
*
|
||||
* @return string CLI Task synopsis
|
||||
*/
|
||||
public function getSynopsis()
|
||||
{
|
||||
return $this->_printer->format($this->getFullName(), 'KEYWORD') . ' '
|
||||
. trim($this->_optionGroup->formatPlain($this->_printer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the complete documentation of associated CLI Task
|
||||
*
|
||||
* @return string CLI Task complete documentation
|
||||
*/
|
||||
public function getCompleteDocumentation()
|
||||
{
|
||||
$printer = $this->_printer;
|
||||
|
||||
return $printer->format('Task: ')
|
||||
. $printer->format($this->getFullName(), 'KEYWORD')
|
||||
. $printer->format(PHP_EOL)
|
||||
. $printer->format('Synopsis: ')
|
||||
. $this->getSynopsis()
|
||||
. $printer->format(PHP_EOL)
|
||||
. $printer->format('Description: ')
|
||||
. $printer->format($this->_description)
|
||||
. $printer->format(PHP_EOL)
|
||||
. $printer->format('Options: ')
|
||||
. $printer->format(PHP_EOL)
|
||||
. $this->_optionGroup->formatWithDescription($printer);
|
||||
}
|
||||
}
|
@ -1,251 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI;
|
||||
|
||||
/**
|
||||
* CLI Namespace class
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class TaskNamespace extends AbstractNamespace
|
||||
{
|
||||
/**
|
||||
* @var boolean CLI Tasks flag to check if they are already initialized
|
||||
*/
|
||||
private $_initialized = false;
|
||||
|
||||
/**
|
||||
* @var string CLI Namespace full name
|
||||
*/
|
||||
private $_fullName = null;
|
||||
|
||||
/**
|
||||
* @var string CLI Namespace name
|
||||
*/
|
||||
private $_name = null;
|
||||
|
||||
/**
|
||||
* @var array Available tasks
|
||||
*/
|
||||
private $_tasks = array();
|
||||
|
||||
/**
|
||||
* The CLI namespace
|
||||
*
|
||||
* @param string $name CLI Namespace name
|
||||
*/
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->_name = self::formatName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an instantiated CLI Task by given its name.
|
||||
*
|
||||
* @param string $name CLI Task name
|
||||
*
|
||||
* @return AbstractTask
|
||||
*/
|
||||
public function getTask($name)
|
||||
{
|
||||
// Check if task exists in namespace
|
||||
if ($this->hasTask($name)) {
|
||||
$taskClass = $this->_tasks[self::formatName($name)];
|
||||
|
||||
return new $taskClass($this);
|
||||
}
|
||||
|
||||
throw CLIException::taskDoesNotExist($name, $this->getFullName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all CLI Task in this Namespace.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTasks()
|
||||
{
|
||||
return $this->_tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all defined CLI Tasks
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAvailableTasks()
|
||||
{
|
||||
$tasks = parent::getAvailableTasks();
|
||||
|
||||
foreach ($this->_tasks as $taskName => $taskClass) {
|
||||
$fullName = $this->getFullName() . ':' . $taskName;
|
||||
|
||||
$tasks[$fullName] = $taskClass;
|
||||
}
|
||||
|
||||
return $tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single task to CLI Namespace.
|
||||
* Example of inclusion support to a single task:
|
||||
*
|
||||
* [php]
|
||||
* $cliOrmNamespace->addTask('my-custom-task', 'MyProject\Cli\Tasks\MyCustomTask');
|
||||
*
|
||||
* @param string $name CLI Task name
|
||||
* @param string $class CLI Task class (FQCN - Fully Qualified Class Name)
|
||||
*
|
||||
* @return TaskNamespace This object instance
|
||||
*/
|
||||
public function addTask($name, $class)
|
||||
{
|
||||
$name = self::formatName($name);
|
||||
|
||||
if ($this->hasTask($name)) {
|
||||
throw CLIException::cannotOverrideTask($name);
|
||||
}
|
||||
|
||||
return $this->overrideTask($name, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides task on CLI Namespace.
|
||||
* Example of inclusion support to a single task:
|
||||
*
|
||||
* [php]
|
||||
* $cliOrmNamespace->overrideTask('schema-tool', 'MyProject\Cli\Tasks\MyCustomTask');
|
||||
*
|
||||
* @param string $name CLI Task name
|
||||
* @param string $class CLI Task class (FQCN - Fully Qualified Class Name)
|
||||
*
|
||||
* @return TaskNamespace This object instance
|
||||
*/
|
||||
public function overrideTask($name, $class)
|
||||
{
|
||||
$name = self::formatName($name);
|
||||
|
||||
$this->_tasks[$name] = $class;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check existance of a CLI Task
|
||||
*
|
||||
* @param string CLI Task name
|
||||
*
|
||||
* @return boolean TRUE if CLI Task if defined, false otherwise
|
||||
*/
|
||||
public function hasTask($name)
|
||||
{
|
||||
$name = self::formatName($name);
|
||||
|
||||
return isset($this->_tasks[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Namespace name
|
||||
*
|
||||
* @return string CLI Namespace name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the full CLI Namespace name
|
||||
*
|
||||
* @return string CLI Namespace full name
|
||||
*/
|
||||
public function getFullName()
|
||||
{
|
||||
if ($this->_fullName === null) {
|
||||
$str = $this->_name;
|
||||
|
||||
while (
|
||||
($parentNamespace = $this->getParentNamespace()) !== null &&
|
||||
! ($parentNamespace instanceof CliController)
|
||||
) {
|
||||
$str = $parentNamespace->getFullName() . ':' . $str;
|
||||
}
|
||||
|
||||
$this->_fullName = $str;
|
||||
}
|
||||
|
||||
return $this->_fullName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Effectively instantiate and execute a given CLI Task
|
||||
*
|
||||
* @param string $name CLI Task name
|
||||
* @param array $arguments CLI Task arguments
|
||||
*/
|
||||
public function runTask($name, $arguments = array())
|
||||
{
|
||||
try {
|
||||
$task = $this->getTask($name);
|
||||
|
||||
// Merge global configuration if it exists
|
||||
if (($globalArgs = $this->getConfiguration()->getAttribute('globalArguments')) !== null) {
|
||||
$arguments = array_merge($globalArgs, $arguments);
|
||||
}
|
||||
|
||||
$task->setArguments($arguments);
|
||||
|
||||
if ((isset($arguments['help']) && $arguments['help']) || (isset($arguments['h']) && $arguments['h'])) {
|
||||
$task->extendedHelp(); // User explicitly asked for help option
|
||||
} else if (isset($arguments['basic-help']) && $arguments['basic-help']) {
|
||||
$task->basicHelp(); // User explicitly asked for basic help option
|
||||
} else if ($task->validate()) {
|
||||
$task->run();
|
||||
}
|
||||
} catch (CLIException $e) {
|
||||
$message = $this->getFullName() . ':' . $name . ' => ' . $e->getMessage();
|
||||
$printer = $this->getPrinter();
|
||||
|
||||
// If we want the trace of calls, append to error message
|
||||
if (isset($arguments['trace']) && $arguments['trace']) {
|
||||
$message .= PHP_EOL . PHP_EOL . $e->getTraceAsString();
|
||||
}
|
||||
|
||||
$printer->writeln($message, 'ERROR');
|
||||
|
||||
// Unable instantiate task or task is not valid
|
||||
if (isset($task) && $task !== null) {
|
||||
$printer->write(PHP_EOL);
|
||||
$task->basicHelp(); // Fallback of not-valid task arguments
|
||||
}
|
||||
|
||||
$printer->write(PHP_EOL);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,200 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI\Tasks;
|
||||
|
||||
use Doctrine\Common\CLI\AbstractNamespace,
|
||||
Doctrine\Common\CLI\TaskDocumentation;
|
||||
|
||||
/**
|
||||
* Base class for CLI Tasks.
|
||||
* Provides basic methods and requires implementation of methods that
|
||||
* each task should implement in order to correctly work.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
abstract class AbstractTask
|
||||
{
|
||||
/**
|
||||
* @var AbstractNamespace CLI Namespace
|
||||
*/
|
||||
protected $_printer;
|
||||
|
||||
/**
|
||||
* @var TaskDocumentation CLI Task Documentation
|
||||
*/
|
||||
protected $_documentation;
|
||||
|
||||
/**
|
||||
* @var array CLI Task arguments
|
||||
*/
|
||||
protected $_arguments = array();
|
||||
|
||||
/**
|
||||
* Constructor of CLI Task
|
||||
*
|
||||
* @param AbstractNamespace CLI Namespace
|
||||
*/
|
||||
public function __construct(AbstractNamespace $namespace)
|
||||
{
|
||||
$this->_namespace = $namespace;
|
||||
$this->_documentation = new TaskDocumentation($namespace);
|
||||
|
||||
// Complete the CLI Task Documentation creation
|
||||
$this->buildDocumentation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Namespace
|
||||
*
|
||||
* @return AbstractNamespace
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return $this->_namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Task Documentation
|
||||
*
|
||||
* @return TaskDocumentation
|
||||
*/
|
||||
public function getDocumentation()
|
||||
{
|
||||
return $this->_documentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the CLI Task arguments
|
||||
*
|
||||
* @param array $arguments CLI Task arguments
|
||||
*
|
||||
* @return AbstractTask
|
||||
*/
|
||||
public function setArguments(array $arguments = array())
|
||||
{
|
||||
$this->_arguments = $arguments;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the CLI Task arguments
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->_arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves currently used CLI Output Printer
|
||||
*
|
||||
* @return AbstractPrinter
|
||||
*/
|
||||
public function getPrinter()
|
||||
{
|
||||
return $this->_namespace->getPrinter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves current used CLI Configuration
|
||||
*
|
||||
* @return Configuration
|
||||
*/
|
||||
public function getConfiguration()
|
||||
{
|
||||
return $this->_namespace->getConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose to CLI Output Printer the extended help of the given task.
|
||||
* This means it should detail all parameters, options and the meaning
|
||||
* of each one.
|
||||
* This method is executed when user types in CLI the following command:
|
||||
*
|
||||
* [bash]
|
||||
* ./doctrine task --help
|
||||
*
|
||||
*/
|
||||
public function extendedHelp()
|
||||
{
|
||||
$this->getPrinter()->output($this->_documentation->getCompleteDocumentation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose to CLI Output Printer the basic help of the given task.
|
||||
* This means it should only expose the basic task call. It is also
|
||||
* executed when user calls the global help; so this means it should
|
||||
* not pollute the Printer.
|
||||
* Basic help exposure is displayed when task does not pass the validate
|
||||
* (which means when user does not type the required options or when given
|
||||
* options are invalid, ie: invalid option), or when user requests to have
|
||||
* description of all available tasks.
|
||||
* This method is executed when user uses the following commands:
|
||||
*
|
||||
* [bash]
|
||||
* ./doctrine task --invalid-option
|
||||
* ./doctrine --help
|
||||
*
|
||||
*/
|
||||
public function basicHelp()
|
||||
{
|
||||
$this->getPrinter()
|
||||
->output($this->_documentation->getSynopsis())
|
||||
->output(PHP_EOL)
|
||||
->output(' ' . $this->_documentation->getDescription())
|
||||
->output(PHP_EOL . PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assures the given arguments matches with required/optional ones.
|
||||
* This method should be used to introspect arguments to check for
|
||||
* missing required arguments and also for invalid defined options.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
// TODO implement DAG here!
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely execution of task.
|
||||
* Each CLI task should implement this as normal flow execution of
|
||||
* what is supposed to do.
|
||||
*/
|
||||
abstract public function run();
|
||||
|
||||
/**
|
||||
* Generate the CLI Task Documentation
|
||||
*/
|
||||
abstract public function buildDocumentation();
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\CLI\Tasks;
|
||||
|
||||
use Doctrine\Common\CLI\CLIException;
|
||||
|
||||
/**
|
||||
* CLI Task to display available commands help
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class HelpTask extends AbstractTask
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function buildDocumentation()
|
||||
{
|
||||
$doc = $this->getDocumentation();
|
||||
$doc->setName('help')
|
||||
->setDescription('Exposes helpful information about all available tasks.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function extendedHelp()
|
||||
{
|
||||
$this->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposes the available tasks
|
||||
*
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->getPrinter()->writeln('Available Tasks:', 'HEADER')->write(PHP_EOL);
|
||||
|
||||
// Find the CLI Controller
|
||||
$cliController = $this->getNamespace()->getParentNamespace();
|
||||
|
||||
// Switch between ALL available tasks and display the basic Help of each one
|
||||
$availableTasks = $cliController->getAvailableTasks();
|
||||
//unset($availableTasks['Core:Help']);
|
||||
|
||||
ksort($availableTasks);
|
||||
|
||||
foreach (array_keys($availableTasks) as $taskName) {
|
||||
$cliController->runTask($taskName, array('basic-help' => 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
|
||||
@ -24,10 +22,7 @@ namespace Doctrine\Common\Cache;
|
||||
/**
|
||||
* Base class for cache driver implementations.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -21,16 +19,12 @@
|
||||
|
||||
namespace Doctrine\Common\Collections;
|
||||
|
||||
use \Closure, \ArrayIterator;
|
||||
use Closure, ArrayIterator;
|
||||
|
||||
/**
|
||||
* An ArrayCollection is a Collection implementation that uses a regular PHP array
|
||||
* internally.
|
||||
* An ArrayCollection is a Collection implementation that wraps a regular PHP array.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -39,7 +33,6 @@ class ArrayCollection implements Collection
|
||||
{
|
||||
/**
|
||||
* An array containing the entries of this collection.
|
||||
* This is the internal php array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
@ -121,7 +114,7 @@ class ArrayCollection implements Collection
|
||||
* Removes an element with a specific key/index from the collection.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
* @return mixed The removed element or NULL, if no element exists for the given key.
|
||||
*/
|
||||
public function remove($key)
|
||||
{
|
||||
@ -413,6 +406,7 @@ class ArrayCollection implements Collection
|
||||
/**
|
||||
* Returns a string representation of this object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@ -421,7 +415,6 @@ class ArrayCollection implements Collection
|
||||
|
||||
/**
|
||||
* Clears the collection.
|
||||
*
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -40,10 +38,7 @@ use Closure, Countable, IteratorAggregate, ArrayAccess;
|
||||
* position unless you explicitly positioned it before. Prefer iteration with
|
||||
* external iterators.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
|
@ -26,7 +26,7 @@ namespace Doctrine\Common;
|
||||
*
|
||||
* This class contains no event data. It is used by events that do not pass state
|
||||
* information to an event handler when an event is raised. The single empty EventArgs
|
||||
* instance can be obtained through {@link getEmptyInstance()}.
|
||||
* instance can be obtained through {@link getEmptyInstance}.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
|
@ -16,7 +16,7 @@
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common;
|
||||
@ -24,13 +24,12 @@ namespace Doctrine\Common;
|
||||
/**
|
||||
* An EventSubscriber knows himself what events he is interested in.
|
||||
* If an EventSubscriber is added to an EventManager, the manager invokes
|
||||
* getSubscribedEvents() and registers the subscriber as a listener for all
|
||||
* {@link getSubscribedEvents} and registers the subscriber as a listener for all
|
||||
* returned events.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -38,7 +37,7 @@ namespace Doctrine\Common;
|
||||
interface EventSubscriber
|
||||
{
|
||||
/**
|
||||
* Returns an array of events that this subscriber listens
|
||||
* Returns an array of events this subscriber wants to listen to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -22,15 +20,13 @@
|
||||
namespace Doctrine\Common;
|
||||
|
||||
/**
|
||||
* Simple generic lexical scanner.
|
||||
* Base class for writing simple lexers, i.e. for creating small DSLs.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @todo Rename: AbstractLexer
|
||||
*/
|
||||
abstract class Lexer
|
||||
{
|
||||
@ -50,7 +46,7 @@ abstract class Lexer
|
||||
private $_peek = 0;
|
||||
|
||||
/**
|
||||
* @var array The next token in the query string.
|
||||
* @var array The next token in the input.
|
||||
*/
|
||||
public $lookahead;
|
||||
|
||||
@ -60,9 +56,12 @@ abstract class Lexer
|
||||
public $token;
|
||||
|
||||
/**
|
||||
* Inputs data to be tokenized
|
||||
* Sets the input data to be tokenized.
|
||||
*
|
||||
* @param string $input input to be tokenized
|
||||
* The Lexer is immediately reset and the new input tokenized.
|
||||
* Any unprocessed tokens from any previous input are lost.
|
||||
*
|
||||
* @param string $input The input to be tokenized.
|
||||
*/
|
||||
public function setInput($input)
|
||||
{
|
||||
@ -72,20 +71,18 @@ abstract class Lexer
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the scanner
|
||||
*
|
||||
* Resets the lexer.
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->lookahead = null;
|
||||
$this->token = null;
|
||||
$this->_peek = 0;
|
||||
$this->token = null;
|
||||
$this->_peek = 0;
|
||||
$this->_position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the peek pointer to 0
|
||||
*
|
||||
* Resets the peek pointer to 0.
|
||||
*/
|
||||
public function resetPeek()
|
||||
{
|
||||
@ -93,7 +90,7 @@ abstract class Lexer
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the lexer position on the input to the given position
|
||||
* Resets the lexer position on the input to the given position.
|
||||
*
|
||||
* @param integer $position Position to place the lexical scanner
|
||||
*/
|
||||
@ -235,14 +232,14 @@ abstract class Lexer
|
||||
}
|
||||
|
||||
/**
|
||||
* Lexical catchable patterns
|
||||
* Lexical catchable patterns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getCatchablePatterns();
|
||||
|
||||
/**
|
||||
* Lexical non-catchable patterns
|
||||
* Lexical non-catchable patterns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -38,7 +36,7 @@ class Version
|
||||
/**
|
||||
* Current Doctrine Version
|
||||
*/
|
||||
const VERSION = '2.0 ALPHA 4';
|
||||
const VERSION = '2.0-DEV';
|
||||
|
||||
/**
|
||||
* Compares a Doctrine version with the current one.
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -21,15 +19,12 @@
|
||||
|
||||
namespace Doctrine\DBAL;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Logging\SQLLogger;
|
||||
|
||||
/**
|
||||
* Configuration container for the Doctrine DBAL.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -46,22 +41,12 @@ class Configuration
|
||||
*/
|
||||
protected $_attributes = array();
|
||||
|
||||
/**
|
||||
* Creates a new DBAL configuration instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_attributes = array(
|
||||
'sqlLogger' => null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SQL logger to use. Defaults to NULL which means SQL logging is disabled.
|
||||
*
|
||||
* @param SQLLogger $logger
|
||||
*/
|
||||
public function setSQLLogger($logger)
|
||||
public function setSQLLogger(SQLLogger $logger)
|
||||
{
|
||||
$this->_attributes['sqlLogger'] = $logger;
|
||||
}
|
||||
@ -73,6 +58,7 @@ class Configuration
|
||||
*/
|
||||
public function getSQLLogger()
|
||||
{
|
||||
return $this->_attributes['sqlLogger'];
|
||||
return isset($this->_attributes['sqlLogger']) ?
|
||||
$this->_attributes['sqlLogger'] : null;
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
|
@ -60,6 +60,7 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
|
||||
* placeholders and converted to a named parameter.
|
||||
*
|
||||
* @param string $statement The SQL statement to convert.
|
||||
* @todo review and test for lost spaces. we experienced missing spaces with oci8 in some sql statements.
|
||||
*/
|
||||
private function _convertPositionalToNamedPlaceholders($statement)
|
||||
{
|
||||
|
@ -510,7 +510,24 @@ class Table extends AbstractAsset
|
||||
*/
|
||||
public function getColumns()
|
||||
{
|
||||
return $this->_columns;
|
||||
$columns = $this->_columns;
|
||||
|
||||
$pkCols = array();
|
||||
$fkCols = array();
|
||||
|
||||
if ($this->hasIndex($this->_primaryKeyName)) {
|
||||
$pkCols = $this->getPrimaryKey()->getColumns();
|
||||
}
|
||||
foreach ($this->getForeignKeys() AS $fk) {
|
||||
/* @var $fk ForeignKeyConstraint */
|
||||
$fkCols = array_merge($fkCols, $fk->getColumns());
|
||||
}
|
||||
$colNames = array_unique(array_merge($pkCols, $fkCols, array_keys($columns)));
|
||||
|
||||
uksort($columns, function($a, $b) use($colNames) {
|
||||
return (array_search($a, $colNames) >= array_search($b, $colNames));
|
||||
});
|
||||
return $columns;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,171 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Tools\CLI\Tasks;
|
||||
|
||||
use Doctrine\Common\CLI\Tasks\AbstractTask,
|
||||
Doctrine\Common\CLI\CLIException,
|
||||
Doctrine\Common\Util\Debug,
|
||||
Doctrine\Common\CLI\Option,
|
||||
Doctrine\Common\CLI\OptionGroup;
|
||||
|
||||
/**
|
||||
* Task for executing arbitrary SQL that can come from a file or directly from
|
||||
* the command line.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class RunSqlTask extends AbstractTask
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function buildDocumentation()
|
||||
{
|
||||
$dqlAndFile = new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
|
||||
new Option(
|
||||
'sql', '<SQL>', 'The SQL to execute.' . PHP_EOL .
|
||||
'If defined, --file can not be requested on same task.'
|
||||
),
|
||||
new Option(
|
||||
'file', '<PATH>', 'The path to the file with the SQL to execute.' . PHP_EOL .
|
||||
'If defined, --sql can not be requested on same task.'
|
||||
)
|
||||
));
|
||||
|
||||
$depth = new OptionGroup(OptionGroup::CARDINALITY_0_1, array(
|
||||
new Option('depth', '<DEPTH>', 'Dumping depth of Entities graph.')
|
||||
));
|
||||
|
||||
$doc = $this->getDocumentation();
|
||||
$doc->setName('run-sql')
|
||||
->setDescription('Executes arbitrary SQL from a file or directly from the command line.')
|
||||
->getOptionGroup()
|
||||
->addOption($dqlAndFile)
|
||||
->addOption($depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
$em = $this->getConfiguration()->getAttribute('em');
|
||||
|
||||
if ($em === null) {
|
||||
throw new CLIException(
|
||||
"Attribute 'em' of CLI Configuration is not defined or it is not a valid EntityManager."
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! (isset($arguments['sql']) ^ isset($arguments['file']))) {
|
||||
throw new CLIException('One of --sql or --file required, and only one.');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the task.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
if (isset($arguments['file'])) {
|
||||
$em = $this->getConfiguration()->getAttribute('em');
|
||||
$conn = $em->getConnection();
|
||||
$printer = $this->getPrinter();
|
||||
|
||||
$fileNames = (array) $arguments['file'];
|
||||
|
||||
foreach ($fileNames as $fileName) {
|
||||
if ( ! file_exists($fileName)) {
|
||||
throw new CLIException(sprintf('The SQL file [%s] does not exist.', $fileName));
|
||||
} else if ( ! is_readable($fileName)) {
|
||||
throw new CLIException(sprintf('The SQL file [%s] does not have read permissions.', $fileName));
|
||||
}
|
||||
|
||||
$printer->write('Processing file [' . $fileName . ']... ');
|
||||
$sql = file_get_contents($fileName);
|
||||
|
||||
if ($conn instanceof \Doctrine\DBAL\Driver\PDOConnection) {
|
||||
// PDO Drivers
|
||||
try {
|
||||
$lines = 0;
|
||||
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute();
|
||||
|
||||
do {
|
||||
// Required due to "MySQL has gone away!" issue
|
||||
$stmt->fetch();
|
||||
$stmt->closeCursor();
|
||||
|
||||
$lines++;
|
||||
} while ($stmt->nextRowset());
|
||||
|
||||
$printer->writeln(sprintf('%d statements executed!', $lines));
|
||||
} catch (\PDOException $e) {
|
||||
$printer->writeln('error!')
|
||||
->writeln($e->getMessage());
|
||||
}
|
||||
} else {
|
||||
// Non-PDO Drivers (ie. OCI8 driver)
|
||||
$stmt = $conn->prepare($sql);
|
||||
$rs = $stmt->execute();
|
||||
|
||||
if ($rs) {
|
||||
$printer->writeln('OK!');
|
||||
} else {
|
||||
$error = $stmt->errorInfo();
|
||||
|
||||
$printer->writeln('error!')
|
||||
->writeln($error['message']);
|
||||
}
|
||||
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
}
|
||||
} else if (isset($arguments['sql'])) {
|
||||
$em = $this->getConfiguration()->getAttribute('em');
|
||||
|
||||
if (preg_match('/^select/i', $arguments['sql'])) {
|
||||
$stmt = $em->getConnection()->executeQuery($arguments['sql']);
|
||||
$resultSet = $stmt->fetchAll(\Doctrine\DBAL\Connection::FETCH_ASSOC);
|
||||
} else {
|
||||
$resultSet = $em->getConnection()->executeUpdate($arguments['sql']);
|
||||
}
|
||||
|
||||
$maxDepth = isset($arguments['depth']) ? $arguments['depth'] : 7;
|
||||
|
||||
Debug::dump($resultSet, $maxDepth);
|
||||
}
|
||||
}
|
||||
}
|
127
lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php
Normal file
127
lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Tools\Console\Command;
|
||||
|
||||
use Symfony\Components\Console\Input\InputArgument,
|
||||
Symfony\Components\Console;
|
||||
|
||||
/**
|
||||
* Task for executing arbitrary SQL that can come from a file or directly from
|
||||
* the command line.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class ImportCommand extends Console\Command\Command
|
||||
{
|
||||
/**
|
||||
* @see Console\Command\Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('dbal:import')
|
||||
->setDescription('Import SQL file(s) directly to Database.')
|
||||
->setDefinition(array(
|
||||
new InputArgument(
|
||||
'file', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'File path(s) of SQL to be executed.'
|
||||
)
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
Import SQL file(s) directly to Database.
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Console\Command\Command
|
||||
*/
|
||||
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
|
||||
{
|
||||
$conn = $this->getHelper('db')->getConnection();
|
||||
|
||||
if (($fileNames = $input->getArgument('file')) !== null) {
|
||||
foreach ((array) $fileNames as $fileName) {
|
||||
$fileName = realpath($fileName);
|
||||
|
||||
if ( ! file_exists($fileName)) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("SQL file '<info>%s</info>' does not exist.", $fileName)
|
||||
);
|
||||
} else if ( ! is_readable($fileName)) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("SQL file '<info>%s</info>' does not have read permissions.", $fileName)
|
||||
);
|
||||
}
|
||||
|
||||
$output->write(sprintf("Processing file '<info>%s</info>'... ", $fileName));
|
||||
$sql = file_get_contents($fileName);
|
||||
|
||||
if ($conn instanceof \Doctrine\DBAL\Driver\PDOConnection) {
|
||||
// PDO Drivers
|
||||
try {
|
||||
$lines = 0;
|
||||
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute();
|
||||
|
||||
do {
|
||||
// Required due to "MySQL has gone away!" issue
|
||||
$stmt->fetch();
|
||||
$stmt->closeCursor();
|
||||
|
||||
$lines++;
|
||||
} while ($stmt->nextRowset());
|
||||
|
||||
$output->write(sprintf('%d statements executed!', $lines) . PHP_EOL);
|
||||
} catch (\PDOException $e) {
|
||||
$output->write('error!' . PHP_EOL);
|
||||
|
||||
throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
} else {
|
||||
// Non-PDO Drivers (ie. OCI8 driver)
|
||||
$stmt = $conn->prepare($sql);
|
||||
$rs = $stmt->execute();
|
||||
|
||||
if ($rs) {
|
||||
$printer->writeln('OK!');
|
||||
} else {
|
||||
$error = $stmt->errorInfo();
|
||||
|
||||
$output->write('error!' . PHP_EOL);
|
||||
|
||||
throw new \RuntimeException($error[2], $error[0]);
|
||||
}
|
||||
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
86
lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php
Normal file
86
lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Tools\Console\Command;
|
||||
|
||||
use Symfony\Components\Console\Input\InputArgument,
|
||||
Symfony\Components\Console\Input\InputOption,
|
||||
Symfony\Components\Console;
|
||||
|
||||
/**
|
||||
* Task for executing arbitrary SQL that can come from a file or directly from
|
||||
* the command line.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class RunSqlCommand extends Console\Command\Command
|
||||
{
|
||||
/**
|
||||
* @see Console\Command\Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('dbal:run-sql')
|
||||
->setDescription('Executes arbitrary SQL directly from the command line.')
|
||||
->setDefinition(array(
|
||||
new InputArgument('sql', InputArgument::REQUIRED, 'The SQL statement to execute.'),
|
||||
new InputOption('depth', null, InputOption::PARAMETER_REQUIRED, 'Dumping depth of result set.', 7)
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
Executes arbitrary SQL directly from the command line.
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Console\Command\Command
|
||||
*/
|
||||
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
|
||||
{
|
||||
$conn = $this->getHelper('db')->getConnection();
|
||||
|
||||
if (($sql = $input->getArgument('sql')) === null) {
|
||||
throw new \RuntimeException("Argument 'SQL' is required in order to execute this command correctly.");
|
||||
}
|
||||
|
||||
$depth = $input->getOption('depth');
|
||||
|
||||
if ( ! is_numeric($depth)) {
|
||||
throw new \LogicException("Option 'depth' must contains an integer value");
|
||||
}
|
||||
|
||||
if (preg_match('/^select/i', $sql)) {
|
||||
$resultSet = $conn->fetchAll($sql);
|
||||
} else {
|
||||
$resultSet = $conn->executeUpdate($sql);
|
||||
}
|
||||
|
||||
\Doctrine\Common\Util\Debug::dump($resultSet, (int) $depth);
|
||||
}
|
||||
}
|
@ -19,13 +19,13 @@
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\DBAL\Tools\CLI\Tasks;
|
||||
namespace Doctrine\DBAL\Tools\Console\Helper;
|
||||
|
||||
use Doctrine\Common\CLI\Tasks\AbstractTask,
|
||||
Doctrine\Common\Version;
|
||||
use Symfony\Components\Console\Helper\Helper,
|
||||
Doctrine\DBAL\Connection;
|
||||
|
||||
/**
|
||||
* CLI Task to display the doctrine version
|
||||
* Doctrine CLI Connection Helper.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
@ -36,27 +36,39 @@ use Doctrine\Common\CLI\Tasks\AbstractTask,
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class VersionTask extends AbstractTask
|
||||
class ConnectionHelper extends Helper
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
* Doctrine Database Connection
|
||||
* @var Connection
|
||||
*/
|
||||
public function buildDocumentation()
|
||||
{
|
||||
// There're no options on this task
|
||||
$this->getDocumentation()->getOptionGroup()->clear();
|
||||
protected $_connection;
|
||||
|
||||
$doc = $this->getDocumentation();
|
||||
$doc->setName('version')
|
||||
->setDescription('Displays the current installed Doctrine version.');
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Connection $connection Doctrine Database Connection
|
||||
*/
|
||||
public function __construct(Connection $connection)
|
||||
{
|
||||
$this->_connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the current version of Doctrine
|
||||
* Retrieves Doctrine Database Connection
|
||||
*
|
||||
* @return Connection
|
||||
*/
|
||||
public function run()
|
||||
public function getConnection()
|
||||
{
|
||||
$this->getPrinter()->writeln('You are currently running Doctrine ' . Version::VERSION, 'INFO');
|
||||
return $this->_connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Helper
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'connection';
|
||||
}
|
||||
}
|
@ -410,11 +410,6 @@ abstract class AbstractQuery
|
||||
throw new NonUniqueResultException;
|
||||
}
|
||||
return array_shift($result);
|
||||
} else if (is_object($result)) {
|
||||
if (count($result) > 1) {
|
||||
throw new NonUniqueResultException;
|
||||
}
|
||||
return $result->first();
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -21,13 +19,15 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\Common\Cache\Cache,
|
||||
Doctrine\ORM\Mapping\Driver\Driver;
|
||||
|
||||
/**
|
||||
* Configuration container for all configuration options of Doctrine.
|
||||
* It combines all configuration options from DBAL & ORM.
|
||||
*
|
||||
* @since 2.0
|
||||
* @internal When adding a new configuration option just write a getter/setter
|
||||
* pair and add the option to the _attributes array with a proper default value.
|
||||
* @internal When adding a new configuration option just write a getter/setter pair.
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
@ -35,24 +35,6 @@ namespace Doctrine\ORM;
|
||||
*/
|
||||
class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
/**
|
||||
* Creates a new configuration that can be used for Doctrine.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->_attributes = array_merge($this->_attributes, array(
|
||||
'resultCacheImpl' => null,
|
||||
'queryCacheImpl' => null,
|
||||
'metadataCacheImpl' => null,
|
||||
'metadataDriverImpl' => null,
|
||||
'proxyDir' => null,
|
||||
'useCExtension' => false,
|
||||
'autoGenerateProxyClasses' => true,
|
||||
'proxyNamespace' => null
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the directory where Doctrine generates any necessary proxy class files.
|
||||
*
|
||||
@ -70,7 +52,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getProxyDir()
|
||||
{
|
||||
return $this->_attributes['proxyDir'];
|
||||
return isset($this->_attributes['proxyDir']) ?
|
||||
$this->_attributes['proxyDir'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,7 +64,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getAutoGenerateProxyClasses()
|
||||
{
|
||||
return $this->_attributes['autoGenerateProxyClasses'];
|
||||
return isset($this->_attributes['autoGenerateProxyClasses']) ?
|
||||
$this->_attributes['autoGenerateProxyClasses'] : true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,7 +86,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getProxyNamespace()
|
||||
{
|
||||
return $this->_attributes['proxyNamespace'];
|
||||
return isset($this->_attributes['proxyNamespace']) ?
|
||||
$this->_attributes['proxyNamespace'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,15 +103,29 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for metadata caching.
|
||||
*
|
||||
* @param object $driverImpl
|
||||
* @param Driver $driverImpl
|
||||
* @todo Force parameter to be a Closure to ensure lazy evaluation
|
||||
* (as soon as a metadata cache is in effect, the driver never needs to initialize).
|
||||
*/
|
||||
public function setMetadataDriverImpl($driverImpl)
|
||||
public function setMetadataDriverImpl(Driver $driverImpl)
|
||||
{
|
||||
$this->_attributes['metadataDriverImpl'] = $driverImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new default annotation driver with a correctly configured annotation reader.
|
||||
*
|
||||
* @param array $paths
|
||||
* @return Mapping\Driver\AnnotationDriver
|
||||
*/
|
||||
public function newDefaultAnnotationDriver($paths = array())
|
||||
{
|
||||
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
|
||||
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
|
||||
|
||||
return new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, (array)$paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a namespace under a certain alias.
|
||||
*
|
||||
@ -168,35 +167,32 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the cache driver implementation that is used for the mapping metadata.
|
||||
*
|
||||
* @return object
|
||||
* @throws ORMException
|
||||
* @return Mapping\Driver\Driver
|
||||
*/
|
||||
public function getMetadataDriverImpl()
|
||||
{
|
||||
if ($this->_attributes['metadataDriverImpl'] == null) {
|
||||
$reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache);
|
||||
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
|
||||
$this->_attributes['metadataDriverImpl'] = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader);
|
||||
}
|
||||
|
||||
return $this->_attributes['metadataDriverImpl'];
|
||||
return isset($this->_attributes['metadataDriverImpl']) ?
|
||||
$this->_attributes['metadataDriverImpl'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache driver implementation that is used for query result caching.
|
||||
*
|
||||
* @return object
|
||||
* @return \Doctrine\Common\Cache\Cache
|
||||
*/
|
||||
public function getResultCacheImpl()
|
||||
{
|
||||
return $this->_attributes['resultCacheImpl'];
|
||||
return isset($this->_attributes['resultCacheImpl']) ?
|
||||
$this->_attributes['resultCacheImpl'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for query result caching.
|
||||
*
|
||||
* @param object $cacheImpl
|
||||
* @param \Doctrine\Common\Cache\Cache $cacheImpl
|
||||
*/
|
||||
public function setResultCacheImpl($cacheImpl)
|
||||
public function setResultCacheImpl(Cache $cacheImpl)
|
||||
{
|
||||
$this->_attributes['resultCacheImpl'] = $cacheImpl;
|
||||
}
|
||||
@ -204,19 +200,20 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the cache driver implementation that is used for the query cache (SQL cache).
|
||||
*
|
||||
* @return object
|
||||
* @return \Doctrine\Common\Cache\Cache
|
||||
*/
|
||||
public function getQueryCacheImpl()
|
||||
{
|
||||
return $this->_attributes['queryCacheImpl'];
|
||||
return isset($this->_attributes['queryCacheImpl']) ?
|
||||
$this->_attributes['queryCacheImpl'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for the query cache (SQL cache).
|
||||
*
|
||||
* @param object $cacheImpl
|
||||
* @param \Doctrine\Common\Cache\Cache $cacheImpl
|
||||
*/
|
||||
public function setQueryCacheImpl($cacheImpl)
|
||||
public function setQueryCacheImpl(Cache $cacheImpl)
|
||||
{
|
||||
$this->_attributes['queryCacheImpl'] = $cacheImpl;
|
||||
}
|
||||
@ -224,19 +221,20 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the cache driver implementation that is used for metadata caching.
|
||||
*
|
||||
* @return object
|
||||
* @return \Doctrine\Common\Cache\Cache
|
||||
*/
|
||||
public function getMetadataCacheImpl()
|
||||
{
|
||||
return $this->_attributes['metadataCacheImpl'];
|
||||
return isset($this->_attributes['metadataCacheImpl']) ?
|
||||
$this->_attributes['metadataCacheImpl'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for metadata caching.
|
||||
*
|
||||
* @param object $cacheImpl
|
||||
* @param \Doctrine\Common\Cache\Cache $cacheImpl
|
||||
*/
|
||||
public function setMetadataCacheImpl($cacheImpl)
|
||||
public function setMetadataCacheImpl(Cache $cacheImpl)
|
||||
{
|
||||
$this->_attributes['metadataCacheImpl'] = $cacheImpl;
|
||||
}
|
||||
@ -249,7 +247,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getUseCExtension()
|
||||
{
|
||||
return $this->_attributes['useCExtension'];
|
||||
return isset($this->_attributes['useCExtension']) ?
|
||||
$this->_attributes['useCExtension'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -340,6 +339,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* Such a function can then be used in any DQL statement in any place where string
|
||||
* functions are allowed.
|
||||
*
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $className
|
||||
*/
|
||||
@ -356,15 +357,33 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getCustomStringFunction($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
return isset($this->_attributes['customStringFunctions'][$name]) ?
|
||||
$this->_attributes['customStringFunctions'][$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of custom DQL string functions.
|
||||
*
|
||||
* Keys must be function names and values the FQCN of the implementing class.
|
||||
* The function names will be case-insensitive in DQL.
|
||||
*
|
||||
* Any previously added string functions are discarded.
|
||||
*
|
||||
* @param array $functions The map of custom DQL string functions.
|
||||
*/
|
||||
public function setCustomStringFunctions(array $functions)
|
||||
{
|
||||
$this->_attributes['customStringFunctions'] = array_change_key_case($functions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a custom DQL function that produces a numeric value.
|
||||
* Such a function can then be used in any DQL statement in any place where numeric
|
||||
* functions are allowed.
|
||||
*
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $className
|
||||
*/
|
||||
@ -381,15 +400,33 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getCustomNumericFunction($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
return isset($this->_attributes['customNumericFunctions'][$name]) ?
|
||||
$this->_attributes['customNumericFunctions'][$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of custom DQL numeric functions.
|
||||
*
|
||||
* Keys must be function names and values the FQCN of the implementing class.
|
||||
* The function names will be case-insensitive in DQL.
|
||||
*
|
||||
* Any previously added numeric functions are discarded.
|
||||
*
|
||||
* @param array $functions The map of custom DQL numeric functions.
|
||||
*/
|
||||
public function setCustomNumericFunctions(array $functions)
|
||||
{
|
||||
$this->_attributes['customNumericFunctions'] = array_change_key_case($functions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a custom DQL function that produces a date/time value.
|
||||
* Such a function can then be used in any DQL statement in any place where date/time
|
||||
* functions are allowed.
|
||||
*
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $className
|
||||
*/
|
||||
@ -406,7 +443,23 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getCustomDatetimeFunction($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
return isset($this->_attributes['customDatetimeFunctions'][$name]) ?
|
||||
$this->_attributes['customDatetimeFunctions'][$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of custom DQL date/time functions.
|
||||
*
|
||||
* Keys must be function names and values the FQCN of the implementing class.
|
||||
* The function names will be case-insensitive in DQL.
|
||||
*
|
||||
* Any previously added date/time functions are discarded.
|
||||
*
|
||||
* @param array $functions The map of custom DQL date/time functions.
|
||||
*/
|
||||
public function setCustomDatetimeFunctions(array $functions)
|
||||
{
|
||||
$this->_attributes['customDatetimeFunctions'] = array_change_key_case($functions);
|
||||
}
|
||||
}
|
@ -440,7 +440,8 @@ class EntityManager
|
||||
*
|
||||
* @param object $entity The entity to copy.
|
||||
* @return object The new entity.
|
||||
* @todo Implementation or remove.
|
||||
* @todo Implementation need. This is necessary since $e2 = clone $e1; throws an E_FATAL when access anything on $e:
|
||||
* Fatal error: Maximum function nesting level of '100' reached, aborting!
|
||||
*/
|
||||
public function copy($entity, $deep = false)
|
||||
{
|
||||
@ -593,9 +594,11 @@ class EntityManager
|
||||
* @param EventManager $eventManager The EventManager instance to use.
|
||||
* @return EntityManager The created EntityManager.
|
||||
*/
|
||||
public static function create($conn, Configuration $config = null, EventManager $eventManager = null)
|
||||
public static function create($conn, Configuration $config, EventManager $eventManager = null)
|
||||
{
|
||||
$config = $config ?: new Configuration();
|
||||
if (!$config->getMetadataDriverImpl()) {
|
||||
throw ORMException::missingMappingDriverImpl();
|
||||
}
|
||||
|
||||
if (is_array($conn)) {
|
||||
$conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, ($eventManager ?: new EventManager()));
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
@ -12,6 +29,6 @@ class EntityNotFoundException extends ORMException
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('Entity was found although one item was expected.');
|
||||
parent::__construct('Entity was not found.');
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -28,10 +26,7 @@ namespace Doctrine\ORM;
|
||||
* This class is designed for inheritance and users can subclass this class to
|
||||
* write their own repositories with business-specific methods to locate entities.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
@ -181,4 +176,28 @@ class EntityRepository
|
||||
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getEntityName()
|
||||
{
|
||||
return $this->_entityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityManager
|
||||
*/
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->_em;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Mapping\ClassMetadata
|
||||
*/
|
||||
protected function getClassMetadata()
|
||||
{
|
||||
return $this->_class;
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -25,12 +23,9 @@ namespace Doctrine\ORM\Event;
|
||||
* Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions
|
||||
* of entities.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class LifecycleEventArgs extends \Doctrine\Common\EventArgs
|
||||
{
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -27,10 +25,7 @@ use Doctrine\ORM\ORMException;
|
||||
/**
|
||||
* Special generator for application-assigned identifiers (doesnt really generate anything).
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -21,7 +19,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Serializable, Doctrine\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* Represents an ID generator that uses a database sequence.
|
||||
@ -29,7 +27,7 @@ use Doctrine\ORM\EntityManager;
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class SequenceGenerator extends AbstractIdGenerator implements \Serializable
|
||||
class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
{
|
||||
private $_allocationSize;
|
||||
private $_sequenceName;
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
@ -7,10 +24,7 @@ use Doctrine\ORM\EntityManager;
|
||||
/**
|
||||
* Id generator that uses a single-row database table and a hi/lo algorithm.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id: Hydrate.php 3192 2007-11-19 17:55:23Z romanb $
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -30,10 +28,7 @@ use PDO,
|
||||
* Base class for all hydrators. A hydrator is a class that provides some form
|
||||
* of transformation of an SQL result set into another structure.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3192 $
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id: UnitOfWork.php 4947 2008-09-12 13:16:05Z romanb $
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -87,8 +85,8 @@ class ObjectHydrator extends AbstractHydrator
|
||||
if ($assoc->mappedBy) {
|
||||
$this->_hints['fetched'][$className][$assoc->mappedBy] = true;
|
||||
} else {
|
||||
if (isset($class->inverseMappings[$sourceClassName][$assoc->sourceFieldName])) {
|
||||
$inverseAssoc = $class->inverseMappings[$sourceClassName][$assoc->sourceFieldName];
|
||||
if ($assoc->inversedBy) {
|
||||
$inverseAssoc = $class->associationMappings[$assoc->inversedBy];
|
||||
if ($inverseAssoc->isOneToOne()) {
|
||||
$this->_hints['fetched'][$className][$inverseAssoc->sourceFieldName] = true;
|
||||
if ($class->subClasses) {
|
||||
@ -242,8 +240,8 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* specified by the FROM clause in a DQL query.
|
||||
*
|
||||
* @param array $data The data of the row to process.
|
||||
* @param array $cache
|
||||
* @param array $result
|
||||
* @param array $cache The cache to use.
|
||||
* @param array $result The result array to fill.
|
||||
*/
|
||||
protected function _hydrateRow(array $data, array &$cache, array &$result)
|
||||
{
|
||||
@ -346,9 +344,10 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
|
||||
$targetClass = $this->_ce[$relation->targetEntityName];
|
||||
if ($relation->isOwningSide) {
|
||||
//TODO: Just check hints['fetched'] here?
|
||||
// If there is an inverse mapping on the target class its bidirectional
|
||||
if (isset($targetClass->inverseMappings[$relation->sourceEntityName][$relationField])) {
|
||||
$inverseAssoc = $targetClass->inverseMappings[$relation->sourceEntityName][$relationField];
|
||||
if ($relation->inversedBy) {
|
||||
$inverseAssoc = $targetClass->associationMappings[$relation->inversedBy];
|
||||
if ($inverseAssoc->isOneToOne()) {
|
||||
$targetClass->reflFields[$inverseAssoc->sourceFieldName]->setValue($element, $parentObject);
|
||||
$this->_uow->setOriginalEntityProperty(spl_object_hash($element), $inverseAssoc->sourceFieldName, $parentObject);
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -36,9 +34,14 @@ class SingleScalarHydrator extends AbstractHydrator
|
||||
{
|
||||
$cache = array();
|
||||
$result = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
if (count($result) > 1 || count($result[key($result)]) > 1) {
|
||||
$num = count($result);
|
||||
|
||||
if ($num == 0) {
|
||||
throw new \Doctrine\ORM\NoResultException;
|
||||
} else if ($num > 1 || count($result[key($result)]) > 1) {
|
||||
throw new \Doctrine\ORM\NonUniqueResultException;
|
||||
}
|
||||
|
||||
$result = $this->_gatherScalarRowData($result[key($result)], $cache);
|
||||
|
||||
return array_shift($result);
|
||||
|
@ -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
|
||||
@ -34,6 +32,7 @@ namespace Doctrine\ORM\Mapping;
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
|
||||
*/
|
||||
abstract class AssociationMapping
|
||||
{
|
||||
@ -60,7 +59,7 @@ abstract class AssociationMapping
|
||||
public $isCascadeRemove;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Whether the association cascades save() operations from the source entity
|
||||
* READ-ONLY: Whether the association cascades persist() operations from the source entity
|
||||
* to the target entity/entities.
|
||||
*
|
||||
* @var boolean
|
||||
@ -152,7 +151,23 @@ abstract class AssociationMapping
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $joinTable = array();
|
||||
public $joinTable;
|
||||
|
||||
/**
|
||||
* READ-ONLY: The name of the entity class from which the association was
|
||||
* inherited in an inheritance hierarchy.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $inherited;
|
||||
|
||||
/**
|
||||
* READ-ONLY: The name of the entity or mapped superclass that declares
|
||||
* the association field in an inheritance hierarchy.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $declared;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of a class derived from AssociationMapping.
|
||||
@ -161,9 +176,7 @@ abstract class AssociationMapping
|
||||
*/
|
||||
public function __construct(array $mapping)
|
||||
{
|
||||
if ($mapping) {
|
||||
$this->_validateAndCompleteMapping($mapping);
|
||||
}
|
||||
$this->_validateAndCompleteMapping($mapping);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -317,8 +330,9 @@ abstract class AssociationMapping
|
||||
abstract public function load($sourceEntity, $target, $em, array $joinColumnValues = array());
|
||||
|
||||
/**
|
||||
* Gets the (possibly quoted) name of the join table.
|
||||
*
|
||||
* @param $platform
|
||||
* @param AbstractPlatform $platform
|
||||
* @return string
|
||||
*/
|
||||
public function getQuotedJoinTableName($platform)
|
||||
@ -328,4 +342,58 @@ abstract class AssociationMapping
|
||||
: $this->joinTable['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which fields get serialized.
|
||||
*
|
||||
* It is only serialized what is necessary for best unserialization performance.
|
||||
* That means any metadata properties that are not set or empty or simply have
|
||||
* their default value are NOT serialized.
|
||||
*
|
||||
* @return array The names of all the fields that should be serialized.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
$serialized = array(
|
||||
'sourceEntityName',
|
||||
'targetEntityName',
|
||||
'sourceFieldName',
|
||||
'fetchMode'
|
||||
);
|
||||
|
||||
if ($this->isCascadeDetach) {
|
||||
$serialized[] = 'isCascadeDetach';
|
||||
}
|
||||
if ($this->isCascadeMerge) {
|
||||
$serialized[] = 'isCascadeMerge';
|
||||
}
|
||||
if ($this->isCascadePersist) {
|
||||
$serialized[] = 'isCascadePersist';
|
||||
}
|
||||
if ($this->isCascadeRefresh) {
|
||||
$serialized[] = 'isCascadeRefresh';
|
||||
}
|
||||
if ($this->isCascadeRemove) {
|
||||
$serialized[] = 'isCascadeRemove';
|
||||
}
|
||||
if ( ! $this->isOwningSide) {
|
||||
$serialized[] = 'isOwningSide';
|
||||
}
|
||||
if ($this->mappedBy) {
|
||||
$serialized[] = 'mappedBy';
|
||||
}
|
||||
if ($this->inversedBy) {
|
||||
$serialized[] = 'inversedBy';
|
||||
}
|
||||
if ($this->joinTable) {
|
||||
$serialized[] = 'joinTable';
|
||||
}
|
||||
if ($this->inherited) {
|
||||
$serialized[] = 'inherited';
|
||||
}
|
||||
if ($this->declared) {
|
||||
$serialized[] = 'declared';
|
||||
}
|
||||
|
||||
return $serialized;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -43,13 +41,6 @@ use ReflectionClass, ReflectionProperty;
|
||||
*/
|
||||
class ClassMetadata extends ClassMetadataInfo
|
||||
{
|
||||
/**
|
||||
* The ReflectionClass instance of the mapped class.
|
||||
*
|
||||
* @var ReflectionClass
|
||||
*/
|
||||
public $reflClass;
|
||||
|
||||
/**
|
||||
* The ReflectionProperty instances of the mapped class.
|
||||
*
|
||||
@ -72,21 +63,10 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
*/
|
||||
public function __construct($entityName)
|
||||
{
|
||||
$this->name = $entityName;
|
||||
$this->reflClass = new \ReflectionClass($entityName);
|
||||
parent::__construct($entityName);
|
||||
$this->reflClass = new ReflectionClass($entityName);
|
||||
$this->namespace = $this->reflClass->getNamespaceName();
|
||||
$this->table['name'] = $this->reflClass->getShortName();
|
||||
$this->rootEntityName = $entityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ReflectionClass instance of the mapped class.
|
||||
*
|
||||
* @return ReflectionClass
|
||||
*/
|
||||
public function getReflectionClass()
|
||||
{
|
||||
return $this->reflClass;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,18 +79,6 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
return $this->reflFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Adds a reflection property. Usually only used by the ClassMetadataFactory
|
||||
* while processing inheritance mappings.
|
||||
*
|
||||
* @param array $props
|
||||
*/
|
||||
public function addReflectionProperty($propName, \ReflectionProperty $property)
|
||||
{
|
||||
$this->reflFields[$propName] = $property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a ReflectionProperty for a specific field of the mapped class.
|
||||
*
|
||||
@ -189,7 +157,7 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
public function setIdentifierValues($entity, $id)
|
||||
{
|
||||
if ($this->isIdentifierComposite) {
|
||||
foreach ((array)$id as $idField => $idValue) {
|
||||
foreach ($id as $idField => $idValue) {
|
||||
$this->reflFields[$idField]->setValue($entity, $idValue);
|
||||
}
|
||||
} else {
|
||||
@ -220,18 +188,6 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
return $this->reflFields[$field]->getValue($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the field mapped to the specified column to the specified value on the given entity.
|
||||
*
|
||||
* @param object $entity
|
||||
* @param string $field
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setColumnValue($entity, $column, $value)
|
||||
{
|
||||
$this->reflFields[$this->fieldNames[$column]]->setValue($entity, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the association mapping.
|
||||
*
|
||||
@ -244,9 +200,9 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
// Store ReflectionProperty of mapped field
|
||||
$sourceFieldName = $assocMapping->sourceFieldName;
|
||||
|
||||
$refProp = $this->reflClass->getProperty($sourceFieldName);
|
||||
$refProp->setAccessible(true);
|
||||
$this->reflFields[$sourceFieldName] = $refProp;
|
||||
$refProp = $this->reflClass->getProperty($sourceFieldName);
|
||||
$refProp->setAccessible(true);
|
||||
$this->reflFields[$sourceFieldName] = $refProp;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -292,7 +248,11 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
/**
|
||||
* Determines which fields get serialized.
|
||||
*
|
||||
* Parts that are NOT serialized because they can not be properly unserialized:
|
||||
* It is only serialized what is necessary for best unserialization performance.
|
||||
* That means any metadata properties that are not set or empty or simply have
|
||||
* their default value are NOT serialized.
|
||||
*
|
||||
* Parts that are also NOT serialized because they can not be properly unserialized:
|
||||
* - reflClass (ReflectionClass)
|
||||
* - reflFields (ReflectionProperty array)
|
||||
*
|
||||
@ -300,33 +260,57 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
return array(
|
||||
'associationMappings', // unserialization "bottleneck" with many associations
|
||||
'changeTrackingPolicy',
|
||||
// This metadata is always serialized/cached.
|
||||
$serialized = array(
|
||||
'associationMappings',
|
||||
'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName']
|
||||
'customRepositoryClassName',
|
||||
'discriminatorColumn',
|
||||
'discriminatorValue',
|
||||
'discriminatorMap',
|
||||
'fieldMappings',//TODO: Not all of this stuff needs to be serialized. Only type, columnName and fieldName.
|
||||
'fieldMappings',
|
||||
'fieldNames',
|
||||
'generatorType',
|
||||
'identifier',
|
||||
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
|
||||
'inheritanceType',
|
||||
'inheritedAssociationFields',
|
||||
'inverseMappings', //TODO: Remove! DDC-193
|
||||
'isIdentifierComposite',
|
||||
'isMappedSuperclass',
|
||||
'isVersioned',
|
||||
'lifecycleCallbacks',
|
||||
'isIdentifierComposite', // TODO: REMOVE
|
||||
'name',
|
||||
'parentClasses',
|
||||
'namespace', // TODO: REMOVE
|
||||
'table',
|
||||
'rootEntityName',
|
||||
'subClasses',
|
||||
'versionField'
|
||||
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
|
||||
);
|
||||
|
||||
// The rest of the metadata is only serialized if necessary.
|
||||
if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) {
|
||||
$serialized[] = 'changeTrackingPolicy';
|
||||
}
|
||||
|
||||
if ($this->customRepositoryClassName) {
|
||||
$serialized[] = 'customRepositoryClassName';
|
||||
}
|
||||
|
||||
if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) {
|
||||
$serialized[] = 'inheritanceType';
|
||||
$serialized[] = 'discriminatorColumn';
|
||||
$serialized[] = 'discriminatorValue';
|
||||
$serialized[] = 'discriminatorMap';
|
||||
$serialized[] = 'parentClasses';
|
||||
$serialized[] = 'subClasses';
|
||||
}
|
||||
|
||||
if ($this->generatorType != self::GENERATOR_TYPE_NONE) {
|
||||
$serialized[] = 'generatorType';
|
||||
}
|
||||
|
||||
if ($this->isMappedSuperclass) {
|
||||
$serialized[] = 'isMappedSuperclass';
|
||||
}
|
||||
|
||||
if ($this->isVersioned) {
|
||||
$serialized[] = 'isVersioned';
|
||||
$serialized[] = 'versionField';
|
||||
}
|
||||
|
||||
if ($this->lifecycleCallbacks) {
|
||||
$serialized[] = 'lifecycleCallbacks';
|
||||
}
|
||||
|
||||
return $serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -340,18 +324,18 @@ class ClassMetadata extends ClassMetadataInfo
|
||||
$this->reflClass = new ReflectionClass($this->name);
|
||||
|
||||
foreach ($this->fieldMappings as $field => $mapping) {
|
||||
if (isset($mapping['inherited'])) {
|
||||
$reflField = new ReflectionProperty($mapping['inherited'], $field);
|
||||
} else {
|
||||
$reflField = $this->reflClass->getProperty($field);
|
||||
}
|
||||
if (isset($mapping['declared'])) {
|
||||
$reflField = new ReflectionProperty($mapping['declared'], $field);
|
||||
} else {
|
||||
$reflField = $this->reflClass->getProperty($field);
|
||||
}
|
||||
$reflField->setAccessible(true);
|
||||
$this->reflFields[$field] = $reflField;
|
||||
}
|
||||
|
||||
foreach ($this->associationMappings as $field => $mapping) {
|
||||
if (isset($this->inheritedAssociationFields[$field])) {
|
||||
$reflField = new ReflectionProperty($this->inheritedAssociationFields[$field], $field);
|
||||
if ($mapping->declared) {
|
||||
$reflField = new ReflectionProperty($mapping->declared, $field);
|
||||
} else {
|
||||
$reflField = $this->reflClass->getProperty($field);
|
||||
}
|
||||
|
@ -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
|
||||
@ -30,10 +28,7 @@ use Doctrine\ORM\ORMException,
|
||||
* metadata mapping informations of a class which describes how a class should be mapped
|
||||
* to a relational database.
|
||||
*
|
||||
* @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>
|
||||
@ -191,6 +186,24 @@ class ClassMetadataFactory
|
||||
$this->_loadedMetadata[$className] = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of parent classes for the given entity class
|
||||
*
|
||||
* @param string $name
|
||||
* @return array $parentClasses
|
||||
*/
|
||||
protected function _getParentClasses($name)
|
||||
{
|
||||
// Collect parent classes, ignoring transient (not-mapped) classes.
|
||||
$parentClasses = array();
|
||||
foreach (array_reverse(class_parents($name)) as $parentClass) {
|
||||
if ( ! $this->_driver->isTransient($parentClass)) {
|
||||
$parentClasses[] = $parentClass;
|
||||
}
|
||||
}
|
||||
return $parentClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the metadata of the class in question and all it's ancestors whose metadata
|
||||
* is still not loaded.
|
||||
@ -206,16 +219,7 @@ class ClassMetadataFactory
|
||||
|
||||
$loaded = array();
|
||||
|
||||
// Collect parent classes, ignoring transient (not-mapped) classes.
|
||||
//TODO: Evaluate whether we can use class_parents() here.
|
||||
$parentClass = $name;
|
||||
$parentClasses = array();
|
||||
while ($parentClass = get_parent_class($parentClass)) {
|
||||
if ( ! $this->_driver->isTransient($parentClass)) {
|
||||
$parentClasses[] = $parentClass;
|
||||
}
|
||||
}
|
||||
$parentClasses = array_reverse($parentClasses);
|
||||
$parentClasses = $this->_getParentClasses($name);
|
||||
$parentClasses[] = $name;
|
||||
|
||||
// Move down the hierarchy of parent classes, starting from the topmost class
|
||||
@ -262,8 +266,8 @@ class ClassMetadataFactory
|
||||
} else if ($parent->isIdGeneratorTable()) {
|
||||
$class->getTableGeneratorDefinition($parent->tableGeneratorDefinition);
|
||||
}
|
||||
if ($generatorType = $parent->generatorType) {
|
||||
$class->setIdGeneratorType($generatorType);
|
||||
if ($parent->generatorType) {
|
||||
$class->setIdGeneratorType($parent->generatorType);
|
||||
}
|
||||
if ($parent->idGenerator) {
|
||||
$class->setIdGenerator($parent->idGenerator);
|
||||
@ -320,7 +324,10 @@ class ClassMetadataFactory
|
||||
if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$mapping['inherited'] = $parentClass->name;
|
||||
}
|
||||
$subClass->addFieldMapping($mapping);
|
||||
if ( ! isset($mapping['declared'])) {
|
||||
$mapping['declared'] = $parentClass->name;
|
||||
}
|
||||
$subClass->addInheritedFieldMapping($mapping);
|
||||
}
|
||||
foreach ($parentClass->reflFields as $name => $field) {
|
||||
$subClass->reflFields[$name] = $field;
|
||||
@ -328,23 +335,22 @@ class ClassMetadataFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds inherited associations to the subclass mapping.
|
||||
* Adds inherited association mappings to the subclass mapping.
|
||||
*
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $subClass
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $parentClass
|
||||
*/
|
||||
private function _addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass)
|
||||
{
|
||||
foreach ($parentClass->associationMappings as $mapping) {
|
||||
if (isset($parentClass->inheritedAssociationFields[$mapping->sourceFieldName])) {
|
||||
// parent class also inherited that one
|
||||
$subClass->addAssociationMapping($mapping, $parentClass->inheritedAssociationFields[$mapping->sourceFieldName]);
|
||||
} else if ( ! $parentClass->isMappedSuperclass) {
|
||||
// parent class defined that one
|
||||
$subClass->addAssociationMapping($mapping, $parentClass->name);
|
||||
} else {
|
||||
$subClass->addAssociationMapping($mapping);
|
||||
foreach ($parentClass->associationMappings as $field => $mapping) {
|
||||
$subclassMapping = clone $mapping;
|
||||
if ( ! isset($mapping->inherited) && ! $parentClass->isMappedSuperclass) {
|
||||
$subclassMapping->inherited = $parentClass->name;
|
||||
}
|
||||
if ( ! isset($mapping->declared)) {
|
||||
$subclassMapping->declared = $parentClass->name;
|
||||
}
|
||||
$subClass->addInheritedAssociationMapping($subclassMapping);
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,7 +360,7 @@ class ClassMetadataFactory
|
||||
*
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $class
|
||||
*/
|
||||
private function _completeIdGeneratorMapping(ClassMetadata $class)
|
||||
private function _completeIdGeneratorMapping(ClassMetadataInfo $class)
|
||||
{
|
||||
$idGenType = $class->generatorType;
|
||||
if ($idGenType == ClassMetadata::GENERATOR_TYPE_AUTO) {
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -21,6 +19,8 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
|
||||
* of an entity and it's associations.
|
||||
@ -127,9 +127,9 @@ class ClassMetadataInfo
|
||||
public $namespace;
|
||||
|
||||
/**
|
||||
* READ-ONLY: The name of the entity class that is at the root of the entity inheritance
|
||||
* hierarchy. If the entity is not part of an inheritance hierarchy this is the same
|
||||
* as $_entityName.
|
||||
* READ-ONLY: The name of the entity class that is at the root of the mapped entity inheritance
|
||||
* hierarchy. If the entity is not part of a mapped inheritance hierarchy this is the same
|
||||
* as {@link $entityName}.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
@ -158,7 +158,7 @@ class ClassMetadataInfo
|
||||
public $parentClasses = array();
|
||||
|
||||
/**
|
||||
* READ-ONLY: The names of all subclasses.
|
||||
* READ-ONLY: The names of all subclasses (descendants).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
@ -195,9 +195,9 @@ class ClassMetadataInfo
|
||||
* - <b>fieldName</b> (string)
|
||||
* The name of the field in the Entity.
|
||||
*
|
||||
* - <b>type</b> (object Doctrine\DBAL\Types\* or custom type)
|
||||
* The type of the column. Can be one of Doctrine's portable types
|
||||
* or a custom type.
|
||||
* - <b>type</b> (string)
|
||||
* The type name of the mapped field. Can be one of Doctrine's mapping types
|
||||
* or a custom mapping type.
|
||||
*
|
||||
* - <b>columnName</b> (string, optional)
|
||||
* The column name. Optional. Defaults to the field name.
|
||||
@ -207,15 +207,9 @@ class ClassMetadataInfo
|
||||
* the type.
|
||||
*
|
||||
* - <b>id</b> (boolean, optional)
|
||||
* Marks the field as the primary key of the Entity. Multiple fields of an
|
||||
* Marks the field as the primary key of the entity. Multiple fields of an
|
||||
* entity can have the id attribute, forming a composite key.
|
||||
*
|
||||
* - <b>idGenerator</b> (string, optional)
|
||||
* Either: idGenerator => 'nameOfGenerator', usually only for TABLE/SEQUENCE generators
|
||||
* Or: idGenerator => 'identity' or 'auto' or 'table' or 'sequence'
|
||||
* Note that 'auto', 'table', 'sequence' and 'identity' are reserved names and
|
||||
* therefore cant be used as a generator name!
|
||||
*
|
||||
* - <b>nullable</b> (boolean, optional)
|
||||
* Whether the column is nullable. Defaults to FALSE.
|
||||
*
|
||||
@ -306,20 +300,12 @@ class ClassMetadataInfo
|
||||
public $lifecycleCallbacks = array();
|
||||
|
||||
/**
|
||||
* READ-ONLY: The association mappings. All mappings, inverse and owning side.
|
||||
* READ-ONLY: The association mappings of this class.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $associationMappings = array();
|
||||
|
||||
/**
|
||||
* READ-ONLY: List of inverse association mappings, indexed by mappedBy field name.
|
||||
*
|
||||
* @var array
|
||||
* @todo Remove! See http://www.doctrine-project.org/jira/browse/DDC-193
|
||||
*/
|
||||
public $inverseMappings = array();
|
||||
|
||||
/**
|
||||
* READ-ONLY: Flag indicating whether the identifier/primary key of the class is composite.
|
||||
*
|
||||
@ -331,6 +317,7 @@ class ClassMetadataInfo
|
||||
* READ-ONLY: The ID generator used for generating IDs for this class.
|
||||
*
|
||||
* @var AbstractIdGenerator
|
||||
* @todo Remove
|
||||
*/
|
||||
public $idGenerator;
|
||||
|
||||
@ -366,15 +353,6 @@ class ClassMetadataInfo
|
||||
*/
|
||||
public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
|
||||
|
||||
/**
|
||||
* READ-ONLY: A map of field names to class names, where the field names are association
|
||||
* fields that have been inherited from another class and values are the names
|
||||
* of the classes that define the association.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $inheritedAssociationFields = array();
|
||||
|
||||
/**
|
||||
* READ-ONLY: A flag for whether or not instances of this class are to be versioned
|
||||
* with optimistic locking.
|
||||
@ -390,6 +368,13 @@ class ClassMetadataInfo
|
||||
*/
|
||||
public $versionField;
|
||||
|
||||
/**
|
||||
* The ReflectionClass instance of the mapped class.
|
||||
*
|
||||
* @var ReflectionClass
|
||||
*/
|
||||
public $reflClass;
|
||||
|
||||
/**
|
||||
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
|
||||
* metadata of the class with the given name.
|
||||
@ -402,6 +387,19 @@ class ClassMetadataInfo
|
||||
$this->rootEntityName = $entityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ReflectionClass instance of the mapped class.
|
||||
*
|
||||
* @return ReflectionClass
|
||||
*/
|
||||
public function getReflectionClass()
|
||||
{
|
||||
if ( ! $this->reflClass) {
|
||||
$this->reflClass = new ReflectionClass($entityName);
|
||||
}
|
||||
return $this->reflClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the change tracking policy used by this class.
|
||||
*
|
||||
@ -531,34 +529,6 @@ class ClassMetadataInfo
|
||||
return $this->associationMappings[$fieldName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the inverse association mapping for the given target class name and
|
||||
* owning fieldname.
|
||||
*
|
||||
* @param string $mappedByFieldName The field on the
|
||||
* @return Doctrine\ORM\Mapping\AssociationMapping The mapping or NULL if there is no such
|
||||
* inverse association mapping.
|
||||
*/
|
||||
public function getInverseAssociationMapping($targetClassName, $mappedByFieldName)
|
||||
{
|
||||
return isset($this->inverseMappings[$targetClassName][$mappedByFieldName]) ?
|
||||
$this->inverseMappings[$targetClassName][$mappedByFieldName] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the class has an inverse association mapping that points to the
|
||||
* specified class and ha the specified mappedBy field.
|
||||
*
|
||||
* @param string $targetClassName The name of the target class.
|
||||
* @param string $mappedByFieldName The name of the mappedBy field that points to the field on
|
||||
* the target class that owns the association.
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasInverseAssociationMapping($targetClassName, $mappedByFieldName)
|
||||
{
|
||||
return isset($this->inverseMappings[$targetClassName][$mappedByFieldName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all association mappings of the class.
|
||||
*
|
||||
@ -628,16 +598,6 @@ class ClassMetadataInfo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps an embedded value object.
|
||||
*
|
||||
* @todo Implementation.
|
||||
*/
|
||||
/*public function mapEmbeddedValue()
|
||||
{
|
||||
//...
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Gets the identifier (primary key) field names of the class.
|
||||
*
|
||||
@ -744,7 +704,7 @@ class ClassMetadataInfo
|
||||
/**
|
||||
* Checks whether the mapped class uses an Id generator.
|
||||
*
|
||||
* @return boolean TRUE if the mapped class uses an Id generator, FALSE otherwise.
|
||||
* @return boolean TRUE if the mapped class uses an Id generator, FALSE otherwise.
|
||||
*/
|
||||
public function usesIdGenerator()
|
||||
{
|
||||
@ -752,7 +712,6 @@ class ClassMetadataInfo
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isInheritanceTypeNone()
|
||||
@ -892,16 +851,6 @@ class ClassMetadataInfo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the class has any persistent subclasses.
|
||||
*
|
||||
* @return boolean TRUE if the class has one or more persistent subclasses, FALSE otherwise.
|
||||
*/
|
||||
public function hasSubclasses()
|
||||
{
|
||||
return ! $this->subClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent class names.
|
||||
* Assumes that the class names in the passed array are in the order:
|
||||
@ -915,16 +864,6 @@ class ClassMetadataInfo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the class has any persistent parent classes.
|
||||
*
|
||||
* @return boolean TRUE if the class has one or more persistent parent classes, FALSE otherwise.
|
||||
*/
|
||||
public function hasParentClasses()
|
||||
{
|
||||
return ! $this->parentClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the inheritance type used by the class and it's subclasses.
|
||||
*
|
||||
@ -939,7 +878,7 @@ class ClassMetadataInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a mapped field is inherited from a superclass.
|
||||
* Checks whether a mapped field is inherited from an entity superclass.
|
||||
*
|
||||
* @return boolean TRUE if the field is inherited, FALSE otherwise.
|
||||
*/
|
||||
@ -956,7 +895,7 @@ class ClassMetadataInfo
|
||||
*/
|
||||
public function isInheritedAssociation($fieldName)
|
||||
{
|
||||
return isset($this->inheritedAssociationFields[$fieldName]);
|
||||
return isset($this->associationMappings[$fieldName]->inherited);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -999,21 +938,6 @@ class ClassMetadataInfo
|
||||
$type == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given type identifies an id generator type.
|
||||
*
|
||||
* @param string $type
|
||||
* @return boolean
|
||||
*/
|
||||
private function _isIdGeneratorType($type)
|
||||
{
|
||||
return $type == self::GENERATOR_TYPE_AUTO ||
|
||||
$type == self::GENERATOR_TYPE_IDENTITY ||
|
||||
$type == self::GENERATOR_TYPE_SEQUENCE ||
|
||||
$type == self::GENERATOR_TYPE_TABLE ||
|
||||
$type == self::GENERATOR_TYPE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes some automatic additions to the association mapping to make the life
|
||||
* easier for the user, and store join columns in the metadata.
|
||||
@ -1031,7 +955,7 @@ class ClassMetadataInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a field mapping.
|
||||
* Adds a mapped field to the class.
|
||||
*
|
||||
* @param array $mapping The field mapping.
|
||||
*/
|
||||
@ -1051,19 +975,13 @@ class ClassMetadataInfo
|
||||
*
|
||||
* @param AssociationMapping $mapping
|
||||
* @param string $owningClassName The name of the class that defined this mapping.
|
||||
* @todo Rename: addInheritedAssociationMapping
|
||||
*/
|
||||
public function addAssociationMapping(AssociationMapping $mapping, $owningClassName = null)
|
||||
public function addInheritedAssociationMapping(AssociationMapping $mapping/*, $owningClassName = null*/)
|
||||
{
|
||||
$sourceFieldName = $mapping->sourceFieldName;
|
||||
if (isset($this->associationMappings[$sourceFieldName])) {
|
||||
throw MappingException::duplicateAssociationMapping($this->name, $sourceFieldName);
|
||||
if (isset($this->associationMappings[$mapping->sourceFieldName])) {
|
||||
throw MappingException::duplicateAssociationMapping($this->name, $mapping->sourceFieldName);
|
||||
}
|
||||
$this->associationMappings[$sourceFieldName] = $mapping;
|
||||
if ($owningClassName !== null) {
|
||||
$this->inheritedAssociationFields[$sourceFieldName] = $owningClassName;
|
||||
}
|
||||
$this->_registerMappingIfInverse($mapping);
|
||||
$this->associationMappings[$mapping->sourceFieldName] = $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1074,7 +992,7 @@ class ClassMetadataInfo
|
||||
* @param array $mapping
|
||||
* @todo Rename: addInheritedFieldMapping
|
||||
*/
|
||||
public function addFieldMapping(array $fieldMapping)
|
||||
public function addInheritedFieldMapping(array $fieldMapping)
|
||||
{
|
||||
$this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
|
||||
$this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
|
||||
@ -1093,20 +1011,6 @@ class ClassMetadataInfo
|
||||
$this->_storeAssociationMapping($oneToOneMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the mapping as an inverse mapping, if it is a mapping on the
|
||||
* inverse side of an association mapping.
|
||||
*
|
||||
* @param AssociationMapping The mapping to register as inverse if it is a mapping
|
||||
* for the inverse side of an association.
|
||||
*/
|
||||
private function _registerMappingIfInverse(AssociationMapping $assoc)
|
||||
{
|
||||
if ( ! $assoc->isOwningSide) {
|
||||
$this->inverseMappings[$assoc->targetEntityName][$assoc->mappedBy] = $assoc;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a one-to-many mapping.
|
||||
*
|
||||
@ -1154,7 +1058,6 @@ class ClassMetadataInfo
|
||||
throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName);
|
||||
}
|
||||
$this->associationMappings[$sourceFieldName] = $assocMapping;
|
||||
$this->_registerMappingIfInverse($assocMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1171,8 +1074,8 @@ class ClassMetadataInfo
|
||||
* Dispatches the lifecycle event of the given entity to the registered
|
||||
* lifecycle callbacks and lifecycle listeners.
|
||||
*
|
||||
* @param string $event The lifecycle event.
|
||||
* @param Entity $entity The Entity on which the event occured.
|
||||
* @param string $event The lifecycle event.
|
||||
* @param Entity $entity The Entity on which the event occured.
|
||||
*/
|
||||
public function invokeLifecycleCallbacks($lifecycleEvent, $entity)
|
||||
{
|
||||
@ -1277,17 +1180,6 @@ class ClassMetadataInfo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given column name is the discriminator column.
|
||||
*
|
||||
* @param string $columnName
|
||||
* @return boolean
|
||||
*/
|
||||
public function isDiscriminatorColumn($columnName)
|
||||
{
|
||||
return $columnName === $this->discriminatorColumn['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the class has a mapped association with the given field name.
|
||||
*
|
||||
@ -1356,7 +1248,7 @@ class ClassMetadataInfo
|
||||
|
||||
/**
|
||||
* Sets the version field mapping used for versioning. Sets the default
|
||||
* value to use depending on the column type
|
||||
* value to use depending on the column type.
|
||||
*
|
||||
* @param array $mapping The version field mapping array
|
||||
*/
|
||||
|
@ -155,7 +155,7 @@ abstract class AbstractFileDriver implements Driver
|
||||
if ($this->_paths) {
|
||||
foreach ((array) $this->_paths as $path) {
|
||||
if ( ! is_dir($path)) {
|
||||
throw MappingException::driverRequiresConfiguredDirectoryPath();
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath();
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
|
@ -143,7 +143,7 @@ class AnnotationDriver implements Driver
|
||||
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
|
||||
}
|
||||
|
||||
// Evaluate DoctrineTable annotation
|
||||
// Evaluate Table annotation
|
||||
if (isset($classAnnotations['Doctrine\ORM\Mapping\Table'])) {
|
||||
$tableAnnot = $classAnnotations['Doctrine\ORM\Mapping\Table'];
|
||||
$primaryTable = array(
|
||||
@ -173,7 +173,7 @@ class AnnotationDriver implements Driver
|
||||
// Evaluate InheritanceType annotation
|
||||
if (isset($classAnnotations['Doctrine\ORM\Mapping\InheritanceType'])) {
|
||||
$inheritanceTypeAnnot = $classAnnotations['Doctrine\ORM\Mapping\InheritanceType'];
|
||||
$metadata->setInheritanceType(constant('\Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAnnot->value));
|
||||
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAnnot->value));
|
||||
}
|
||||
|
||||
// Evaluate DiscriminatorColumn annotation
|
||||
@ -195,7 +195,7 @@ class AnnotationDriver implements Driver
|
||||
// Evaluate DoctrineChangeTrackingPolicy annotation
|
||||
if (isset($classAnnotations['Doctrine\ORM\Mapping\ChangeTrackingPolicy'])) {
|
||||
$changeTrackingAnnot = $classAnnotations['Doctrine\ORM\Mapping\ChangeTrackingPolicy'];
|
||||
$metadata->setChangeTrackingPolicy(constant('\Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . $changeTrackingAnnot->value));
|
||||
$metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . $changeTrackingAnnot->value));
|
||||
}
|
||||
|
||||
// Evaluate annotations on properties/fields
|
||||
@ -428,40 +428,41 @@ class AnnotationDriver implements Driver
|
||||
return $this->_classNames;
|
||||
}
|
||||
|
||||
if (!$this->_paths) {
|
||||
throw MappingException::pathRequired();
|
||||
}
|
||||
|
||||
$classes = array();
|
||||
$includedFiles = array();
|
||||
|
||||
if ($this->_paths) {
|
||||
$includedFiles = array();
|
||||
|
||||
foreach ((array) $this->_paths as $path) {
|
||||
if ( ! is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath();
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($path),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
if (($fileName = $file->getBasename($this->_fileExtension)) == $file->getBasename()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sourceFile = realpath($file->getPathName());
|
||||
require_once $sourceFile;
|
||||
$includedFiles[] = $sourceFile;
|
||||
}
|
||||
foreach ($this->_paths as $path) {
|
||||
if ( ! is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath();
|
||||
}
|
||||
|
||||
$declared = get_declared_classes();
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($path),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($declared as $className) {
|
||||
$rc = new \ReflectionClass($className);
|
||||
$sourceFile = $rc->getFileName();
|
||||
if (in_array($sourceFile, $includedFiles) && ! $this->isTransient($className)) {
|
||||
$classes[] = $className;
|
||||
foreach ($iterator as $file) {
|
||||
if (($fileName = $file->getBasename($this->_fileExtension)) == $file->getBasename()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sourceFile = realpath($file->getPathName());
|
||||
require_once $sourceFile;
|
||||
$includedFiles[] = $sourceFile;
|
||||
}
|
||||
}
|
||||
|
||||
$declared = get_declared_classes();
|
||||
|
||||
foreach ($declared as $className) {
|
||||
$rc = new \ReflectionClass($className);
|
||||
$sourceFile = $rc->getFileName();
|
||||
if (in_array($sourceFile, $includedFiles) && ! $this->isTransient($className)) {
|
||||
$classes[] = $className;
|
||||
}
|
||||
}
|
||||
|
||||
@ -470,4 +471,19 @@ class AnnotationDriver implements Driver
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for the Annotation Driver
|
||||
*
|
||||
* @param array|string $paths
|
||||
* @param AnnotationReader $reader
|
||||
* @return AnnotationDriver
|
||||
*/
|
||||
static public function create($paths = array(), AnnotationReader $reader = null)
|
||||
{
|
||||
if ($reader == null) {
|
||||
$reader = new AnnotationReader();
|
||||
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
|
||||
}
|
||||
return new self($reader, $paths);
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ use Doctrine\Common\Cache\ArrayCache,
|
||||
Doctrine\Common\Util\Inflector;
|
||||
|
||||
/**
|
||||
* The DatabaseDriver reverse engineers the mapping metadata from a database
|
||||
* The DatabaseDriver reverse engineers the mapping metadata from a database.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
@ -67,7 +67,7 @@ class DatabaseDriver implements Driver
|
||||
|
||||
$columns = $this->_sm->listTableColumns($tableName);
|
||||
|
||||
if($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$foreignKeys = $this->_sm->listTableForeignKeys($tableName);
|
||||
} else {
|
||||
$foreignKeys = array();
|
||||
|
@ -37,7 +37,6 @@ final class DiscriminatorColumn extends Annotation {
|
||||
public $length;
|
||||
}
|
||||
final class DiscriminatorMap extends Annotation {}
|
||||
/*final class SubClasses extends Annotation {}*/
|
||||
final class Id extends Annotation {}
|
||||
final class GeneratedValue extends Annotation {
|
||||
public $strategy = 'AUTO';
|
||||
@ -124,7 +123,6 @@ final class SequenceGenerator extends Annotation {
|
||||
public $initialValue = 1;
|
||||
}
|
||||
final class ChangeTrackingPolicy extends Annotation {}
|
||||
|
||||
final class OrderBy extends Annotation {}
|
||||
|
||||
/* Annotations for lifecycle callbacks */
|
||||
|
@ -26,12 +26,9 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
/**
|
||||
* Contract for metadata drivers.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @since 2.0
|
||||
* @version $Revision: 1393 $
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @todo Rename: MetadataDriver
|
||||
* @since 2.0
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @todo Rename: MetadataDriver or MappingDriver
|
||||
*/
|
||||
interface Driver
|
||||
{
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -29,14 +27,12 @@ use Doctrine\ORM\Mapping\Driver\Driver,
|
||||
* The DriverChain allows you to add multiple other mapping drivers for
|
||||
* certain namespaces
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @todo Rename: MappingDriverChain or MetadataDriverChain
|
||||
*/
|
||||
class DriverChain implements Driver
|
||||
{
|
||||
@ -46,7 +42,7 @@ class DriverChain implements Driver
|
||||
private $_drivers = array();
|
||||
|
||||
/**
|
||||
* Add a nested driver
|
||||
* Add a nested driver.
|
||||
*
|
||||
* @param Driver $nestedDriver
|
||||
* @param string $namespace
|
||||
@ -57,7 +53,7 @@ class DriverChain implements Driver
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of nested drivers
|
||||
* Get the array of nested drivers.
|
||||
*
|
||||
* @return array $drivers
|
||||
*/
|
||||
@ -74,7 +70,7 @@ class DriverChain implements Driver
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
|
||||
{
|
||||
foreach ($this->_drivers AS $namespace => $driver) {
|
||||
foreach ($this->_drivers as $namespace => $driver) {
|
||||
if (strpos($className, $namespace) === 0) {
|
||||
$driver->loadMetadataForClass($className, $metadata);
|
||||
return;
|
||||
|
@ -30,7 +30,7 @@ use Doctrine\Common\Cache\ArrayCache,
|
||||
Doctrine\ORM\Mapping\Driver\AbstractFileDriver;
|
||||
|
||||
/**
|
||||
* The PhpDriver includes php files which just populate ClassMetadataInfo
|
||||
* The PHPDriver includes php files which just populate ClassMetadataInfo
|
||||
* instances with plain php code
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
@ -43,13 +43,12 @@ use Doctrine\Common\Cache\ArrayCache,
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @todo Rename: PHPDriver
|
||||
*/
|
||||
class PhpDriver extends AbstractFileDriver
|
||||
class PHPDriver extends AbstractFileDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $_fileExtension = '.php';
|
||||
|
||||
protected $_metadata;
|
||||
|
||||
/**
|
122
lib/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php
Normal file
122
lib/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo,
|
||||
Doctrine\ORM\Mapping\MappingException;
|
||||
|
||||
/**
|
||||
* The StaticPHPDriver calls a static loadMetadata() method on your entity
|
||||
* classes where you can manually populate the ClassMetadata instance.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class StaticPHPDriver implements Driver
|
||||
{
|
||||
private $_paths = array();
|
||||
|
||||
public function __construct($paths)
|
||||
{
|
||||
$this->addPaths((array) $paths);
|
||||
}
|
||||
|
||||
public function addPaths(array $paths)
|
||||
{
|
||||
$this->_paths = array_unique(array_merge($this->_paths, $paths));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
|
||||
{
|
||||
call_user_func_array(array($className, 'loadMetadata'), array($metadata));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @todo Same code exists in AnnotationDriver, should we re-use it somehow or not worry about it?
|
||||
*/
|
||||
public function getAllClassNames()
|
||||
{
|
||||
if ($this->_classNames !== null) {
|
||||
return $this->_classNames;
|
||||
}
|
||||
|
||||
if (!$this->_paths) {
|
||||
throw MappingException::pathRequired();
|
||||
}
|
||||
|
||||
$classes = array();
|
||||
$includedFiles = array();
|
||||
|
||||
foreach ($this->_paths as $path) {
|
||||
if ( ! is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath();
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($path),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
if (($fileName = $file->getBasename($this->_fileExtension)) == $file->getBasename()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sourceFile = realpath($file->getPathName());
|
||||
require_once $sourceFile;
|
||||
$includedFiles[] = $sourceFile;
|
||||
}
|
||||
}
|
||||
|
||||
$declared = get_declared_classes();
|
||||
|
||||
foreach ($declared as $className) {
|
||||
$rc = new \ReflectionClass($className);
|
||||
$sourceFile = $rc->getFileName();
|
||||
if (in_array($sourceFile, $includedFiles) && ! $this->isTransient($className)) {
|
||||
$classes[] = $className;
|
||||
}
|
||||
}
|
||||
|
||||
$this->_classNames = $classes;
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isTransient($className)
|
||||
{
|
||||
return method_exists($className, 'loadMetadata') ? false : true;
|
||||
}
|
||||
}
|
@ -21,7 +21,8 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo,
|
||||
use SimpleXMLElement,
|
||||
Doctrine\ORM\Mapping\ClassMetadataInfo,
|
||||
Doctrine\ORM\Mapping\MappingException;
|
||||
|
||||
/**
|
||||
@ -117,15 +118,17 @@ class XmlDriver extends AbstractFileDriver
|
||||
// Evaluate <unique-constraints..>
|
||||
if (isset($xmlRoot->{'unique-constraints'})) {
|
||||
foreach ($xmlRoot->{'unique-constraints'}->{'unique-constraint'} as $unique) {
|
||||
if (is_string($unique['columns'])) {
|
||||
$columns = explode(',', $unique['columns']);
|
||||
} else {
|
||||
$columns = $unique['columns'];
|
||||
}
|
||||
$columns = explode(',', (string)$unique['columns']);
|
||||
|
||||
$metadata->table['uniqueConstraints'][$unique['name']] = array(
|
||||
'columns' => $columns
|
||||
);
|
||||
if (isset($unique['name'])) {
|
||||
$metadata->table['uniqueConstraints'][(string)$unique['name']] = array(
|
||||
'columns' => $columns
|
||||
);
|
||||
} else {
|
||||
$metadata->table['uniqueConstraints'][] = array(
|
||||
'columns' => $columns
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,9 +205,9 @@ class XmlDriver extends AbstractFileDriver
|
||||
if (isset($idElement->{'sequence-generator'})) {
|
||||
$seqGenerator = $idElement->{'sequence-generator'};
|
||||
$metadata->setSequenceGeneratorDefinition(array(
|
||||
'sequenceName' => $seqGenerator->{'sequence-name'},
|
||||
'allocationSize' => $seqGenerator->{'allocation-size'},
|
||||
'initialValue' => $seqGeneratorAnnot->{'initial-value'}
|
||||
'sequenceName' => (string)$seqGenerator['sequence-name'],
|
||||
'allocationSize' => (string)$seqGenerator['allocation-size'],
|
||||
'initialValue' => (string)$seqGenerator['initial-value']
|
||||
));
|
||||
} else if (isset($idElement->{'table-generator'})) {
|
||||
throw MappingException::tableIdGeneratorNotImplemented($className);
|
||||
@ -226,6 +229,9 @@ class XmlDriver extends AbstractFileDriver
|
||||
if (isset($oneToOneElement['mapped-by'])) {
|
||||
$mapping['mappedBy'] = (string)$oneToOneElement['mapped-by'];
|
||||
} else {
|
||||
if (isset($oneToOneElement['inversed-by'])) {
|
||||
$mapping['inversedBy'] = (string)$oneToOneElement['inversed-by'];
|
||||
}
|
||||
$joinColumns = array();
|
||||
|
||||
if (isset($oneToOneElement->{'join-column'})) {
|
||||
@ -296,6 +302,10 @@ class XmlDriver extends AbstractFileDriver
|
||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . (string)$manyToOneElement['fetch']);
|
||||
}
|
||||
|
||||
if (isset($manyToOneElement['inversed-by'])) {
|
||||
$mapping['inversedBy'] = (string)$manyToOneElement['inversed-by'];
|
||||
}
|
||||
|
||||
$joinColumns = array();
|
||||
|
||||
if (isset($manyToOneElement->{'join-column'})) {
|
||||
@ -305,7 +315,6 @@ class XmlDriver extends AbstractFileDriver
|
||||
if (!isset($joinColumnElement['name'])) {
|
||||
$joinColumnElement['name'] = $name;
|
||||
}
|
||||
|
||||
$joinColumns[] = $this->_getJoinColumnMapping($joinColumnElement);
|
||||
}
|
||||
}
|
||||
@ -339,6 +348,10 @@ class XmlDriver extends AbstractFileDriver
|
||||
if (isset($manyToManyElement['mapped-by'])) {
|
||||
$mapping['mappedBy'] = (string)$manyToManyElement['mapped-by'];
|
||||
} else if (isset($manyToManyElement->{'join-table'})) {
|
||||
if (isset($manyToManyElement['inversed-by'])) {
|
||||
$mapping['inversedBy'] = (string)$manyToManyElement['inversed-by'];
|
||||
}
|
||||
|
||||
$joinTableElement = $manyToManyElement->{'join-table'};
|
||||
$joinTable = array(
|
||||
'name' => (string)$joinTableElement['name']
|
||||
@ -382,7 +395,7 @@ class XmlDriver extends AbstractFileDriver
|
||||
// Evaluate <lifecycle-callbacks...>
|
||||
if (isset($xmlRoot->{'lifecycle-callbacks'})) {
|
||||
foreach ($xmlRoot->{'lifecycle-callbacks'}->{'lifecycle-callback'} as $lifecycleCallback) {
|
||||
$metadata->addLifecycleCallback((string)$lifecycleCallback['method'], constant('\Doctrine\ORM\Events::' . (string)$lifecycleCallback['type']));
|
||||
$metadata->addLifecycleCallback((string)$lifecycleCallback['method'], constant('Doctrine\ORM\Events::' . (string)$lifecycleCallback['type']));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -394,7 +407,7 @@ class XmlDriver extends AbstractFileDriver
|
||||
* @param $joinColumnElement The XML element.
|
||||
* @return array The mapping array.
|
||||
*/
|
||||
private function _getJoinColumnMapping(\SimpleXMLElement $joinColumnElement)
|
||||
private function _getJoinColumnMapping(SimpleXMLElement $joinColumnElement)
|
||||
{
|
||||
$joinColumn = array(
|
||||
'name' => (string)$joinColumnElement['name'],
|
||||
|
@ -135,6 +135,10 @@ class YamlDriver extends AbstractFileDriver
|
||||
if (isset($element['id'])) {
|
||||
// Evaluate identifier settings
|
||||
foreach ($element['id'] as $name => $idElement) {
|
||||
if (!isset($idElement['type'])) {
|
||||
throw MappingException::propertyTypeIsRequired($className, $name);
|
||||
}
|
||||
|
||||
$mapping = array(
|
||||
'id' => true,
|
||||
'fieldName' => $name,
|
||||
@ -151,6 +155,12 @@ class YamlDriver extends AbstractFileDriver
|
||||
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
|
||||
. strtoupper($idElement['generator']['strategy'])));
|
||||
}
|
||||
// Check for SequenceGenerator/TableGenerator definition
|
||||
if (isset($idElement['sequenceGenerator'])) {
|
||||
$metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']);
|
||||
} else if (isset($idElement['tableGenerator'])) {
|
||||
throw MappingException::tableIdGeneratorNotImplemented($className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,12 +187,6 @@ class YamlDriver extends AbstractFileDriver
|
||||
. strtoupper($fieldMapping['generator']['strategy'])));
|
||||
}
|
||||
}
|
||||
// Check for SequenceGenerator/TableGenerator definition
|
||||
if (isset($fieldMapping['sequenceGenerator'])) {
|
||||
$metadata->setSequenceGeneratorDefinition($fieldMapping['sequenceGenerator']);
|
||||
} else if (isset($fieldMapping['tableGenerator'])) {
|
||||
throw MappingException::tableIdGeneratorNotImplemented($className);
|
||||
}
|
||||
if (isset($fieldMapping['column'])) {
|
||||
$mapping['columnName'] = $fieldMapping['column'];
|
||||
}
|
||||
@ -230,6 +234,10 @@ class YamlDriver extends AbstractFileDriver
|
||||
if (isset($oneToOneElement['mappedBy'])) {
|
||||
$mapping['mappedBy'] = $oneToOneElement['mappedBy'];
|
||||
} else {
|
||||
if (isset($oneToOneElement['inversedBy'])) {
|
||||
$mapping['inversedBy'] = $oneToOneElement['inversedBy'];
|
||||
}
|
||||
|
||||
$joinColumns = array();
|
||||
|
||||
if (isset($oneToOneElement['joinColumn'])) {
|
||||
@ -292,6 +300,10 @@ class YamlDriver extends AbstractFileDriver
|
||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $manyToOneElement['fetch']);
|
||||
}
|
||||
|
||||
if (isset($manyToOneElement['inversedBy'])) {
|
||||
$mapping['inversedBy'] = $manyToOneElement['inversedBy'];
|
||||
}
|
||||
|
||||
$joinColumns = array();
|
||||
|
||||
if (isset($manyToOneElement['joinColumn'])) {
|
||||
@ -331,6 +343,10 @@ class YamlDriver extends AbstractFileDriver
|
||||
if (isset($manyToManyElement['mappedBy'])) {
|
||||
$mapping['mappedBy'] = $manyToManyElement['mappedBy'];
|
||||
} else if (isset($manyToManyElement['joinTable'])) {
|
||||
if (isset($manyToManyElement['inversedBy'])) {
|
||||
$mapping['inversedBy'] = $manyToManyElement['inversedBy'];
|
||||
}
|
||||
|
||||
$joinTableElement = $manyToManyElement['joinTable'];
|
||||
$joinTable = array(
|
||||
'name' => $joinTableElement['name']
|
||||
@ -375,7 +391,7 @@ class YamlDriver extends AbstractFileDriver
|
||||
if (isset($element['lifecycleCallbacks'])) {
|
||||
foreach ($element['lifecycleCallbacks'] as $type => $methods) {
|
||||
foreach ($methods as $method) {
|
||||
$metadata->addLifecycleCallback($method, constant('\Doctrine\ORM\Events::' . $type));
|
||||
$metadata->addLifecycleCallback($method, constant('Doctrine\ORM\Events::' . $type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -39,6 +37,7 @@ namespace Doctrine\ORM\Mapping;
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
|
||||
*/
|
||||
class ManyToManyMapping extends AssociationMapping
|
||||
{
|
||||
@ -70,10 +69,7 @@ class ManyToManyMapping extends AssociationMapping
|
||||
public $orderBy;
|
||||
|
||||
/**
|
||||
* Validates and completes the mapping.
|
||||
*
|
||||
* @param array $mapping
|
||||
* @override
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function _validateAndCompleteMapping(array $mapping)
|
||||
{
|
||||
@ -89,13 +85,15 @@ class ManyToManyMapping extends AssociationMapping
|
||||
'joinColumns' => array(
|
||||
array(
|
||||
'name' => $sourceShortName . '_id',
|
||||
'referencedColumnName' => 'id'
|
||||
'referencedColumnName' => 'id',
|
||||
'onDelete' => 'CASCADE'
|
||||
)
|
||||
),
|
||||
'inverseJoinColumns' => array(
|
||||
array(
|
||||
'name' => $targetShortName . '_id',
|
||||
'referencedColumnName' => 'id'
|
||||
'referencedColumnName' => 'id',
|
||||
'onDelete' => 'CASCADE'
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -143,43 +141,37 @@ class ManyToManyMapping extends AssociationMapping
|
||||
* @param object The owner of the collection.
|
||||
* @param object The collection to populate.
|
||||
* @param array
|
||||
* @todo Remove
|
||||
*/
|
||||
public function load($sourceEntity, $targetCollection, $em, array $joinColumnValues = array())
|
||||
{
|
||||
$sourceClass = $em->getClassMetadata($this->sourceEntityName);
|
||||
$joinTableConditions = array();
|
||||
if ($this->isOwningSide) {
|
||||
foreach ($this->relationToSourceKeyColumns as $relationKeyColumn => $sourceKeyColumn) {
|
||||
// getting id
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$joinTableConditions[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$owningAssoc = $em->getClassMetadata($this->targetEntityName)->associationMappings[$this->mappedBy];
|
||||
// TRICKY: since the association is inverted source and target are flipped
|
||||
foreach ($owningAssoc->relationToTargetKeyColumns as $relationKeyColumn => $sourceKeyColumn) {
|
||||
// getting id
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$joinTableConditions[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$persister = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName);
|
||||
$persister->loadManyToManyCollection($this, $joinTableConditions, $targetCollection);
|
||||
$em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->loadManyToManyCollection($this, $sourceEntity, $targetCollection);
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function isManyToMany()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which fields get serialized.
|
||||
*
|
||||
* It is only serialized what is necessary for best unserialization performance.
|
||||
* That means any metadata properties that are not set or empty or simply have
|
||||
* their default value are NOT serialized.
|
||||
*
|
||||
* @return array The names of all the fields that should be serialized.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
$serialized = parent::__sleep();
|
||||
$serialized[] = 'joinTableColumns';
|
||||
$serialized[] = 'relationToSourceKeyColumns';
|
||||
$serialized[] = 'relationToTargetKeyColumns';
|
||||
if ($this->orderBy) {
|
||||
$serialized[] = 'orderBy';
|
||||
}
|
||||
return $serialized;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -28,6 +26,12 @@ namespace Doctrine\ORM\Mapping;
|
||||
*/
|
||||
class MappingException extends \Doctrine\ORM\ORMException
|
||||
{
|
||||
public static function pathRequired()
|
||||
{
|
||||
return new self("Specifying the paths to your entities is required ".
|
||||
"in the AnnotationDriver to retrieve all class names.");
|
||||
}
|
||||
|
||||
public static function identifierRequired($entityName)
|
||||
{
|
||||
return new self("No identifier/primary key specified for Entity '$entityName'."
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -43,6 +41,7 @@ namespace Doctrine\ORM\Mapping;
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @since 2.0
|
||||
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
|
||||
*/
|
||||
class OneToManyMapping extends AssociationMapping
|
||||
{
|
||||
@ -101,8 +100,6 @@ class OneToManyMapping extends AssociationMapping
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
public function isOneToMany()
|
||||
{
|
||||
@ -117,23 +114,31 @@ class OneToManyMapping extends AssociationMapping
|
||||
* @param $em The EntityManager to use.
|
||||
* @param $joinColumnValues
|
||||
* @return void
|
||||
* @todo Remove
|
||||
*/
|
||||
public function load($sourceEntity, $targetCollection, $em, array $joinColumnValues = array())
|
||||
{
|
||||
$persister = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName);
|
||||
// a one-to-many is always inverse (does not have foreign key)
|
||||
$sourceClass = $em->getClassMetadata($this->sourceEntityName);
|
||||
$owningAssoc = $em->getClassMetadata($this->targetEntityName)->associationMappings[$this->mappedBy];
|
||||
// TRICKY: since the association is specular source and target are flipped
|
||||
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
|
||||
// getting id
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$conditions[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
$conditions[$targetKeyColumn] = $joinColumnValues[$sourceKeyColumn];
|
||||
}
|
||||
}
|
||||
$em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->loadOneToManyCollection($this, $sourceEntity, $targetCollection);
|
||||
}
|
||||
|
||||
$persister->loadOneToManyCollection($this, $conditions, $targetCollection);
|
||||
/**
|
||||
* Determines which fields get serialized.
|
||||
*
|
||||
* It is only serialized what is necessary for best unserialization performance.
|
||||
* That means any metadata properties that are not set or empty or simply have
|
||||
* their default value are NOT serialized.
|
||||
*
|
||||
* @return array The names of all the fields that should be serialized.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
$serialized = parent::__sleep();
|
||||
if ($this->orderBy) {
|
||||
$serialized[] = 'orderBy';
|
||||
}
|
||||
if ($this->orphanRemoval) {
|
||||
$serialized[] = 'orphanRemoval';
|
||||
}
|
||||
return $serialized;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -39,6 +37,7 @@ namespace Doctrine\ORM\Mapping;
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
|
||||
*/
|
||||
class OneToOneMapping extends AssociationMapping
|
||||
{
|
||||
@ -135,60 +134,32 @@ class OneToOneMapping extends AssociationMapping
|
||||
* @param object $targetEntity the entity to load data in
|
||||
* @param EntityManager $em
|
||||
* @param array $joinColumnValues Values of the join columns of $sourceEntity.
|
||||
* @todo Remove
|
||||
*/
|
||||
public function load($sourceEntity, $targetEntity, $em, array $joinColumnValues = array())
|
||||
{
|
||||
$targetClass = $em->getClassMetadata($this->targetEntityName);
|
||||
return $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->loadOneToOneEntity($this, $sourceEntity, $targetEntity, $joinColumnValues);
|
||||
}
|
||||
|
||||
if ($this->isOwningSide) {
|
||||
$inverseField = isset($targetClass->inverseMappings[$this->sourceEntityName][$this->sourceFieldName]) ?
|
||||
$targetClass->inverseMappings[$this->sourceEntityName][$this->sourceFieldName]->sourceFieldName
|
||||
: false;
|
||||
|
||||
// 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 ($inverseField) {
|
||||
$hints['fetched'][$targetClass->name][$inverseField] = true;
|
||||
if ($targetClass->subClasses) {
|
||||
foreach ($targetClass->subClasses as $targetSubclassName) {
|
||||
$hints['fetched'][$targetSubclassName][$inverseField] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* cascade read-only status
|
||||
if ($em->getUnitOfWork()->isReadOnly($sourceEntity)) {
|
||||
$hints[Query::HINT_READ_ONLY] = true;
|
||||
}
|
||||
*/
|
||||
|
||||
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($joinColumnValues, $targetEntity, $this, $hints);
|
||||
|
||||
if ($targetEntity !== null && $inverseField && ! $targetClass->isCollectionValuedAssociation($inverseField)) {
|
||||
$targetClass->reflFields[$inverseField]->setValue($targetEntity, $sourceEntity);
|
||||
}
|
||||
} else {
|
||||
$conditions = array();
|
||||
$sourceClass = $em->getClassMetadata($this->sourceEntityName);
|
||||
$owningAssoc = $targetClass->getAssociationMapping($this->mappedBy);
|
||||
// TRICKY: since the association is specular source and target are flipped
|
||||
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$conditions[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity, $this);
|
||||
|
||||
if ($targetEntity !== null) {
|
||||
$targetClass->setFieldValue($targetEntity, $this->mappedBy, $sourceEntity);
|
||||
}
|
||||
/**
|
||||
* Determines which fields get serialized.
|
||||
*
|
||||
* It is only serialized what is necessary for best unserialization performance.
|
||||
* That means any metadata properties that are not set or empty or simply have
|
||||
* their default value are NOT serialized.
|
||||
*
|
||||
* @return array The names of all the fields that should be serialized.
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
$serialized = parent::__sleep();
|
||||
$serialized[] = 'joinColumns';
|
||||
$serialized[] = 'joinColumnFieldNames';
|
||||
$serialized[] = 'sourceToTargetKeyColumns';
|
||||
$serialized[] = 'targetToSourceKeyColumns';
|
||||
if ($this->orphanRemoval) {
|
||||
$serialized[] = 'orphanRemoval';
|
||||
}
|
||||
|
||||
return $targetEntity;
|
||||
return $serialized;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -21,8 +19,6 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
/**
|
||||
* Represents a native SQL query.
|
||||
*
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
|
@ -1,4 +1,21 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
@ -10,6 +27,12 @@ namespace Doctrine\ORM;
|
||||
*/
|
||||
class ORMException extends \Exception
|
||||
{
|
||||
public static function missingMappingDriverImpl()
|
||||
{
|
||||
return new self("It's a requirement to specify a Metadata Driver and pass it ".
|
||||
"to Doctrine\ORM\Configuration::setMetadataDriverImpl().");
|
||||
}
|
||||
|
||||
public static function entityMissingAssignedId($entity)
|
||||
{
|
||||
return new self("Entity of type " . get_class($entity) . " is missing an assigned ID.");
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -24,11 +22,8 @@ namespace Doctrine\ORM;
|
||||
/**
|
||||
* OptimisticLockException
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
*/
|
||||
class OptimisticLockException extends ORMException
|
||||
{
|
||||
|
@ -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
|
||||
@ -134,18 +132,7 @@ final class PersistentCollection implements Collection
|
||||
{
|
||||
$this->_owner = $entity;
|
||||
$this->_association = $assoc;
|
||||
|
||||
// Check for bidirectionality
|
||||
//$this->_backRefFieldName = $assoc->inversedBy ?: $assoc->mappedBy;
|
||||
if ( ! $assoc->isOwningSide) {
|
||||
// For sure bi-directional
|
||||
$this->_backRefFieldName = $assoc->mappedBy;
|
||||
} else {
|
||||
if (isset($this->_typeClass->inverseMappings[$assoc->sourceEntityName][$assoc->sourceFieldName])) {
|
||||
// Bi-directional
|
||||
$this->_backRefFieldName = $this->_typeClass->inverseMappings[$assoc->sourceEntityName][$assoc->sourceFieldName]->sourceFieldName;
|
||||
}
|
||||
}
|
||||
$this->_backRefFieldName = $assoc->inversedBy ?: $assoc->mappedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,8 +161,8 @@ final class PersistentCollection implements Collection
|
||||
public function hydrateAdd($element)
|
||||
{
|
||||
$this->_coll->add($element);
|
||||
// If _backRefFieldName is set, then the association is bidirectional
|
||||
// and we need to set the back reference.
|
||||
// If _backRefFieldName is set and its a one-to-many association,
|
||||
// we need to set the back reference.
|
||||
if ($this->_backRefFieldName && $this->_association->isOneToMany()) {
|
||||
// Set back reference to owner
|
||||
$this->_typeClass->reflFields[$this->_backRefFieldName]
|
||||
|
@ -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
|
||||
@ -33,24 +31,22 @@ use Doctrine\ORM\EntityManager,
|
||||
abstract class AbstractCollectionPersister
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var EntityManager
|
||||
*/
|
||||
protected $_em;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\DBAL\Connection
|
||||
* @var Doctrine\DBAL\Connection
|
||||
*/
|
||||
protected $_conn;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var \Doctrine\ORM\UnitOfWork
|
||||
* @var Doctrine\ORM\UnitOfWork
|
||||
*/
|
||||
protected $_uow;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of a class derived from {@link AbstractCollectionPersister}.
|
||||
* Initializes a new instance of a class derived from AbstractCollectionPersister.
|
||||
*
|
||||
* @param Doctrine\ORM\EntityManager $em
|
||||
*/
|
||||
@ -71,8 +67,8 @@ abstract class AbstractCollectionPersister
|
||||
if ( ! $coll->getMapping()->isOwningSide) {
|
||||
return; // ignore inverse side
|
||||
}
|
||||
$sql = $this->_getDeleteSql($coll);
|
||||
$this->_conn->executeUpdate($sql, $this->_getDeleteSqlParameters($coll));
|
||||
$sql = $this->_getDeleteSQL($coll);
|
||||
$this->_conn->executeUpdate($sql, $this->_getDeleteSQLParameters($coll));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,7 +76,7 @@ abstract class AbstractCollectionPersister
|
||||
*
|
||||
* @param PersistentCollection $coll
|
||||
*/
|
||||
abstract protected function _getDeleteSql(PersistentCollection $coll);
|
||||
abstract protected function _getDeleteSQL(PersistentCollection $coll);
|
||||
|
||||
/**
|
||||
* Gets the SQL parameters for the corresponding SQL statement to delete
|
||||
@ -88,7 +84,7 @@ abstract class AbstractCollectionPersister
|
||||
*
|
||||
* @param PersistentCollection $coll
|
||||
*/
|
||||
abstract protected function _getDeleteSqlParameters(PersistentCollection $coll);
|
||||
abstract protected function _getDeleteSQLParameters(PersistentCollection $coll);
|
||||
|
||||
/**
|
||||
* Updates the given collection, synchronizing it's state with the database
|
||||
@ -109,9 +105,9 @@ abstract class AbstractCollectionPersister
|
||||
public function deleteRows(PersistentCollection $coll)
|
||||
{
|
||||
$deleteDiff = $coll->getDeleteDiff();
|
||||
$sql = $this->_getDeleteRowSql($coll);
|
||||
$sql = $this->_getDeleteRowSQL($coll);
|
||||
foreach ($deleteDiff as $element) {
|
||||
$this->_conn->executeUpdate($sql, $this->_getDeleteRowSqlParameters($coll, $element));
|
||||
$this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element));
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,9 +117,9 @@ abstract class AbstractCollectionPersister
|
||||
public function insertRows(PersistentCollection $coll)
|
||||
{
|
||||
$insertDiff = $coll->getInsertDiff();
|
||||
$sql = $this->_getInsertRowSql($coll);
|
||||
$sql = $this->_getInsertRowSQL($coll);
|
||||
foreach ($insertDiff as $element) {
|
||||
$this->_conn->executeUpdate($sql, $this->_getInsertRowSqlParameters($coll, $element));
|
||||
$this->_conn->executeUpdate($sql, $this->_getInsertRowSQLParameters($coll, $element));
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,7 +128,7 @@ abstract class AbstractCollectionPersister
|
||||
*
|
||||
* @param PersistentCollection $coll
|
||||
*/
|
||||
abstract protected function _getDeleteRowSql(PersistentCollection $coll);
|
||||
abstract protected function _getDeleteRowSQL(PersistentCollection $coll);
|
||||
|
||||
/**
|
||||
* Gets the SQL parameters for the corresponding SQL statement to delete the given
|
||||
@ -141,21 +137,21 @@ abstract class AbstractCollectionPersister
|
||||
* @param PersistentCollection $coll
|
||||
* @param mixed $element
|
||||
*/
|
||||
abstract protected function _getDeleteRowSqlParameters(PersistentCollection $coll, $element);
|
||||
abstract protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element);
|
||||
|
||||
/**
|
||||
* Gets the SQL statement used for updating a row in the collection.
|
||||
*
|
||||
* @param PersistentCollection $coll
|
||||
*/
|
||||
abstract protected function _getUpdateRowSql(PersistentCollection $coll);
|
||||
abstract protected function _getUpdateRowSQL(PersistentCollection $coll);
|
||||
|
||||
/**
|
||||
* Gets the SQL statement used for inserting a row in the collection.
|
||||
*
|
||||
* @param PersistentCollection $coll
|
||||
*/
|
||||
abstract protected function _getInsertRowSql(PersistentCollection $coll);
|
||||
abstract protected function _getInsertRowSQL(PersistentCollection $coll);
|
||||
|
||||
/**
|
||||
* Gets the SQL parameters for the corresponding SQL statement to insert the given
|
||||
@ -164,5 +160,5 @@ abstract class AbstractCollectionPersister
|
||||
* @param PersistentCollection $coll
|
||||
* @param mixed $element
|
||||
*/
|
||||
abstract protected function _getInsertRowSqlParameters(PersistentCollection $coll, $element);
|
||||
abstract protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element);
|
||||
}
|
@ -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
|
||||
@ -32,7 +30,7 @@ use Doctrine\ORM\Mapping\ClassMetadata,
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class AbstractEntityInheritancePersister extends StandardEntityPersister
|
||||
abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
{
|
||||
/**
|
||||
* Map from column names to class names that declare the field the column is mapped to.
|
||||
@ -93,7 +91,7 @@ abstract class AbstractEntityInheritancePersister extends StandardEntityPersiste
|
||||
protected function _getSelectColumnSQL($field, ClassMetadata $class)
|
||||
{
|
||||
$columnName = $class->columnNames[$field];
|
||||
$sql = $this->_getSQLTableAlias($class) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$sql = $this->_getSQLTableAlias($class->name) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
|
||||
if ( ! isset($this->_resultColumnNames[$columnAlias])) {
|
||||
$this->_resultColumnNames[$columnAlias] = $columnName;
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -28,19 +26,52 @@ use PDO,
|
||||
Doctrine\ORM\EntityManager,
|
||||
Doctrine\ORM\Query,
|
||||
Doctrine\ORM\PersistentCollection,
|
||||
Doctrine\ORM\Mapping\ClassMetadata;
|
||||
Doctrine\ORM\Mapping\MappingException,
|
||||
Doctrine\ORM\Mapping\ClassMetadata,
|
||||
Doctrine\ORM\Mapping\OneToOneMapping,
|
||||
Doctrine\ORM\Mapping\OneToManyMapping,
|
||||
Doctrine\ORM\Mapping\ManyToManyMapping;
|
||||
|
||||
/**
|
||||
* A basic entity persister that maps an entity with no (mapped) inheritance to a single table
|
||||
* in the relational database.
|
||||
* A BasicEntityPersiter maps an entity to a single table in a relational database.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @since 2.0
|
||||
* @todo Rename: BasicEntityPersister
|
||||
* A persister is always responsible for a single entity type.
|
||||
*
|
||||
* EntityPersisters are used during a UnitOfWork to apply any changes to the persistent
|
||||
* state of entities onto a relational database when the UnitOfWork is committed,
|
||||
* as well as for basic querying of entities and their associations (not DQL).
|
||||
*
|
||||
* The persisting operations that are invoked during a commit of a UnitOfWork to
|
||||
* persist the persistent entity state are:
|
||||
*
|
||||
* - {@link addInsert} : To schedule an entity for insertion.
|
||||
* - {@link executeInserts} : To execute all scheduled insertions.
|
||||
* - {@link update} : To update the persistent state of an entity.
|
||||
* - {@link delete} : To delete the persistent state of an entity.
|
||||
*
|
||||
* As can be seen from the above list, insertions are batched and executed all at once
|
||||
* for increased efficiency.
|
||||
*
|
||||
* The querying operations invoked during a UnitOfWork, either through direct find
|
||||
* requests or lazy-loading, are the following:
|
||||
*
|
||||
* - {@link load} : Loads (the state of) a single, managed entity.
|
||||
* - {@link loadAll} : Loads multiple, managed entities.
|
||||
* - {@link loadOneToOneEntity} : Loads a one/many-to-one association (lazy-loading).
|
||||
* - {@link loadOneToManyCollection} : Loads a one-to-many association (lazy-loading).
|
||||
* - {@link loadManyToManyCollection} : Loads a many-to-many association (lazy-loading).
|
||||
*
|
||||
* The BasicEntityPersister implementation provides the default behavior for
|
||||
* persisting and querying entities that are mapped to a single database table.
|
||||
*
|
||||
* Subclasses can be created to provide custom persisting and querying strategies,
|
||||
* i.e. spanning multiple tables.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class StandardEntityPersister
|
||||
class BasicEntityPersister
|
||||
{
|
||||
/**
|
||||
* Metadata object that describes the mapping of the mapped entity class.
|
||||
@ -50,7 +81,7 @@ class StandardEntityPersister
|
||||
protected $_class;
|
||||
|
||||
/**
|
||||
* The underlying Connection of the used EntityManager.
|
||||
* The underlying DBAL Connection of the used EntityManager.
|
||||
*
|
||||
* @var Doctrine\DBAL\Connection $conn
|
||||
*/
|
||||
@ -59,7 +90,7 @@ class StandardEntityPersister
|
||||
/**
|
||||
* The database platform.
|
||||
*
|
||||
* @var AbstractPlatform
|
||||
* @var Doctrine\DBAL\Platforms\AbstractPlatform
|
||||
*/
|
||||
protected $_platform;
|
||||
|
||||
@ -87,8 +118,8 @@ class StandardEntityPersister
|
||||
protected $_resultColumnNames = array();
|
||||
|
||||
/**
|
||||
* The map of column names to DBAL mapping types of all prepared columns used when INSERTing
|
||||
* or UPDATEing an entity.
|
||||
* The map of column names to DBAL mapping types of all prepared columns used
|
||||
* when INSERTing or UPDATEing an entity.
|
||||
*
|
||||
* @var array
|
||||
* @see _prepareInsertData($entity)
|
||||
@ -127,7 +158,7 @@ class StandardEntityPersister
|
||||
protected $_sqlTableAliases = array();
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>StandardEntityPersister</tt> that uses the given EntityManager
|
||||
* Initializes a new <tt>BasicEntityPersister</tt> that uses the given EntityManager
|
||||
* and persists instances of the class described by the given ClassMetadata descriptor.
|
||||
*
|
||||
* @param Doctrine\ORM\EntityManager $em
|
||||
@ -143,9 +174,9 @@ class StandardEntityPersister
|
||||
|
||||
/**
|
||||
* Adds an entity to the queued insertions.
|
||||
* The entity remains queued until {@link executeInserts()} is invoked.
|
||||
* The entity remains queued until {@link executeInserts} is invoked.
|
||||
*
|
||||
* @param object $entity The entitiy to queue for insertion.
|
||||
* @param object $entity The entity to queue for insertion.
|
||||
*/
|
||||
public function addInsert($entity)
|
||||
{
|
||||
@ -171,7 +202,7 @@ class StandardEntityPersister
|
||||
$idGen = $this->_class->idGenerator;
|
||||
$isPostInsertId = $idGen->isPostInsertGenerator();
|
||||
|
||||
$stmt = $this->_conn->prepare($this->getInsertSQL());
|
||||
$stmt = $this->_conn->prepare($this->_getInsertSQL());
|
||||
$tableName = $this->_class->table['name'];
|
||||
|
||||
foreach ($this->_queuedInserts as $entity) {
|
||||
@ -209,9 +240,9 @@ class StandardEntityPersister
|
||||
* by the preceding INSERT statement and assigns it back in to the
|
||||
* entities version field.
|
||||
*
|
||||
* @param $class
|
||||
* @param $entity
|
||||
* @param $id
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $class
|
||||
* @param object $entity
|
||||
* @param mixed $id
|
||||
*/
|
||||
protected function _assignDefaultVersionValue($class, $entity, $id)
|
||||
{
|
||||
@ -226,7 +257,16 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an entity.
|
||||
* Updates a managed entity. The entity is updated according to its current changeset
|
||||
* in the running UnitOfWork. If there is no changeset, nothing is updated.
|
||||
*
|
||||
* The data to update is retrieved through {@link _prepareUpdateData}.
|
||||
* Subclasses that override this method are supposed to obtain the update data
|
||||
* in the same way, through {@link _prepareUpdateData}.
|
||||
*
|
||||
* Subclasses are also supposed to take care of versioning when overriding this method,
|
||||
* if necessary. The {@link _updateTable} method can be used to apply the data retrieved
|
||||
* from {@_prepareUpdateData} on the target tables, thereby optionally applying versioning.
|
||||
*
|
||||
* @param object $entity The entity to update.
|
||||
*/
|
||||
@ -241,14 +281,14 @@ class StandardEntityPersister
|
||||
|
||||
/**
|
||||
* Performs an UPDATE statement for an entity on a specific table.
|
||||
* The UPDATE can be optionally versioned, which requires the entity to have a version field.
|
||||
* The UPDATE can optionally be versioned, which requires the entity to have a version field.
|
||||
*
|
||||
* @param object $entity The entity object being updated.
|
||||
* @param string $tableName The name of the table to apply the UPDATE on.
|
||||
* @param array $updateData The map of columns to update (column => value).
|
||||
* @param boolean $versioned Whether the UPDATE should be versioned.
|
||||
*/
|
||||
protected function _updateTable($entity, $tableName, $updateData, $versioned = false)
|
||||
protected final function _updateTable($entity, $tableName, array $updateData, $versioned = false)
|
||||
{
|
||||
$set = $params = $types = array();
|
||||
|
||||
@ -284,7 +324,7 @@ class StandardEntityPersister
|
||||
$types[] = $this->_class->fieldMappings[$versionField]['type'];
|
||||
}
|
||||
|
||||
$sql = 'UPDATE ' . $tableName . ' SET ' . implode(', ', $set)
|
||||
$sql = "UPDATE $tableName SET " . implode(', ', $set)
|
||||
. ' WHERE ' . implode(' = ? AND ', $where) . ' = ?';
|
||||
|
||||
$result = $this->_conn->executeUpdate($sql, $params, $types);
|
||||
@ -295,7 +335,12 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an entity.
|
||||
* Deletes a managed entity.
|
||||
*
|
||||
* The entity to delete must be managed and have a persistent identifier.
|
||||
* The deletion happens instantaneously.
|
||||
*
|
||||
* Subclasses may override this method to customize the semantics of entity deletion.
|
||||
*
|
||||
* @param object $entity The entity to delete.
|
||||
*/
|
||||
@ -319,7 +364,9 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the data changeset of an entity for database insertion.
|
||||
* Prepares the changeset of an entity for database insertion (UPDATE).
|
||||
*
|
||||
* The changeset is obtained from the currently running UnitOfWork.
|
||||
*
|
||||
* During this preparation the array that is passed as the second parameter is filled with
|
||||
* <columnName> => <value> pairs, grouped by table name.
|
||||
@ -333,8 +380,6 @@ class StandardEntityPersister
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* Notes to inheritors: Be sure to call <code>parent::_prepareData($entity, $result, $isInsert);</code>
|
||||
*
|
||||
* @param object $entity The entity for which to prepare the data.
|
||||
* @return array The prepared data.
|
||||
*/
|
||||
@ -348,7 +393,7 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
foreach ($uow->getEntityChangeSet($entity) as $field => $change) {
|
||||
if ($versioned && $versionField == $field) {
|
||||
if ($versioned && $versionField == $field) { //TODO: Needed?
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -356,9 +401,9 @@ class StandardEntityPersister
|
||||
$newVal = $change[1];
|
||||
|
||||
if (isset($this->_class->associationMappings[$field])) {
|
||||
$assocMapping = $this->_class->associationMappings[$field];
|
||||
$assoc = $this->_class->associationMappings[$field];
|
||||
// Only owning side of x-1 associations can have a FK column.
|
||||
if ( ! $assocMapping->isOwningSide || ! $assocMapping->isOneToOne()) {
|
||||
if ( ! $assoc->isOwningSide || ! $assoc->isOneToOne()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -379,10 +424,10 @@ class StandardEntityPersister
|
||||
$newValId = $uow->getEntityIdentifier($newVal);
|
||||
}
|
||||
|
||||
$targetClass = $this->_em->getClassMetadata($assocMapping->targetEntityName);
|
||||
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
|
||||
$owningTable = $this->getOwningTable($field);
|
||||
|
||||
foreach ($assocMapping->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
|
||||
foreach ($assoc->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
|
||||
if ($newVal === null) {
|
||||
$result[$owningTable][$sourceColumn] = null;
|
||||
} else {
|
||||
@ -399,6 +444,16 @@ class StandardEntityPersister
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the data changeset of a managed entity for database insertion (initial INSERT).
|
||||
* The changeset of the entity is obtained from the currently running UnitOfWork.
|
||||
*
|
||||
* The default insert data preparation is the same as for updates.
|
||||
*
|
||||
* @param object $entity The entity for which to prepare the data.
|
||||
* @return array The prepared data for the tables to update.
|
||||
* @see _prepareUpdateData
|
||||
*/
|
||||
protected function _prepareInsertData($entity)
|
||||
{
|
||||
return $this->_prepareUpdateData($entity);
|
||||
@ -407,8 +462,12 @@ class StandardEntityPersister
|
||||
/**
|
||||
* Gets the name of the table that owns the column the given field is mapped to.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @return string
|
||||
* The default implementation in BasicEntityPersister always returns the name
|
||||
* of the table the entity type of this persister is mapped to, since an entity
|
||||
* is always persisted to a single table with a BasicEntityPersister.
|
||||
*
|
||||
* @param string $fieldName The field name.
|
||||
* @return string The table name.
|
||||
*/
|
||||
public function getOwningTable($fieldName)
|
||||
{
|
||||
@ -423,13 +482,13 @@ class StandardEntityPersister
|
||||
* a new entity is created.
|
||||
* @param $assoc The association that connects the entity to load to another entity, if any.
|
||||
* @param array $hints Hints for entity creation.
|
||||
* @return The loaded entity instance or NULL if the entity/the data can not be found.
|
||||
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
|
||||
* @todo Check identity map? loadById method? Try to guess whether $criteria is the id?
|
||||
*/
|
||||
public function load(array $criteria, $entity = null, $assoc = null, array $hints = array())
|
||||
{
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc);
|
||||
$params = array_values($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
$stmt = $this->_conn->executeQuery($sql, array_values($criteria));
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
@ -437,17 +496,80 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes an entity.
|
||||
* Loads an entity of this persister's mapped class as part of a single-valued
|
||||
* association from another entity.
|
||||
*
|
||||
* @param array $id The identifier of the entity as an associative array from column names to values.
|
||||
* @param OneToOneMapping $assoc The association to load.
|
||||
* @param object $sourceEntity The entity that owns the association (not necessarily the "owning side").
|
||||
* @param object $targetEntity The existing ghost entity (proxy) to load, if any.
|
||||
* @param array $identifier The identifier of the entity to load. Must be provided if
|
||||
* the association to load represents the owning side, otherwise
|
||||
* the identifier is derived from the $sourceEntity.
|
||||
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
|
||||
*/
|
||||
public function loadOneToOneEntity(OneToOneMapping $assoc, $sourceEntity, $targetEntity, array $identifier = array())
|
||||
{
|
||||
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
|
||||
|
||||
if ($assoc->isOwningSide) {
|
||||
// Mark inverse side as fetched in the hints, otherwise the UoW would
|
||||
// try to load it in a separate query (remember: to-one inverse sides can not be lazy).
|
||||
$hints = array();
|
||||
if ($assoc->inversedBy) {
|
||||
$hints['fetched'][$targetClass->name][$assoc->inversedBy] = true;
|
||||
if ($targetClass->subClasses) {
|
||||
foreach ($targetClass->subClasses as $targetSubclassName) {
|
||||
$hints['fetched'][$targetSubclassName][$assoc->inversedBy] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* cascade read-only status
|
||||
if ($this->_em->getUnitOfWork()->isReadOnly($sourceEntity)) {
|
||||
$hints[Query::HINT_READ_ONLY] = true;
|
||||
}
|
||||
*/
|
||||
|
||||
$targetEntity = $this->load($identifier, $targetEntity, $assoc, $hints);
|
||||
|
||||
// Complete bidirectional association, if necessary
|
||||
if ($targetEntity !== null && $assoc->inversedBy && ! $targetClass->isCollectionValuedAssociation($assoc->inversedBy)) {
|
||||
$targetClass->reflFields[$assoc->inversedBy]->setValue($targetEntity, $sourceEntity);
|
||||
}
|
||||
} else {
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc->sourceEntityName);
|
||||
$owningAssoc = $targetClass->getAssociationMapping($assoc->mappedBy);
|
||||
// TRICKY: since the association is specular source and target are flipped
|
||||
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$identifier[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$targetEntity = $this->load($identifier, $targetEntity, $assoc);
|
||||
|
||||
if ($targetEntity !== null) {
|
||||
$targetClass->setFieldValue($targetEntity, $assoc->mappedBy, $sourceEntity);
|
||||
}
|
||||
}
|
||||
|
||||
return $targetEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes a managed entity.
|
||||
*
|
||||
* @param array $id The identifier of the entity as an associative array from
|
||||
* column or field names to values.
|
||||
* @param object $entity The entity to refresh.
|
||||
*/
|
||||
public function refresh(array $id, $entity)
|
||||
{
|
||||
$sql = $this->_getSelectEntitiesSQL($id);
|
||||
$params = array_values($id);
|
||||
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
$stmt = $this->_conn->executeQuery($sql, array_values($id));
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
@ -492,8 +614,8 @@ class StandardEntityPersister
|
||||
if ($found = $this->_em->getUnitOfWork()->tryGetById($joinColumnValues, $targetClass->rootEntityName)) {
|
||||
$this->_class->reflFields[$field]->setValue($entity, $found);
|
||||
// Complete inverse side, if necessary.
|
||||
if (isset($targetClass->inverseMappings[$this->_class->name][$field])) {
|
||||
$inverseAssoc = $targetClass->inverseMappings[$this->_class->name][$field];
|
||||
if ($assoc->inversedBy) {
|
||||
$inverseAssoc = $targetClass->associationMappings[$assoc->inversedBy];
|
||||
$targetClass->reflFields[$inverseAssoc->sourceFieldName]->setValue($found, $entity);
|
||||
}
|
||||
$newData[$field] = $found;
|
||||
@ -527,10 +649,8 @@ class StandardEntityPersister
|
||||
public function loadAll(array $criteria = array())
|
||||
{
|
||||
$entities = array();
|
||||
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria);
|
||||
$params = array_values($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
$stmt = $this->_conn->executeQuery($sql, array_values($criteria));
|
||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
@ -541,37 +661,44 @@ class StandardEntityPersister
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a collection of entities in a one-to-many association.
|
||||
*
|
||||
* @param OneToManyMapping $assoc
|
||||
* @param array $criteria The criteria by which to select the entities.
|
||||
* @param PersistentCollection The collection to fill.
|
||||
*/
|
||||
public function loadOneToManyCollection($assoc, array $criteria, PersistentCollection $coll)
|
||||
{
|
||||
$owningAssoc = $this->_class->associationMappings[$coll->getMapping()->mappedBy];
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $owningAssoc, $assoc->orderBy);
|
||||
$params = array_values($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$coll->hydrateAdd($this->_createEntity($result));
|
||||
}
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a collection of entities of a many-to-many association.
|
||||
*
|
||||
* @param ManyToManyMapping $assoc
|
||||
* @param array $criteria
|
||||
* @param ManyToManyMapping $assoc The association mapping of the association being loaded.
|
||||
* @param object $sourceEntity The entity that owns the collection.
|
||||
* @param PersistentCollection $coll The collection to fill.
|
||||
*/
|
||||
public function loadManyToManyCollection($assoc, array $criteria, PersistentCollection $coll)
|
||||
public function loadManyToManyCollection(ManyToManyMapping $assoc, $sourceEntity, PersistentCollection $coll)
|
||||
{
|
||||
$sql = $this->_getSelectManyToManyEntityCollectionSQL($assoc, $criteria);
|
||||
$params = array_values($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
$criteria = array();
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc->sourceEntityName);
|
||||
$joinTableConditions = array();
|
||||
if ($assoc->isOwningSide) {
|
||||
foreach ($assoc->relationToSourceKeyColumns as $relationKeyColumn => $sourceKeyColumn) {
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$criteria[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$owningAssoc = $this->_em->getClassMetadata($assoc->targetEntityName)->associationMappings[$assoc->mappedBy];
|
||||
// TRICKY: since the association is inverted source and target are flipped
|
||||
foreach ($owningAssoc->relationToTargetKeyColumns as $relationKeyColumn => $sourceKeyColumn) {
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$criteria[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc);
|
||||
$stmt = $this->_conn->executeQuery($sql, array_values($criteria));
|
||||
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$coll->hydrateAdd($this->_createEntity($result));
|
||||
}
|
||||
@ -614,9 +741,14 @@ class StandardEntityPersister
|
||||
* Processes an SQL result set row that contains data for an entity of the type
|
||||
* this persister is responsible for.
|
||||
*
|
||||
* Subclasses are supposed to override this method if they need to change the
|
||||
* hydration procedure for entities loaded through basic find operations or
|
||||
* lazy-loading (not DQL).
|
||||
*
|
||||
* @param array $sqlResult The SQL result set row to process.
|
||||
* @return array A tuple where the first value is the actual type of the entity and
|
||||
* the second value the prepared data of the entity.
|
||||
* the second value the prepared data of the entity (a map from field
|
||||
* names to values).
|
||||
*/
|
||||
protected function _processSQLResult(array $sqlResult)
|
||||
{
|
||||
@ -640,51 +772,37 @@ class StandardEntityPersister
|
||||
*
|
||||
* @param array $criteria
|
||||
* @param AssociationMapping $assoc
|
||||
* @param string $orderBy
|
||||
* @return string
|
||||
* @todo Refactor: _getSelectSQL(...)
|
||||
*/
|
||||
protected function _getSelectEntitiesSQL(array &$criteria, $assoc = null, $orderBy = null)
|
||||
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null)
|
||||
{
|
||||
// Construct WHERE conditions
|
||||
$conditionSql = '';
|
||||
foreach ($criteria as $field => $value) {
|
||||
if ($conditionSql != '') {
|
||||
$conditionSql .= ' AND ';
|
||||
}
|
||||
$joinSql = $assoc != null && $assoc->isManyToMany() ?
|
||||
$this->_getSelectManyToManyJoinSQL($assoc) : '';
|
||||
|
||||
if (isset($this->_class->columnNames[$field])) {
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
} else if (isset($this->_class->fieldNames[$field])) {
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($this->_class->fieldNames[$field], $this->_platform);
|
||||
} else if ($assoc !== null) {
|
||||
$conditionSql .= $field;
|
||||
} else {
|
||||
throw ORMException::unrecognizedField($field);
|
||||
}
|
||||
$conditionSql .= ' = ?';
|
||||
}
|
||||
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
|
||||
|
||||
$orderBySql = '';
|
||||
if ($orderBy !== null) {
|
||||
$orderBySql = $this->_getCollectionOrderBySQL(
|
||||
$orderBy, $this->_getSQLTableAlias($this->_class)
|
||||
);
|
||||
}
|
||||
$orderBySql = $assoc !== null && isset($assoc->orderBy) ?
|
||||
$this->_getCollectionOrderBySQL($assoc->orderBy, $this->_getSQLTableAlias($this->_class->name))
|
||||
: '';
|
||||
|
||||
return 'SELECT ' . $this->_getSelectColumnListSQL()
|
||||
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->_getSQLTableAlias($this->_class)
|
||||
. ($conditionSql ? ' WHERE ' . $conditionSql : '') . $orderBySql;
|
||||
. $this->_getSQLTableAlias($this->_class->name)
|
||||
. $joinSql
|
||||
. ($conditionSql ? ' WHERE ' . $conditionSql : '')
|
||||
. $orderBySql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate ORDER BY SQL snippet for ordered collections.
|
||||
* Gets the ORDER BY SQL snippet for ordered collections.
|
||||
*
|
||||
* @param array $orderBy
|
||||
* @param string $baseTableAlias
|
||||
* @return string
|
||||
* @todo Rename: _getOrderBySQL
|
||||
*/
|
||||
protected function _getCollectionOrderBySQL(array $orderBy, $baseTableAlias)
|
||||
protected final function _getCollectionOrderBySQL(array $orderBy, $baseTableAlias)
|
||||
{
|
||||
$orderBySql = '';
|
||||
foreach ($orderBy as $fieldName => $orientation) {
|
||||
@ -693,14 +811,11 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
$tableAlias = isset($this->_class->fieldMappings[$fieldName]['inherited']) ?
|
||||
$this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->fieldMappings[$fieldName]['inherited']))
|
||||
$this->_getSQLTableAlias($this->_class->fieldMappings[$fieldName]['inherited'])
|
||||
: $baseTableAlias;
|
||||
|
||||
$columnName = $this->_class->getQuotedColumnName($fieldName, $this->_platform);
|
||||
if ($orderBySql != '') {
|
||||
$orderBySql .= ', ';
|
||||
} else {
|
||||
$orderBySql = ' ORDER BY ';
|
||||
}
|
||||
$orderBySql .= $orderBySql ? ', ' : ' ORDER BY ';
|
||||
$orderBySql .= $tableAlias . '.' . $columnName . ' ' . $orientation;
|
||||
}
|
||||
|
||||
@ -709,10 +824,15 @@ class StandardEntityPersister
|
||||
|
||||
/**
|
||||
* Gets the SQL fragment with the list of columns to select when querying for
|
||||
* an entity within this persister.
|
||||
* an entity in this persister.
|
||||
*
|
||||
* Subclasses should override this method to alter or change the select column
|
||||
* list SQL fragment. Note that in the implementation of BasicEntityPersister
|
||||
* the resulting SQL fragment is generated only once and cached in {@link _selectColumnListSql}.
|
||||
* Subclasses may or may not do the same.
|
||||
*
|
||||
* @return string The SQL fragment.
|
||||
* @todo Rename: _getSelectColumnListSQL()
|
||||
* @todo Rename: _getSelectColumnsSQL()
|
||||
*/
|
||||
protected function _getSelectColumnListSQL()
|
||||
{
|
||||
@ -724,7 +844,7 @@ class StandardEntityPersister
|
||||
|
||||
// Add regular columns to select list
|
||||
foreach ($this->_class->fieldNames as $field) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
if ($columnList) $columnList .= ', ';
|
||||
$columnList .= $this->_getSelectColumnSQL($field, $this->_class);
|
||||
}
|
||||
|
||||
@ -734,13 +854,13 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL to select a collection of entities in a many-many association.
|
||||
* Gets the SQL join fragment used when selecting entities from a
|
||||
* many-to-many association.
|
||||
*
|
||||
* @param ManyToManyMapping $manyToMany
|
||||
* @param array $criteria
|
||||
* @return string
|
||||
*/
|
||||
protected function _getSelectManyToManyEntityCollectionSQL($manyToMany, array &$criteria)
|
||||
protected function _getSelectManyToManyJoinSQL(ManyToManyMapping $manyToMany)
|
||||
{
|
||||
if ($manyToMany->isOwningSide) {
|
||||
$owningAssoc = $manyToMany;
|
||||
@ -755,32 +875,12 @@ class StandardEntityPersister
|
||||
$joinSql = '';
|
||||
foreach ($joinClauses as $joinTableColumn => $sourceColumn) {
|
||||
if ($joinSql != '') $joinSql .= ' AND ';
|
||||
$joinSql .= $this->_getSQLTableAlias($this->_class) .
|
||||
$joinSql .= $this->_getSQLTableAlias($this->_class->name) .
|
||||
'.' . $this->_class->getQuotedColumnName($this->_class->fieldNames[$sourceColumn], $this->_platform) . ' = '
|
||||
. $joinTableName . '.' . $joinTableColumn;
|
||||
}
|
||||
|
||||
$joinSql = ' INNER JOIN ' . $joinTableName . ' ON ' . $joinSql;
|
||||
|
||||
$conditionSql = '';
|
||||
foreach ($criteria as $joinColumn => $value) {
|
||||
if ($conditionSql != '') $conditionSql .= ' AND ';
|
||||
$columnName = $joinTableName . '.' . $joinColumn;
|
||||
$conditionSql .= $columnName . ' = ?';
|
||||
}
|
||||
|
||||
$orderBySql = '';
|
||||
if ($manyToMany->orderBy !== null) {
|
||||
$orderBySql = $this->_getCollectionOrderBySQL(
|
||||
$manyToMany->orderBy, $this->_getSQLTableAlias($this->_class)
|
||||
);
|
||||
}
|
||||
|
||||
return 'SELECT ' . $this->_getSelectColumnListSQL()
|
||||
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->_getSQLTableAlias($this->_class)
|
||||
. $joinSql
|
||||
. ' WHERE ' . $conditionSql . $orderBySql;
|
||||
return " INNER JOIN $joinTableName ON $joinSql";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -788,10 +888,25 @@ class StandardEntityPersister
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInsertSQL()
|
||||
protected function _getInsertSQL()
|
||||
{
|
||||
if ($this->_insertSql === null) {
|
||||
$this->_insertSql = $this->_generateInsertSQL();
|
||||
$insertSql = '';
|
||||
$columns = $this->_getInsertColumnList();
|
||||
if (empty($columns)) {
|
||||
$insertSql = $this->_platform->getEmptyIdentityInsertSQL(
|
||||
$this->_class->getQuotedTableName($this->_platform),
|
||||
$this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform)
|
||||
);
|
||||
} else {
|
||||
$columns = array_unique($columns);
|
||||
$values = array_fill(0, count($columns), '?');
|
||||
|
||||
$insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform)
|
||||
. ' (' . implode(', ', $columns) . ') '
|
||||
. 'VALUES (' . implode(', ', $values) . ')';
|
||||
}
|
||||
$this->_insertSql = $insertSql;
|
||||
}
|
||||
return $this->_insertSql;
|
||||
}
|
||||
@ -799,8 +914,10 @@ class StandardEntityPersister
|
||||
/**
|
||||
* Gets the list of columns to put in the INSERT SQL statement.
|
||||
*
|
||||
* Subclasses should override this method to alter or change the list of
|
||||
* columns placed in the INSERT statements used by the persister.
|
||||
*
|
||||
* @return array The list of columns.
|
||||
* @internal INSERT SQL is cached by getInsertSQL() per request.
|
||||
*/
|
||||
protected function _getInsertColumnList()
|
||||
{
|
||||
@ -825,33 +942,6 @@ class StandardEntityPersister
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the INSERT SQL used by the persister to persist entities.
|
||||
*
|
||||
* @return string
|
||||
* @internal Result is cached by getInsertSQL() per request.
|
||||
*/
|
||||
protected function _generateInsertSQL()
|
||||
{
|
||||
$insertSql = '';
|
||||
$columns = $this->_getInsertColumnList();
|
||||
if (empty($columns)) {
|
||||
$insertSql = $this->_platform->getEmptyIdentityInsertSQL(
|
||||
$this->_class->getQuotedTableName($this->_platform),
|
||||
$this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform)
|
||||
);
|
||||
} else {
|
||||
$columns = array_unique($columns);
|
||||
$values = array_fill(0, count($columns), '?');
|
||||
|
||||
$insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform)
|
||||
. ' (' . implode(', ', $columns) . ') '
|
||||
. 'VALUES (' . implode(', ', $values) . ')';
|
||||
}
|
||||
|
||||
return $insertSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL snippet of a qualified column name for the given field name.
|
||||
*
|
||||
@ -862,7 +952,7 @@ class StandardEntityPersister
|
||||
protected function _getSelectColumnSQL($field, ClassMetadata $class)
|
||||
{
|
||||
$columnName = $class->columnNames[$field];
|
||||
$sql = $this->_getSQLTableAlias($class) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$sql = $this->_getSQLTableAlias($class->name) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
|
||||
if ( ! isset($this->_resultColumnNames[$columnAlias])) {
|
||||
$this->_resultColumnNames[$columnAlias] = $columnName;
|
||||
@ -875,16 +965,18 @@ class StandardEntityPersister
|
||||
* Gets the SQL snippet for all join columns of the given class that are to be
|
||||
* placed in an SQL SELECT statement.
|
||||
*
|
||||
* @param $class
|
||||
* @return string
|
||||
* @todo Not reused... inline?
|
||||
*/
|
||||
protected function _getSelectJoinColumnsSQL(ClassMetadata $class)
|
||||
private function _getSelectJoinColumnsSQL(ClassMetadata $class)
|
||||
{
|
||||
$sql = '';
|
||||
foreach ($class->associationMappings as $assoc) {
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
|
||||
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$sql .= ', ' . $this->_getSQLTableAlias($this->_class) . ".$srcColumn AS $columnAlias";
|
||||
$sql .= ', ' . $this->_getSQLTableAlias($this->_class->name) . ".$srcColumn AS $columnAlias";
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
if ( ! isset($this->_resultColumnNames[$resultColumnName])) {
|
||||
$this->_resultColumnNames[$resultColumnName] = $srcColumn;
|
||||
@ -897,19 +989,92 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL table alias for the given class.
|
||||
* Gets the SQL table alias for the given class name.
|
||||
*
|
||||
* @param ClassMetadata $class
|
||||
* @param string $className
|
||||
* @return string The SQL table alias.
|
||||
* @todo Remove. Binding table aliases to class names is not such a good idea.
|
||||
*/
|
||||
protected function _getSQLTableAlias(ClassMetadata $class)
|
||||
protected function _getSQLTableAlias($className)
|
||||
{
|
||||
if (isset($this->_sqlTableAliases[$class->name])) {
|
||||
return $this->_sqlTableAliases[$class->name];
|
||||
if (isset($this->_sqlTableAliases[$className])) {
|
||||
return $this->_sqlTableAliases[$className];
|
||||
}
|
||||
$tableAlias = $class->table['name'][0] . $this->_sqlAliasCounter++;
|
||||
$this->_sqlTableAliases[$class->name] = $tableAlias;
|
||||
$tableAlias = 't' . $this->_sqlAliasCounter++;
|
||||
$this->_sqlTableAliases[$className] = $tableAlias;
|
||||
|
||||
return $tableAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the conditional SQL fragment used in the WHERE clause when selecting
|
||||
* entities in this persister.
|
||||
*
|
||||
* Subclasses are supposed to override this method if they intend to change
|
||||
* or alter the criteria by which entities are selected.
|
||||
*
|
||||
* @param array $criteria
|
||||
* @param AssociationMapping $assoc
|
||||
* @return string
|
||||
*/
|
||||
protected function _getSelectConditionSQL(array $criteria, $assoc = null)
|
||||
{
|
||||
$conditionSql = '';
|
||||
foreach ($criteria as $field => $value) {
|
||||
$conditionSql .= $conditionSql ? ' AND ' : '';
|
||||
|
||||
if (isset($this->_class->columnNames[$field])) {
|
||||
if (isset($this->_class->fieldMappings[$field]['inherited'])) {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->fieldMappings[$field]['inherited']) . '.';
|
||||
} else {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
|
||||
}
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
} else if ($assoc !== null) {
|
||||
if ($assoc->isManyToMany()) {
|
||||
$owningAssoc = $assoc->isOwningSide ? $assoc : $this->_em->getClassMetadata($assoc->targetEntityName)
|
||||
->associationMappings[$assoc->mappedBy];
|
||||
$conditionSql .= $owningAssoc->getQuotedJoinTableName($this->_platform) . '.' . $field;
|
||||
} else {
|
||||
$conditionSql .= $field;
|
||||
}
|
||||
} else {
|
||||
throw ORMException::unrecognizedField($field);
|
||||
}
|
||||
$conditionSql .= ' = ?';
|
||||
}
|
||||
|
||||
return $conditionSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a collection of entities in a one-to-many association.
|
||||
*
|
||||
* @param OneToManyMapping $assoc
|
||||
* @param array $criteria The criteria by which to select the entities.
|
||||
* @param PersistentCollection The collection to load/fill.
|
||||
*/
|
||||
public function loadOneToManyCollection(OneToManyMapping $assoc, $sourceEntity, PersistentCollection $coll)
|
||||
{
|
||||
$criteria = array();
|
||||
$owningAssoc = $this->_class->associationMappings[$assoc->mappedBy];
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc->sourceEntityName);
|
||||
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
|
||||
$criteria[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
}
|
||||
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc);
|
||||
$params = array_values($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params);
|
||||
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$coll->hydrateAdd($this->_createEntity($result));
|
||||
}
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
|
||||
//TODO
|
||||
/*protected function _getOneToOneEagerFetchSQL()
|
||||
{
|
||||
|
||||
}*/
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -21,15 +19,14 @@
|
||||
|
||||
namespace Doctrine\ORM\Persisters;
|
||||
|
||||
use Doctrine\ORM\ORMException;
|
||||
use Doctrine\ORM\ORMException,
|
||||
Doctrine\ORM\Mapping\ManyToManyMapping;
|
||||
|
||||
/**
|
||||
* The joined subclass persister maps a single entity instance to several tables in the
|
||||
* database as it is defined by the <tt>Class Table Inheritance</tt> strategy.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @see http://martinfowler.com/eaaCatalog/classTableInheritance.html
|
||||
*/
|
||||
@ -78,14 +75,10 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
public function getOwningTable($fieldName)
|
||||
{
|
||||
if ( ! isset($this->_owningTableMap[$fieldName])) {
|
||||
if (isset($this->_class->associationMappings[$fieldName])) {
|
||||
if (isset($this->_class->inheritedAssociationFields[$fieldName])) {
|
||||
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
|
||||
$this->_class->inheritedAssociationFields[$fieldName]
|
||||
)->table['name'];
|
||||
} else {
|
||||
$this->_owningTableMap[$fieldName] = $this->_class->table['name'];
|
||||
}
|
||||
if (isset($this->_class->associationMappings[$fieldName]->inherited)) {
|
||||
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
|
||||
$this->_class->associationMappings[$fieldName]->inherited
|
||||
)->table['name'];
|
||||
} else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) {
|
||||
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
|
||||
$this->_class->fieldMappings[$fieldName]['inherited']
|
||||
@ -120,19 +113,19 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$this->_class : $this->_em->getClassMetadata($this->_class->rootEntityName);
|
||||
$rootPersister = $this->_em->getUnitOfWork()->getEntityPersister($rootClass->name);
|
||||
$rootTableName = $rootClass->table['name'];
|
||||
$rootTableStmt = $this->_conn->prepare($rootPersister->getInsertSQL());
|
||||
$rootTableStmt = $this->_conn->prepare($rootPersister->_getInsertSQL());
|
||||
|
||||
// Prepare statements for sub tables.
|
||||
$subTableStmts = array();
|
||||
if ($rootClass !== $this->_class) {
|
||||
$subTableStmts[$this->_class->table['name']] = $this->_conn->prepare($this->getInsertSQL());
|
||||
$subTableStmts[$this->_class->table['name']] = $this->_conn->prepare($this->_getInsertSQL());
|
||||
}
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$parentTableName = $parentClass->table['name'];
|
||||
if ($parentClass !== $rootClass) {
|
||||
$parentPersister = $this->_em->getUnitOfWork()->getEntityPersister($parentClassName);
|
||||
$subTableStmts[$parentTableName] = $this->_conn->prepare($parentPersister->getInsertSQL());
|
||||
$subTableStmts[$parentTableName] = $this->_conn->prepare($parentPersister->_getInsertSQL());
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,27 +228,30 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function _getSelectEntitiesSQL(array &$criteria, $assoc = null, $orderBy = null)
|
||||
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null)
|
||||
{
|
||||
$idColumns = $this->_class->getIdentifierColumnNames();
|
||||
$baseTableAlias = $this->_getSQLTableAlias($this->_class);
|
||||
$baseTableAlias = $this->_getSQLTableAlias($this->_class->name);
|
||||
|
||||
// Create the column list fragment only once
|
||||
if ($this->_selectColumnListSql === null) {
|
||||
// Add regular columns
|
||||
$columnList = '';
|
||||
foreach ($this->_class->fieldMappings as $fieldName => $mapping) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
$columnList .= $this->_getSelectColumnSQL($fieldName,
|
||||
isset($mapping['inherited']) ? $this->_em->getClassMetadata($mapping['inherited']) : $this->_class);
|
||||
isset($mapping['inherited']) ?
|
||||
$this->_em->getClassMetadata($mapping['inherited']) :
|
||||
$this->_class);
|
||||
}
|
||||
|
||||
// Add foreign key columns
|
||||
foreach ($this->_class->associationMappings as $assoc) {
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
|
||||
$tableAlias = isset($this->_class->inheritedAssociationFields[$assoc->sourceFieldName]) ?
|
||||
$this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->inheritedAssociationFields[$assoc->sourceFieldName]))
|
||||
: $baseTableAlias;
|
||||
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
||||
foreach ($this->_class->associationMappings as $assoc2) {
|
||||
if ($assoc2->isOwningSide && $assoc2->isOneToOne()) {
|
||||
$tableAlias = $assoc2->inherited ?
|
||||
$this->_getSQLTableAlias($assoc2->inherited)
|
||||
: $baseTableAlias;
|
||||
foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$columnList .= ", $tableAlias.$srcColumn AS $columnAlias";
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
@ -266,12 +262,12 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
}
|
||||
|
||||
// Add discriminator column (DO NOT ALIAS THIS COLUMN, see StandardEntityPersister#_processSQLResultInheritanceAware).
|
||||
// Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#_processSQLResult).
|
||||
$discrColumn = $this->_class->discriminatorColumn['name'];
|
||||
if ($this->_class->rootEntityName == $this->_class->name) {
|
||||
$columnList .= ", $baseTableAlias.$discrColumn";
|
||||
} else {
|
||||
$columnList .= ', ' . $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->rootEntityName))
|
||||
$columnList .= ', ' . $this->_getSQLTableAlias($this->_class->rootEntityName)
|
||||
. ".$discrColumn";
|
||||
}
|
||||
|
||||
@ -283,7 +279,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$joinSql = '';
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$tableAlias = $this->_getSQLTableAlias($parentClass);
|
||||
$tableAlias = $this->_getSQLTableAlias($parentClassName);
|
||||
$joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
foreach ($idColumns as $idColumn) {
|
||||
@ -295,7 +291,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
// OUTER JOIN sub tables
|
||||
foreach ($this->_class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
$tableAlias = $this->_getSQLTableAlias($subClass);
|
||||
$tableAlias = $this->_getSQLTableAlias($subClassName);
|
||||
|
||||
if ($this->_selectColumnListSql === null) {
|
||||
// Add subclass columns
|
||||
@ -308,7 +304,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// Add join columns (foreign keys)
|
||||
foreach ($subClass->associationMappings as $assoc2) {
|
||||
if ($assoc2->isOwningSide && $assoc2->isOneToOne() && ! isset($subClass->inheritedAssociationFields[$assoc2->sourceFieldName])) {
|
||||
if ($assoc2->isOwningSide && $assoc2->isOneToOne() && ! $assoc2->inherited) {
|
||||
foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$columnList .= ', ' . $tableAlias . ".$srcColumn AS $columnAlias";
|
||||
@ -330,27 +326,14 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
}
|
||||
|
||||
$conditionSql = '';
|
||||
foreach ($criteria as $field => $value) {
|
||||
if ($conditionSql != '') $conditionSql .= ' AND ';
|
||||
if (isset($this->_class->fieldMappings[$field]['inherited'])) {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_em->getClassMetadata($this->_class->fieldMappings[$field]['inherited'])) . '.';
|
||||
} else {
|
||||
$conditionSql .= $baseTableAlias . '.';
|
||||
}
|
||||
if (isset($this->_class->columnNames[$field])) {
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
} else if ($assoc !== null) {
|
||||
$conditionSql .= $field;
|
||||
} else {
|
||||
throw ORMException::unrecognizedField($field);
|
||||
}
|
||||
$conditionSql .= ' = ?';
|
||||
}
|
||||
$joinSql .= $assoc != null && $assoc->isManyToMany() ?
|
||||
$this->_getSelectManyToManyJoinSQL($assoc) : '';
|
||||
|
||||
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
|
||||
|
||||
$orderBySql = '';
|
||||
if ($orderBy !== null) {
|
||||
$orderBySql = $this->_getCollectionOrderBySQL($orderBy, $baseTableAlias);
|
||||
if ($assoc != null && isset($assoc->orderBy)) {
|
||||
$orderBySql = $this->_getCollectionOrderBySQL($assoc->orderBy, $baseTableAlias);
|
||||
}
|
||||
|
||||
if ($this->_selectColumnListSql === null) {
|
||||
@ -363,10 +346,10 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
. ($conditionSql != '' ? ' WHERE ' . $conditionSql : '') . $orderBySql;
|
||||
}
|
||||
|
||||
/** Ensure this method is never called. This persister overrides _getSelectEntitiesSQL directly. */
|
||||
/* Ensure this method is never called. This persister overrides _getSelectEntitiesSQL directly. */
|
||||
protected function _getSelectColumnListSQL()
|
||||
{
|
||||
throw new \BadMethodCallException("Illegal invocation of ".__METHOD__." on JoinedSubclassPersister.");
|
||||
throw new \BadMethodCallException("Illegal invocation of ".__METHOD__.".");
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
@ -377,7 +360,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
foreach ($this->_class->reflFields as $name => $field) {
|
||||
if (isset($this->_class->fieldMappings[$name]['inherited']) && ! isset($this->_class->fieldMappings[$name]['id'])
|
||||
|| isset($this->_class->inheritedAssociationFields[$name])
|
||||
|| isset($this->_class->associationMappings[$name]->inherited)
|
||||
|| ($this->_class->isVersioned && $this->_class->versionField == $name)) {
|
||||
continue;
|
||||
}
|
||||
@ -402,17 +385,4 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL to select a collection of entities in a many-many association.
|
||||
*
|
||||
* @param ManyToManyMapping $manyToMany
|
||||
* @param array $criteria
|
||||
* @return string
|
||||
*/
|
||||
protected function _getSelectManyToManyEntityCollectionSQL($manyToMany, array &$criteria)
|
||||
{
|
||||
// @todo
|
||||
throw new \BadMethodCallException("Not yet implemented, see http://www.doctrine-project.org/jira/browse/DDC-342");
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -28,7 +26,6 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
* SINGLE_TABLE strategy.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @since 2.0
|
||||
* @link http://martinfowler.com/eaaCatalog/singleTableInheritance.html
|
||||
*/
|
||||
@ -44,26 +41,27 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
protected function _getSelectColumnListSQL()
|
||||
{
|
||||
$columnList = parent::_getSelectColumnListSQL();
|
||||
|
||||
// Append discriminator column
|
||||
$discrColumn = $this->_class->discriminatorColumn['name'];
|
||||
$columnList .= ", $discrColumn";
|
||||
$rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName);
|
||||
$tableAlias = $this->_getSQLTableAlias($rootClass);
|
||||
$tableAlias = $this->_getSQLTableAlias($rootClass->name);
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($discrColumn);
|
||||
$this->_resultColumnNames[$resultColumnName] = $discrColumn;
|
||||
|
||||
// Append subclass columns
|
||||
foreach ($this->_class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
// Append subclass columns
|
||||
// Regular columns
|
||||
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
|
||||
if ( ! isset($mapping['inherited'])) {
|
||||
$columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass);
|
||||
}
|
||||
}
|
||||
|
||||
// Append subclass foreign keys
|
||||
// Foreign key columns
|
||||
foreach ($subClass->associationMappings as $assoc) {
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne() && ! isset($subClass->inheritedAssociationFields[$assoc->sourceFieldName])) {
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne() && ! $assoc->inherited) {
|
||||
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$columnList .= ', ' . $tableAlias . ".$srcColumn AS $columnAlias";
|
||||
@ -90,14 +88,27 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function _getSQLTableAlias(ClassMetadata $class)
|
||||
protected function _getSQLTableAlias($className)
|
||||
{
|
||||
if (isset($this->_sqlTableAliases[$class->rootEntityName])) {
|
||||
return $this->_sqlTableAliases[$class->rootEntityName];
|
||||
}
|
||||
$tableAlias = $this->_em->getClassMetadata($class->rootEntityName)->table['name'][0] . $this->_sqlAliasCounter++;
|
||||
$this->_sqlTableAliases[$class->rootEntityName] = $tableAlias;
|
||||
return parent::_getSQLTableAlias($this->_class->rootEntityName);
|
||||
}
|
||||
|
||||
return $tableAlias;
|
||||
/** {@inheritdoc} */
|
||||
protected function _getSelectConditionSQL(array $criteria, $assoc = null)
|
||||
{
|
||||
$conditionSql = parent::_getSelectConditionSQL($criteria, $assoc);
|
||||
|
||||
// Append discriminator condition
|
||||
if ($conditionSql) $conditionSql .= ' AND ';
|
||||
$values = array($this->_conn->quote($this->_class->discriminatorValue));
|
||||
$discrValues = array_flip($this->_class->discriminatorMap);
|
||||
foreach ($this->_class->subClasses as $subclassName) {
|
||||
$values[] = $this->_conn->quote($discrValues[$subclassName]);
|
||||
}
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.'
|
||||
. $this->_class->discriminatorColumn['name']
|
||||
. ' IN (' . implode(', ', $values) . ')';
|
||||
|
||||
return $conditionSql;
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Persisters;
|
||||
|
||||
class UnionSubclassPersister extends StandardEntityPersister
|
||||
class UnionSubclassPersister extends BasicEntityPersister
|
||||
{
|
||||
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -44,13 +42,13 @@ class ProxyFactory
|
||||
private $_proxyDir;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the <tt>ProxyFactory</tt> class that is
|
||||
* connected to the given <tt>EntityManager</tt>.
|
||||
*
|
||||
* @param EntityManager $em The EntityManager the new factory works for.
|
||||
* @param string $proxyDir The directory to use for the proxy classes. It must exist.
|
||||
* @param string $proxyNs The namespace to use for the proxy classes.
|
||||
* @param boolean $autoGenerate Whether to automatically generate proxy classes.
|
||||
* Initializes a new instance of the <tt>ProxyFactory</tt> class that is
|
||||
* connected to the given <tt>EntityManager</tt>.
|
||||
*
|
||||
* @param EntityManager $em The EntityManager the new factory works for.
|
||||
* @param string $proxyDir The directory to use for the proxy classes. It must exist.
|
||||
* @param string $proxyNs The namespace to use for the proxy classes.
|
||||
* @param boolean $autoGenerate Whether to automatically generate proxy classes.
|
||||
*/
|
||||
public function __construct(EntityManager $em, $proxyDir, $proxyNs, $autoGenerate = false)
|
||||
{
|
||||
@ -240,7 +238,7 @@ class ProxyFactory
|
||||
return $sleepImpl;
|
||||
}
|
||||
|
||||
/** Reference Proxy class code template */
|
||||
/** Proxy class code template */
|
||||
private static $_proxyClassTemplate =
|
||||
'<?php
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -27,13 +25,10 @@ use Doctrine\ORM\Query\Parser,
|
||||
/**
|
||||
* A Query object represents a DQL query.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 1.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 1.0
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
final class Query extends AbstractQuery
|
||||
{
|
||||
@ -62,6 +57,7 @@ final class Query extends AbstractQuery
|
||||
* partial objects.
|
||||
*
|
||||
* @var string
|
||||
* @todo Rename: HINT_OPTIMIZE
|
||||
*/
|
||||
const HINT_FORCE_PARTIAL_LOAD = 'doctrine.forcePartialLoad';
|
||||
/**
|
||||
@ -149,10 +145,10 @@ final class Query extends AbstractQuery
|
||||
*
|
||||
* @param Doctrine\ORM\EntityManager $entityManager
|
||||
*/
|
||||
public function __construct(EntityManager $entityManager)
|
||||
/*public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
parent::__construct($entityManager);
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Gets the SQL query/queries that correspond to this DQL query.
|
||||
@ -162,7 +158,7 @@ final class Query extends AbstractQuery
|
||||
*/
|
||||
public function getSQL()
|
||||
{
|
||||
return $this->_parse()->getSqlExecutor()->getSqlStatements();
|
||||
return $this->_parse()->getSQLExecutor()->getSQLStatements();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -366,7 +362,7 @@ final class Query extends AbstractQuery
|
||||
* @param string $dqlQuery DQL Query
|
||||
* @return Doctrine\ORM\AbstractQuery
|
||||
*/
|
||||
public function setDql($dqlQuery)
|
||||
public function setDQL($dqlQuery)
|
||||
{
|
||||
if ($dqlQuery !== null) {
|
||||
$this->_dql = $dqlQuery;
|
||||
@ -380,7 +376,7 @@ final class Query extends AbstractQuery
|
||||
*
|
||||
* @return string DQL query
|
||||
*/
|
||||
public function getDql()
|
||||
public function getDQL()
|
||||
{
|
||||
return $this->_dql;
|
||||
}
|
||||
@ -408,7 +404,7 @@ final class Query extends AbstractQuery
|
||||
*/
|
||||
public function contains($dql)
|
||||
{
|
||||
return stripos($this->getDql(), $dql) === false ? false : true;
|
||||
return stripos($this->getDQL(), $dql) === false ? false : 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
|
||||
@ -31,10 +29,7 @@ namespace Doctrine\ORM\Query\AST;
|
||||
* SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField
|
||||
* SimpleStateFieldAssociationPathExpression ::= SingleValuedAssociationPathExpression "." StateField
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -29,11 +27,8 @@ use Doctrine\DBAL\Connection,
|
||||
* Executes the SQL statements for bulk DQL UPDATE statements on classes in
|
||||
* Class Table Inheritance (JOINED).
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
*/
|
||||
class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
||||
{
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -27,10 +25,7 @@ use Doctrine\ORM\Query;
|
||||
* An LL(*) recursive-descent parser for the context-free grammar of the Doctrine Query Language.
|
||||
* Parses a DQL query, reports any errors in it, and generates an AST.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
@ -208,12 +203,15 @@ class Parser
|
||||
// Process any deferred validations of some nodes in the AST.
|
||||
// This also allows post-processing of the AST for modification purposes.
|
||||
$this->_processDeferredIdentificationVariables();
|
||||
|
||||
if ($this->_deferredPartialObjectExpressions) {
|
||||
$this->_processDeferredPartialObjectExpressions();
|
||||
}
|
||||
|
||||
if ($this->_deferredPathExpressions) {
|
||||
$this->_processDeferredPathExpressions($AST);
|
||||
}
|
||||
|
||||
if ($this->_deferredResultVariables) {
|
||||
$this->_processDeferredResultVariables();
|
||||
}
|
||||
@ -461,7 +459,7 @@ class Parser
|
||||
// Check if IdentificationVariable exists in queryComponents
|
||||
if ( ! isset($this->_queryComponents[$identVariable])) {
|
||||
$this->semanticalError(
|
||||
"'$identVariable' is not defined.", $deferredItem['token']
|
||||
"'$identVariable' is not defined.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
@ -470,14 +468,14 @@ class Parser
|
||||
// Check if queryComponent points to an AbstractSchemaName or a ResultVariable
|
||||
if ( ! isset($qComp['metadata'])) {
|
||||
$this->semanticalError(
|
||||
"'$identVariable' does not point to a Class.", $deferredItem['token']
|
||||
"'$identVariable' does not point to a Class.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
// Validate if identification variable nesting level is lower or equal than the current one
|
||||
if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) {
|
||||
$this->semanticalError(
|
||||
"'$identVariable' is used outside the scope of its declaration.", $deferredItem['token']
|
||||
"'$identVariable' is used outside the scope of its declaration.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -491,15 +489,15 @@ class Parser
|
||||
foreach ($expr->partialFieldSet as $field) {
|
||||
if ( ! isset($class->fieldMappings[$field])) {
|
||||
$this->semanticalError(
|
||||
"There is no mapped field named '$field' on class " . $class->name . ".",
|
||||
$deferredItem['token']
|
||||
"There is no mapped field named '$field' on class " . $class->name . ".",
|
||||
$deferredItem['token']
|
||||
);
|
||||
}
|
||||
}
|
||||
if (array_intersect($class->identifier, $expr->partialFieldSet) != $class->identifier) {
|
||||
$this->semanticalError(
|
||||
"The partial field selection of class " . $class->name . " must contain the identifier.",
|
||||
$deferredItem['token']
|
||||
"The partial field selection of class " . $class->name . " must contain the identifier.",
|
||||
$deferredItem['token']
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -519,7 +517,7 @@ class Parser
|
||||
// Check if ResultVariable exists in queryComponents
|
||||
if ( ! isset($this->_queryComponents[$resultVariable])) {
|
||||
$this->semanticalError(
|
||||
"'$resultVariable' is not defined.", $deferredItem['token']
|
||||
"'$resultVariable' is not defined.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
@ -528,14 +526,14 @@ class Parser
|
||||
// Check if queryComponent points to an AbstractSchemaName or a ResultVariable
|
||||
if ( ! isset($qComp['resultVariable'])) {
|
||||
$this->semanticalError(
|
||||
"'$identVariable' does not point to a ResultVariable.", $deferredItem['token']
|
||||
"'$identVariable' does not point to a ResultVariable.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
// Validate if identification variable nesting level is lower or equal than the current one
|
||||
if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) {
|
||||
$this->semanticalError(
|
||||
"'$resultVariable' is used outside the scope of its declaration.", $deferredItem['token']
|
||||
"'$resultVariable' is used outside the scope of its declaration.", $deferredItem['token']
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -557,11 +555,16 @@ class Parser
|
||||
{
|
||||
foreach ($this->_deferredPathExpressions as $deferredItem) {
|
||||
$pathExpression = $deferredItem['expression'];
|
||||
$parts = $pathExpression->parts;
|
||||
$numParts = count($parts);
|
||||
|
||||
$qComp = $this->_queryComponents[$pathExpression->identificationVariable];
|
||||
$numParts = count($pathExpression->parts);
|
||||
|
||||
if ($numParts == 0) {
|
||||
$pathExpression->parts = array($qComp['metadata']->identifier[0]);
|
||||
$numParts++;
|
||||
}
|
||||
|
||||
$parts = $pathExpression->parts;
|
||||
$aliasIdentificationVariable = $pathExpression->identificationVariable;
|
||||
$parentField = $pathExpression->identificationVariable;
|
||||
$class = $qComp['metadata'];
|
||||
@ -572,24 +575,24 @@ class Parser
|
||||
// Check if it is not in a state field
|
||||
if ($fieldType & AST\PathExpression::TYPE_STATE_FIELD) {
|
||||
$this->semanticalError(
|
||||
'Cannot navigate through state field named ' . $field . ' on ' . $parentField,
|
||||
$deferredItem['token']
|
||||
'Cannot navigate through state field named ' . $field . ' on ' . $parentField,
|
||||
$deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
// Check if it is not a collection field
|
||||
if ($fieldType & AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION) {
|
||||
$this->semanticalError(
|
||||
'Cannot navigate through collection field named ' . $field . ' on ' . $parentField,
|
||||
$deferredItem['token']
|
||||
'Cannot navigate through collection field named ' . $field . ' on ' . $parentField,
|
||||
$deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
// Check if field or association exists
|
||||
if ( ! isset($class->associationMappings[$field]) && ! isset($class->fieldMappings[$field])) {
|
||||
$this->semanticalError(
|
||||
'Class ' . $class->name . ' has no field or association named ' . $field,
|
||||
$deferredItem['token']
|
||||
'Class ' . $class->name . ' has no field or association named ' . $field,
|
||||
$deferredItem['token']
|
||||
);
|
||||
}
|
||||
|
||||
@ -602,8 +605,8 @@ class Parser
|
||||
$class = $this->_em->getClassMetadata($assoc->targetEntityName);
|
||||
|
||||
if (
|
||||
($curIndex != $numParts - 1) &&
|
||||
! isset($this->_queryComponents[$aliasIdentificationVariable . '.' . $field])
|
||||
($curIndex != $numParts - 1) &&
|
||||
! isset($this->_queryComponents[$aliasIdentificationVariable . '.' . $field])
|
||||
) {
|
||||
// Building queryComponent
|
||||
$joinQueryComponent = array(
|
||||
@ -617,14 +620,15 @@ class Parser
|
||||
|
||||
// Create AST node
|
||||
$joinVariableDeclaration = new AST\JoinVariableDeclaration(
|
||||
new AST\Join(
|
||||
AST\Join::JOIN_TYPE_INNER,
|
||||
new AST\JoinAssociationPathExpression($aliasIdentificationVariable, $field),
|
||||
$aliasIdentificationVariable . '.' . $field,
|
||||
false
|
||||
),
|
||||
null
|
||||
new AST\Join(
|
||||
AST\Join::JOIN_TYPE_INNER,
|
||||
new AST\JoinAssociationPathExpression($aliasIdentificationVariable, $field),
|
||||
$aliasIdentificationVariable . '.' . $field,
|
||||
false
|
||||
),
|
||||
null
|
||||
);
|
||||
|
||||
$AST->fromClause->identificationVariableDeclarations[0]->joinVariableDeclarations[] = $joinVariableDeclaration;
|
||||
|
||||
$this->_queryComponents[$aliasIdentificationVariable . '.' . $field] = $joinQueryComponent;
|
||||
@ -915,12 +919,12 @@ class Parser
|
||||
$identVariable = $this->IdentificationVariable();
|
||||
$parts = array();
|
||||
|
||||
do {
|
||||
while ($this->_lexer->isNextToken(Lexer::T_DOT)) {
|
||||
$this->match(Lexer::T_DOT);
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
|
||||
$parts[] = $this->_lexer->token['value'];
|
||||
} while ($this->_lexer->isNextToken(Lexer::T_DOT));
|
||||
}
|
||||
|
||||
// Creating AST node
|
||||
$pathExpr = new AST\PathExpression($expectedTypes, $identVariable, $parts);
|
||||
@ -2168,7 +2172,7 @@ class Parser
|
||||
return $this->SingleValuedPathExpression();
|
||||
}
|
||||
|
||||
return $this->IdentificationVariable();
|
||||
return $this->SimpleStateFieldPathExpression();
|
||||
|
||||
case Lexer::T_INPUT_PARAMETER:
|
||||
return $this->InputParameter();
|
||||
@ -2619,9 +2623,10 @@ class Parser
|
||||
|
||||
public function CustomFunctionsReturningNumerics()
|
||||
{
|
||||
$funcNameLower = strtolower($this->_lexer->lookahead['value']);
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomNumericFunction($funcNameLower);
|
||||
$function = new $funcClass($funcNameLower);
|
||||
$funcName = strtolower($this->_lexer->lookahead['value']);
|
||||
// getCustomNumericFunction is case-insensitive
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomNumericFunction($funcName);
|
||||
$function = new $funcClass($funcName);
|
||||
$function->parse($this);
|
||||
|
||||
return $function;
|
||||
@ -2642,9 +2647,10 @@ class Parser
|
||||
|
||||
public function CustomFunctionsReturningDatetime()
|
||||
{
|
||||
$funcNameLower = strtolower($this->_lexer->lookahead['value']);
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomDatetimeFunction($funcNameLower);
|
||||
$function = new $funcClass($funcNameLower);
|
||||
$funcName = $this->_lexer->lookahead['value'];
|
||||
// getCustomDatetimeFunction is case-insensitive
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomDatetimeFunction($funcName);
|
||||
$function = new $funcClass($funcName);
|
||||
$function->parse($this);
|
||||
|
||||
return $function;
|
||||
@ -2670,9 +2676,10 @@ class Parser
|
||||
|
||||
public function CustomFunctionsReturningStrings()
|
||||
{
|
||||
$funcNameLower = strtolower($this->_lexer->lookahead['value']);
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomStringFunction($funcNameLower);
|
||||
$function = new $funcClass($funcNameLower);
|
||||
$funcName = $this->_lexer->lookahead['value'];
|
||||
// getCustomStringFunction is case-insensitive
|
||||
$funcClass = $this->_em->getConfiguration()->getCustomStringFunction($funcName);
|
||||
$function = new $funcClass($funcName);
|
||||
$function->parse($this);
|
||||
|
||||
return $function;
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -240,16 +238,17 @@ class SqlWalker implements TreeWalker
|
||||
{
|
||||
$sql = '';
|
||||
|
||||
$baseTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
|
||||
$baseTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
|
||||
|
||||
// INNER JOIN parent class tables
|
||||
foreach ($class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$tableAlias = $this->getSqlTableAlias($parentClass->table['name'], $dqlAlias);
|
||||
$sql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform)
|
||||
$tableAlias = $this->getSQLTableAlias($parentClass->table['name'], $dqlAlias);
|
||||
// If this is a joined association we must use left joins to preserve the correct result.
|
||||
$sql .= isset($this->_queryComponents[$dqlAlias]['relation']) ? ' LEFT ' : ' INNER ';
|
||||
$sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform)
|
||||
. ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
|
||||
foreach ($class->identifier as $idField) {
|
||||
if ($first) $first = false; else $sql .= ' AND ';
|
||||
|
||||
@ -260,14 +259,13 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
}
|
||||
|
||||
// LEFT JOIN subclass tables, if partial objects disallowed
|
||||
// LEFT JOIN subclass tables, if partial objects disallowed.
|
||||
if ( ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
|
||||
foreach ($class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
$tableAlias = $this->getSqlTableAlias($subClass->table['name'], $dqlAlias);
|
||||
$tableAlias = $this->getSQLTableAlias($subClass->table['name'], $dqlAlias);
|
||||
$sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform)
|
||||
. ' ' . $tableAlias . ' ON ';
|
||||
|
||||
$first = true;
|
||||
foreach ($class->identifier as $idField) {
|
||||
if ($first) $first = false; else $sql .= ' AND ';
|
||||
@ -288,9 +286,7 @@ class SqlWalker implements TreeWalker
|
||||
$sql = '';
|
||||
foreach ($this->_selectedClasses AS $dqlAlias => $class) {
|
||||
$qComp = $this->_queryComponents[$dqlAlias];
|
||||
if (isset($qComp['relation']) && ($qComp['relation']->isManyToMany() || $qComp['relation']->isOneToMany())
|
||||
&& $qComp['relation']->orderBy != null) {
|
||||
|
||||
if (isset($qComp['relation']->orderBy)) {
|
||||
foreach ($qComp['relation']->orderBy AS $fieldName => $orientation) {
|
||||
if ($qComp['metadata']->isInheritanceTypeJoined()) {
|
||||
$tableName = $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName);
|
||||
@ -301,8 +297,8 @@ class SqlWalker implements TreeWalker
|
||||
if ($sql != '') {
|
||||
$sql .= ', ';
|
||||
}
|
||||
$sql .= $this->getSqlTableAlias($tableName, $dqlAlias) . "." .
|
||||
$qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform) . " ".$orientation;
|
||||
$sql .= $this->getSqlTableAlias($tableName, $dqlAlias) . '.' .
|
||||
$qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform) . " $orientation";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -315,7 +311,7 @@ class SqlWalker implements TreeWalker
|
||||
* @param string $dqlAlias
|
||||
* @return string
|
||||
*/
|
||||
private function _generateDiscriminatorColumnConditionSql($dqlAlias)
|
||||
private function _generateDiscriminatorColumnConditionSQL($dqlAlias)
|
||||
{
|
||||
$sql = '';
|
||||
|
||||
@ -340,7 +336,6 @@ class SqlWalker implements TreeWalker
|
||||
return $sql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Walks down a SelectStatement AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
@ -353,7 +348,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
if (($whereClause = $AST->whereClause) !== null) {
|
||||
$sql .= $this->walkWhereClause($whereClause);
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias)) !== '') {
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSQL($this->_currentRootAlias)) !== '') {
|
||||
$sql .= ' WHERE ' . $discSql;
|
||||
}
|
||||
|
||||
@ -387,7 +382,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
if (($whereClause = $AST->whereClause) !== null) {
|
||||
$sql .= $this->walkWhereClause($whereClause);
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias)) !== '') {
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSQL($this->_currentRootAlias)) !== '') {
|
||||
$sql .= ' WHERE ' . $discSql;
|
||||
}
|
||||
|
||||
@ -407,7 +402,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
if (($whereClause = $AST->whereClause) !== null) {
|
||||
$sql .= $this->walkWhereClause($whereClause);
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias)) !== '') {
|
||||
} else if (($discSql = $this->_generateDiscriminatorColumnConditionSQL($this->_currentRootAlias)) !== '') {
|
||||
$sql .= ' WHERE ' . $discSql;
|
||||
}
|
||||
|
||||
@ -432,7 +427,7 @@ class SqlWalker implements TreeWalker
|
||||
$class = $this->_em->getClassMetadata($class->fieldMappings[$fieldName]['inherited']);
|
||||
}
|
||||
|
||||
return $this->getSqlTableAlias($class->table['name'], $identificationVariable);
|
||||
return $this->getSQLTableAlias($class->table['name'], $identificationVariable);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -458,6 +453,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
$sql .= $class->getQuotedColumnName($fieldName, $this->_platform);
|
||||
break;
|
||||
|
||||
case AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION:
|
||||
// 1- the owning side:
|
||||
// Just use the foreign key, i.e. u.group_id
|
||||
@ -465,6 +461,11 @@ class SqlWalker implements TreeWalker
|
||||
$fieldName = array_pop($parts);
|
||||
$dqlAlias = $pathExpr->identificationVariable;
|
||||
$class = $this->_queryComponents[$dqlAlias]['metadata'];
|
||||
|
||||
if (isset($class->associationMappings[$fieldName]->inherited)) {
|
||||
$class = $this->_em->getClassMetadata($class->associationMappings[$fieldName]->inherited);
|
||||
}
|
||||
|
||||
$assoc = $class->associationMappings[$fieldName];
|
||||
|
||||
if ($assoc->isOwningSide) {
|
||||
@ -472,13 +473,18 @@ class SqlWalker implements TreeWalker
|
||||
if (count($assoc->sourceToTargetKeyColumns) > 1) {
|
||||
throw QueryException::associationPathCompositeKeyNotSupported();
|
||||
}
|
||||
$sql .= $this->walkIdentificationVariable($dqlAlias) . '.'
|
||||
. reset($assoc->targetToSourceKeyColumns);
|
||||
|
||||
if ($this->_useSqlTableAliases) {
|
||||
$sql .= $this->getSqlTableAlias($class->table['name'], $dqlAlias) . '.';
|
||||
}
|
||||
|
||||
$sql .= reset($assoc->targetToSourceKeyColumns);
|
||||
} else {
|
||||
// 2- Inverse side: NOT (YET?) SUPPORTED
|
||||
throw QueryException::associationPathInverseSideNotSupported();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw QueryException::invalidPathExpression($pathExpr);
|
||||
}
|
||||
@ -533,8 +539,8 @@ class SqlWalker implements TreeWalker
|
||||
//FIXME: Include foreign key columns of child classes also!!??
|
||||
foreach ($class->associationMappings as $assoc) {
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
|
||||
if (isset($class->inheritedAssociationFields[$assoc->sourceFieldName])) {
|
||||
$owningClass = $this->_em->getClassMetadata($class->inheritedAssociationFields[$assoc->sourceFieldName]);
|
||||
if ($assoc->inherited) {
|
||||
$owningClass = $this->_em->getClassMetadata($assoc->inherited);
|
||||
$sqlTableAlias = $this->getSqlTableAlias($owningClass->table['name'], $dqlAlias);
|
||||
} else {
|
||||
$sqlTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
|
||||
@ -683,23 +689,15 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
$joinAssocPathExpr = $join->joinAssociationPathExpression;
|
||||
$joinedDqlAlias = $join->aliasIdentificationVariable;
|
||||
$targetQComp = $this->_queryComponents[$joinedDqlAlias];
|
||||
$targetClass = $targetQComp['metadata'];
|
||||
$relation = $targetQComp['relation'];
|
||||
$sourceClass = $this->_queryComponents[$joinAssocPathExpr->identificationVariable]['metadata'];
|
||||
|
||||
$relation = $this->_queryComponents[$joinedDqlAlias]['relation'];
|
||||
$targetClass = $this->_em->getClassMetadata($relation->targetEntityName);
|
||||
$sourceClass = $this->_em->getClassMetadata($relation->sourceEntityName);
|
||||
$targetTableName = $targetClass->getQuotedTableName($this->_platform);
|
||||
$targetTableAlias = $this->getSqlTableAlias($targetClass->getTableName(), $joinedDqlAlias);
|
||||
$sourceTableAlias = $this->getSqlTableAlias(
|
||||
$sourceClass->getTableName(), $joinAssocPathExpr->identificationVariable
|
||||
);
|
||||
$targetTableAlias = $this->getSqlTableAlias($targetClass->table['name'], $joinedDqlAlias);
|
||||
$sourceTableAlias = $this->getSqlTableAlias($sourceClass->table['name'], $joinAssocPathExpr->identificationVariable);
|
||||
|
||||
// Ensure we got the owning side, since it has all mapping info
|
||||
if ( ! $relation->isOwningSide) {
|
||||
$assoc = $targetClass->associationMappings[$relation->mappedBy];
|
||||
} else {
|
||||
$assoc = $relation;
|
||||
}
|
||||
$assoc = ( ! $relation->isOwningSide) ? $targetClass->associationMappings[$relation->mappedBy] : $relation;
|
||||
|
||||
if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true) {
|
||||
if ($relation->isOneToMany() || $relation->isManyToMany()) {
|
||||
@ -783,12 +781,13 @@ class SqlWalker implements TreeWalker
|
||||
). ')';
|
||||
}
|
||||
|
||||
$discrSql = $this->_generateDiscriminatorColumnConditionSql($joinedDqlAlias);
|
||||
$discrSql = $this->_generateDiscriminatorColumnConditionSQL($joinedDqlAlias);
|
||||
|
||||
if ($discrSql) {
|
||||
$sql .= ' AND ' . $discrSql;
|
||||
}
|
||||
|
||||
//FIXME: these should either be nested or all forced to be left joins (DDC-XXX)
|
||||
if ($targetClass->isInheritanceTypeJoined()) {
|
||||
$sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias);
|
||||
}
|
||||
@ -960,7 +959,7 @@ class SqlWalker implements TreeWalker
|
||||
// Add join columns (foreign keys) of the subclass
|
||||
//TODO: Probably better do this in walkSelectClause to honor the INCLUDE_META_COLUMNS hint
|
||||
foreach ($subClass->associationMappings as $fieldName => $assoc) {
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne() && ! isset($subClass->inheritedAssociationFields[$fieldName])) {
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne() && ! $assoc->inherited) {
|
||||
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
||||
if ($beginning) $beginning = false; else $sql .= ', ';
|
||||
$columnAlias = $this->getSqlColumnAlias($srcColumn);
|
||||
@ -1219,7 +1218,7 @@ class SqlWalker implements TreeWalker
|
||||
' OR ', array_map(array($this, 'walkConditionalTerm'), $condExpr->conditionalTerms)
|
||||
);
|
||||
|
||||
$discrSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias);
|
||||
$discrSql = $this->_generateDiscriminatorColumnConditionSQL($this->_currentRootAlias);
|
||||
|
||||
if ($discrSql) {
|
||||
$sql .= ' AND ' . $discrSql;
|
||||
|
@ -168,7 +168,7 @@ class QueryBuilder
|
||||
*
|
||||
* @return string The DQL string
|
||||
*/
|
||||
public function getDql()
|
||||
public function getDQL()
|
||||
{
|
||||
if ($this->_dql !== null && $this->_state === self::STATE_CLEAN) {
|
||||
return $this->_dql;
|
||||
@ -178,16 +178,16 @@ class QueryBuilder
|
||||
|
||||
switch ($this->_type) {
|
||||
case self::DELETE:
|
||||
$dql = $this->_getDqlForDelete();
|
||||
$dql = $this->_getDQLForDelete();
|
||||
break;
|
||||
|
||||
case self::UPDATE:
|
||||
$dql = $this->_getDqlForUpdate();
|
||||
$dql = $this->_getDQLForUpdate();
|
||||
break;
|
||||
|
||||
case self::SELECT:
|
||||
default:
|
||||
$dql = $this->_getDqlForSelect();
|
||||
$dql = $this->_getDQLForSelect();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ class QueryBuilder
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->_em->createQuery($this->getDql())
|
||||
return $this->_em->createQuery($this->getDQL())
|
||||
->setParameters($this->_params)
|
||||
->setFirstResult($this->_firstResult)
|
||||
->setMaxResults($this->_maxResults);
|
||||
@ -613,7 +613,7 @@ class QueryBuilder
|
||||
*/
|
||||
public function andWhere($where)
|
||||
{
|
||||
$where = $this->getDqlPart('where');
|
||||
$where = $this->getDQLPart('where');
|
||||
$args = func_get_args();
|
||||
|
||||
if ($where instanceof Expr\Andx) {
|
||||
@ -779,7 +779,7 @@ class QueryBuilder
|
||||
* @param string $queryPartName
|
||||
* @return mixed $queryPart
|
||||
*/
|
||||
public function getDqlPart($queryPartName)
|
||||
public function getDQLPart($queryPartName)
|
||||
{
|
||||
return $this->_dqlParts[$queryPartName];
|
||||
}
|
||||
@ -789,43 +789,43 @@ class QueryBuilder
|
||||
*
|
||||
* @return array $dqlParts
|
||||
*/
|
||||
public function getDqlParts()
|
||||
public function getDQLParts()
|
||||
{
|
||||
return $this->_dqlParts;
|
||||
}
|
||||
|
||||
private function _getDqlForDelete()
|
||||
private function _getDQLForDelete()
|
||||
{
|
||||
return 'DELETE'
|
||||
. $this->_getReducedDqlQueryPart('from', array('pre' => ' ', 'separator' => ', '))
|
||||
. $this->_getReducedDqlQueryPart('where', array('pre' => ' WHERE '))
|
||||
. $this->_getReducedDqlQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
|
||||
. $this->_getReducedDQLQueryPart('from', array('pre' => ' ', 'separator' => ', '))
|
||||
. $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
|
||||
. $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
|
||||
}
|
||||
|
||||
private function _getDqlForUpdate()
|
||||
private function _getDQLForUpdate()
|
||||
{
|
||||
return 'UPDATE'
|
||||
. $this->_getReducedDqlQueryPart('from', array('pre' => ' ', 'separator' => ', '))
|
||||
. $this->_getReducedDqlQueryPart('set', array('pre' => ' SET ', 'separator' => ', '))
|
||||
. $this->_getReducedDqlQueryPart('where', array('pre' => ' WHERE '))
|
||||
. $this->_getReducedDqlQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
|
||||
. $this->_getReducedDQLQueryPart('from', array('pre' => ' ', 'separator' => ', '))
|
||||
. $this->_getReducedDQLQueryPart('set', array('pre' => ' SET ', 'separator' => ', '))
|
||||
. $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
|
||||
. $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
|
||||
}
|
||||
|
||||
private function _getDqlForSelect()
|
||||
private function _getDQLForSelect()
|
||||
{
|
||||
return 'SELECT'
|
||||
. $this->_getReducedDqlQueryPart('select', array('pre' => ' ', 'separator' => ', '))
|
||||
. $this->_getReducedDqlQueryPart('from', array('pre' => ' FROM ', 'separator' => ', '))
|
||||
. $this->_getReducedDqlQueryPart('join', array('pre' => ' ', 'separator' => ' '))
|
||||
. $this->_getReducedDqlQueryPart('where', array('pre' => ' WHERE '))
|
||||
. $this->_getReducedDqlQueryPart('groupBy', array('pre' => ' GROUP BY ', 'separator' => ', '))
|
||||
. $this->_getReducedDqlQueryPart('having', array('pre' => ' HAVING '))
|
||||
. $this->_getReducedDqlQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
|
||||
. $this->_getReducedDQLQueryPart('select', array('pre' => ' ', 'separator' => ', '))
|
||||
. $this->_getReducedDQLQueryPart('from', array('pre' => ' FROM ', 'separator' => ', '))
|
||||
. $this->_getReducedDQLQueryPart('join', array('pre' => ' ', 'separator' => ' '))
|
||||
. $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
|
||||
. $this->_getReducedDQLQueryPart('groupBy', array('pre' => ' GROUP BY ', 'separator' => ', '))
|
||||
. $this->_getReducedDQLQueryPart('having', array('pre' => ' HAVING '))
|
||||
. $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
|
||||
}
|
||||
|
||||
private function _getReducedDqlQueryPart($queryPartName, $options = array())
|
||||
private function _getReducedDQLQueryPart($queryPartName, $options = array())
|
||||
{
|
||||
$queryPart = $this->getDqlPart($queryPartName);
|
||||
$queryPart = $this->getDQLPart($queryPartName);
|
||||
|
||||
if (empty($queryPart)) {
|
||||
return (isset($options['empty']) ? $options['empty'] : '');
|
||||
@ -838,11 +838,6 @@ class QueryBuilder
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getDql();
|
||||
return $this->getDQL();
|
||||
}
|
||||
|
||||
/*public function __clone()
|
||||
{
|
||||
$this->_q = clone $this->_q;
|
||||
}*/
|
||||
}
|
@ -1,205 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools\CLI\Tasks;
|
||||
|
||||
use Doctrine\Common\CLI\Tasks\AbstractTask,
|
||||
Doctrine\Common\CLI\CliException,
|
||||
Doctrine\Common\CLI\Option,
|
||||
Doctrine\Common\CLI\OptionGroup,
|
||||
Doctrine\Common\Cache\AbstractDriver;
|
||||
|
||||
/**
|
||||
* CLI Task to clear the cache of the various cache drivers
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class ClearCacheTask extends AbstractTask
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function buildDocumentation()
|
||||
{
|
||||
$cacheOptions = new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
|
||||
new Option('query', null, 'Clear the query cache.'),
|
||||
new Option('metadata', null, 'Clear the metadata cache.'),
|
||||
new OptionGroup(OptionGroup::CARDINALITY_M_N, array(
|
||||
new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
|
||||
new Option('result', null, 'Clear the result cache.')
|
||||
)),
|
||||
new OptionGroup(OptionGroup::CARDINALITY_0_N, array(
|
||||
new Option('id', '<ID>', 'The id of the cache entry to delete (accepts * wildcards).'),
|
||||
new Option('regex', '<REGEX>', 'Delete cache entries that match the given regular expression.'),
|
||||
new Option('prefix', '<PREFIX>', 'Delete cache entries that have the given prefix.'),
|
||||
new Option('suffix', '<SUFFIX>', 'Delete cache entries that have the given suffix.')
|
||||
))
|
||||
))
|
||||
));
|
||||
|
||||
$doc = $this->getDocumentation();
|
||||
$doc->setName('clear-cache')
|
||||
->setDescription('Clear cache from configured query, result and metadata drivers.')
|
||||
->getOptionGroup()
|
||||
->addOption($cacheOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
// Check if we have an active EntityManager
|
||||
$em = $this->getConfiguration()->getAttribute('em');
|
||||
|
||||
if ($em === null) {
|
||||
throw new CLIException(
|
||||
"Attribute 'em' of CLI Configuration is not defined or it is not a valid EntityManager."
|
||||
);
|
||||
}
|
||||
|
||||
// When clearing the query cache no need to specify
|
||||
// id, regex, prefix or suffix.
|
||||
if (
|
||||
(isset($arguments['query']) || isset($arguments['metadata'])) && (isset($arguments['id']) ||
|
||||
isset($arguments['regex']) || isset($arguments['prefix']) || isset($arguments['suffix']))
|
||||
) {
|
||||
throw new CLIException(
|
||||
'When clearing the query or metadata cache do not ' .
|
||||
'specify any --id, --regex, --prefix or --suffix.'
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
$printer = $this->getPrinter();
|
||||
|
||||
$query = isset($arguments['query']);
|
||||
$result = isset($arguments['result']);
|
||||
$metadata = isset($arguments['metadata']);
|
||||
$id = isset($arguments['id']) ? $arguments['id'] : null;
|
||||
$regex = isset($arguments['regex']) ? $arguments['regex'] : null;
|
||||
$prefix = isset($arguments['prefix']) ? $arguments['prefix'] : null;
|
||||
$suffix = isset($arguments['suffix']) ? $arguments['suffix'] : null;
|
||||
|
||||
$all = false;
|
||||
|
||||
if ( ! $query && ! $result && ! $metadata) {
|
||||
$all = true;
|
||||
}
|
||||
|
||||
$em = $this->getConfiguration()->getAttribute('em');
|
||||
$configuration = $em->getConfiguration();
|
||||
|
||||
if ($query || $all) {
|
||||
$this->_doDelete(
|
||||
'query', $configuration->getQueryCacheImpl(), $id, $regex, $prefix, $suffix
|
||||
);
|
||||
}
|
||||
|
||||
if ($result || $all) {
|
||||
$this->_doDelete(
|
||||
'result', $configuration->getResultCacheImpl(), $id, $regex, $prefix, $suffix
|
||||
);
|
||||
}
|
||||
|
||||
if ($metadata || $all) {
|
||||
$this->_doDelete(
|
||||
'metadata', $configuration->getMetadataCacheImpl(), $id, $regex, $prefix, $suffix
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function _doDelete($type, $cacheDriver, $id, $regex, $prefix, $suffix)
|
||||
{
|
||||
$printer = $this->getPrinter();
|
||||
|
||||
if ( ! $cacheDriver) {
|
||||
throw new CLIException('No driver has been configured for the ' . $type . ' cache.');
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$printer->writeln('Clearing ' . $type . ' cache entries that match the id "' . $id . '".', 'INFO');
|
||||
|
||||
$deleted = $cacheDriver->delete($id);
|
||||
|
||||
if (is_array($deleted)) {
|
||||
$this->_printDeleted($type, $deleted);
|
||||
} else if (is_bool($deleted) && $deleted) {
|
||||
$this->_printDeleted($type, array($id));
|
||||
}
|
||||
}
|
||||
|
||||
if ($regex) {
|
||||
$printer->writeln('Clearing ' . $type . ' cache entries that match the regular expression ".' . $regex . '"', 'INFO');
|
||||
|
||||
$this->_printDeleted($type, $cacheDriver->deleteByRegex('/' . $regex. '/'));
|
||||
}
|
||||
|
||||
if ($prefix) {
|
||||
$printer->writeln('Clearing ' . $type . ' cache entries that have the prefix "' . $prefix . '".', 'INFO');
|
||||
|
||||
$this->_printDeleted($type, $cacheDriver->deleteByPrefix($prefix));
|
||||
}
|
||||
|
||||
if ($suffix) {
|
||||
$printer->writeln('Clearing ' . $type . ' cache entries that have the suffix "' . $suffix . '".', 'INFO');
|
||||
|
||||
$this->_printDeleted($type, $cacheDriver->deleteBySuffix($suffix));
|
||||
}
|
||||
|
||||
if ( ! $id && ! $regex && ! $prefix && ! $suffix) {
|
||||
$printer->writeln('Clearing all ' . $type . ' cache entries.', 'INFO');
|
||||
|
||||
$this->_printDeleted($type, $cacheDriver->deleteAll());
|
||||
}
|
||||
}
|
||||
|
||||
private function _printDeleted($type, array $ids)
|
||||
{
|
||||
$printer = $this->getPrinter();
|
||||
|
||||
if ( ! empty($ids)) {
|
||||
foreach ($ids as $id) {
|
||||
$printer->writeln(' - ' . $id);
|
||||
}
|
||||
} else {
|
||||
throw new CLIException('No ' . $type . ' cache entries found.');
|
||||
}
|
||||
|
||||
$printer->write(PHP_EOL);
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools\CLI\Tasks;
|
||||
|
||||
use Doctrine\Common\CLI\Tasks\AbstractTask,
|
||||
Doctrine\ORM\Tools\Export\ClassMetadataExporter,
|
||||
Doctrine\Common\CLI\CliException,
|
||||
Doctrine\Common\CLI\Option,
|
||||
Doctrine\Common\CLI\OptionGroup,
|
||||
Doctrine\ORM\Tools\ConvertDoctrine1Schema,
|
||||
Doctrine\ORM\Tools\EntityGenerator;
|
||||
|
||||
/**
|
||||
* CLI Task to convert a Doctrine 1 schema to a Doctrine 2 mapping file
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class ConvertDoctrine1SchemaTask extends AbstractTask
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function buildDocumentation()
|
||||
{
|
||||
$options = new OptionGroup(OptionGroup::CARDINALITY_N_N, array(
|
||||
new Option('from', '<FROM>', 'The path to the Doctrine 1 schema.'),
|
||||
new Option('to', '<TO>', 'The Doctrine 2 mapping format to convert to.'),
|
||||
new Option('dest', '<DEST>', 'The path to export the converted schema.')
|
||||
));
|
||||
|
||||
$doc = $this->getDocumentation();
|
||||
$doc->setName('convert-10-schema')
|
||||
->setDescription('Converts a Doctrine 1.X schema into a Doctrine 2.X schema.')
|
||||
->getOptionGroup()
|
||||
->addOption($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
$em = $this->getConfiguration()->getAttribute('em');
|
||||
|
||||
if ( ! isset($arguments['from']) || ! isset($arguments['to']) || ! isset($arguments['dest'])) {
|
||||
throw new CLIException('You must specify a value for --from, --to and --dest');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
$printer = $this->getPrinter();
|
||||
|
||||
$printer->writeln(sprintf(
|
||||
'Converting Doctrine 1 schema at "%s" to the "%s" format',
|
||||
$printer->format($arguments['from'], 'KEYWORD'),
|
||||
$printer->format($arguments['to'], 'KEYWORD')
|
||||
)
|
||||
);
|
||||
|
||||
$cme = new ClassMetadataExporter();
|
||||
$exporter = $cme->getExporter($arguments['to'], $arguments['dest']);
|
||||
|
||||
if ($arguments['to'] === 'annotation') {
|
||||
$entityGenerator = new EntityGenerator();
|
||||
$exporter->setEntityGenerator($entityGenerator);
|
||||
}
|
||||
|
||||
$converter = new ConvertDoctrine1Schema($arguments['from']);
|
||||
$metadatas = $converter->getMetadatas();
|
||||
|
||||
foreach ($metadatas as $metadata) {
|
||||
$printer->writeln(
|
||||
sprintf('Processing entity "%s"', $printer->format($metadata->name, 'KEYWORD'))
|
||||
);
|
||||
}
|
||||
|
||||
$exporter->setMetadatas($metadatas);
|
||||
$exporter->export();
|
||||
|
||||
$printer->writeln(sprintf(
|
||||
'Writing Doctrine 2 mapping files to "%s"',
|
||||
$printer->format($arguments['dest'], 'KEYWORD')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,163 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools\CLI\Tasks;
|
||||
|
||||
use Doctrine\Common\CLI\Tasks\AbstractTask,
|
||||
Doctrine\Common\CLI\CliException,
|
||||
Doctrine\Common\CLI\Option,
|
||||
Doctrine\Common\CLI\OptionGroup,
|
||||
Doctrine\ORM\Tools\EntityGenerator,
|
||||
Doctrine\ORM\Tools\Export\ClassMetadataExporter,
|
||||
Doctrine\ORM\Mapping\Driver\DriverChain,
|
||||
Doctrine\ORM\Mapping\Driver\AnnotationDriver,
|
||||
Doctrine\ORM\Mapping\Driver\Driver;
|
||||
|
||||
/**
|
||||
* CLI Task to convert your mapping information between the various formats
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class ConvertMappingTask extends AbstractTask
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function buildDocumentation()
|
||||
{
|
||||
$convertOptions = new OptionGroup(OptionGroup::CARDINALITY_N_N, array(
|
||||
new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
|
||||
new Option('from', '<SOURCE>', 'The path to the mapping information to convert from (yml, xml, php, annotation).'),
|
||||
new Option('from-database', null, 'Use this option if you wish to reverse engineer your database to a set of Doctrine mapping files.')
|
||||
)),
|
||||
new Option('to', '<TYPE>', 'The format to convert to (yml, xml, php, annotation).'),
|
||||
new Option('dest', '<PATH>', 'The path to write the converted mapping information.')
|
||||
));
|
||||
|
||||
$doc = $this->getDocumentation();
|
||||
$doc->setName('convert-mapping')
|
||||
->setDescription('Convert mapping information between supported formats.')
|
||||
->getOptionGroup()
|
||||
->addOption($convertOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
if (isset($arguments['from-database']) && $arguments['from-database']) {
|
||||
$arguments['from'] = 'database';
|
||||
|
||||
$this->setArguments($arguments);
|
||||
}
|
||||
|
||||
if (!(isset($arguments['from']) && isset($arguments['to']) && isset($arguments['dest']))) {
|
||||
throw new CLIException(
|
||||
'You must include a value for all three options: --from, --to and --dest.'
|
||||
);
|
||||
}
|
||||
|
||||
if (strtolower($arguments['to']) != 'annotation' && isset($arguments['extend'])) {
|
||||
throw new CLIException(
|
||||
'You can only use the --extend argument when converting to annotations.'
|
||||
);
|
||||
}
|
||||
|
||||
if (strtolower($arguments['from']) == 'database') {
|
||||
// Check if we have an active EntityManager
|
||||
$em = $this->getConfiguration()->getAttribute('em');
|
||||
|
||||
if ($em === null) {
|
||||
throw new CLIException(
|
||||
"Attribute 'em' of CLI Configuration is not defined or it is not a valid EntityManager."
|
||||
);
|
||||
}
|
||||
|
||||
$config = $em->getConfiguration();
|
||||
$config->setMetadataDriverImpl(
|
||||
new \Doctrine\ORM\Mapping\Driver\DatabaseDriver(
|
||||
$em->getConnection()->getSchemaManager()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
$cme = new ClassMetadataExporter();
|
||||
$cme->setEntityManager($this->getConfiguration()->getAttribute('em'));
|
||||
$printer = $this->getPrinter();
|
||||
|
||||
// Get exporter and configure it
|
||||
$exporter = $cme->getExporter($arguments['to'], $arguments['dest']);
|
||||
|
||||
if ($arguments['to'] === 'annotation') {
|
||||
$entityGenerator = new EntityGenerator();
|
||||
$exporter->setEntityGenerator($entityGenerator);
|
||||
|
||||
if (isset($arguments['extend']) && $arguments['extend']) {
|
||||
$entityGenerator->setClassToExtend($arguments['extend']);
|
||||
}
|
||||
|
||||
if (isset($arguments['num-spaces']) && $arguments['extend']) {
|
||||
$entityGenerator->setNumSpaces($arguments['num-spaces']);
|
||||
}
|
||||
}
|
||||
|
||||
$from = (array) $arguments['from'];
|
||||
|
||||
foreach ($from as $source) {
|
||||
$cme->addMappingSource($source);
|
||||
}
|
||||
|
||||
$metadatas = $cme->getMetadatas();
|
||||
|
||||
foreach ($metadatas as $metadata) {
|
||||
$printer->writeln(
|
||||
sprintf('Processing entity "%s"', $printer->format($metadata->name, 'KEYWORD'))
|
||||
);
|
||||
}
|
||||
|
||||
$printer->writeln('');
|
||||
$printer->writeln(
|
||||
sprintf(
|
||||
'Exporting "%s" mapping information to "%s"',
|
||||
$printer->format($arguments['to'], 'KEYWORD'),
|
||||
$printer->format($arguments['dest'], 'KEYWORD')
|
||||
)
|
||||
);
|
||||
|
||||
$exporter->setMetadatas($metadatas);
|
||||
$exporter->export();
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools\CLI\Tasks;
|
||||
|
||||
use Doctrine\Common\CLI\Tasks\AbstractTask,
|
||||
Doctrine\Common\CLI\Option,
|
||||
Doctrine\Common\CLI\OptionGroup,
|
||||
Doctrine\Common\CLI\CLIException,
|
||||
Doctrine\ORM\Tools\EntityGenerator,
|
||||
Doctrine\ORM\Tools\ClassMetadataReader;
|
||||
|
||||
/**
|
||||
* CLI Task to generate entity classes and method stubs from your mapping information.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class GenerateEntitiesTask extends AbstractTask
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function buildDocumentation()
|
||||
{
|
||||
$options = new OptionGroup(OptionGroup::CARDINALITY_N_N, array(
|
||||
new Option('from', '<FROM>', 'The path to mapping information.'),
|
||||
new Option('dest', '<DEST>', 'The path to generate your entity classes.')
|
||||
));
|
||||
|
||||
$doc = $this->getDocumentation();
|
||||
$doc->setName('generate-entities')
|
||||
->setDescription('Generate entity classes and method stubs from your mapping information.')
|
||||
->getOptionGroup()
|
||||
->addOption($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
if ( ! isset($arguments['from']) || ! isset($arguments['dest'])) {
|
||||
throw new CLIException('You must specify a value for --from and --dest');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$printer = $this->getPrinter();
|
||||
$arguments = $this->getArguments();
|
||||
$from = $arguments['from'];
|
||||
$dest = realpath($arguments['dest']);
|
||||
|
||||
$entityGenerator = new EntityGenerator();
|
||||
$entityGenerator->setGenerateAnnotations(false);
|
||||
$entityGenerator->setGenerateStubMethods(true);
|
||||
$entityGenerator->setRegenerateEntityIfExists(false);
|
||||
$entityGenerator->setUpdateEntityIfExists(true);
|
||||
|
||||
if (isset($arguments['extend']) && $arguments['extend']) {
|
||||
$entityGenerator->setClassToExtend($arguments['extend']);
|
||||
}
|
||||
|
||||
if (isset($arguments['num-spaces']) && $arguments['extend']) {
|
||||
$entityGenerator->setNumSpaces($arguments['num-spaces']);
|
||||
}
|
||||
|
||||
$reader = new ClassMetadataReader();
|
||||
$reader->setEntityManager($this->getConfiguration()->getAttribute('em'));
|
||||
$reader->addMappingSource($from);
|
||||
$metadatas = $reader->getMetadatas();
|
||||
|
||||
foreach ($metadatas as $metadata) {
|
||||
$printer->writeln(
|
||||
sprintf('Processing entity "%s"', $printer->format($metadata->name, 'KEYWORD'))
|
||||
);
|
||||
}
|
||||
|
||||
$entityGenerator->generate($metadatas, $dest);
|
||||
|
||||
$printer->write(PHP_EOL);
|
||||
$printer->writeln(
|
||||
sprintf('Entity classes generated to "%s"',
|
||||
$printer->format($dest, 'KEYWORD')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\ORM\Tools\CLI\Tasks;
|
||||
|
||||
use Doctrine\Common\CLI\Tasks\AbstractTask,
|
||||
Doctrine\Common\CLI\CLIException,
|
||||
Doctrine\Common\CLI\Option,
|
||||
Doctrine\Common\CLI\OptionGroup;
|
||||
|
||||
/**
|
||||
* Task to (re)generate the proxy classes used by doctrine.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class GenerateProxiesTask extends AbstractTask
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function buildDocumentation()
|
||||
{
|
||||
$classDir = new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
|
||||
new Option('class-dir', '<PATH>', 'Specified directory where mapping classes are located.')
|
||||
));
|
||||
|
||||
$toDir = new OptionGroup(OptionGroup::CARDINALITY_0_1, array(
|
||||
new Option('to-dir', '<PATH>', 'Generates the classes in the specified directory.')
|
||||
));
|
||||
|
||||
$doc = $this->getDocumentation();
|
||||
$doc->setName('generate-proxies')
|
||||
->setDescription('Generates proxy classes for entity classes.')
|
||||
->getOptionGroup()
|
||||
->addOption($classDir)
|
||||
->addOption($toDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
$em = $this->getConfiguration()->getAttribute('em');
|
||||
|
||||
if ($em === null) {
|
||||
throw new CLIException(
|
||||
"Attribute 'em' of CLI Configuration is not defined or it is not a valid EntityManager."
|
||||
);
|
||||
}
|
||||
|
||||
$metadataDriver = $em->getConfiguration()->getMetadataDriverImpl();
|
||||
|
||||
if ($metadataDriver instanceof \Doctrine\ORM\Mapping\Driver\AnnotationDriver) {
|
||||
if (isset($arguments['class-dir'])) {
|
||||
$metadataDriver->addPaths((array) $arguments['class-dir']);
|
||||
} else {
|
||||
throw new CLIException(
|
||||
'The supplied configuration uses the annotation metadata driver. ' .
|
||||
"The 'class-dir' argument is required for this driver."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
$printer = $this->getPrinter();
|
||||
|
||||
$em = $this->getConfiguration()->getAttribute('em');
|
||||
$cmf = $em->getMetadataFactory();
|
||||
$classes = $cmf->getAllMetadata();
|
||||
$factory = $em->getProxyFactory();
|
||||
|
||||
if (empty($classes)) {
|
||||
$printer->writeln('No classes to process.', 'INFO');
|
||||
} else {
|
||||
foreach ($classes as $class) {
|
||||
$printer->writeln(
|
||||
sprintf('Processing entity "%s"', $printer->format($class->name, 'KEYWORD'))
|
||||
);
|
||||
}
|
||||
|
||||
$factory->generateProxyClasses(
|
||||
$classes, isset($arguments['to-dir']) ? $arguments['to-dir'] : null
|
||||
);
|
||||
|
||||
$printer->writeln('');
|
||||
|
||||
$printer->writeln(
|
||||
sprintf('Proxy classes generated to "%s"',
|
||||
$printer->format(isset($arguments['to-dir']) ? $arguments['to-dir'] : $em->getConfiguration()->getProxyDir(), 'KEYWORD'))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools\CLI\Tasks;
|
||||
|
||||
use Doctrine\Common\CLI\Tasks\AbstractTask,
|
||||
Doctrine\Common\CLI\Option,
|
||||
Doctrine\Common\CLI\OptionGroup,
|
||||
Doctrine\Common\CLI\CLIException,
|
||||
Doctrine\ORM\Tools\ClassMetadataReader;
|
||||
|
||||
/**
|
||||
* CLI Task to generate repository classes for some mapping information
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class GenerateRepositoriesTask extends ConvertMappingTask
|
||||
{
|
||||
private static $_template =
|
||||
'<?php
|
||||
|
||||
namespace <namespace>;
|
||||
|
||||
use \Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* <className>
|
||||
*
|
||||
* This class was generated by the Doctrine ORM. Add your own custom
|
||||
* repository methods below.
|
||||
*/
|
||||
class <className> extends EntityRepository
|
||||
{
|
||||
}';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function buildDocumentation()
|
||||
{
|
||||
$options = new OptionGroup(OptionGroup::CARDINALITY_N_N, array(
|
||||
new Option('from', '<FROM>', 'The path to mapping information.'),
|
||||
new Option('dest', '<DEST>', 'The path to generate your repository classes.')
|
||||
));
|
||||
|
||||
$doc = $this->getDocumentation();
|
||||
$doc->setName('generate-repositories')
|
||||
->setDescription('Generate repository classes for some mapping information.')
|
||||
->getOptionGroup()
|
||||
->addOption($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
$em = $this->getConfiguration()->getAttribute('em');
|
||||
|
||||
if ( ! isset($arguments['from']) || ! isset($arguments['dest'])) {
|
||||
throw new CLIException('You must specify a value for --from and --dest');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$printer = $this->getPrinter();
|
||||
$arguments = $this->getArguments();
|
||||
$dest = realpath($arguments['dest']);
|
||||
|
||||
$reader = new ClassMetadataReader();
|
||||
$reader->setEntityManager($this->getConfiguration()->getAttribute('em'));
|
||||
$reader->addMappingSource($arguments['from']);
|
||||
$metadatas = $reader->getMetadatas();
|
||||
|
||||
foreach ($metadatas as $metadata) {
|
||||
if ($metadata->customRepositoryClassName) {
|
||||
$code = $this->_generateRepositoryClass($metadata->customRepositoryClassName);
|
||||
$path = $dest . '/' . str_replace('\\', '/', $metadata->customRepositoryClassName) . '.php';
|
||||
$dir = dirname($path);
|
||||
if ( ! is_dir($dir)) {
|
||||
mkdir($dir, 0777, true);
|
||||
}
|
||||
$printer->writeln(
|
||||
sprintf('Processing entity "%s"',
|
||||
$printer->format($metadata->customRepositoryClassName, 'KEYWORD')
|
||||
)
|
||||
);
|
||||
file_put_contents($path, $code);
|
||||
}
|
||||
}
|
||||
$printer->writeln('');
|
||||
$printer->writeln(
|
||||
sprintf('Entity repository classes generated to "%s"',
|
||||
$printer->format($dest, 'KEYWORD')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function _generateRepositoryClass($fullyQualifiedClassName)
|
||||
{
|
||||
$namespace = substr($fullyQualifiedClassName, 0, strrpos($fullyQualifiedClassName, '\\'));
|
||||
|
||||
$pos = strrpos($fullyQualifiedClassName, '\\');
|
||||
$className = substr($fullyQualifiedClassName, $pos + 1, strlen($fullyQualifiedClassName));
|
||||
|
||||
$placeHolders = array(
|
||||
'<namespace>',
|
||||
'<className>'
|
||||
);
|
||||
$replacements = array(
|
||||
$namespace,
|
||||
$className
|
||||
);
|
||||
$code = str_replace($placeHolders, $replacements, self::$_template);
|
||||
return $code;
|
||||
}
|
||||
}
|
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