Merge master into DDC-117
This commit is contained in:
commit
e7b4dca611
9
bin/doctrine.bat
Normal file
9
bin/doctrine.bat
Normal file
@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
|
||||
if "%PHPBIN%" == "" set PHPBIN=@php_bin@
|
||||
if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
|
||||
GOTO RUN
|
||||
:USE_PEAR_PATH
|
||||
set PHPBIN=%PHP_PEAR_PHP_BIN%
|
||||
:RUN
|
||||
"%PHPBIN%" "@bin_dir@\doctrine" %*
|
@ -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>.
|
||||
*/
|
||||
|
||||
require_once 'Doctrine/Common/ClassLoader.php';
|
||||
|
||||
@ -19,7 +36,7 @@ if (file_exists($configFile)) {
|
||||
}
|
||||
|
||||
require $configFile;
|
||||
|
||||
|
||||
foreach ($GLOBALS as $helperSetCandidate) {
|
||||
if ($helperSetCandidate instanceof \Symfony\Component\Console\Helper\HelperSet) {
|
||||
$helperSet = $helperSetCandidate;
|
||||
@ -30,29 +47,4 @@ if (file_exists($configFile)) {
|
||||
|
||||
$helperSet = ($helperSet) ?: new \Symfony\Component\Console\Helper\HelperSet();
|
||||
|
||||
$cli = new \Symfony\Component\Console\Application('Doctrine Command Line Interface', Doctrine\ORM\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(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(),
|
||||
|
||||
));
|
||||
$cli->run();
|
||||
\Doctrine\ORM\Tools\Console\ConsoleRunner::run($helperSet);
|
||||
|
@ -1,10 +1,13 @@
|
||||
version=2.0.0BETA2
|
||||
dependencies.common=2.0.0BETA4
|
||||
dependencies.dbal=2.0.0BETA4
|
||||
stability=beta
|
||||
build.dir=build
|
||||
dist.dir=dist
|
||||
report.dir=reports
|
||||
log.archive.dir=logs
|
||||
svn.path=/usr/bin/svn
|
||||
project.pirum_dir=
|
||||
project.download_dir=
|
||||
test.phpunit_configuration_file=
|
||||
test.phpunit_generate_coverage=0
|
||||
test.pmd_reports=0
|
||||
|
73
build.xml
73
build.xml
@ -5,8 +5,6 @@
|
||||
-->
|
||||
|
||||
<project name="Doctrine2" default="build" basedir=".">
|
||||
|
||||
<taskdef classname="NativePhpunitTask" classpath="./tests/" name="nativephpunit" />
|
||||
<taskdef classname="phing.tasks.ext.d51PearPkg2Task" name="d51pearpkg2" />
|
||||
|
||||
<property file="build.properties" />
|
||||
@ -24,6 +22,7 @@
|
||||
<fileset id="bin-scripts" dir="./bin">
|
||||
<include name="doctrine"/>
|
||||
<include name="doctrine.php"/>
|
||||
<include name="doctrine.bat"/>
|
||||
</fileset>
|
||||
|
||||
<!--
|
||||
@ -51,7 +50,7 @@
|
||||
Fileset for source of the Symfony YAML and Console components.
|
||||
-->
|
||||
<fileset id="symfony-sources" dir="./lib/vendor">
|
||||
<include name="Symfony/Components/**"/>
|
||||
<include name="Symfony/Component/**"/>
|
||||
</fileset>
|
||||
|
||||
<!--
|
||||
@ -83,23 +82,24 @@
|
||||
<!--
|
||||
Builds ORM package, preparing it for distribution.
|
||||
-->
|
||||
<target name="build-orm" depends="test">
|
||||
<copy todir="${build.dir}/orm">
|
||||
<target name="build-orm" depends="prepare">
|
||||
<exec command="grep '${version}' ${project.basedir}/lib/Doctrine/ORM/Version.php" checkreturn="true"/>
|
||||
<copy todir="${build.dir}/doctrine-orm">
|
||||
<fileset refid="shared-artifacts"/>
|
||||
</copy>
|
||||
<copy todir="${build.dir}/orm">
|
||||
<copy todir="${build.dir}/doctrine-orm">
|
||||
<fileset refid="common-sources"/>
|
||||
<fileset refid="dbal-sources"/>
|
||||
<fileset refid="orm-sources"/>
|
||||
</copy>
|
||||
<copy todir="${build.dir}/orm/Doctrine">
|
||||
<copy todir="${build.dir}/doctrine-orm/Doctrine">
|
||||
<fileset refid="symfony-sources"/>
|
||||
</copy>
|
||||
<copy todir="${build.dir}/orm/bin">
|
||||
<copy todir="${build.dir}/doctrine-orm/bin">
|
||||
<fileset refid="bin-scripts"/>
|
||||
</copy>
|
||||
<exec command="sed 's/${version}-DEV/${version}/' ${build.dir}/orm/Doctrine/ORM/Version.php > ${build.dir}/orm/Doctrine/ORM/Version2.php" passthru="true" />
|
||||
<exec command="mv ${build.dir}/orm/Doctrine/ORM/Version2.php ${build.dir}/orm/Doctrine/ORM/Version.php" passthru="true" />
|
||||
<exec command="sed 's/${version}-DEV/${version}/' ${build.dir}/doctrine-orm/Doctrine/ORM/Version.php > ${build.dir}/doctrine-orm/Doctrine/ORM/Version2.php" passthru="true" />
|
||||
<exec command="mv ${build.dir}/doctrine-orm/Doctrine/ORM/Version2.php ${build.dir}/doctrine-orm/Doctrine/ORM/Version.php" passthru="true" />
|
||||
</target>
|
||||
|
||||
<target name="build" depends="test, build-orm"/>
|
||||
@ -141,8 +141,8 @@
|
||||
<!--
|
||||
Builds distributable PEAR packages.
|
||||
-->
|
||||
<target name="build-packages" depends="build">
|
||||
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/orm">
|
||||
<target name="build-packages" depends="build-orm">
|
||||
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/doctrine-orm">
|
||||
<name>DoctrineORM</name>
|
||||
<summary>Doctrine Object Relational Mapper</summary>
|
||||
<channel>pear.doctrine-project.org</channel>
|
||||
@ -150,6 +150,7 @@
|
||||
<lead user="jwage" name="Jonathan H. Wage" email="jonwage@gmail.com" />
|
||||
<lead user="guilhermeblanco" name="Guilherme Blanco" email="guilhermeblanco@gmail.com" />
|
||||
<lead user="romanb" name="Roman Borschel" email="roman@code-factory.org" />
|
||||
<lead user="beberlei" name="Benjamin Eberlei" email="kontakt@beberlei.de" />
|
||||
<license>LGPL</license>
|
||||
<version release="${version}" api="${version}" />
|
||||
<stability release="${stability}" api="${stability}" />
|
||||
@ -157,17 +158,55 @@
|
||||
<dependencies>
|
||||
<php minimum_version="5.3.0" />
|
||||
<pear minimum_version="1.6.0" recommended_version="1.6.1" />
|
||||
<package name="DoctrineCommon" channel="pear.doctrine-project.org" minimum_version="${dependencies.common}" />
|
||||
<package name="DoctrineDBAL" channel="pear.doctrine-project.org" minimum_version="${dependencies.dbal}" />
|
||||
</dependencies>
|
||||
<dirroles key="bin">script</dirroles>
|
||||
<replacement path="bin/doctrine" type="pear-config" from="@php_bin@" to="php_bin" />
|
||||
<replacement path="bin/doctrine.php" type="pear-config" from="@php_bin@" to="php_bin" />
|
||||
<replacement path="bin/doctrine.php" type="pear-config" from="@bin_dir@" to="bin_dir" />
|
||||
<ignore>Doctrine/Common/</ignore>
|
||||
<ignore>Doctrine/DBAL/</ignore>
|
||||
<release>
|
||||
<install as="doctrine" name="bin/doctrine" />
|
||||
<install as="doctrine.php" name="bin/doctrine.php" />
|
||||
<install as="doctrine.bat" name="bin/doctrine.bat" />
|
||||
</release>
|
||||
<replacement path="bin/doctrine.bat" type="pear-config" from="@php_bin@" to="php_bin" />
|
||||
<replacement path="bin/doctrine.bat" type="pear-config" from="@bin_dir@" to="bin_dir" />
|
||||
</d51pearpkg2>
|
||||
<exec command="pear package" dir="${build.dir}/orm" passthru="true" />
|
||||
<exec command="mv DoctrineORM-${version}.tgz ../../dist" dir="${build.dir}/orm" passthru="true" />
|
||||
<exec command="pear package" dir="${build.dir}/doctrine-orm" passthru="true" />
|
||||
<exec command="mv DoctrineORM-${version}.tgz ../../dist" dir="${build.dir}/doctrine-orm" passthru="true" />
|
||||
<tar destfile="dist/DoctrineORM-${version}-full.tar.gz" compression="gzip" basedir="${build.dir}">
|
||||
<fileset dir="${build.dir}">
|
||||
<include name="**/**" />
|
||||
<exclude name="logs/" />
|
||||
<exclude name="doctrine-orm/package.xml" />
|
||||
</fileset>
|
||||
</tar>
|
||||
</target>
|
||||
|
||||
<target name="git-tag">
|
||||
<exec command="grep '${version}' ${project.basedir}/lib/Doctrine/ORM/Version.php" checkreturn="true"/>
|
||||
<exec command="git tag -a ${version}" passthru="true" />
|
||||
<exec command="git push origin ${version}" passthru="true" />
|
||||
</target>
|
||||
|
||||
<target name="pirum-release">
|
||||
<exec command="sudo pirum add ${project.pirum_dir} ${project.basedir}/dist/DoctrineORM-${version}.tgz" dir="." passthru="true" />
|
||||
<exec command="sudo pirum build ${project.pirum_dir}" passthru="true" />
|
||||
</target>
|
||||
|
||||
<target name="distribute-download">
|
||||
<copy file="dist/DoctrineORM-${version}-full.tar.gz" todir="${project.download_dir}" />
|
||||
</target>
|
||||
|
||||
<target name="update-dev-version">
|
||||
<exec command="grep '${version}' ${project.basedir}/lib/Doctrine/ORM/Version.php" checkreturn="true"/>
|
||||
<propertyprompt propertyName="next_version" defaultValue="${version}" promptText="Enter next version string (without -DEV)" />
|
||||
<exec command="sed 's/${version}-DEV/${next_version}-DEV/' ${project.basedir}/lib/Doctrine/ORM/Version.php > ${project.basedir}/lib/Doctrine/ORM/Version2.php" passthru="true" />
|
||||
<exec command="mv ${project.basedir}/lib/Doctrine/ORM/Version2.php ${project.basedir}/lib/Doctrine/ORM/Version.php" passthru="true" />
|
||||
<exec command="git add ${project.basedir}/lib/Doctrine/ORM/Version.php" passthru="true" />
|
||||
<exec command="git commit -m 'Bump Dev Version to ${next_version}-DEV'" passthru="true" />
|
||||
<exec command="git push origin master" passthru="true" />
|
||||
</target>
|
||||
|
||||
<target name="release" depends="git-tag,build-packages,distribute-download,pirum-release,update-dev-version" />
|
||||
</project>
|
@ -63,7 +63,7 @@
|
||||
<xs:element name="discriminator-column" type="orm:discriminator-column" minOccurs="0"/>
|
||||
<xs:element name="discriminator-map" type="orm:discriminator-map" minOccurs="0"/>
|
||||
<xs:element name="lifecycle-callbacks" type="orm:lifecycle-callbacks" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="id" type="orm:id" />
|
||||
<xs:element name="id" type="orm:id" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="field" type="orm:field" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="one-to-one" type="orm:one-to-one" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="one-to-many" type="orm:one-to-many" minOccurs="0" maxOccurs="unbounded" />
|
||||
@ -73,7 +73,7 @@
|
||||
<xs:attribute name="name" type="xs:string" use="required" />
|
||||
<xs:attribute name="table" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="schema" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="repository-class" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="repository-class" type="xs:string"/>
|
||||
<xs:attribute name="inheritance-type" type="orm:inheritance-type"/>
|
||||
<xs:attribute name="change-tracking-policy" type="orm:change-tracking-policy" />
|
||||
</xs:complexType>
|
||||
@ -252,7 +252,7 @@
|
||||
<xs:element name="join-table" type="orm:join-table" minOccurs="0" />
|
||||
<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="target-entity" type="xs:string" 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" />
|
||||
@ -264,7 +264,7 @@
|
||||
<xs:element name="cascade" type="orm:cascade-type" minOccurs="0" />
|
||||
<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="target-entity" type="xs:string" use="required" />
|
||||
<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" />
|
||||
@ -279,7 +279,7 @@
|
||||
<xs:element name="join-columns" type="orm:join-columns"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="target-entity" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="target-entity" type="xs:string" 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" />
|
||||
@ -295,11 +295,11 @@
|
||||
</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="target-entity" type="xs:string" use="required" />
|
||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
|
||||
<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>
|
||||
|
||||
</xs:schema>
|
||||
</xs:schema>
|
||||
|
@ -482,15 +482,6 @@ abstract class AbstractQuery
|
||||
*/
|
||||
public function execute($params = array(), $hydrationMode = null)
|
||||
{
|
||||
// If there are still pending insertions in the UnitOfWork we need to flush
|
||||
// in order to guarantee a correct result.
|
||||
//TODO: Think this over. Its tricky. Not doing this can lead to strange results
|
||||
// potentially, but doing it could result in endless loops when querying during
|
||||
// a flush, i.e. inside an event listener.
|
||||
if ($this->_em->getUnitOfWork()->hasPendingInsertions()) {
|
||||
$this->_em->flush();
|
||||
}
|
||||
|
||||
if ($hydrationMode !== null) {
|
||||
$this->setHydrationMode($hydrationMode);
|
||||
}
|
||||
@ -562,9 +553,22 @@ abstract class AbstractQuery
|
||||
if ($this->_resultCacheId) {
|
||||
return $this->_resultCacheId;
|
||||
} else {
|
||||
$params = $this->_params;
|
||||
foreach ($params AS $key => $value) {
|
||||
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value))) {
|
||||
if ($this->_em->getUnitOfWork()->getEntityState($value) == UnitOfWork::STATE_MANAGED) {
|
||||
$idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
} else {
|
||||
$class = $this->_em->getClassMetadata(get_class($value));
|
||||
$idValues = $class->getIdentifierValues($value);
|
||||
}
|
||||
$params[$key] = $idValues;
|
||||
}
|
||||
}
|
||||
|
||||
$sql = $this->getSql();
|
||||
ksort($this->_hints);
|
||||
return md5(implode(";", (array)$sql) . var_export($this->_params, true) .
|
||||
return md5(implode(";", (array)$sql) . var_export($params, true) .
|
||||
var_export($this->_hints, true)."&hydrationMode=".$this->_hydrationMode);
|
||||
}
|
||||
}
|
||||
@ -583,6 +587,8 @@ abstract class AbstractQuery
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->free();
|
||||
$this->_params = array();
|
||||
$this->_paramTypes = array();
|
||||
$this->_hints = array();
|
||||
}
|
||||
}
|
||||
|
@ -462,4 +462,25 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
$this->_attributes['customHydrationModes'][$modeName] = $hydrator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a class metadata factory.
|
||||
*
|
||||
* @param string $cmf
|
||||
*/
|
||||
public function setClassMetadataFactoryName($cmfName)
|
||||
{
|
||||
$this->_attributes['classMetadataFactoryName'] = $cmfName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClassMetadataFactoryName()
|
||||
{
|
||||
if (!isset($this->_attributes['classMetadataFactoryName'])) {
|
||||
$this->_attributes['classMetadataFactoryName'] = 'Doctrine\ORM\Mapping\ClassMetadataFactory';
|
||||
}
|
||||
return $this->_attributes['classMetadataFactoryName'];
|
||||
}
|
||||
}
|
@ -118,8 +118,12 @@ class EntityManager
|
||||
$this->conn = $conn;
|
||||
$this->config = $config;
|
||||
$this->eventManager = $eventManager;
|
||||
$this->metadataFactory = new ClassMetadataFactory($this);
|
||||
|
||||
$metadataFactoryClassName = $config->getClassMetadataFactoryName();
|
||||
$this->metadataFactory = new $metadataFactoryClassName;
|
||||
$this->metadataFactory->setEntityManager($this);
|
||||
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
|
||||
|
||||
$this->unitOfWork = new UnitOfWork($this);
|
||||
$this->proxyFactory = new ProxyFactory($this,
|
||||
$config->getProxyDir(),
|
||||
@ -352,11 +356,15 @@ class EntityManager
|
||||
if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
|
||||
return $entity;
|
||||
}
|
||||
if ( ! is_array($identifier)) {
|
||||
$identifier = array($class->identifier[0] => $identifier);
|
||||
if ($class->subClasses) {
|
||||
$entity = $this->find($entityName, $identifier);
|
||||
} else {
|
||||
if ( ! is_array($identifier)) {
|
||||
$identifier = array($class->identifier[0] => $identifier);
|
||||
}
|
||||
$entity = $this->proxyFactory->getProxy($class->name, $identifier);
|
||||
$this->unitOfWork->registerManaged($entity, $identifier, array());
|
||||
}
|
||||
$entity = $this->proxyFactory->getProxy($class->name, $identifier);
|
||||
$this->unitOfWork->registerManaged($entity, $identifier, array());
|
||||
|
||||
return $entity;
|
||||
}
|
||||
@ -611,6 +619,16 @@ class EntityManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Entity manager is open or closed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isOpen()
|
||||
{
|
||||
return (!$this->closed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the UnitOfWork used by the EntityManager to coordinate operations.
|
||||
*
|
||||
|
@ -133,7 +133,6 @@ class EntityRepository
|
||||
/**
|
||||
* Finds all entities in the repository.
|
||||
*
|
||||
* @param int $hydrationMode
|
||||
* @return array The entities.
|
||||
*/
|
||||
public function findAll()
|
||||
@ -144,8 +143,7 @@ class EntityRepository
|
||||
/**
|
||||
* Finds entities by a set of criteria.
|
||||
*
|
||||
* @param string $column
|
||||
* @param string $value
|
||||
* @param array $criteria
|
||||
* @return array
|
||||
*/
|
||||
public function findBy(array $criteria)
|
||||
@ -156,8 +154,7 @@ class EntityRepository
|
||||
/**
|
||||
* Finds a single entity by a set of criteria.
|
||||
*
|
||||
* @param string $column
|
||||
* @param string $value
|
||||
* @param array $criteria
|
||||
* @return object
|
||||
*/
|
||||
public function findOneBy(array $criteria)
|
||||
@ -188,13 +185,14 @@ class EntityRepository
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! isset($arguments[0])) {
|
||||
if ( !isset($arguments[0])) {
|
||||
// we dont even want to allow null at this point, because we cannot (yet) transform it into IS NULL.
|
||||
throw ORMException::findByRequiresParameter($method.$by);
|
||||
}
|
||||
|
||||
$fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by));
|
||||
|
||||
if ($this->_class->hasField($fieldName)) {
|
||||
if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) {
|
||||
return $this->$method(array($fieldName => $arguments[0]));
|
||||
} else {
|
||||
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
|
||||
|
@ -4,6 +4,9 @@ namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* Class that holds event arguments for a loadMetadata event.
|
||||
*
|
||||
@ -12,16 +15,40 @@ use Doctrine\Common\EventArgs;
|
||||
*/
|
||||
class LoadClassMetadataEventArgs extends EventArgs
|
||||
{
|
||||
private $_classMetadata;
|
||||
/**
|
||||
* @var ClassMetadata
|
||||
*/
|
||||
private $classMetadata;
|
||||
|
||||
public function __construct(\Doctrine\ORM\Mapping\ClassMetadata $classMetadata)
|
||||
/**
|
||||
* @var EntityManager
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @param ClassMetadataInfo $classMetadata
|
||||
* @param EntityManager $em
|
||||
*/
|
||||
public function __construct(ClassMetadataInfo $classMetadata, EntityManager $em)
|
||||
{
|
||||
$this->_classMetadata = $classMetadata;
|
||||
$this->classMetadata = $classMetadata;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadataInfo
|
||||
*/
|
||||
public function getClassMetadata()
|
||||
{
|
||||
return $this->_classMetadata;
|
||||
return $this->classMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
return $this->em;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,12 +145,12 @@ class ObjectHydrator extends AbstractHydrator
|
||||
{
|
||||
$oid = spl_object_hash($entity);
|
||||
$relation = $class->associationMappings[$fieldName];
|
||||
|
||||
|
||||
$value = $class->reflFields[$fieldName]->getValue($entity);
|
||||
if ($value === null) {
|
||||
$value = new ArrayCollection;
|
||||
}
|
||||
|
||||
|
||||
if ( ! $value instanceof PersistentCollection) {
|
||||
$value = new PersistentCollection(
|
||||
$this->_em,
|
||||
@ -161,17 +161,19 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$class->reflFields[$fieldName]->setValue($entity, $value);
|
||||
$this->_uow->setOriginalEntityProperty($oid, $fieldName, $value);
|
||||
$this->_initializedCollections[$oid . $fieldName] = $value;
|
||||
} else if (isset($this->_hints[Query::HINT_REFRESH])) {
|
||||
// Is already PersistentCollection, but REFRESH
|
||||
} else if (isset($this->_hints[Query::HINT_REFRESH]) ||
|
||||
isset($this->_hints['fetched'][$class->name][$fieldName]) &&
|
||||
! $value->isInitialized()) {
|
||||
// Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED!
|
||||
$value->setDirty(false);
|
||||
$value->setInitialized(true);
|
||||
$value->unwrap()->clear();
|
||||
$this->_initializedCollections[$oid . $fieldName] = $value;
|
||||
} else {
|
||||
// Is already PersistentCollection, and DONT REFRESH
|
||||
// Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN!
|
||||
$this->_existingCollections[$oid . $fieldName] = $value;
|
||||
}
|
||||
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
@ -269,6 +271,9 @@ class ObjectHydrator extends AbstractHydrator
|
||||
// It's a joined result
|
||||
|
||||
$parentAlias = $this->_rsm->parentAliasMap[$dqlAlias];
|
||||
// we need the $path to save into the identifier map which entities were already
|
||||
// seen for this parent-child relationship
|
||||
$path = $parentAlias . '.' . $dqlAlias;
|
||||
|
||||
// Get a reference to the parent object to which the joined element belongs.
|
||||
if ($this->_rsm->isMixed && isset($this->_rootAliases[$parentAlias])) {
|
||||
@ -298,8 +303,8 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField);
|
||||
}
|
||||
|
||||
$indexExists = isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]]);
|
||||
$index = $indexExists ? $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] : false;
|
||||
$indexExists = isset($this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]);
|
||||
$index = $indexExists ? $this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false;
|
||||
$indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false;
|
||||
|
||||
if ( ! $indexExists || ! $indexIsValid) {
|
||||
@ -317,11 +322,11 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$field = $this->_rsm->indexByMap[$dqlAlias];
|
||||
$indexValue = $this->_ce[$entityName]->reflFields[$field]->getValue($element);
|
||||
$reflFieldValue->hydrateSet($indexValue, $element);
|
||||
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $indexValue;
|
||||
$this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
|
||||
} else {
|
||||
$reflFieldValue->hydrateAdd($element);
|
||||
$reflFieldValue->last();
|
||||
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $reflFieldValue->key();
|
||||
$this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key();
|
||||
}
|
||||
// Update result pointer
|
||||
$this->_resultPointers[$dqlAlias] = $element;
|
||||
@ -332,6 +337,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
} else if ( ! $reflField->getValue($parentObject)) {
|
||||
$coll = new PersistentCollection($this->_em, $this->_ce[$entityName], new ArrayCollection);
|
||||
$coll->setOwner($parentObject, $relation);
|
||||
$reflField->setValue($parentObject, $coll);
|
||||
$this->_uow->setOriginalEntityProperty($oid, $relationField, $coll);
|
||||
}
|
||||
|
@ -74,11 +74,9 @@ class ClassMetadataFactory
|
||||
private $initialized = false;
|
||||
|
||||
/**
|
||||
* Creates a new factory instance that uses the given metadata driver implementation.
|
||||
*
|
||||
* @param $driver The metadata driver to use.
|
||||
* @param EntityManager $$em
|
||||
*/
|
||||
public function __construct(EntityManager $em)
|
||||
public function setEntityManager(EntityManager $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
}
|
||||
@ -262,15 +260,19 @@ class ClassMetadataFactory
|
||||
$class = $this->newClassMetadataInstance($className);
|
||||
|
||||
if ($parent) {
|
||||
$class->setInheritanceType($parent->inheritanceType);
|
||||
$class->setDiscriminatorColumn($parent->discriminatorColumn);
|
||||
if (!$parent->isMappedSuperclass) {
|
||||
$class->setInheritanceType($parent->inheritanceType);
|
||||
$class->setDiscriminatorColumn($parent->discriminatorColumn);
|
||||
}
|
||||
$class->setIdGeneratorType($parent->generatorType);
|
||||
$this->addInheritedFields($class, $parent);
|
||||
$this->addInheritedRelations($class, $parent);
|
||||
$class->setIdentifier($parent->identifier);
|
||||
$class->setVersioned($parent->isVersioned);
|
||||
$class->setVersionField($parent->versionField);
|
||||
$class->setDiscriminatorMap($parent->discriminatorMap);
|
||||
if (!$parent->isMappedSuperclass) {
|
||||
$class->setDiscriminatorMap($parent->discriminatorMap);
|
||||
}
|
||||
$class->setLifecycleCallbacks($parent->lifecycleCallbacks);
|
||||
$class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
|
||||
}
|
||||
@ -302,6 +304,17 @@ class ClassMetadataFactory
|
||||
$this->completeIdGeneratorMapping($class);
|
||||
}
|
||||
|
||||
if ($parent && $parent->isInheritanceTypeSingleTable()) {
|
||||
$class->setPrimaryTable($parent->table);
|
||||
}
|
||||
|
||||
$class->setParentClasses($visited);
|
||||
|
||||
if ($this->evm->hasListeners(Events::loadClassMetadata)) {
|
||||
$eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class, $this->em);
|
||||
$this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
|
||||
}
|
||||
|
||||
// verify inheritance
|
||||
if (!$parent && !$class->isMappedSuperclass && !$class->isInheritanceTypeNone()) {
|
||||
if (count($class->discriminatorMap) == 0) {
|
||||
@ -312,17 +325,6 @@ class ClassMetadataFactory
|
||||
}
|
||||
}
|
||||
|
||||
if ($parent && $parent->isInheritanceTypeSingleTable()) {
|
||||
$class->setPrimaryTable($parent->table);
|
||||
}
|
||||
|
||||
$class->setParentClasses($visited);
|
||||
|
||||
if ($this->evm->hasListeners(Events::loadClassMetadata)) {
|
||||
$eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class);
|
||||
$this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
|
||||
}
|
||||
|
||||
$this->loadedMetadata[$className] = $class;
|
||||
|
||||
$parent = $class;
|
||||
@ -379,6 +381,13 @@ class ClassMetadataFactory
|
||||
private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass)
|
||||
{
|
||||
foreach ($parentClass->associationMappings as $field => $mapping) {
|
||||
if ($parentClass->isMappedSuperclass) {
|
||||
if ($mapping['type'] & ClassMetadata::TO_MANY) {
|
||||
throw MappingException::illegalToManyAssocationOnMappedSuperclass($parentClass->name, $field);
|
||||
}
|
||||
$mapping['sourceEntity'] = $subClass->name;
|
||||
}
|
||||
|
||||
//$subclassMapping = $mapping;
|
||||
if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$mapping['inherited'] = $parentClass->name;
|
||||
|
@ -598,9 +598,10 @@ class ClassMetadataInfo
|
||||
/**
|
||||
* Gets the mapping of an association.
|
||||
*
|
||||
* @see ClassMetadataInfo::$associationMappings
|
||||
* @param string $fieldName The field name that represents the association in
|
||||
* the object model.
|
||||
* @return Doctrine\ORM\Mapping\AssociationMapping The mapping.
|
||||
* @return array The mapping.
|
||||
*/
|
||||
public function getAssociationMapping($fieldName)
|
||||
{
|
||||
@ -669,6 +670,10 @@ class ClassMetadataInfo
|
||||
|
||||
// Complete id mapping
|
||||
if (isset($mapping['id']) && $mapping['id'] === true) {
|
||||
if ($this->versionField == $mapping['fieldName']) {
|
||||
throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName']);
|
||||
}
|
||||
|
||||
if ( ! in_array($mapping['fieldName'], $this->identifier)) {
|
||||
$this->identifier[] = $mapping['fieldName'];
|
||||
}
|
||||
@ -947,6 +952,7 @@ class ClassMetadataInfo
|
||||
public function setIdentifier(array $identifier)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
$this->isIdentifierComposite = (count($this->identifier) > 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1485,6 +1491,13 @@ class ClassMetadataInfo
|
||||
if ( ! isset($columnDef['fieldName'])) {
|
||||
$columnDef['fieldName'] = $columnDef['name'];
|
||||
}
|
||||
if ( ! isset($columnDef['type'])) {
|
||||
$columnDef['type'] = "string";
|
||||
}
|
||||
if (in_array($columnDef['type'], array("boolean", "array", "object", "datetime", "time", "date"))) {
|
||||
throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']);
|
||||
}
|
||||
|
||||
$this->discriminatorColumn = $columnDef;
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ abstract class AbstractFileDriver implements Driver
|
||||
if ($this->_paths) {
|
||||
foreach ((array) $this->_paths as $path) {
|
||||
if ( ! is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath();
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
|
@ -179,6 +179,8 @@ class AnnotationDriver implements Driver
|
||||
'type' => $discrColumnAnnot->type,
|
||||
'length' => $discrColumnAnnot->length
|
||||
));
|
||||
} else {
|
||||
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
|
||||
}
|
||||
|
||||
// Evaluate DiscriminatorMap annotation
|
||||
@ -443,7 +445,7 @@ class AnnotationDriver implements Driver
|
||||
|
||||
foreach ($this->_paths as $path) {
|
||||
if ( ! is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath();
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
|
@ -48,7 +48,7 @@ class DatabaseDriver implements Driver
|
||||
*/
|
||||
private $tables = null;
|
||||
|
||||
private $classes = array();
|
||||
private $classToTableNames = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
@ -73,11 +73,11 @@ class DatabaseDriver implements Driver
|
||||
}
|
||||
|
||||
foreach ($this->_sm->listTableNames() as $tableName) {
|
||||
$tables[strtolower($tableName)] = $this->_sm->listTableDetails($tableName);
|
||||
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
|
||||
}
|
||||
|
||||
$this->tables = array();
|
||||
foreach ($tables AS $name => $table) {
|
||||
foreach ($tables AS $tableName => $table) {
|
||||
/* @var $table Table */
|
||||
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$foreignKeys = $table->getForeignKeys();
|
||||
@ -89,21 +89,23 @@ class DatabaseDriver implements Driver
|
||||
foreach ($foreignKeys AS $foreignKey) {
|
||||
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
|
||||
}
|
||||
|
||||
|
||||
$pkColumns = $table->getPrimaryKey()->getColumns();
|
||||
sort($pkColumns);
|
||||
sort($allForeignKeyColumns);
|
||||
|
||||
if ($pkColumns == $allForeignKeyColumns) {
|
||||
if (count($table->getForeignKeys()) > 2) {
|
||||
throw new \InvalidArgumentException("ManyToMany table '" . $name . "' with more or less than two foreign keys are not supported by the Database Reverese Engineering Driver.");
|
||||
throw new \InvalidArgumentException("ManyToMany table '" . $tableName . "' with more or less than two foreign keys are not supported by the Database Reverese Engineering Driver.");
|
||||
}
|
||||
|
||||
$this->manyToManyTables[$name] = $table;
|
||||
$this->manyToManyTables[$tableName] = $table;
|
||||
} else {
|
||||
$className = Inflector::classify($name);
|
||||
$this->tables[$name] = $table;
|
||||
$this->classes[$className] = $name;
|
||||
// lower-casing is necessary because of Oracle Uppercase Tablenames,
|
||||
// assumption is lower-case + underscore separated.
|
||||
$className = Inflector::classify(strtolower($tableName));
|
||||
$this->tables[$tableName] = $table;
|
||||
$this->classToTableNames[$className] = $tableName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -115,11 +117,11 @@ class DatabaseDriver implements Driver
|
||||
{
|
||||
$this->reverseEngineerMappingFromDatabase();
|
||||
|
||||
if (!isset($this->classes[$className])) {
|
||||
if (!isset($this->classToTableNames[$className])) {
|
||||
throw new \InvalidArgumentException("Unknown class " . $className);
|
||||
}
|
||||
|
||||
$tableName = Inflector::tableize($className);
|
||||
$tableName = $this->classToTableNames[$className];
|
||||
|
||||
$metadata->name = $className;
|
||||
$metadata->table['name'] = $tableName;
|
||||
@ -183,7 +185,7 @@ class DatabaseDriver implements Driver
|
||||
|
||||
foreach ($this->manyToManyTables AS $manyTable) {
|
||||
foreach ($manyTable->getForeignKeys() AS $foreignKey) {
|
||||
if ($tableName == strtolower($foreignKey->getForeignTableName())) {
|
||||
if (strtolower($tableName) == strtolower($foreignKey->getForeignTableName())) {
|
||||
$myFk = $foreignKey;
|
||||
foreach ($manyTable->getForeignKeys() AS $foreignKey) {
|
||||
if ($foreignKey != $myFk) {
|
||||
@ -269,6 +271,6 @@ class DatabaseDriver implements Driver
|
||||
{
|
||||
$this->reverseEngineerMappingFromDatabase();
|
||||
|
||||
return array_keys($this->classes);
|
||||
return array_keys($this->classToTableNames);
|
||||
}
|
||||
}
|
@ -114,8 +114,8 @@ final class Index extends Annotation {
|
||||
final class JoinTable extends Annotation {
|
||||
public $name;
|
||||
public $schema;
|
||||
public $joinColumns;
|
||||
public $inverseJoinColumns;
|
||||
public $joinColumns = array();
|
||||
public $inverseJoinColumns = array();
|
||||
}
|
||||
final class SequenceGenerator extends Annotation {
|
||||
public $sequenceName;
|
||||
|
@ -88,10 +88,15 @@ class DriverChain implements Driver
|
||||
public function getAllClassNames()
|
||||
{
|
||||
$classNames = array();
|
||||
foreach ($this->_drivers AS $driver) {
|
||||
$classNames = array_merge($classNames, $driver->getAllClassNames());
|
||||
foreach ($this->_drivers AS $namespace => $driver) {
|
||||
$driverClasses = $driver->getAllClassNames();
|
||||
foreach ($driverClasses AS $className) {
|
||||
if (strpos($className, $namespace) === 0) {
|
||||
$classNames[] = $className;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $classNames;
|
||||
return array_unique($classNames);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,7 +78,7 @@ class StaticPHPDriver implements Driver
|
||||
|
||||
foreach ($this->_paths as $path) {
|
||||
if ( ! is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath();
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
|
@ -87,6 +87,8 @@ class XmlDriver extends AbstractFileDriver
|
||||
'type' => (string)$discrColumn['type'],
|
||||
'length' => (string)$discrColumn['length']
|
||||
));
|
||||
} else {
|
||||
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
|
||||
}
|
||||
|
||||
// Evaluate <discriminator-map...>
|
||||
|
@ -79,6 +79,8 @@ class YamlDriver extends AbstractFileDriver
|
||||
'type' => $discrColumn['type'],
|
||||
'length' => $discrColumn['length']
|
||||
));
|
||||
} else {
|
||||
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
|
||||
}
|
||||
|
||||
// Evaluate discriminatorMap
|
||||
|
@ -68,9 +68,9 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
return new self("No mapping file found named '$fileName' for class '$entityName'.");
|
||||
}
|
||||
|
||||
public static function mappingNotFound($fieldName)
|
||||
public static function mappingNotFound($className, $fieldName)
|
||||
{
|
||||
return new self("No mapping found for field '$fieldName'.");
|
||||
return new self("No mapping found for field '$fieldName' on class '$className'.");
|
||||
}
|
||||
|
||||
public static function oneToManyRequiresMappedBy($fieldName)
|
||||
@ -170,9 +170,16 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
);
|
||||
}
|
||||
|
||||
public static function fileMappingDriversRequireConfiguredDirectoryPath()
|
||||
public static function fileMappingDriversRequireConfiguredDirectoryPath($path = null)
|
||||
{
|
||||
return new self('File mapping drivers must have a valid directory path, however the given path seems to be incorrect!');
|
||||
if ( ! empty($path)) {
|
||||
$path = '[' . $path . ']';
|
||||
}
|
||||
|
||||
return new self(
|
||||
'File mapping drivers must have a valid directory path, ' .
|
||||
'however the given path ' . $path . ' seems to be incorrect!'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,6 +207,16 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
return new self("Entity class '$className' is using inheritance but no discriminator column was defined.");
|
||||
}
|
||||
|
||||
public static function invalidDiscriminatorColumnType($className, $type)
|
||||
{
|
||||
return new self("Discriminator column type on entity class '$className' is not allowed to be '$type'. 'string' or 'integer' type variables are suggested!");
|
||||
}
|
||||
|
||||
public static function cannotVersionIdField($className, $fieldName)
|
||||
{
|
||||
return new self("Setting Id field '$fieldName' as versionale in entity class '$className' is not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $columnName
|
||||
@ -209,4 +226,9 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
{
|
||||
return new self("Duplicate definition of column '".$columnName."' on entity '".$className."' in a field or discriminator column mapping.");
|
||||
}
|
||||
|
||||
public static function illegalToManyAssocationOnMappedSuperclass($className, $field)
|
||||
{
|
||||
return new self("It is illegal to put a one-to-many or many-to-many association on mapped superclass '".$className."#".$field."'.");
|
||||
}
|
||||
}
|
@ -78,6 +78,14 @@ class ORMException extends Exception
|
||||
);
|
||||
}
|
||||
|
||||
public static function invalidFindByInverseAssociation($entityName, $associationFieldName)
|
||||
{
|
||||
return new self(
|
||||
"You cannot search for the association field '".$entityName."#".$associationFieldName."', ".
|
||||
"because it is the inverse side of an association. Find methods only work on owning side associations."
|
||||
);
|
||||
}
|
||||
|
||||
public static function invalidResultCacheDriver() {
|
||||
return new self("Invalid result cache driver; it must implement \Doctrine\Common\Cache\Cache.");
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ final class PersistentCollection implements Collection
|
||||
* Initializes the collection by loading its contents from the database
|
||||
* if the collection is not yet initialized.
|
||||
*/
|
||||
private function initialize()
|
||||
public function initialize()
|
||||
{
|
||||
if ( ! $this->initialized && $this->association) {
|
||||
if ($this->isDirty) {
|
||||
|
@ -33,11 +33,18 @@ use Doctrine\ORM\Mapping\ClassMetadata,
|
||||
abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
{
|
||||
/**
|
||||
* Map from column names to class names that declare the field the column is mapped to.
|
||||
* Map from column names to class metadata instances that declare the field the column is mapped to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_declaringClassMap = array();
|
||||
private $declaringClassMap = array();
|
||||
|
||||
/**
|
||||
* Map from column names to class names that declare the field the association with join column is mapped to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $declaringJoinColumnMap = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@ -70,8 +77,8 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
unset($sqlResult[$discrColumnName]);
|
||||
foreach ($sqlResult as $column => $value) {
|
||||
$realColumnName = $this->_resultColumnNames[$column];
|
||||
if (isset($this->_declaringClassMap[$column])) {
|
||||
$class = $this->_declaringClassMap[$column];
|
||||
if (isset($this->declaringClassMap[$column])) {
|
||||
$class = $this->declaringClassMap[$column];
|
||||
if ($class->name == $entityName || is_subclass_of($entityName, $class->name)) {
|
||||
$field = $class->fieldNames[$realColumnName];
|
||||
if (isset($data[$field])) {
|
||||
@ -81,6 +88,10 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
->convertToPHPValue($value, $this->_platform);
|
||||
}
|
||||
}
|
||||
} else if (isset($this->declaringJoinColumnMap[$column])) {
|
||||
if ($this->declaringJoinColumnMap[$column] == $entityName || is_subclass_of($entityName, $this->declaringJoinColumnMap[$column])) {
|
||||
$data[$realColumnName] = $value;
|
||||
}
|
||||
} else {
|
||||
$data[$realColumnName] = $value;
|
||||
}
|
||||
@ -99,9 +110,21 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
|
||||
if ( ! isset($this->_resultColumnNames[$columnAlias])) {
|
||||
$this->_resultColumnNames[$columnAlias] = $columnName;
|
||||
$this->_declaringClassMap[$columnAlias] = $class;
|
||||
$this->declaringClassMap[$columnAlias] = $class;
|
||||
}
|
||||
|
||||
return "$sql AS $columnAlias";
|
||||
}
|
||||
|
||||
protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className)
|
||||
{
|
||||
$columnAlias = $joinColumnName . $this->_sqlAliasCounter++;
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
if ( ! isset($this->_resultColumnNames[$resultColumnName])) {
|
||||
$this->_resultColumnNames[$resultColumnName] = $joinColumnName;
|
||||
$this->declaringJoinColumnMap[$resultColumnName] = $className;
|
||||
}
|
||||
|
||||
return $tableAlias . ".$joinColumnName AS $columnAlias";
|
||||
}
|
||||
}
|
@ -251,6 +251,8 @@ class BasicEntityPersister
|
||||
$sql = "SELECT " . $versionFieldColumnName . " FROM " . $class->getQuotedTableName($this->_platform)
|
||||
. " WHERE " . implode(' = ? AND ', $identifier) . " = ?";
|
||||
$value = $this->_conn->fetchColumn($sql, array_values((array)$id));
|
||||
|
||||
$value = Type::getType($class->fieldMappings[$versionField]['type'])->convertToPHPValue($value, $this->_platform);
|
||||
$this->_class->setFieldValue($entity, $versionField, $value);
|
||||
}
|
||||
|
||||
@ -273,7 +275,15 @@ class BasicEntityPersister
|
||||
$updateData = $this->_prepareUpdateData($entity);
|
||||
$tableName = $this->_class->table['name'];
|
||||
if (isset($updateData[$tableName]) && $updateData[$tableName]) {
|
||||
$this->_updateTable($entity, $tableName, $updateData[$tableName], $this->_class->isVersioned);
|
||||
$this->_updateTable(
|
||||
$entity, $this->_class->getQuotedTableName($this->_platform),
|
||||
$updateData[$tableName], $this->_class->isVersioned
|
||||
);
|
||||
|
||||
if ($this->_class->isVersioned) {
|
||||
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity);
|
||||
$this->_assignDefaultVersionValue($this->_class, $entity, $id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,11 +292,11 @@ class BasicEntityPersister
|
||||
* 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 string $quotedTableName The quoted 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 final function _updateTable($entity, $tableName, array $updateData, $versioned = false)
|
||||
protected final function _updateTable($entity, $quotedTableName, array $updateData, $versioned = false)
|
||||
{
|
||||
$set = $params = $types = array();
|
||||
|
||||
@ -317,7 +327,7 @@ class BasicEntityPersister
|
||||
|
||||
if ($versioned) {
|
||||
$versionField = $this->_class->versionField;
|
||||
$versionFieldType = $this->_class->getTypeOfField($versionField);
|
||||
$versionFieldType = $this->_class->fieldMappings[$versionField]['type'];
|
||||
$versionColumn = $this->_class->getQuotedColumnName($versionField, $this->_platform);
|
||||
if ($versionFieldType == Type::INTEGER) {
|
||||
$set[] = $versionColumn . ' = ' . $versionColumn . ' + 1';
|
||||
@ -329,7 +339,7 @@ class BasicEntityPersister
|
||||
$types[] = $this->_class->fieldMappings[$versionField]['type'];
|
||||
}
|
||||
|
||||
$sql = "UPDATE $tableName SET " . implode(', ', $set)
|
||||
$sql = "UPDATE $quotedTableName SET " . implode(', ', $set)
|
||||
. ' WHERE ' . implode(' = ? AND ', $where) . ' = ?';
|
||||
|
||||
$result = $this->_conn->executeUpdate($sql, $params, $types);
|
||||
@ -393,17 +403,7 @@ class BasicEntityPersister
|
||||
$this->deleteJoinTableRecords($identifier);
|
||||
|
||||
$id = array_combine($this->_class->getIdentifierColumnNames(), $identifier);
|
||||
$this->_conn->delete($this->_class->table['name'], $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ClassMetadata instance of the entity class this persister is used for.
|
||||
*
|
||||
* @return Doctrine\ORM\Mapping\ClassMetadata
|
||||
*/
|
||||
public function getClassMetadata()
|
||||
{
|
||||
return $this->_class;
|
||||
$this->_conn->delete($this->_class->getQuotedTableName($this->_platform), $id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -660,7 +660,7 @@ class BasicEntityPersister
|
||||
if ($found = $this->_em->getUnitOfWork()->tryGetById($joinColumnValues, $targetClass->rootEntityName)) {
|
||||
$this->_class->reflFields[$field]->setValue($entity, $found);
|
||||
// Complete inverse side, if necessary.
|
||||
if ($assoc['inversedBy']) {
|
||||
if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
|
||||
$inverseAssoc = $targetClass->associationMappings[$assoc['inversedBy']];
|
||||
$targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($found, $entity);
|
||||
}
|
||||
@ -681,6 +681,9 @@ class BasicEntityPersister
|
||||
}
|
||||
} else if ($value instanceof PersistentCollection && $value->isInitialized()) {
|
||||
$value->setInitialized(false);
|
||||
// no matter if dirty or non-dirty entities are already loaded, smoke them out!
|
||||
// the beauty of it being, they are still in the identity map
|
||||
$value->unwrap()->clear();
|
||||
$newData[$field] = $value;
|
||||
}
|
||||
}
|
||||
@ -848,8 +851,8 @@ class BasicEntityPersister
|
||||
}
|
||||
|
||||
return 'SELECT ' . $this->_getSelectColumnListSQL()
|
||||
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->_getSQLTableAlias($this->_class->name)
|
||||
. $this->_platform->appendLockHint(' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->_getSQLTableAlias($this->_class->name), $lockMode)
|
||||
. $joinSql
|
||||
. ($conditionSql ? ' WHERE ' . $conditionSql : '')
|
||||
. $orderBySql
|
||||
@ -1086,7 +1089,7 @@ class BasicEntityPersister
|
||||
}
|
||||
|
||||
$sql = 'SELECT 1 '
|
||||
. $this->getLockTablesSql()
|
||||
. $this->_platform->appendLockHint($this->getLockTablesSql(), $lockMode)
|
||||
. ($conditionSql ? ' WHERE ' . $conditionSql : '') . ' ' . $lockSql;
|
||||
$params = array_values($criteria);
|
||||
$this->_conn->executeQuery($sql, $params);
|
||||
@ -1128,9 +1131,16 @@ class BasicEntityPersister
|
||||
}
|
||||
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
} else if (isset($this->_class->associationMappings[$field])) {
|
||||
// TODO: Inherited?
|
||||
// TODO: Composite Keys as Foreign Key PK? That would be super ugly! And should probably be disallowed ;)
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
|
||||
if (!$this->_class->associationMappings[$field]['isOwningSide']) {
|
||||
throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field);
|
||||
}
|
||||
|
||||
if (isset($this->_class->associationMappings[$field]['inherited'])) {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->associationMappings[$field]['inherited']) . '.';
|
||||
} else {
|
||||
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
|
||||
}
|
||||
|
||||
$conditionSql .= $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
|
||||
} else if ($assoc !== null) {
|
||||
|
@ -35,9 +35,18 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
/**
|
||||
* Map that maps column names to the table names that own them.
|
||||
* This is mainly a temporary cache, used during a single request.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_owningTableMap = array();
|
||||
|
||||
/**
|
||||
* Map of table to quoted table names.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_quotedTableMap = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -74,18 +83,16 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
*/
|
||||
public function getOwningTable($fieldName)
|
||||
{
|
||||
if ( ! isset($this->_owningTableMap[$fieldName])) {
|
||||
if (!isset($this->_owningTableMap[$fieldName])) {
|
||||
if (isset($this->_class->associationMappings[$fieldName]['inherited'])) {
|
||||
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
|
||||
$this->_class->associationMappings[$fieldName]['inherited']
|
||||
)->table['name'];
|
||||
$cm = $this->_em->getClassMetadata($this->_class->associationMappings[$fieldName]['inherited']);
|
||||
} else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) {
|
||||
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
|
||||
$this->_class->fieldMappings[$fieldName]['inherited']
|
||||
)->table['name'];
|
||||
$cm = $this->_em->getClassMetadata($this->_class->fieldMappings[$fieldName]['inherited']);
|
||||
} else {
|
||||
$this->_owningTableMap[$fieldName] = $this->_class->table['name'];
|
||||
$cm = $this->_class;
|
||||
}
|
||||
$this->_owningTableMap[$fieldName] = $cm->table['name'];
|
||||
$this->_quotedTableMap[$cm->table['name']] = $cm->getQuotedTableName($this->_platform);
|
||||
}
|
||||
|
||||
return $this->_owningTableMap[$fieldName];
|
||||
@ -186,17 +193,21 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$updateData = $this->_prepareUpdateData($entity);
|
||||
|
||||
if ($isVersioned = $this->_class->isVersioned) {
|
||||
$versionedTable = $this->_getVersionedClassMetadata()->table['name'];
|
||||
$versionedClass = $this->_getVersionedClassMetadata();
|
||||
$versionedTable = $versionedClass->table['name'];
|
||||
}
|
||||
|
||||
if ($updateData) {
|
||||
foreach ($updateData as $tableName => $data) {
|
||||
$this->_updateTable($entity, $tableName, $data, $isVersioned && $versionedTable == $tableName);
|
||||
$this->_updateTable($entity, $this->_quotedTableMap[$tableName], $data, $isVersioned && $versionedTable == $tableName);
|
||||
}
|
||||
// Make sure the table with the version column is updated even if no columns on that
|
||||
// table were affected.
|
||||
if ($isVersioned && ! isset($updateData[$versionedTable])) {
|
||||
$this->_updateTable($entity, $versionedTable, array(), true);
|
||||
$this->_updateTable($entity, $versionedClass->getQuotedTableName($this->_platform), array(), true);
|
||||
|
||||
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity);
|
||||
$this->_assignDefaultVersionValue($this->_class, $entity, $id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -252,12 +263,10 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$this->_getSQLTableAlias($assoc2['inherited'])
|
||||
: $baseTableAlias;
|
||||
foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$columnList .= ", $tableAlias.$srcColumn AS $columnAlias";
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
if ( ! isset($this->_resultColumnNames[$resultColumnName])) {
|
||||
$this->_resultColumnNames[$resultColumnName] = $srcColumn;
|
||||
}
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
$columnList .= $this->getSelectJoinColumnSQL($tableAlias, $srcColumn,
|
||||
isset($assoc2['inherited']) ? $assoc2['inherited'] : $this->_class->name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -307,12 +316,10 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE
|
||||
&& ! isset($assoc2['inherited'])) {
|
||||
foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$columnList .= ', ' . $tableAlias . ".$srcColumn AS $columnAlias";
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
if ( ! isset($this->_resultColumnNames[$resultColumnName])) {
|
||||
$this->_resultColumnNames[$resultColumnName] = $srcColumn;
|
||||
}
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
$columnList .= $this->getSelectJoinColumnSQL($tableAlias, $srcColumn,
|
||||
isset($assoc2['inherited']) ? $assoc2['inherited'] : $subClass->name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -354,6 +361,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
*/
|
||||
public function getLockTablesSql()
|
||||
{
|
||||
$idColumns = $this->_class->getIdentifierColumnNames();
|
||||
$baseTableAlias = $this->_getSQLTableAlias($this->_class->name);
|
||||
|
||||
// INNER JOIN parent tables
|
||||
|
@ -63,12 +63,10 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
foreach ($subClass->associationMappings as $assoc) {
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE && ! isset($assoc['inherited'])) {
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$columnList .= ', ' . $tableAlias . ".$srcColumn AS $columnAlias";
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
if ( ! isset($this->_resultColumnNames[$resultColumnName])) {
|
||||
$this->_resultColumnNames[$resultColumnName] = $srcColumn;
|
||||
}
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
$columnList .= $this->getSelectJoinColumnSQL($tableAlias, $srcColumn,
|
||||
isset($assoc['inherited']) ? $assoc['inherited'] : $this->_class->name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,9 +77,11 @@ class ProxyFactory
|
||||
$proxyClassName = str_replace('\\', '', $className) . 'Proxy';
|
||||
$fqn = $this->_proxyNamespace . '\\' . $proxyClassName;
|
||||
|
||||
if ($this->_autoGenerate && ! class_exists($fqn, false)) {
|
||||
if (! class_exists($fqn, false)) {
|
||||
$fileName = $this->_proxyDir . DIRECTORY_SEPARATOR . $proxyClassName . '.php';
|
||||
$this->_generateProxyClass($this->_em->getClassMetadata($className), $proxyClassName, $fileName, self::$_proxyClassTemplate);
|
||||
if ($this->_autoGenerate) {
|
||||
$this->_generateProxyClass($this->_em->getClassMetadata($className), $proxyClassName, $fileName, self::$_proxyClassTemplate);
|
||||
}
|
||||
require $fileName;
|
||||
}
|
||||
|
||||
|
@ -242,10 +242,14 @@ final class Query extends AbstractQuery
|
||||
}
|
||||
|
||||
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value))) {
|
||||
//TODO: Check that $value is MANAGED?
|
||||
$values = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
if ($this->_em->getUnitOfWork()->getEntityState($value) == UnitOfWork::STATE_MANAGED) {
|
||||
$idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
} else {
|
||||
$class = $this->_em->getClassMetadata(get_class($value));
|
||||
$idValues = $class->getIdentifierValues($value);
|
||||
}
|
||||
$sqlPositions = $paramMappings[$key];
|
||||
$sqlParams += array_combine((array)$sqlPositions, $values);
|
||||
$sqlParams += array_combine((array)$sqlPositions, $idValues);
|
||||
} else {
|
||||
foreach ($paramMappings[$key] as $position) {
|
||||
$sqlParams[$position] = $value;
|
||||
@ -544,4 +548,15 @@ final class Query extends AbstractQuery
|
||||
'&hydrationMode='.$this->_hydrationMode.'DOCTRINE_QUERY_CACHE_SALT'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup Query resource when clone is called.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
parent::__clone();
|
||||
$this->_state = self::STATE_DIRTY;
|
||||
}
|
||||
}
|
@ -41,8 +41,9 @@ class LengthFunction extends FunctionNode
|
||||
*/
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
{
|
||||
//TODO: Use platform to get SQL
|
||||
return 'LENGTH(' . $sqlWalker->walkStringPrimary($this->stringPrimary) . ')';
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getLengthExpression(
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,8 +41,9 @@ class LowerFunction extends FunctionNode
|
||||
*/
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
{
|
||||
//TODO: Use platform to get SQL
|
||||
return 'LOWER(' . $sqlWalker->walkStringPrimary($this->stringPrimary) . ')';
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getLowerExpression(
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -42,12 +42,10 @@ class ModFunction extends FunctionNode
|
||||
*/
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
{
|
||||
//TODO: Use platform to get SQL
|
||||
return 'MOD('
|
||||
. $sqlWalker->walkSimpleArithmeticExpression($this->firstSimpleArithmeticExpression)
|
||||
. ', '
|
||||
. $sqlWalker->walkSimpleArithmeticExpression($this->secondSimpleArithmeticExpression)
|
||||
. ')';
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getModExpression(
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->firstSimpleArithmeticExpression),
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->secondSimpleArithmeticExpression)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,8 +41,9 @@ class UpperFunction extends FunctionNode
|
||||
*/
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
{
|
||||
//TODO: Use platform to get SQL
|
||||
return 'UPPER(' . $sqlWalker->walkStringPrimary($this->stringPrimary) . ')';
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getUpperExpression(
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,6 +125,11 @@ class Parser
|
||||
*/
|
||||
private $_customOutputWalker;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $_identVariableExpressions = array();
|
||||
|
||||
/**
|
||||
* Creates a new query parser object.
|
||||
*
|
||||
@ -272,6 +277,9 @@ class Parser
|
||||
{
|
||||
$AST = $this->getAST();
|
||||
|
||||
$this->fixIdentificationVariableOrder($AST);
|
||||
$this->assertSelectEntityRootAliasRequirement();
|
||||
|
||||
if (($customWalkers = $this->_query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) {
|
||||
$this->_customTreeWalkers = $customWalkers;
|
||||
}
|
||||
@ -312,6 +320,46 @@ class Parser
|
||||
|
||||
return $this->_parserResult;
|
||||
}
|
||||
|
||||
private function assertSelectEntityRootAliasRequirement()
|
||||
{
|
||||
if ( count($this->_identVariableExpressions) > 0) {
|
||||
$foundRootEntity = false;
|
||||
foreach ($this->_identVariableExpressions AS $dqlAlias => $expr) {
|
||||
if (isset($this->_queryComponents[$dqlAlias]) && $this->_queryComponents[$dqlAlias]['parent'] === null) {
|
||||
$foundRootEntity = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$foundRootEntity) {
|
||||
$this->semanticalError('Cannot select entity through identification variables without choosing at least one root entity alias.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix order of identification variables.
|
||||
*
|
||||
* They have to appear in the select clause in the same order as the
|
||||
* declarations (from ... x join ... y join ... z ...) appear in the query
|
||||
* as the hydration process relies on that order for proper operation.
|
||||
*
|
||||
* @param AST\SelectStatement|AST\DeleteStatement|AST\UpdateStatement $AST
|
||||
* @return void
|
||||
*/
|
||||
private function fixIdentificationVariableOrder($AST)
|
||||
{
|
||||
if ( count($this->_identVariableExpressions) > 1) {
|
||||
foreach ($this->_queryComponents as $dqlAlias => $qComp) {
|
||||
if (isset($this->_identVariableExpressions[$dqlAlias])) {
|
||||
$expr = $this->_identVariableExpressions[$dqlAlias];
|
||||
$key = array_search($expr, $AST->selectClause->selectExpressions);
|
||||
unset($AST->selectClause->selectExpressions[$key]);
|
||||
$AST->selectClause->selectExpressions[] = $expr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new syntax error.
|
||||
@ -1628,6 +1676,7 @@ class Parser
|
||||
public function SelectExpression()
|
||||
{
|
||||
$expression = null;
|
||||
$identVariable = null;
|
||||
$fieldAliasIdentificationVariable = null;
|
||||
$peek = $this->_lexer->glimpse();
|
||||
|
||||
@ -1639,7 +1688,7 @@ class Parser
|
||||
$expression = $this->ScalarExpression();
|
||||
} else {
|
||||
$supportsAlias = false;
|
||||
$expression = $this->IdentificationVariable();
|
||||
$expression = $identVariable = $this->IdentificationVariable();
|
||||
}
|
||||
} else if ($this->_lexer->lookahead['value'] == '(') {
|
||||
if ($peek['type'] == Lexer::T_SELECT) {
|
||||
@ -1666,6 +1715,7 @@ class Parser
|
||||
} else if ($this->_lexer->lookahead['type'] == Lexer::T_PARTIAL) {
|
||||
$supportsAlias = false;
|
||||
$expression = $this->PartialObjectExpression();
|
||||
$identVariable = $expression->identificationVariable;
|
||||
} else if ($this->_lexer->lookahead['type'] == Lexer::T_INTEGER ||
|
||||
$this->_lexer->lookahead['type'] == Lexer::T_FLOAT) {
|
||||
// Shortcut: ScalarExpression => SimpleArithmeticExpression
|
||||
@ -1694,7 +1744,11 @@ class Parser
|
||||
}
|
||||
}
|
||||
|
||||
return new AST\SelectExpression($expression, $fieldAliasIdentificationVariable);
|
||||
$expr = new AST\SelectExpression($expression, $fieldAliasIdentificationVariable);
|
||||
if (!$supportsAlias) {
|
||||
$this->_identVariableExpressions[$identVariable] = $expr;
|
||||
}
|
||||
return $expr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -689,7 +689,7 @@ class SqlWalker implements TreeWalker
|
||||
$sql = $this->_scalarResultAliasMap[$columnName];
|
||||
}
|
||||
|
||||
return $sql . ' ' . strtoupper($orderByItem->type);;
|
||||
return $sql . ' ' . strtoupper($orderByItem->type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -888,6 +888,40 @@ class QueryBuilder
|
||||
. (isset($options['post']) ? $options['post'] : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset DQL parts
|
||||
*
|
||||
* @param array $parts
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function resetDQLParts($parts = null)
|
||||
{
|
||||
if (is_null($parts)) {
|
||||
$parts = array_keys($this->_dqlParts);
|
||||
}
|
||||
foreach ($parts as $part) {
|
||||
$this->resetDQLPart($part);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset single DQL part
|
||||
*
|
||||
* @param string $part
|
||||
* @return QueryBuilder;
|
||||
*/
|
||||
public function resetDQLPart($part)
|
||||
{
|
||||
if (is_array($this->_dqlParts[$part])) {
|
||||
$this->_dqlParts[$part] = array();
|
||||
} else {
|
||||
$this->_dqlParts[$part] = null;
|
||||
}
|
||||
$this->_state = self::STATE_DIRTY;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string representation of this QueryBuilder which corresponds to
|
||||
* the final DQL query being constructed.
|
||||
@ -898,4 +932,24 @@ class QueryBuilder
|
||||
{
|
||||
return $this->getDQL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep clone of all expression objects in the DQL parts.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
foreach ($this->_dqlParts AS $part => $elements) {
|
||||
if (is_array($this->_dqlParts[$part])) {
|
||||
foreach ($this->_dqlParts[$part] AS $idx => $element) {
|
||||
if (is_object($element)) {
|
||||
$this->_dqlParts[$part][$idx] = clone $element;
|
||||
}
|
||||
}
|
||||
} else if (\is_object($elements)) {
|
||||
$this->_dqlParts[$part] = clone $elements;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -49,19 +49,19 @@ class ResultCommand extends Console\Command\Command
|
||||
->setDescription('Clear result cache of the various cache drivers.')
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'id', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY,
|
||||
'id', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'ID(s) of the cache entry to delete (accepts * wildcards).', array()
|
||||
),
|
||||
new InputOption(
|
||||
'regex', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY,
|
||||
'regex', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Delete cache entries that match the given regular expression(s).', array()
|
||||
),
|
||||
new InputOption(
|
||||
'prefix', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY,
|
||||
'prefix', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Delete cache entries that have the given prefix(es).', array()
|
||||
),
|
||||
new InputOption(
|
||||
'suffix', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY,
|
||||
'suffix', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Delete cache entries that have the given suffix(es).', array()
|
||||
),
|
||||
))
|
||||
|
@ -112,16 +112,16 @@ class ConvertDoctrine1SchemaCommand extends Console\Command\Command
|
||||
'The path to generate your Doctrine 2.X mapping information.'
|
||||
),
|
||||
new InputOption(
|
||||
'from', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY,
|
||||
'from', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Optional paths of Doctrine 1.X schema information.',
|
||||
array()
|
||||
),
|
||||
new InputOption(
|
||||
'extend', null, InputOption::PARAMETER_OPTIONAL,
|
||||
'extend', null, InputOption::VALUE_OPTIONAL,
|
||||
'Defines a base class to be extended by generated entity classes.'
|
||||
),
|
||||
new InputOption(
|
||||
'num-spaces', null, InputOption::PARAMETER_OPTIONAL,
|
||||
'num-spaces', null, InputOption::VALUE_OPTIONAL,
|
||||
'Defines the number of indentation spaces', 4
|
||||
)
|
||||
))
|
||||
|
@ -53,7 +53,7 @@ class ConvertMappingCommand extends Console\Command\Command
|
||||
->setDescription('Convert mapping information between supported formats.')
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'filter', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY,
|
||||
'filter', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'A string pattern used to match entities that should be processed.'
|
||||
),
|
||||
new InputArgument(
|
||||
@ -67,11 +67,11 @@ class ConvertMappingCommand extends Console\Command\Command
|
||||
'from-database', null, null, 'Whether or not to convert mapping information from existing database.'
|
||||
),
|
||||
new InputOption(
|
||||
'extend', null, InputOption::PARAMETER_OPTIONAL,
|
||||
'extend', null, InputOption::VALUE_OPTIONAL,
|
||||
'Defines a base class to be extended by generated entity classes.'
|
||||
),
|
||||
new InputOption(
|
||||
'num-spaces', null, InputOption::PARAMETER_OPTIONAL,
|
||||
'num-spaces', null, InputOption::VALUE_OPTIONAL,
|
||||
'Defines the number of indentation spaces', 4
|
||||
)
|
||||
))
|
||||
@ -96,7 +96,8 @@ EOT
|
||||
);
|
||||
}
|
||||
|
||||
$cmf = new DisconnectedClassMetadataFactory($em);
|
||||
$cmf = new DisconnectedClassMetadataFactory();
|
||||
$cmf->setEntityManager($em);
|
||||
$metadata = $cmf->getAllMetadata();
|
||||
$metadata = MetadataFilter::filter($metadata, $input->getOption('filter'));
|
||||
|
||||
|
@ -49,7 +49,7 @@ class EnsureProductionSettingsCommand extends Console\Command\Command
|
||||
->setDescription('Verify that Doctrine is properly configured for a production environment.')
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'complete', null, InputOption::PARAMETER_NONE,
|
||||
'complete', null, InputOption::VALUE_NONE,
|
||||
'Flag to also inspect database connection existance.'
|
||||
)
|
||||
))
|
||||
|
@ -52,34 +52,34 @@ class GenerateEntitiesCommand extends Console\Command\Command
|
||||
->setDescription('Generate entity classes and method stubs from your mapping information.')
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'filter', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY,
|
||||
'filter', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'A string pattern used to match entities that should be processed.'
|
||||
),
|
||||
new InputArgument(
|
||||
'dest-path', InputArgument::REQUIRED, 'The path to generate your entity classes.'
|
||||
),
|
||||
new InputOption(
|
||||
'generate-annotations', null, InputOption::PARAMETER_OPTIONAL,
|
||||
'generate-annotations', null, InputOption::VALUE_OPTIONAL,
|
||||
'Flag to define if generator should generate annotation metadata on entities.', false
|
||||
),
|
||||
new InputOption(
|
||||
'generate-methods', null, InputOption::PARAMETER_OPTIONAL,
|
||||
'generate-methods', null, InputOption::VALUE_OPTIONAL,
|
||||
'Flag to define if generator should generate stub methods on entities.', true
|
||||
),
|
||||
new InputOption(
|
||||
'regenerate-entities', null, InputOption::PARAMETER_OPTIONAL,
|
||||
'regenerate-entities', null, InputOption::VALUE_OPTIONAL,
|
||||
'Flag to define if generator should regenerate entity if it exists.', false
|
||||
),
|
||||
new InputOption(
|
||||
'update-entities', null, InputOption::PARAMETER_OPTIONAL,
|
||||
'update-entities', null, InputOption::VALUE_OPTIONAL,
|
||||
'Flag to define if generator should only update entity if it exists.', true
|
||||
),
|
||||
new InputOption(
|
||||
'extend', null, InputOption::PARAMETER_OPTIONAL,
|
||||
'extend', null, InputOption::VALUE_OPTIONAL,
|
||||
'Defines a base class to be extended by generated entity classes.'
|
||||
),
|
||||
new InputOption(
|
||||
'num-spaces', null, InputOption::PARAMETER_OPTIONAL,
|
||||
'num-spaces', null, InputOption::VALUE_OPTIONAL,
|
||||
'Defines the number of indentation spaces', 4
|
||||
)
|
||||
))
|
||||
@ -96,7 +96,8 @@ EOT
|
||||
{
|
||||
$em = $this->getHelper('em')->getEntityManager();
|
||||
|
||||
$cmf = new DisconnectedClassMetadataFactory($em);
|
||||
$cmf = new DisconnectedClassMetadataFactory();
|
||||
$cmf->setEntityManager($em);
|
||||
$metadatas = $cmf->getAllMetadata();
|
||||
$metadatas = MetadataFilter::filter($metadatas, $input->getOption('filter'));
|
||||
|
||||
|
@ -50,7 +50,7 @@ class GenerateProxiesCommand extends Console\Command\Command
|
||||
->setDescription('Generates proxy classes for entity classes.')
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'filter', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY,
|
||||
'filter', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'A string pattern used to match entities that should be processed.'
|
||||
),
|
||||
new InputArgument(
|
||||
|
@ -51,7 +51,7 @@ class GenerateRepositoriesCommand extends Console\Command\Command
|
||||
->setDescription('Generate repository classes from your mapping information.')
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'filter', null, InputOption::PARAMETER_REQUIRED | InputOption::PARAMETER_IS_ARRAY,
|
||||
'filter', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'A string pattern used to match entities that should be processed.'
|
||||
),
|
||||
new InputArgument(
|
||||
|
@ -50,20 +50,20 @@ class RunDqlCommand extends Console\Command\Command
|
||||
->setDefinition(array(
|
||||
new InputArgument('dql', InputArgument::REQUIRED, 'The DQL to execute.'),
|
||||
new InputOption(
|
||||
'hydrate', null, InputOption::PARAMETER_REQUIRED,
|
||||
'hydrate', null, InputOption::VALUE_REQUIRED,
|
||||
'Hydration mode of result set. Should be either: object, array, scalar or single-scalar.',
|
||||
'object'
|
||||
),
|
||||
new InputOption(
|
||||
'first-result', null, InputOption::PARAMETER_REQUIRED,
|
||||
'first-result', null, InputOption::VALUE_REQUIRED,
|
||||
'The first result in the result set.'
|
||||
),
|
||||
new InputOption(
|
||||
'max-result', null, InputOption::PARAMETER_REQUIRED,
|
||||
'max-result', null, InputOption::VALUE_REQUIRED,
|
||||
'The maximum number of results in the result set.'
|
||||
),
|
||||
new InputOption(
|
||||
'depth', null, InputOption::PARAMETER_REQUIRED,
|
||||
'depth', null, InputOption::VALUE_REQUIRED,
|
||||
'Dumping depth of Entity graph.', 7
|
||||
)
|
||||
))
|
||||
@ -114,7 +114,7 @@ EOT
|
||||
throw new \LogicException("Option 'max-result' must contains an integer value");
|
||||
}
|
||||
|
||||
$query->setMaxResult((int) $maxResult);
|
||||
$query->setMaxResults((int) $maxResult);
|
||||
}
|
||||
|
||||
$resultSet = $query->execute(array(), constant($hydrationMode));
|
||||
|
@ -53,7 +53,7 @@ class CreateCommand extends AbstractCommand
|
||||
)
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'dump-sql', null, InputOption::PARAMETER_NONE,
|
||||
'dump-sql', null, InputOption::VALUE_NONE,
|
||||
'Instead of try to apply generated SQLs into EntityManager Storage Connection, output them.'
|
||||
)
|
||||
))
|
||||
@ -65,6 +65,8 @@ EOT
|
||||
|
||||
protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas)
|
||||
{
|
||||
$output->write('ATTENTION: This operation should not be executed in an production enviroment.' . PHP_EOL . PHP_EOL);
|
||||
|
||||
if ($input->getOption('dump-sql') === true) {
|
||||
$sqls = $schemaTool->getCreateSchemaSql($metadatas);
|
||||
$output->write(implode(';' . PHP_EOL, $sqls) . PHP_EOL);
|
||||
|
@ -49,13 +49,21 @@ class DropCommand extends AbstractCommand
|
||||
$this
|
||||
->setName('orm:schema-tool:drop')
|
||||
->setDescription(
|
||||
'Processes the schema and either drop the database schema of EntityManager Storage Connection or generate the SQL output.'
|
||||
'Drop the complete database schema of EntityManager Storage Connection or generate the corresponding SQL output.'
|
||||
)
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'dump-sql', null, InputOption::PARAMETER_NONE,
|
||||
'dump-sql', null, InputOption::VALUE_NONE,
|
||||
'Instead of try to apply generated SQLs into EntityManager Storage Connection, output them.'
|
||||
)
|
||||
),
|
||||
new InputOption(
|
||||
'force', null, InputOption::VALUE_NONE,
|
||||
"Don't ask for the deletion of the database, but force the operation to run."
|
||||
),
|
||||
new InputOption(
|
||||
'full-database', null, InputOption::VALUE_NONE,
|
||||
'Instead of using the Class Metadata to detect the database table schema, drop ALL assets that the database contains.'
|
||||
),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
Processes the schema and either drop the database schema of EntityManager Storage Connection or generate the SQL output.
|
||||
@ -66,13 +74,38 @@ EOT
|
||||
|
||||
protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas)
|
||||
{
|
||||
$isFullDatabaseDrop = ($input->getOption('full-database'));
|
||||
|
||||
if ($input->getOption('dump-sql') === true) {
|
||||
$sqls = $schemaTool->getDropSchemaSql($metadatas);
|
||||
if ($isFullDatabaseDrop) {
|
||||
$sqls = $schemaTool->getDropDatabaseSQL();
|
||||
} else {
|
||||
$sqls = $schemaTool->getDropSchemaSQL($metadatas);
|
||||
}
|
||||
$output->write(implode(';' . PHP_EOL, $sqls) . PHP_EOL);
|
||||
} else {
|
||||
} else if ($input->getOption('force') === true) {
|
||||
$output->write('Dropping database schema...' . PHP_EOL);
|
||||
$schemaTool->dropSchema($metadatas);
|
||||
if ($isFullDatabaseDrop) {
|
||||
$schemaTool->dropDatabase();
|
||||
} else {
|
||||
$schemaTool->dropSchema($metadatas);
|
||||
}
|
||||
$output->write('Database schema dropped successfully!' . PHP_EOL);
|
||||
} else {
|
||||
$output->write('ATTENTION: This operation should not be executed in an production enviroment.' . PHP_EOL . PHP_EOL);
|
||||
|
||||
if ($isFullDatabaseDrop) {
|
||||
$sqls = $schemaTool->getDropDatabaseSQL();
|
||||
} else {
|
||||
$sqls = $schemaTool->getDropSchemaSQL($metadatas);
|
||||
}
|
||||
|
||||
if (count($sqls)) {
|
||||
$output->write('Schema-Tool would execute ' . count($sqls) . ' queries to drop the database.' . PHP_EOL);
|
||||
$output->write('Please run the operation with --force to execute these queries or use --dump-sql to see them.' . PHP_EOL);
|
||||
} else {
|
||||
$output->write('Nothing to drop. The database is empty!' . PHP_EOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,13 +53,17 @@ class UpdateCommand extends AbstractCommand
|
||||
)
|
||||
->setDefinition(array(
|
||||
new InputOption(
|
||||
'complete', null, InputOption::PARAMETER_NONE,
|
||||
'complete', null, InputOption::VALUE_NONE,
|
||||
'If defined, all assets of the database which are not relevant to the current metadata will be dropped.'
|
||||
),
|
||||
new InputOption(
|
||||
'dump-sql', null, InputOption::PARAMETER_NONE,
|
||||
'dump-sql', null, InputOption::VALUE_NONE,
|
||||
'Instead of try to apply generated SQLs into EntityManager Storage Connection, output them.'
|
||||
)
|
||||
),
|
||||
new InputOption(
|
||||
'force', null, InputOption::VALUE_NONE,
|
||||
"Don't ask for the incremental update of the database, but force the operation to run."
|
||||
),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
Processes the schema and either update the database schema of EntityManager Storage Connection or generate the SQL output.
|
||||
@ -72,15 +76,28 @@ EOT
|
||||
protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas)
|
||||
{
|
||||
// Defining if update is complete or not (--complete not defined means $saveMode = true)
|
||||
$saveMode = ($input->getOption('complete') === true);
|
||||
$saveMode = ($input->getOption('complete') !== true);
|
||||
|
||||
if ($input->getOption('dump-sql') === true) {
|
||||
$sqls = $schemaTool->getUpdateSchemaSql($metadatas, $saveMode);
|
||||
$output->write(implode(';' . PHP_EOL, $sqls) . PHP_EOL);
|
||||
} else {
|
||||
} else if ($input->getOption('force') === true) {
|
||||
$output->write('Updating database schema...' . PHP_EOL);
|
||||
$schemaTool->updateSchema($metadatas, $saveMode);
|
||||
$output->write('Database schema updated successfully!' . PHP_EOL);
|
||||
} else {
|
||||
$output->write('ATTENTION: This operation should not be executed in an production enviroment.' . PHP_EOL);
|
||||
$output->write('Use the incremental update to detect changes during development and use' . PHP_EOL);
|
||||
$output->write('this SQL DDL to manually update your database in production.' . PHP_EOL . PHP_EOL);
|
||||
|
||||
$sqls = $schemaTool->getUpdateSchemaSql($metadatas, $saveMode);
|
||||
|
||||
if (count($sqls)) {
|
||||
$output->write('Schema-Tool would execute ' . count($sqls) . ' queries to update the database.' . PHP_EOL);
|
||||
$output->write('Please run the operation with --force to execute these queries or use --dump-sql to see them.' . PHP_EOL);
|
||||
} else {
|
||||
$output->write('Nothing to update. The database is in sync with the current entity metadata.' . PHP_EOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
69
lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php
Normal file
69
lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?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\Tools\Console;
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
|
||||
class ConsoleRunner
|
||||
{
|
||||
/**
|
||||
* Run console with the given helperset.
|
||||
*
|
||||
* @param \Symfony\Component\Console\Helper\HelperSet $helperSet
|
||||
* @return void
|
||||
*/
|
||||
static public function run(HelperSet $helperSet)
|
||||
{
|
||||
$cli = new Application('Doctrine Command Line Interface', \Doctrine\ORM\Version::VERSION);
|
||||
$cli->setCatchExceptions(true);
|
||||
$cli->setHelperSet($helperSet);
|
||||
self::addCommands($cli);
|
||||
$cli->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Application $cli
|
||||
*/
|
||||
static public function addCommands(Application $cli)
|
||||
{
|
||||
$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(),
|
||||
new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(),
|
||||
));
|
||||
}
|
||||
}
|
@ -188,7 +188,6 @@ class ConvertDoctrine1Schema
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
|
||||
} else if (isset($column['sequence'])) {
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
|
||||
$metadata->setSequenceGeneratorDefinition($definition);
|
||||
$definition = array(
|
||||
'sequenceName' => is_array($column['sequence']) ? $column['sequence']['name']:$column['sequence']
|
||||
);
|
||||
@ -198,6 +197,7 @@ class ConvertDoctrine1Schema
|
||||
if (isset($column['sequence']['value'])) {
|
||||
$definition['initialValue'] = $column['sequence']['value'];
|
||||
}
|
||||
$metadata->setSequenceGeneratorDefinition($definition);
|
||||
}
|
||||
return $fieldMapping;
|
||||
}
|
||||
|
@ -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,7 +31,6 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
@ -46,7 +43,13 @@ class DisconnectedClassMetadataFactory extends ClassMetadataFactory
|
||||
*/
|
||||
protected function newClassMetadataInstance($className)
|
||||
{
|
||||
return new ClassMetadataInfo($className);
|
||||
$metadata = new ClassMetadataInfo($className);
|
||||
if (strpos($className, "\\") !== false) {
|
||||
$metadata->namespace = strrev(substr( strrev($className), strpos(strrev($className), "\\")+1 ));
|
||||
} else {
|
||||
$metadata->namespace = "";
|
||||
}
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
@ -82,7 +80,7 @@ class EntityGenerator
|
||||
private static $_classTemplate =
|
||||
'<?php
|
||||
|
||||
<namespace><use>
|
||||
<namespace>
|
||||
|
||||
<entityAnnotation>
|
||||
<entityClassName>
|
||||
@ -189,7 +187,6 @@ public function <methodName>()
|
||||
{
|
||||
$placeHolders = array(
|
||||
'<namespace>',
|
||||
'<use>',
|
||||
'<entityAnnotation>',
|
||||
'<entityClassName>',
|
||||
'<entityBody>'
|
||||
@ -197,7 +194,6 @@ public function <methodName>()
|
||||
|
||||
$replacements = array(
|
||||
$this->_generateEntityNamespace($metadata),
|
||||
$this->_generateEntityUse($metadata),
|
||||
$this->_generateEntityDocBlock($metadata),
|
||||
$this->_generateEntityClassName($metadata),
|
||||
$this->_generateEntityBody($metadata)
|
||||
@ -222,7 +218,7 @@ public function <methodName>()
|
||||
$body = str_replace('<spaces>', $this->_spaces, $body);
|
||||
$last = strrpos($currentCode, '}');
|
||||
|
||||
return substr($currentCode, 0, $last) . $body . "\n}";
|
||||
return substr($currentCode, 0, $last) . $body . (strlen($body) > 0 ? "\n" : ''). "}";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -309,13 +305,6 @@ public function <methodName>()
|
||||
}
|
||||
}
|
||||
|
||||
private function _generateEntityUse(ClassMetadataInfo $metadata)
|
||||
{
|
||||
if ($this->_extendsClass()) {
|
||||
return "\n\nuse " . $this->_getClassToExtendNamespace() . ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
private function _generateEntityClassName(ClassMetadataInfo $metadata)
|
||||
{
|
||||
return 'class ' . $this->_getClassName($metadata) .
|
||||
@ -379,14 +368,7 @@ public function <methodName>()
|
||||
{
|
||||
$refl = new \ReflectionClass($this->_getClassToExtend());
|
||||
|
||||
return $refl->getName();
|
||||
}
|
||||
|
||||
private function _getClassToExtendNamespace()
|
||||
{
|
||||
$refl = new \ReflectionClass($this->_getClassToExtend());
|
||||
|
||||
return $refl->getNamespaceName() ? $refl->getNamespaceName():$refl->getShortName();
|
||||
return '\\' . $refl->getName();
|
||||
}
|
||||
|
||||
private function _getClassName(ClassMetadataInfo $metadata)
|
||||
|
@ -46,11 +46,14 @@ class XmlExporter extends AbstractExporter
|
||||
*/
|
||||
public function exportClassMetadata(ClassMetadataInfo $metadata)
|
||||
{
|
||||
$xml = new \SimpleXmlElement("<?xml version=\"1.0\" encoding=\"utf-8\"?><doctrine-mapping/>");
|
||||
$xml = new \SimpleXmlElement("<?xml version=\"1.0\" encoding=\"utf-8\"?><doctrine-mapping ".
|
||||
"xmlns=\"http://doctrine-project.org/schemas/orm/doctrine-mapping\" " .
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ".
|
||||
"xsi:schemaLocation=\"http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd\" />");
|
||||
|
||||
$xml->addAttribute('xmlns', 'http://doctrine-project.org/schemas/orm/doctrine-mapping');
|
||||
/*$xml->addAttribute('xmlns', 'http://doctrine-project.org/schemas/orm/doctrine-mapping');
|
||||
$xml->addAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
|
||||
$xml->addAttribute('xsi:schemaLocation', 'http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd');
|
||||
$xml->addAttribute('xsi:schemaLocation', 'http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd');*/
|
||||
|
||||
if ($metadata->isMappedSuperclass) {
|
||||
$root = $xml->addChild('mapped-superclass');
|
||||
@ -109,7 +112,7 @@ class XmlExporter extends AbstractExporter
|
||||
|
||||
foreach ($metadata->table['uniqueConstraints'] as $unique) {
|
||||
$uniqueConstraintXml = $uniqueConstraintsXml->addChild('unique-constraint');
|
||||
$uniqueConstraintXml->addAttribute('name', $name);
|
||||
$uniqueConstraintXml->addAttribute('name', $unique['name']);
|
||||
$uniqueConstraintXml->addAttribute('columns', implode(',', $unique['columns']));
|
||||
}
|
||||
}
|
||||
@ -128,6 +131,21 @@ class XmlExporter extends AbstractExporter
|
||||
$id[$metadata->getSingleIdentifierFieldName()]['generator']['strategy'] = $idGeneratorType;
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
foreach ($id as $field) {
|
||||
$idXml = $root->addChild('id');
|
||||
$idXml->addAttribute('name', $field['fieldName']);
|
||||
$idXml->addAttribute('type', $field['type']);
|
||||
if (isset($field['columnName'])) {
|
||||
$idXml->addAttribute('column', $field['columnName']);
|
||||
}
|
||||
if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) {
|
||||
$generatorXml = $idXml->addChild('generator');
|
||||
$generatorXml->addAttribute('strategy', $idGeneratorType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($fields) {
|
||||
foreach ($fields as $field) {
|
||||
$fieldXml = $root->addChild('field');
|
||||
@ -163,21 +181,6 @@ class XmlExporter extends AbstractExporter
|
||||
}
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
foreach ($id as $field) {
|
||||
$idXml = $root->addChild('id');
|
||||
$idXml->addAttribute('name', $field['fieldName']);
|
||||
$idXml->addAttribute('type', $field['type']);
|
||||
if (isset($field['columnName'])) {
|
||||
$idXml->addAttribute('column', $field['columnName']);
|
||||
}
|
||||
if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) {
|
||||
$generatorXml = $idXml->addChild('generator');
|
||||
$generatorXml->addAttribute('strategy', $idGeneratorType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($metadata->associationMappings as $name => $associationMapping) {
|
||||
if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_ONE) {
|
||||
$associationMappingXml = $root->addChild('one-to-one');
|
||||
@ -305,47 +308,16 @@ class XmlExporter extends AbstractExporter
|
||||
}
|
||||
|
||||
/**
|
||||
* Code originally taken from
|
||||
* http://recurser.com/articles/2007/04/05/format-xml-with-php/
|
||||
*
|
||||
* @param string $simpleXml
|
||||
* @param \SimpleXMLElement $simpleXml
|
||||
* @return string $xml
|
||||
*/
|
||||
private function _asXml($simpleXml)
|
||||
{
|
||||
$xml = $simpleXml->asXml();
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->loadXML($simpleXml->asXML());
|
||||
$dom->formatOutput = true;
|
||||
|
||||
// add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries)
|
||||
$xml = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $xml);
|
||||
|
||||
// now indent the tags
|
||||
$token = strtok($xml, "\n");
|
||||
$result = ''; // holds formatted version as it is built
|
||||
$pad = 0; // initial indent
|
||||
$matches = array(); // returns from preg_matches()
|
||||
|
||||
// test for the various tag states
|
||||
while ($token !== false) {
|
||||
// 1. open and closing tags on same line - no change
|
||||
if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) {
|
||||
$indent = 0;
|
||||
// 2. closing tag - outdent now
|
||||
} else if (preg_match('/^<\/\w/', $token, $matches)) {
|
||||
$pad = $pad - 4;
|
||||
// 3. opening tag - don't pad this one, only subsequent tags
|
||||
} elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches)) {
|
||||
$indent = 4;
|
||||
// 4. no indentation needed
|
||||
} else {
|
||||
$indent = 0;
|
||||
}
|
||||
|
||||
// pad the line with the required number of leading spaces
|
||||
$line = str_pad($token, strlen($token)+$pad, ' ', STR_PAD_LEFT);
|
||||
$result .= $line . "\n"; // add to the cumulative result, with linefeed
|
||||
$token = strtok("\n"); // get the next token
|
||||
$pad += $indent; // update the pad size for subsequent lines
|
||||
}
|
||||
$result = $dom->saveXML();
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -89,11 +89,6 @@ class YamlExporter extends AbstractExporter
|
||||
|
||||
$ids = array();
|
||||
foreach ($fieldMappings as $name => $fieldMapping) {
|
||||
if (isset($fieldMapping['length'])) {
|
||||
$fieldMapping['type'] = $fieldMapping['type'] . '(' . $fieldMapping['length'] . ')';
|
||||
unset($fieldMapping['length']);
|
||||
}
|
||||
|
||||
$fieldMapping['column'] = $fieldMapping['columnName'];
|
||||
unset(
|
||||
$fieldMapping['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
|
||||
@ -94,6 +92,22 @@ class SchemaTool
|
||||
return $schema->toSql($this->_platform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some instances of ClassMetadata don't need to be processed in the SchemaTool context. This method detects them.
|
||||
*
|
||||
* @param ClassMetadata $class
|
||||
* @param array $processedClasses
|
||||
* @return bool
|
||||
*/
|
||||
private function processingNotRequired($class, array $processedClasses)
|
||||
{
|
||||
return (
|
||||
isset($processedClasses[$class->name]) ||
|
||||
$class->isMappedSuperclass ||
|
||||
($class->isInheritanceTypeSingleTable() && $class->name != $class->rootEntityName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* From a given set of metadata classes this method creates a Schema instance.
|
||||
*
|
||||
@ -112,19 +126,12 @@ class SchemaTool
|
||||
$evm = $this->_em->getEventManager();
|
||||
|
||||
foreach ($classes as $class) {
|
||||
if (isset($processedClasses[$class->name]) || $class->isMappedSuperclass) {
|
||||
if ($this->processingNotRequired($class, $processedClasses)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$table = $schema->createTable($class->getQuotedTableName($this->_platform));
|
||||
|
||||
// TODO: Remove
|
||||
/**if ($class->isIdGeneratorIdentity()) {
|
||||
$table->setIdGeneratorType(\Doctrine\DBAL\Schema\Table::ID_IDENTITY);
|
||||
} else if ($class->isIdGeneratorSequence()) {
|
||||
$table->setIdGeneratorType(\Doctrine\DBAL\Schema\Table::ID_SEQUENCE);
|
||||
}*/
|
||||
|
||||
$columns = array(); // table columns
|
||||
|
||||
if ($class->isInheritanceTypeSingleTable()) {
|
||||
@ -171,16 +178,14 @@ class SchemaTool
|
||||
$idMapping = $class->fieldMappings[$class->identifier[0]];
|
||||
$this->_gatherColumn($class, $idMapping, $table);
|
||||
$columnName = $class->getQuotedColumnName($class->identifier[0], $this->_platform);
|
||||
// TODO: This seems rather hackish, can we optimize it?
|
||||
$table->getColumn($class->identifier[0])->setAutoincrement(false);
|
||||
|
||||
$pkColumns[] = $columnName;
|
||||
// TODO: REMOVE
|
||||
/*if ($table->isIdGeneratorIdentity()) {
|
||||
$table->setIdGeneratorType(\Doctrine\DBAL\Schema\Table::ID_NONE);
|
||||
}*/
|
||||
|
||||
// Add a FK constraint on the ID column
|
||||
$table->addUnnamedForeignKeyConstraint(
|
||||
$this->_em->getClassMetadata($class->rootEntityName)->getQuotedTableName($this->_platform),
|
||||
$this->_em->getClassMetadata($class->rootEntityName)->getTableName(),
|
||||
array($columnName), array($columnName), array('onDelete' => 'CASCADE')
|
||||
);
|
||||
}
|
||||
@ -318,6 +323,9 @@ class SchemaTool
|
||||
$options = array();
|
||||
$options['length'] = isset($mapping['length']) ? $mapping['length'] : null;
|
||||
$options['notnull'] = isset($mapping['nullable']) ? ! $mapping['nullable'] : true;
|
||||
if ($class->isInheritanceTypeSingleTable() && count($class->parentClasses) > 0) {
|
||||
$options['notnull'] = false;
|
||||
}
|
||||
|
||||
$options['platformOptions'] = array();
|
||||
$options['platformOptions']['version'] = $class->isVersioned && $class->versionField == $mapping['fieldName'] ? true : false;
|
||||
@ -345,6 +353,9 @@ class SchemaTool
|
||||
if ($class->isIdGeneratorIdentity() && $class->getIdentifierFieldNames() == array($mapping['fieldName'])) {
|
||||
$options['autoincrement'] = true;
|
||||
}
|
||||
if ($class->isInheritanceTypeJoined() && $class->name != $class->rootEntityName) {
|
||||
$options['autoincrement'] = false;
|
||||
}
|
||||
|
||||
if ($table->hasColumn($columnName)) {
|
||||
// required in some inheritance scenarios
|
||||
@ -459,6 +470,12 @@ class SchemaTool
|
||||
if (isset($joinColumn['nullable'])) {
|
||||
$columnOptions['notnull'] = !$joinColumn['nullable'];
|
||||
}
|
||||
if ($fieldMapping['type'] == "string") {
|
||||
$columnOptions['length'] = $fieldMapping['length'];
|
||||
} else if ($fieldMapping['type'] == "decimal") {
|
||||
$columnOptions['scale'] = $fieldMapping['scale'];
|
||||
$columnOptions['precision'] = $fieldMapping['precision'];
|
||||
}
|
||||
|
||||
$theJoinTable->addColumn(
|
||||
$columnName, $class->getTypeOfColumn($joinColumn['referencedColumnName']), $columnOptions
|
||||
@ -479,7 +496,7 @@ class SchemaTool
|
||||
}
|
||||
|
||||
$theJoinTable->addUnnamedForeignKeyConstraint(
|
||||
$class->getQuotedTableName($this->_platform), $localColumns, $foreignColumns, $fkOptions
|
||||
$class->getTableName(), $localColumns, $foreignColumns, $fkOptions
|
||||
);
|
||||
}
|
||||
|
||||
@ -494,7 +511,26 @@ class SchemaTool
|
||||
*/
|
||||
public function dropSchema(array $classes)
|
||||
{
|
||||
$dropSchemaSql = $this->getDropSchemaSql($classes);
|
||||
$dropSchemaSql = $this->getDropSchemaSQL($classes);
|
||||
$conn = $this->_em->getConnection();
|
||||
|
||||
foreach ($dropSchemaSql as $sql) {
|
||||
try {
|
||||
$conn->executeQuery($sql);
|
||||
} catch(\Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops all elements in the database of the current connection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropDatabase()
|
||||
{
|
||||
$dropSchemaSql = $this->getDropDatabaseSQL();
|
||||
$conn = $this->_em->getConnection();
|
||||
|
||||
foreach ($dropSchemaSql as $sql) {
|
||||
@ -503,12 +539,11 @@ class SchemaTool
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL needed to drop the database schema for the given classes.
|
||||
* Gets the SQL needed to drop the database schema for the connections database.
|
||||
*
|
||||
* @param array $classes
|
||||
* @return array
|
||||
*/
|
||||
public function getDropSchemaSql(array $classes)
|
||||
public function getDropDatabaseSQL()
|
||||
{
|
||||
$sm = $this->_em->getConnection()->getSchemaManager();
|
||||
$schema = $sm->createSchema();
|
||||
@ -520,39 +555,31 @@ class SchemaTool
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all tables of the database connection.
|
||||
*
|
||||
* @param array $classes
|
||||
* @return array
|
||||
*/
|
||||
private function _getDropSchemaTablesDatabaseMode($classes)
|
||||
public function getDropSchemaSQL(array $classes)
|
||||
{
|
||||
$conn = $this->_em->getConnection();
|
||||
$sm = $this->_em->getConnection()->getSchemaManager();
|
||||
|
||||
$sql = array();
|
||||
$orderedTables = array();
|
||||
|
||||
$sm = $conn->getSchemaManager();
|
||||
/* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */
|
||||
|
||||
$allTables = $sm->listTables();
|
||||
|
||||
$orderedTables = $this->_getDropSchemaTablesMetadataMode($classes);
|
||||
foreach($allTables AS $tableName) {
|
||||
if(!in_array($tableName, $orderedTables)) {
|
||||
$orderedTables[] = $tableName;
|
||||
foreach ($classes AS $class) {
|
||||
if ($class->isIdGeneratorSequence() && !$class->isMappedSuperclass && $class->name == $class->rootEntityName && $this->_platform->supportsSequences()) {
|
||||
$sql[] = $this->_platform->getDropSequenceSQL($class->sequenceGeneratorDefinition['sequenceName']);
|
||||
}
|
||||
}
|
||||
|
||||
return $orderedTables;
|
||||
}
|
||||
|
||||
private function _getDropSchemaTablesMetadataMode(array $classes)
|
||||
{
|
||||
$orderedTables = array();
|
||||
|
||||
$commitOrder = $this->_getCommitOrder($classes);
|
||||
$associationTables = $this->_getAssociationTables($commitOrder);
|
||||
|
||||
// Drop association tables first
|
||||
foreach ($associationTables as $associationTable) {
|
||||
$orderedTables[] = $associationTable;
|
||||
if (!in_array($associationTable, $orderedTables)) {
|
||||
$orderedTables[] = $associationTable;
|
||||
}
|
||||
}
|
||||
|
||||
// Drop tables in reverse commit order
|
||||
@ -564,17 +591,27 @@ class SchemaTool
|
||||
continue;
|
||||
}
|
||||
|
||||
$orderedTables[] = $class->getTableName();
|
||||
if (!in_array($class->getTableName(), $orderedTables)) {
|
||||
$orderedTables[] = $class->getTableName();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Drop other schema elements, like sequences etc.
|
||||
$dropTablesSql = array();
|
||||
foreach ($orderedTables AS $tableName) {
|
||||
/* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */
|
||||
$foreignKeys = $sm->listTableForeignKeys($tableName);
|
||||
foreach ($foreignKeys AS $foreignKey) {
|
||||
$sql[] = $this->_platform->getDropForeignKeySQL($foreignKey, $tableName);
|
||||
}
|
||||
$dropTablesSql[] = $this->_platform->getDropTableSQL($tableName);
|
||||
}
|
||||
|
||||
return $orderedTables;
|
||||
return array_merge($sql, $dropTablesSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the database schema of the given classes by comparing the ClassMetadata
|
||||
* instances to the current database schema that is inspected.
|
||||
* ins$tableNametances to the current database schema that is inspected.
|
||||
*
|
||||
* @param array $classes
|
||||
* @return void
|
||||
@ -645,7 +682,7 @@ class SchemaTool
|
||||
foreach ($classes as $class) {
|
||||
foreach ($class->associationMappings as $assoc) {
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] == ClassMetadata::MANY_TO_MANY) {
|
||||
$associationTables[] = $assoc->joinTable['name'];
|
||||
$associationTables[] = $assoc['joinTable']['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -573,7 +573,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$this->computeChangeSet($targetClass, $entry);
|
||||
} else if ($state == self::STATE_REMOVED) {
|
||||
return new InvalidArgumentException("Removed entity detected during flush: "
|
||||
. self::objToStr($removedEntity).". Remove deleted entities from associations.");
|
||||
. self::objToStr($entry).". Remove deleted entities from associations.");
|
||||
} else if ($state == self::STATE_DETACHED) {
|
||||
// Can actually not happen right now as we assume STATE_NEW,
|
||||
// so the exception will be raised from the DBAL layer (constraint violation).
|
||||
@ -1437,7 +1437,16 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$prop->setValue($managedCopy, $managedCol);
|
||||
$this->originalEntityData[$oid][$name] = $managedCol;
|
||||
}
|
||||
$managedCol->setInitialized($assoc2['isCascadeMerge']);
|
||||
if ($assoc2['isCascadeMerge']) {
|
||||
$managedCol->initialize();
|
||||
if (!$managedCol->isEmpty()) {
|
||||
$managedCol->unwrap()->clear();
|
||||
$managedCol->setDirty(true);
|
||||
if ($assoc2['isOwningSide'] && $assoc2['type'] == ClassMetadata::MANY_TO_MANY && $class->isChangeTrackingNotify()) {
|
||||
$this->scheduleForDirtyCheck($managedCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($class->isChangeTrackingNotify()) {
|
||||
@ -1456,7 +1465,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
if ($assoc['type'] & ClassMetadata::TO_ONE) {
|
||||
$prevClass->reflFields[$assocField]->setValue($prevManagedCopy, $managedCopy);
|
||||
} else {
|
||||
$prevClass->reflFields[$assocField]->getValue($prevManagedCopy)->unwrap()->add($managedCopy);
|
||||
$prevClass->reflFields[$assocField]->getValue($prevManagedCopy)->add($managedCopy);
|
||||
if ($assoc['type'] == ClassMetadata::ONE_TO_MANY) {
|
||||
$class->reflFields[$assoc['mappedBy']]->setValue($managedCopy, $prevManagedCopy);
|
||||
}
|
||||
@ -1500,7 +1509,9 @@ class UnitOfWork implements PropertyChangedListener
|
||||
|
||||
switch ($this->getEntityState($entity, self::STATE_DETACHED)) {
|
||||
case self::STATE_MANAGED:
|
||||
$this->removeFromIdentityMap($entity);
|
||||
if ($this->isInIdentityMap($entity)) {
|
||||
$this->removeFromIdentityMap($entity);
|
||||
}
|
||||
unset($this->entityInsertions[$oid], $this->entityUpdates[$oid],
|
||||
$this->entityDeletions[$oid], $this->entityIdentifiers[$oid],
|
||||
$this->entityStates[$oid], $this->originalEntityData[$oid]);
|
||||
@ -1889,7 +1900,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
if ($assoc['isOwningSide']) {
|
||||
$associatedId = array();
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
|
||||
$joinColumnValue = $data[$srcColumn];
|
||||
$joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
|
||||
if ($joinColumnValue !== null) {
|
||||
$associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue;
|
||||
}
|
||||
@ -1937,14 +1948,12 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
} else {
|
||||
// Inject collection
|
||||
$reflField = $class->reflFields[$field];
|
||||
$pColl = new PersistentCollection(
|
||||
$this->em, $targetClass,
|
||||
//TODO: getValue might be superfluous once DDC-79 is implemented.
|
||||
$reflField->getValue($entity) ?: new ArrayCollection
|
||||
);
|
||||
$pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection);
|
||||
$pColl->setOwner($entity, $assoc);
|
||||
|
||||
$reflField = $class->reflFields[$field];
|
||||
$reflField->setValue($entity, $pColl);
|
||||
|
||||
if ($assoc['fetch'] == ClassMetadata::FETCH_LAZY) {
|
||||
$pColl->setInitialized(false);
|
||||
} else {
|
||||
|
@ -36,7 +36,7 @@ class Version
|
||||
/**
|
||||
* Current Doctrine Version
|
||||
*/
|
||||
const VERSION = '2.0.0BETA4-DEV';
|
||||
const VERSION = '2.1.0-DEV';
|
||||
|
||||
/**
|
||||
* Compares a Doctrine version with the current one.
|
||||
@ -52,4 +52,4 @@ class Version
|
||||
|
||||
return version_compare($version, $currentVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1411
lib/vendor/Symfony/Component/Console/Application.php
vendored
1411
lib/vendor/Symfony/Component/Console/Application.php
vendored
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -21,510 +21,492 @@ use Symfony\Component\Console\Application;
|
||||
/**
|
||||
* Base class for all commands.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class Command
|
||||
{
|
||||
protected $name;
|
||||
protected $namespace;
|
||||
protected $aliases;
|
||||
protected $definition;
|
||||
protected $help;
|
||||
protected $application;
|
||||
protected $description;
|
||||
protected $ignoreValidationErrors;
|
||||
protected $formatter;
|
||||
protected $applicationDefinitionMerged;
|
||||
protected $code;
|
||||
protected $name;
|
||||
protected $namespace;
|
||||
protected $aliases;
|
||||
protected $definition;
|
||||
protected $help;
|
||||
protected $application;
|
||||
protected $description;
|
||||
protected $ignoreValidationErrors;
|
||||
protected $applicationDefinitionMerged;
|
||||
protected $code;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The name of the command
|
||||
*/
|
||||
public function __construct($name = null)
|
||||
{
|
||||
$this->definition = new InputDefinition();
|
||||
$this->ignoreValidationErrors = false;
|
||||
$this->applicationDefinitionMerged = false;
|
||||
$this->aliases = array();
|
||||
|
||||
if (null !== $name)
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The name of the command
|
||||
*
|
||||
* @throws \LogicException When the command name is empty
|
||||
*/
|
||||
public function __construct($name = null)
|
||||
{
|
||||
$this->setName($name);
|
||||
$this->definition = new InputDefinition();
|
||||
$this->ignoreValidationErrors = false;
|
||||
$this->applicationDefinitionMerged = false;
|
||||
$this->aliases = array();
|
||||
|
||||
if (null !== $name) {
|
||||
$this->setName($name);
|
||||
}
|
||||
|
||||
$this->configure();
|
||||
|
||||
if (!$this->name) {
|
||||
throw new \LogicException('The command name cannot be empty.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->configure();
|
||||
|
||||
if (!$this->name)
|
||||
/**
|
||||
* Sets the application instance for this command.
|
||||
*
|
||||
* @param Application $application An Application instance
|
||||
*/
|
||||
public function setApplication(Application $application = null)
|
||||
{
|
||||
throw new \LogicException('The command name cannot be empty.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the application instance for this command.
|
||||
*
|
||||
* @param Application $application An Application instance
|
||||
*/
|
||||
public function setApplication(Application $application = null)
|
||||
{
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the current command.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return integer 0 if everything went fine, or an error code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
throw new \LogicException('You must override the execute() method in the concrete command class.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Interacts with the user.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
protected function interact(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the command just after the input has been validated.
|
||||
*
|
||||
* This is mainly useful when a lot of commands extends one main command
|
||||
* where some things need to be initialized based on the input arguments and options.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
protected function initialize(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
public function run(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// add the application arguments and options
|
||||
$this->mergeApplicationDefinition();
|
||||
|
||||
// bind the input against the command specific arguments/options
|
||||
try
|
||||
{
|
||||
$input->bind($this->definition);
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
if (!$this->ignoreValidationErrors)
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
$this->initialize($input, $output);
|
||||
|
||||
if ($input->isInteractive())
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->interact($input, $output);
|
||||
}
|
||||
|
||||
$input->validate();
|
||||
|
||||
if ($this->code)
|
||||
/**
|
||||
* Executes the current command.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return integer 0 if everything went fine, or an error code
|
||||
*
|
||||
* @throws \LogicException When this abstract class is not implemented
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
return call_user_func($this->code, $input, $output);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->execute($input, $output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the code to execute when running this command.
|
||||
*
|
||||
* @param \Closure $code A \Closure
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setCode(\Closure $code)
|
||||
{
|
||||
$this->code = $code;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the application definition with the command definition.
|
||||
*/
|
||||
protected function mergeApplicationDefinition()
|
||||
{
|
||||
if (null === $this->application || true === $this->applicationDefinitionMerged)
|
||||
{
|
||||
return;
|
||||
throw new \LogicException('You must override the execute() method in the concrete command class.');
|
||||
}
|
||||
|
||||
$this->definition->setArguments(array_merge(
|
||||
$this->application->getDefinition()->getArguments(),
|
||||
$this->definition->getArguments()
|
||||
));
|
||||
|
||||
$this->definition->addOptions($this->application->getDefinition()->getOptions());
|
||||
|
||||
$this->applicationDefinitionMerged = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an array of argument and option instances.
|
||||
*
|
||||
* @param array|Definition $definition An array of argument and option instances or a definition instance
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setDefinition($definition)
|
||||
{
|
||||
if ($definition instanceof InputDefinition)
|
||||
/**
|
||||
* Interacts with the user.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
protected function interact(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->definition = $definition;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->definition->setDefinition($definition);
|
||||
}
|
||||
|
||||
$this->applicationDefinitionMerged = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the InputDefinition attached to this Command.
|
||||
*
|
||||
* @return InputDefinition $definition An InputDefinition instance
|
||||
*/
|
||||
public function getDefinition()
|
||||
{
|
||||
return $this->definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an argument.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param integer $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (for InputArgument::OPTIONAL mode only)
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function addArgument($name, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
$this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an option.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string $shortcut The shortcut (can be null)
|
||||
* @param integer $mode The option mode: self::PARAMETER_REQUIRED, self::PARAMETER_NONE or self::PARAMETER_OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (must be null for self::PARAMETER_REQUIRED or self::PARAMETER_NONE)
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
$this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the command.
|
||||
*
|
||||
* This method can set both the namespace and the name if
|
||||
* you separate them by a colon (:)
|
||||
*
|
||||
* $command->setName('foo:bar');
|
||||
*
|
||||
* @param string $name The command name
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
if (false !== $pos = strrpos($name, ':'))
|
||||
/**
|
||||
* Initializes the command just after the input has been validated.
|
||||
*
|
||||
* This is mainly useful when a lot of commands extends one main command
|
||||
* where some things need to be initialized based on the input arguments and options.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
protected function initialize(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$namespace = substr($name, 0, $pos);
|
||||
$name = substr($name, $pos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$namespace = $this->namespace;
|
||||
}
|
||||
|
||||
if (!$name)
|
||||
/**
|
||||
* Runs the command.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
public function run(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
throw new \InvalidArgumentException('A command name cannot be empty');
|
||||
// add the application arguments and options
|
||||
$this->mergeApplicationDefinition();
|
||||
|
||||
// bind the input against the command specific arguments/options
|
||||
try {
|
||||
$input->bind($this->definition);
|
||||
} catch (\Exception $e) {
|
||||
if (!$this->ignoreValidationErrors) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$this->initialize($input, $output);
|
||||
|
||||
if ($input->isInteractive()) {
|
||||
$this->interact($input, $output);
|
||||
}
|
||||
|
||||
$input->validate();
|
||||
|
||||
if ($this->code) {
|
||||
return call_user_func($this->code, $input, $output);
|
||||
} else {
|
||||
return $this->execute($input, $output);
|
||||
}
|
||||
}
|
||||
|
||||
$this->namespace = $namespace;
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command namespace.
|
||||
*
|
||||
* @return string The command namespace
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command name
|
||||
*
|
||||
* @return string The command name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fully qualified command name.
|
||||
*
|
||||
* @return string The fully qualified command name
|
||||
*/
|
||||
public function getFullName()
|
||||
{
|
||||
return $this->getNamespace() ? $this->getNamespace().':'.$this->getName() : $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description for the command.
|
||||
*
|
||||
* @param string $description The description for the command
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setDescription($description)
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description for the command.
|
||||
*
|
||||
* @return string The description for the command
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the help for the command.
|
||||
*
|
||||
* @param string $help The help for the command
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setHelp($help)
|
||||
{
|
||||
$this->help = $help;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the help for the command.
|
||||
*
|
||||
* @return string The help for the command
|
||||
*/
|
||||
public function getHelp()
|
||||
{
|
||||
return $this->help;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the processed help for the command replacing the %command.name% and
|
||||
* %command.full_name% patterns with the real values dynamically.
|
||||
*
|
||||
* @return string The processed help for the command
|
||||
*/
|
||||
public function getProcessedHelp()
|
||||
{
|
||||
$name = $this->namespace.':'.$this->name;
|
||||
|
||||
$placeholders = array(
|
||||
'%command.name%',
|
||||
'%command.full_name%'
|
||||
);
|
||||
$replacements = array(
|
||||
$name,
|
||||
$_SERVER['PHP_SELF'].' '.$name
|
||||
);
|
||||
|
||||
return str_replace($placeholders, $replacements, $this->getHelp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases for the command.
|
||||
*
|
||||
* @param array $aliases An array of aliases for the command
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setAliases($aliases)
|
||||
{
|
||||
$this->aliases = $aliases;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aliases for the command.
|
||||
*
|
||||
* @return array An array of aliases for the command
|
||||
*/
|
||||
public function getAliases()
|
||||
{
|
||||
return $this->aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the synopsis for the command.
|
||||
*
|
||||
* @return string The synopsis
|
||||
*/
|
||||
public function getSynopsis()
|
||||
{
|
||||
return sprintf('%s %s', $this->getFullName(), $this->definition->getSynopsis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a helper instance by name.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return mixed The helper value
|
||||
*
|
||||
* @throws \InvalidArgumentException if the helper is not defined
|
||||
*/
|
||||
protected function getHelper($name)
|
||||
{
|
||||
return $this->application->getHelperSet()->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a helper instance by name.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return mixed The helper value
|
||||
*
|
||||
* @throws \InvalidArgumentException if the helper is not defined
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->application->getHelperSet()->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a text representation of the command.
|
||||
*
|
||||
* @return string A string representing the command
|
||||
*/
|
||||
public function asText()
|
||||
{
|
||||
$messages = array(
|
||||
'<comment>Usage:</comment>',
|
||||
' '.$this->getSynopsis(),
|
||||
'',
|
||||
);
|
||||
|
||||
if ($this->getAliases())
|
||||
/**
|
||||
* Sets the code to execute when running this command.
|
||||
*
|
||||
* @param \Closure $code A \Closure
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setCode(\Closure $code)
|
||||
{
|
||||
$messages[] = '<comment>Aliases:</comment> <info>'.implode(', ', $this->getAliases()).'</info>';
|
||||
$this->code = $code;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$messages[] = $this->definition->asText();
|
||||
|
||||
if ($help = $this->getProcessedHelp())
|
||||
/**
|
||||
* Merges the application definition with the command definition.
|
||||
*/
|
||||
protected function mergeApplicationDefinition()
|
||||
{
|
||||
$messages[] = '<comment>Help:</comment>';
|
||||
$messages[] = ' '.implode("\n ", explode("\n", $help))."\n";
|
||||
if (null === $this->application || true === $this->applicationDefinitionMerged) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->definition->setArguments(array_merge(
|
||||
$this->application->getDefinition()->getArguments(),
|
||||
$this->definition->getArguments()
|
||||
));
|
||||
|
||||
$this->definition->addOptions($this->application->getDefinition()->getOptions());
|
||||
|
||||
$this->applicationDefinitionMerged = true;
|
||||
}
|
||||
|
||||
return implode("\n", $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML representation of the command.
|
||||
*
|
||||
* @param Boolean $asDom Whether to return a DOM or an XML string
|
||||
*
|
||||
* @return string|DOMDocument An XML string representing the command
|
||||
*/
|
||||
public function asXml($asDom = false)
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->formatOutput = true;
|
||||
$dom->appendChild($commandXML = $dom->createElement('command'));
|
||||
$commandXML->setAttribute('id', $this->getFullName());
|
||||
$commandXML->setAttribute('namespace', $this->getNamespace() ? $this->getNamespace() : '_global');
|
||||
$commandXML->setAttribute('name', $this->getName());
|
||||
|
||||
$commandXML->appendChild($usageXML = $dom->createElement('usage'));
|
||||
$usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
|
||||
|
||||
$commandXML->appendChild($descriptionXML = $dom->createElement('description'));
|
||||
$descriptionXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $this->getDescription()))));
|
||||
|
||||
$commandXML->appendChild($helpXML = $dom->createElement('help'));
|
||||
$help = $this->help;
|
||||
$helpXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $help))));
|
||||
|
||||
$commandXML->appendChild($aliasesXML = $dom->createElement('aliases'));
|
||||
foreach ($this->getAliases() as $alias)
|
||||
/**
|
||||
* Sets an array of argument and option instances.
|
||||
*
|
||||
* @param array|Definition $definition An array of argument and option instances or a definition instance
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setDefinition($definition)
|
||||
{
|
||||
$aliasesXML->appendChild($aliasXML = $dom->createElement('alias'));
|
||||
$aliasXML->appendChild($dom->createTextNode($alias));
|
||||
if ($definition instanceof InputDefinition) {
|
||||
$this->definition = $definition;
|
||||
} else {
|
||||
$this->definition->setDefinition($definition);
|
||||
}
|
||||
|
||||
$this->applicationDefinitionMerged = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$definition = $this->definition->asXml(true);
|
||||
$commandXML->appendChild($dom->importNode($definition->getElementsByTagName('arguments')->item(0), true));
|
||||
$commandXML->appendChild($dom->importNode($definition->getElementsByTagName('options')->item(0), true));
|
||||
/**
|
||||
* Gets the InputDefinition attached to this Command.
|
||||
*
|
||||
* @return InputDefinition An InputDefinition instance
|
||||
*/
|
||||
public function getDefinition()
|
||||
{
|
||||
return $this->definition;
|
||||
}
|
||||
|
||||
return $asDom ? $dom : $dom->saveXml();
|
||||
}
|
||||
/**
|
||||
* Adds an argument.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param integer $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (for InputArgument::OPTIONAL mode only)
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function addArgument($name, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
$this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an option.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string $shortcut The shortcut (can be null)
|
||||
* @param integer $mode The option mode: One of the InputOption::VALUE_* constants
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (must be null for InputOption::VALUE_REQUIRED or self::VALUE_NONE)
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
$this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the command.
|
||||
*
|
||||
* This method can set both the namespace and the name if
|
||||
* you separate them by a colon (:)
|
||||
*
|
||||
* $command->setName('foo:bar');
|
||||
*
|
||||
* @param string $name The command name
|
||||
*
|
||||
* @return Command The current instance
|
||||
*
|
||||
* @throws \InvalidArgumentException When command name given is empty
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
if (false !== $pos = strrpos($name, ':')) {
|
||||
$namespace = substr($name, 0, $pos);
|
||||
$name = substr($name, $pos + 1);
|
||||
} else {
|
||||
$namespace = $this->namespace;
|
||||
}
|
||||
|
||||
if (!$name) {
|
||||
throw new \InvalidArgumentException('A command name cannot be empty.');
|
||||
}
|
||||
|
||||
$this->namespace = $namespace;
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command namespace.
|
||||
*
|
||||
* @return string The command namespace
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command name
|
||||
*
|
||||
* @return string The command name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fully qualified command name.
|
||||
*
|
||||
* @return string The fully qualified command name
|
||||
*/
|
||||
public function getFullName()
|
||||
{
|
||||
return $this->getNamespace() ? $this->getNamespace().':'.$this->getName() : $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description for the command.
|
||||
*
|
||||
* @param string $description The description for the command
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setDescription($description)
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description for the command.
|
||||
*
|
||||
* @return string The description for the command
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the help for the command.
|
||||
*
|
||||
* @param string $help The help for the command
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setHelp($help)
|
||||
{
|
||||
$this->help = $help;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the help for the command.
|
||||
*
|
||||
* @return string The help for the command
|
||||
*/
|
||||
public function getHelp()
|
||||
{
|
||||
return $this->help;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the processed help for the command replacing the %command.name% and
|
||||
* %command.full_name% patterns with the real values dynamically.
|
||||
*
|
||||
* @return string The processed help for the command
|
||||
*/
|
||||
public function getProcessedHelp()
|
||||
{
|
||||
$name = $this->namespace.':'.$this->name;
|
||||
|
||||
$placeholders = array(
|
||||
'%command.name%',
|
||||
'%command.full_name%'
|
||||
);
|
||||
$replacements = array(
|
||||
$name,
|
||||
$_SERVER['PHP_SELF'].' '.$name
|
||||
);
|
||||
|
||||
return str_replace($placeholders, $replacements, $this->getHelp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases for the command.
|
||||
*
|
||||
* @param array $aliases An array of aliases for the command
|
||||
*
|
||||
* @return Command The current instance
|
||||
*/
|
||||
public function setAliases($aliases)
|
||||
{
|
||||
$this->aliases = $aliases;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aliases for the command.
|
||||
*
|
||||
* @return array An array of aliases for the command
|
||||
*/
|
||||
public function getAliases()
|
||||
{
|
||||
return $this->aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the synopsis for the command.
|
||||
*
|
||||
* @return string The synopsis
|
||||
*/
|
||||
public function getSynopsis()
|
||||
{
|
||||
return sprintf('%s %s', $this->getFullName(), $this->definition->getSynopsis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a helper instance by name.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return mixed The helper value
|
||||
*
|
||||
* @throws \InvalidArgumentException if the helper is not defined
|
||||
*/
|
||||
protected function getHelper($name)
|
||||
{
|
||||
return $this->application->getHelperSet()->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a helper instance by name.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return mixed The helper value
|
||||
*
|
||||
* @throws \InvalidArgumentException if the helper is not defined
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->application->getHelperSet()->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a text representation of the command.
|
||||
*
|
||||
* @return string A string representing the command
|
||||
*/
|
||||
public function asText()
|
||||
{
|
||||
$messages = array(
|
||||
'<comment>Usage:</comment>',
|
||||
' '.$this->getSynopsis(),
|
||||
'',
|
||||
);
|
||||
|
||||
if ($this->getAliases()) {
|
||||
$messages[] = '<comment>Aliases:</comment> <info>'.implode(', ', $this->getAliases()).'</info>';
|
||||
}
|
||||
|
||||
$messages[] = $this->definition->asText();
|
||||
|
||||
if ($help = $this->getProcessedHelp()) {
|
||||
$messages[] = '<comment>Help:</comment>';
|
||||
$messages[] = ' '.implode("\n ", explode("\n", $help))."\n";
|
||||
}
|
||||
|
||||
return implode("\n", $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML representation of the command.
|
||||
*
|
||||
* @param Boolean $asDom Whether to return a DOM or an XML string
|
||||
*
|
||||
* @return string|DOMDocument An XML string representing the command
|
||||
*/
|
||||
public function asXml($asDom = false)
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->formatOutput = true;
|
||||
$dom->appendChild($commandXML = $dom->createElement('command'));
|
||||
$commandXML->setAttribute('id', $this->getFullName());
|
||||
$commandXML->setAttribute('namespace', $this->getNamespace() ? $this->getNamespace() : '_global');
|
||||
$commandXML->setAttribute('name', $this->getName());
|
||||
|
||||
$commandXML->appendChild($usageXML = $dom->createElement('usage'));
|
||||
$usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
|
||||
|
||||
$commandXML->appendChild($descriptionXML = $dom->createElement('description'));
|
||||
$descriptionXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $this->getDescription()))));
|
||||
|
||||
$commandXML->appendChild($helpXML = $dom->createElement('help'));
|
||||
$help = $this->help;
|
||||
$helpXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $help))));
|
||||
|
||||
$commandXML->appendChild($aliasesXML = $dom->createElement('aliases'));
|
||||
foreach ($this->getAliases() as $alias) {
|
||||
$aliasesXML->appendChild($aliasXML = $dom->createElement('alias'));
|
||||
$aliasXML->appendChild($dom->createTextNode($alias));
|
||||
}
|
||||
|
||||
$definition = $this->definition->asXml(true);
|
||||
$commandXML->appendChild($dom->importNode($definition->getElementsByTagName('arguments')->item(0), true));
|
||||
$commandXML->appendChild($dom->importNode($definition->getElementsByTagName('options')->item(0), true));
|
||||
|
||||
return $asDom ? $dom : $dom->saveXml();
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use Symfony\Component\Console\Output\Output;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -21,63 +21,57 @@ use Symfony\Component\Console\Command\Command;
|
||||
/**
|
||||
* HelpCommand displays the help for a given command.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class HelpCommand extends Command
|
||||
{
|
||||
protected $command;
|
||||
protected $command;
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->ignoreValidationErrors = true;
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->ignoreValidationErrors = true;
|
||||
|
||||
$this
|
||||
->setDefinition(array(
|
||||
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
|
||||
new InputOption('xml', null, InputOption::PARAMETER_NONE, 'To output help as XML'),
|
||||
))
|
||||
->setName('help')
|
||||
->setAliases(array('?'))
|
||||
->setDescription('Displays help for a command')
|
||||
->setHelp(<<<EOF
|
||||
$this
|
||||
->setDefinition(array(
|
||||
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
|
||||
new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
|
||||
))
|
||||
->setName('help')
|
||||
->setAliases(array('?'))
|
||||
->setDescription('Displays help for a command')
|
||||
->setHelp(<<<EOF
|
||||
The <info>help</info> command displays help for a given command:
|
||||
|
||||
<info>./symfony help test:all</info>
|
||||
<info>./symfony help list</info>
|
||||
|
||||
You can also output the help as XML by using the <comment>--xml</comment> option:
|
||||
|
||||
<info>./symfony help --xml test:all</info>
|
||||
<info>./symfony help --xml list</info>
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
public function setCommand(Command $command)
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if (null === $this->command)
|
||||
{
|
||||
$this->command = $this->application->getCommand($input->getArgument('command_name'));
|
||||
);
|
||||
}
|
||||
|
||||
if ($input->getOption('xml'))
|
||||
public function setCommand(Command $command)
|
||||
{
|
||||
$output->writeln($this->command->asXml(), Output::OUTPUT_RAW);
|
||||
$this->command = $command;
|
||||
}
|
||||
else
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln($this->command->asText());
|
||||
if (null === $this->command) {
|
||||
$this->command = $this->application->get($input->getArgument('command_name'));
|
||||
}
|
||||
|
||||
if ($input->getOption('xml')) {
|
||||
$output->writeln($this->command->asXml(), Output::OUTPUT_RAW);
|
||||
} else {
|
||||
$output->writeln($this->command->asText());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use Symfony\Component\Console\Output\Output;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -21,25 +21,23 @@ use Symfony\Component\Console\Command\Command;
|
||||
/**
|
||||
* ListCommand displays the list of all available commands for the application.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class ListCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition(array(
|
||||
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
|
||||
new InputOption('xml', null, InputOption::PARAMETER_NONE, 'To output help as XML'),
|
||||
))
|
||||
->setName('list')
|
||||
->setDescription('Lists commands')
|
||||
->setHelp(<<<EOF
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition(array(
|
||||
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
|
||||
new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
|
||||
))
|
||||
->setName('list')
|
||||
->setDescription('Lists commands')
|
||||
->setHelp(<<<EOF
|
||||
The <info>list</info> command lists all commands:
|
||||
|
||||
<info>./symfony list</info>
|
||||
@ -52,21 +50,18 @@ You can also output the information as XML by using the <comment>--xml</comment>
|
||||
|
||||
<info>./symfony list --xml</info>
|
||||
EOF
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('xml'))
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln($this->application->asXml($input->getArgument('namespace')), Output::OUTPUT_RAW);
|
||||
if ($input->getOption('xml')) {
|
||||
$output->writeln($this->application->asXml($input->getArgument('namespace')), Output::OUTPUT_RAW);
|
||||
} else {
|
||||
$output->writeln($this->application->asText($input->getArgument('namespace')));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$output->writeln($this->application->asText($input->getArgument('namespace')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ namespace Symfony\Component\Console\Helper;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -16,104 +16,95 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
/**
|
||||
* The Dialog class provides helpers to interact with the user.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class DialogHelper extends Helper
|
||||
{
|
||||
/**
|
||||
* Asks a question to the user.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param string|array $question The question to ask
|
||||
* @param string $default The default answer if none is given by the user
|
||||
*
|
||||
* @param string The user answer
|
||||
*/
|
||||
public function ask(OutputInterface $output, $question, $default = null)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
$output->writeln($question);
|
||||
|
||||
$ret = trim(fgets(STDIN));
|
||||
|
||||
return $ret ? $ret : $default;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks a confirmation to the user.
|
||||
*
|
||||
* The question will be asked until the user answer by nothing, yes, or no.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param string|array $question The question to ask
|
||||
* @param Boolean $default The default answer if the user enters nothing
|
||||
*
|
||||
* @param Boolean true if the user has confirmed, false otherwise
|
||||
*/
|
||||
public function askConfirmation(OutputInterface $output, $question, $default = true)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
$answer = 'z';
|
||||
while ($answer && !in_array(strtolower($answer[0]), array('y', 'n')))
|
||||
/**
|
||||
* Asks a question to the user.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param string|array $question The question to ask
|
||||
* @param string $default The default answer if none is given by the user
|
||||
*
|
||||
* @return string The user answer
|
||||
*/
|
||||
public function ask(OutputInterface $output, $question, $default = null)
|
||||
{
|
||||
$answer = $this->ask($output, $question);
|
||||
// @codeCoverageIgnoreStart
|
||||
$output->writeln($question);
|
||||
|
||||
$ret = trim(fgets(STDIN));
|
||||
|
||||
return $ret ? $ret : $default;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if (false === $default)
|
||||
/**
|
||||
* Asks a confirmation to the user.
|
||||
*
|
||||
* The question will be asked until the user answer by nothing, yes, or no.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param string|array $question The question to ask
|
||||
* @param Boolean $default The default answer if the user enters nothing
|
||||
*
|
||||
* @return Boolean true if the user has confirmed, false otherwise
|
||||
*/
|
||||
public function askConfirmation(OutputInterface $output, $question, $default = true)
|
||||
{
|
||||
return $answer && 'y' == strtolower($answer[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return !$answer || 'y' == strtolower($answer[0]);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
// @codeCoverageIgnoreStart
|
||||
$answer = 'z';
|
||||
while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) {
|
||||
$answer = $this->ask($output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks for a value and validates the response.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param string|array $question
|
||||
* @param Closure $validator
|
||||
* @param integer $attempts Max number of times to ask before giving up (false by default, which means infinite)
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function askAndValidate(OutputInterface $output, $question, \Closure $validator, $attempts = false)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
$error = null;
|
||||
while (false === $attempts || $attempts--)
|
||||
{
|
||||
if (null !== $error)
|
||||
{
|
||||
$output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'));
|
||||
}
|
||||
|
||||
$value = $this->ask($output, $question, null);
|
||||
|
||||
try
|
||||
{
|
||||
return $validator($value);
|
||||
}
|
||||
catch (\Exception $error)
|
||||
{
|
||||
}
|
||||
if (false === $default) {
|
||||
return $answer && 'y' == strtolower($answer[0]);
|
||||
} else {
|
||||
return !$answer || 'y' == strtolower($answer[0]);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
throw $error;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
/**
|
||||
* Asks for a value and validates the response.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param string|array $question
|
||||
* @param Closure $validator
|
||||
* @param integer $attempts Max number of times to ask before giving up (false by default, which means infinite)
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception When any of the validator returns an error
|
||||
*/
|
||||
public function askAndValidate(OutputInterface $output, $question, \Closure $validator, $attempts = false)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
$error = null;
|
||||
while (false === $attempts || $attempts--) {
|
||||
if (null !== $error) {
|
||||
$output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the helper's canonical name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'dialog';
|
||||
}
|
||||
$value = $this->ask($output, $question, null);
|
||||
|
||||
try {
|
||||
return $validator($value);
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
}
|
||||
|
||||
throw $error;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the helper's canonical name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'dialog';
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -14,76 +14,69 @@ namespace Symfony\Component\Console\Helper;
|
||||
/**
|
||||
* The Formatter class provides helpers to format messages.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class FormatterHelper extends Helper
|
||||
{
|
||||
/**
|
||||
* Formats a message within a section.
|
||||
*
|
||||
* @param string $section The section name
|
||||
* @param string $message The message
|
||||
* @param string $style The style to apply to the section
|
||||
*/
|
||||
public function formatSection($section, $message, $style = 'info')
|
||||
{
|
||||
return sprintf("<%s>[%s]</%s> %s", $style, $section, $style, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a message as a block of text.
|
||||
*
|
||||
* @param string|array $messages The message to write in the block
|
||||
* @param string $style The style to apply to the whole block
|
||||
* @param Boolean $large Whether to return a large block
|
||||
*
|
||||
* @return string The formatter message
|
||||
*/
|
||||
public function formatBlock($messages, $style, $large = false)
|
||||
{
|
||||
if (!is_array($messages))
|
||||
/**
|
||||
* Formats a message within a section.
|
||||
*
|
||||
* @param string $section The section name
|
||||
* @param string $message The message
|
||||
* @param string $style The style to apply to the section
|
||||
*/
|
||||
public function formatSection($section, $message, $style = 'info')
|
||||
{
|
||||
$messages = array($messages);
|
||||
return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
|
||||
}
|
||||
|
||||
$len = 0;
|
||||
$lines = array();
|
||||
foreach ($messages as $message)
|
||||
/**
|
||||
* Formats a message as a block of text.
|
||||
*
|
||||
* @param string|array $messages The message to write in the block
|
||||
* @param string $style The style to apply to the whole block
|
||||
* @param Boolean $large Whether to return a large block
|
||||
*
|
||||
* @return string The formatter message
|
||||
*/
|
||||
public function formatBlock($messages, $style, $large = false)
|
||||
{
|
||||
$lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
|
||||
$len = max($this->strlen($message) + ($large ? 4 : 2), $len);
|
||||
if (!is_array($messages)) {
|
||||
$messages = array($messages);
|
||||
}
|
||||
|
||||
$len = 0;
|
||||
$lines = array();
|
||||
foreach ($messages as $message) {
|
||||
$lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
|
||||
$len = max($this->strlen($message) + ($large ? 4 : 2), $len);
|
||||
}
|
||||
|
||||
$messages = $large ? array(str_repeat(' ', $len)) : array();
|
||||
foreach ($lines as $line) {
|
||||
$messages[] = $line.str_repeat(' ', $len - $this->strlen($line));
|
||||
}
|
||||
if ($large) {
|
||||
$messages[] = str_repeat(' ', $len);
|
||||
}
|
||||
|
||||
foreach ($messages as &$message) {
|
||||
$message = sprintf('<%s>%s</%s>', $style, $message, $style);
|
||||
}
|
||||
|
||||
return implode("\n", $messages);
|
||||
}
|
||||
|
||||
$messages = $large ? array(str_repeat(' ', $len)) : array();
|
||||
foreach ($lines as $line)
|
||||
protected function strlen($string)
|
||||
{
|
||||
$messages[] = $line.str_repeat(' ', $len - $this->strlen($line));
|
||||
}
|
||||
if ($large)
|
||||
{
|
||||
$messages[] = str_repeat(' ', $len);
|
||||
return function_exists('mb_strlen') ? mb_strlen($string) : strlen($string);
|
||||
}
|
||||
|
||||
foreach ($messages as &$message)
|
||||
/**
|
||||
* Returns the helper's canonical name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
$message = sprintf('<%s>%s</%s>', $style, $message, $style);
|
||||
return 'formatter';
|
||||
}
|
||||
|
||||
return implode("\n", $messages);
|
||||
}
|
||||
|
||||
protected function strlen($string)
|
||||
{
|
||||
return function_exists('mb_strlen') ? mb_strlen($string) : strlen($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the helper's canonical name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'formatter';
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -14,32 +14,29 @@ namespace Symfony\Component\Console\Helper;
|
||||
/**
|
||||
* Helper is the base class for all helper classes.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
abstract class Helper implements HelperInterface
|
||||
{
|
||||
protected
|
||||
$helperSet = null;
|
||||
protected $helperSet = null;
|
||||
|
||||
/**
|
||||
* Sets the helper set associated with this helper.
|
||||
*
|
||||
* @param HelperSet $helperSet A HelperSet instance
|
||||
*/
|
||||
public function setHelperSet(HelperSet $helperSet = null)
|
||||
{
|
||||
$this->helperSet = $helperSet;
|
||||
}
|
||||
/**
|
||||
* Sets the helper set associated with this helper.
|
||||
*
|
||||
* @param HelperSet $helperSet A HelperSet instance
|
||||
*/
|
||||
public function setHelperSet(HelperSet $helperSet = null)
|
||||
{
|
||||
$this->helperSet = $helperSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the helper set associated with this helper.
|
||||
*
|
||||
* @return HelperSet A HelperSet instance
|
||||
*/
|
||||
public function getHelperSet()
|
||||
{
|
||||
return $this->helperSet;
|
||||
}
|
||||
/**
|
||||
* Gets the helper set associated with this helper.
|
||||
*
|
||||
* @return HelperSet A HelperSet instance
|
||||
*/
|
||||
public function getHelperSet()
|
||||
{
|
||||
return $this->helperSet;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -14,30 +14,28 @@ namespace Symfony\Component\Console\Helper;
|
||||
/**
|
||||
* HelperInterface is the interface all helpers must implement.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
interface HelperInterface
|
||||
{
|
||||
/**
|
||||
* Sets the helper set associated with this helper.
|
||||
*
|
||||
* @param HelperSet $helperSet A HelperSet instance
|
||||
*/
|
||||
function setHelperSet(HelperSet $helperSet = null);
|
||||
/**
|
||||
* Sets the helper set associated with this helper.
|
||||
*
|
||||
* @param HelperSet $helperSet A HelperSet instance
|
||||
*/
|
||||
function setHelperSet(HelperSet $helperSet = null);
|
||||
|
||||
/**
|
||||
* Gets the helper set associated with this helper.
|
||||
*
|
||||
* @return HelperSet A HelperSet instance
|
||||
*/
|
||||
function getHelperSet();
|
||||
/**
|
||||
* Gets the helper set associated with this helper.
|
||||
*
|
||||
* @return HelperSet A HelperSet instance
|
||||
*/
|
||||
function getHelperSet();
|
||||
|
||||
/**
|
||||
* Returns the canonical name of this helper.
|
||||
*
|
||||
* @return string The canonical name
|
||||
*/
|
||||
function getName();
|
||||
/**
|
||||
* Returns the canonical name of this helper.
|
||||
*
|
||||
* @return string The canonical name
|
||||
*/
|
||||
function getName();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ namespace Symfony\Component\Console\Helper;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -16,89 +16,87 @@ use Symfony\Component\Console\Command\Command;
|
||||
/**
|
||||
* HelperSet represents a set of helpers to be used with a command.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class HelperSet
|
||||
{
|
||||
protected
|
||||
$helpers = array(),
|
||||
$command = null;
|
||||
protected $helpers;
|
||||
protected $command;
|
||||
|
||||
public function __construct(array $helpers = array())
|
||||
{
|
||||
foreach ($helpers as $alias => $helper)
|
||||
/**
|
||||
* @param Helper[] $helpers An array of helper.
|
||||
*/
|
||||
public function __construct(array $helpers = array())
|
||||
{
|
||||
$this->set($helper, is_int($alias) ? null : $alias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a helper.
|
||||
*
|
||||
* @param HelperInterface $value The helper instance
|
||||
* @param string $alias An alias
|
||||
*/
|
||||
public function set(HelperInterface $helper, $alias = null)
|
||||
{
|
||||
$this->helpers[$helper->getName()] = $helper;
|
||||
if (null !== $alias)
|
||||
{
|
||||
$this->helpers[$alias] = $helper;
|
||||
$this->helpers = array();
|
||||
foreach ($helpers as $alias => $helper) {
|
||||
$this->set($helper, is_int($alias) ? null : $alias);
|
||||
}
|
||||
}
|
||||
|
||||
$helper->setHelperSet($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the helper if defined.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return Boolean true if the helper is defined, false otherwise
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return isset($this->helpers[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a helper value.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return HelperInterface The helper instance
|
||||
*
|
||||
* @throws \InvalidArgumentException if the helper is not defined
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!$this->has($name))
|
||||
/**
|
||||
* Sets a helper.
|
||||
*
|
||||
* @param HelperInterface $value The helper instance
|
||||
* @param string $alias An alias
|
||||
*/
|
||||
public function set(HelperInterface $helper, $alias = null)
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
|
||||
$this->helpers[$helper->getName()] = $helper;
|
||||
if (null !== $alias) {
|
||||
$this->helpers[$alias] = $helper;
|
||||
}
|
||||
|
||||
$helper->setHelperSet($this);
|
||||
}
|
||||
|
||||
return $this->helpers[$name];
|
||||
}
|
||||
/**
|
||||
* Returns true if the helper if defined.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return Boolean true if the helper is defined, false otherwise
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return isset($this->helpers[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command associated with this helper set.
|
||||
*
|
||||
* @param Command $command A Command instance
|
||||
*/
|
||||
public function setCommand(Command $command = null)
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
||||
/**
|
||||
* Gets a helper value.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return HelperInterface The helper instance
|
||||
*
|
||||
* @throws \InvalidArgumentException if the helper is not defined
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!$this->has($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command associated with this helper set.
|
||||
*
|
||||
* @return Command A Command instance
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
return $this->helpers[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command associated with this helper set.
|
||||
*
|
||||
* @param Command $command A Command instance
|
||||
*/
|
||||
public function setCommand(Command $command = null)
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command associated with this helper set.
|
||||
*
|
||||
* @return Command A Command instance
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Input;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -20,7 +20,7 @@ namespace Symfony\Component\Console\Input;
|
||||
*
|
||||
* By default, the `$_SERVER['argv']` array is used for the input values.
|
||||
*
|
||||
* This can be overriden by explicitly passing the input values in the constructor:
|
||||
* This can be overridden by explicitly passing the input values in the constructor:
|
||||
*
|
||||
* $input = new ArgvInput($_SERVER['argv']);
|
||||
*
|
||||
@ -31,254 +31,225 @@ namespace Symfony\Component\Console\Input;
|
||||
* the same rules as the argv one. It's almost always better to use the
|
||||
* `StringInput` when you want to provide your own input.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
|
||||
* @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
|
||||
*/
|
||||
class ArgvInput extends Input
|
||||
{
|
||||
protected $tokens;
|
||||
protected $parsed;
|
||||
protected $tokens;
|
||||
protected $parsed;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $argv An array of parameters from the CLI (in the argv format)
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function __construct(array $argv = null, InputDefinition $definition = null)
|
||||
{
|
||||
if (null === $argv)
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $argv An array of parameters from the CLI (in the argv format)
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function __construct(array $argv = null, InputDefinition $definition = null)
|
||||
{
|
||||
$argv = $_SERVER['argv'];
|
||||
if (null === $argv) {
|
||||
$argv = $_SERVER['argv'];
|
||||
}
|
||||
|
||||
// strip the program name
|
||||
array_shift($argv);
|
||||
|
||||
$this->tokens = $argv;
|
||||
|
||||
parent::__construct($definition);
|
||||
}
|
||||
|
||||
// strip the program name
|
||||
array_shift($argv);
|
||||
|
||||
$this->tokens = $argv;
|
||||
|
||||
parent::__construct($definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes command line arguments.
|
||||
*/
|
||||
protected function parse()
|
||||
{
|
||||
$this->parsed = $this->tokens;
|
||||
while (null !== ($token = array_shift($this->parsed)))
|
||||
/**
|
||||
* Processes command line arguments.
|
||||
*/
|
||||
protected function parse()
|
||||
{
|
||||
if ('--' === substr($token, 0, 2))
|
||||
{
|
||||
$this->parseLongOption($token);
|
||||
}
|
||||
elseif ('-' === $token[0])
|
||||
{
|
||||
$this->parseShortOption($token);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->parseArgument($token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a short option.
|
||||
*
|
||||
* @param string $token The current token.
|
||||
*/
|
||||
protected function parseShortOption($token)
|
||||
{
|
||||
$name = substr($token, 1);
|
||||
|
||||
if (strlen($name) > 1)
|
||||
{
|
||||
if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptParameter())
|
||||
{
|
||||
// an option with a value (with no space)
|
||||
$this->addShortOption($name[0], substr($name, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->parseShortOptionSet($name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->addShortOption($name, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a short option set.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*/
|
||||
protected function parseShortOptionSet($name)
|
||||
{
|
||||
$len = strlen($name);
|
||||
for ($i = 0; $i < $len; $i++)
|
||||
{
|
||||
if (!$this->definition->hasShortcut($name[$i]))
|
||||
{
|
||||
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
|
||||
}
|
||||
|
||||
$option = $this->definition->getOptionForShortcut($name[$i]);
|
||||
if ($option->acceptParameter())
|
||||
{
|
||||
$this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->addLongOption($option->getName(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a long option.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*/
|
||||
protected function parseLongOption($token)
|
||||
{
|
||||
$name = substr($token, 2);
|
||||
|
||||
if (false !== $pos = strpos($name, '='))
|
||||
{
|
||||
$this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->addLongOption($name, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an argument.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*/
|
||||
protected function parseArgument($token)
|
||||
{
|
||||
if (!$this->definition->hasArgument(count($this->arguments)))
|
||||
{
|
||||
throw new \RuntimeException('Too many arguments.');
|
||||
$this->parsed = $this->tokens;
|
||||
while (null !== $token = array_shift($this->parsed)) {
|
||||
if ('--' === substr($token, 0, 2)) {
|
||||
$this->parseLongOption($token);
|
||||
} elseif ('-' === $token[0]) {
|
||||
$this->parseShortOption($token);
|
||||
} else {
|
||||
$this->parseArgument($token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->arguments[$this->definition->getArgument(count($this->arguments))->getName()] = $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a short option value.
|
||||
*
|
||||
* @param string $shortcut The short option key
|
||||
* @param mixed $value The value for the option
|
||||
*/
|
||||
protected function addShortOption($shortcut, $value)
|
||||
{
|
||||
if (!$this->definition->hasShortcut($shortcut))
|
||||
/**
|
||||
* Parses a short option.
|
||||
*
|
||||
* @param string $token The current token.
|
||||
*/
|
||||
protected function parseShortOption($token)
|
||||
{
|
||||
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
$name = substr($token, 1);
|
||||
|
||||
if (strlen($name) > 1) {
|
||||
if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
|
||||
// an option with a value (with no space)
|
||||
$this->addShortOption($name[0], substr($name, 1));
|
||||
} else {
|
||||
$this->parseShortOptionSet($name);
|
||||
}
|
||||
} else {
|
||||
$this->addShortOption($name, null);
|
||||
}
|
||||
}
|
||||
|
||||
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a long option value.
|
||||
*
|
||||
* @param string $name The long option key
|
||||
* @param mixed $value The value for the option
|
||||
*/
|
||||
protected function addLongOption($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasOption($name))
|
||||
/**
|
||||
* Parses a short option set.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*
|
||||
* @throws \RuntimeException When option given doesn't exist
|
||||
*/
|
||||
protected function parseShortOptionSet($name)
|
||||
{
|
||||
throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
|
||||
$len = strlen($name);
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
if (!$this->definition->hasShortcut($name[$i])) {
|
||||
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
|
||||
}
|
||||
|
||||
$option = $this->definition->getOptionForShortcut($name[$i]);
|
||||
if ($option->acceptValue()) {
|
||||
$this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
|
||||
|
||||
break;
|
||||
} else {
|
||||
$this->addLongOption($option->getName(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$option = $this->definition->getOption($name);
|
||||
|
||||
if (null === $value && $option->acceptParameter())
|
||||
/**
|
||||
* Parses a long option.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*/
|
||||
protected function parseLongOption($token)
|
||||
{
|
||||
// if option accepts an optional or mandatory argument
|
||||
// let's see if there is one provided
|
||||
$next = array_shift($this->parsed);
|
||||
if ('-' !== $next[0])
|
||||
{
|
||||
$value = $next;
|
||||
}
|
||||
else
|
||||
{
|
||||
array_unshift($this->parsed, $next);
|
||||
}
|
||||
$name = substr($token, 2);
|
||||
|
||||
if (false !== $pos = strpos($name, '=')) {
|
||||
$this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
|
||||
} else {
|
||||
$this->addLongOption($name, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $value)
|
||||
/**
|
||||
* Parses an argument.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*
|
||||
* @throws \RuntimeException When too many arguments are given
|
||||
*/
|
||||
protected function parseArgument($token)
|
||||
{
|
||||
if ($option->isParameterRequired())
|
||||
{
|
||||
throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
|
||||
}
|
||||
if (!$this->definition->hasArgument(count($this->arguments))) {
|
||||
throw new \RuntimeException('Too many arguments.');
|
||||
}
|
||||
|
||||
$value = $option->isParameterOptional() ? $option->getDefault() : true;
|
||||
$this->arguments[$this->definition->getArgument(count($this->arguments))->getName()] = $token;
|
||||
}
|
||||
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first argument from the raw parameters (not parsed).
|
||||
*
|
||||
* @return string The value of the first argument or null otherwise
|
||||
*/
|
||||
public function getFirstArgument()
|
||||
{
|
||||
foreach ($this->tokens as $token)
|
||||
/**
|
||||
* Adds a short option value.
|
||||
*
|
||||
* @param string $shortcut The short option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @throws \RuntimeException When option given doesn't exist
|
||||
*/
|
||||
protected function addShortOption($shortcut, $value)
|
||||
{
|
||||
if ($token && '-' === $token[0])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!$this->definition->hasShortcut($shortcut)) {
|
||||
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the raw parameters (not parsed) contains a value.
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before it has been validated. It must be used carefully.
|
||||
*
|
||||
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
|
||||
*
|
||||
* @return Boolean true if the value is contained in the raw parameters
|
||||
*/
|
||||
public function hasParameterOption($values)
|
||||
{
|
||||
if (!is_array($values))
|
||||
{
|
||||
$values = array($values);
|
||||
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
|
||||
}
|
||||
|
||||
foreach ($this->tokens as $v)
|
||||
/**
|
||||
* Adds a long option value.
|
||||
*
|
||||
* @param string $name The long option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @throws \RuntimeException When option given doesn't exist
|
||||
*/
|
||||
protected function addLongOption($name, $value)
|
||||
{
|
||||
if (in_array($v, $values))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
$option = $this->definition->getOption($name);
|
||||
|
||||
if (null === $value && $option->acceptValue()) {
|
||||
// if option accepts an optional or mandatory argument
|
||||
// let's see if there is one provided
|
||||
$next = array_shift($this->parsed);
|
||||
if ('-' !== $next[0]) {
|
||||
$value = $next;
|
||||
} else {
|
||||
array_unshift($this->parsed, $next);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
if ($option->isValueRequired()) {
|
||||
throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
|
||||
}
|
||||
|
||||
$value = $option->isValueOptional() ? $option->getDefault() : true;
|
||||
}
|
||||
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns the first argument from the raw parameters (not parsed).
|
||||
*
|
||||
* @return string The value of the first argument or null otherwise
|
||||
*/
|
||||
public function getFirstArgument()
|
||||
{
|
||||
foreach ($this->tokens as $token) {
|
||||
if ($token && '-' === $token[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the raw parameters (not parsed) contains a value.
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before it has been validated. It must be used carefully.
|
||||
*
|
||||
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
|
||||
*
|
||||
* @return Boolean true if the value is contained in the raw parameters
|
||||
*/
|
||||
public function hasParameterOption($values)
|
||||
{
|
||||
if (!is_array($values)) {
|
||||
$values = array($values);
|
||||
}
|
||||
|
||||
foreach ($this->tokens as $v) {
|
||||
if (in_array($v, $values)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Input;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -18,157 +18,145 @@ namespace Symfony\Component\Console\Input;
|
||||
*
|
||||
* $input = new ArrayInput(array('name' => 'foo', '--bar' => 'foobar'));
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class ArrayInput extends Input
|
||||
{
|
||||
protected $parameters;
|
||||
protected $parameters;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $param An array of parameters
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function __construct(array $parameters, InputDefinition $definition = null)
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
|
||||
parent::__construct($definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first argument from the raw parameters (not parsed).
|
||||
*
|
||||
* @return string The value of the first argument or null otherwise
|
||||
*/
|
||||
public function getFirstArgument()
|
||||
{
|
||||
foreach ($this->parameters as $key => $value)
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $param An array of parameters
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function __construct(array $parameters, InputDefinition $definition = null)
|
||||
{
|
||||
if ($key && '-' === $key[0])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$this->parameters = $parameters;
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the raw parameters (not parsed) contains a value.
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before it has been validated. It must be used carefully.
|
||||
*
|
||||
* @param string|array $value The values to look for in the raw parameters (can be an array)
|
||||
*
|
||||
* @return Boolean true if the value is contained in the raw parameters
|
||||
*/
|
||||
public function hasParameterOption($values)
|
||||
{
|
||||
if (!is_array($values))
|
||||
{
|
||||
$values = array($values);
|
||||
parent::__construct($definition);
|
||||
}
|
||||
|
||||
foreach ($this->parameters as $k => $v)
|
||||
/**
|
||||
* Returns the first argument from the raw parameters (not parsed).
|
||||
*
|
||||
* @return string The value of the first argument or null otherwise
|
||||
*/
|
||||
public function getFirstArgument()
|
||||
{
|
||||
if (!is_int($k))
|
||||
{
|
||||
$v = $k;
|
||||
}
|
||||
foreach ($this->parameters as $key => $value) {
|
||||
if ($key && '-' === $key[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($v, $values))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes command line arguments.
|
||||
*/
|
||||
protected function parse()
|
||||
{
|
||||
foreach ($this->parameters as $key => $value)
|
||||
/**
|
||||
* Returns true if the raw parameters (not parsed) contains a value.
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before it has been validated. It must be used carefully.
|
||||
*
|
||||
* @param string|array $value The values to look for in the raw parameters (can be an array)
|
||||
*
|
||||
* @return Boolean true if the value is contained in the raw parameters
|
||||
*/
|
||||
public function hasParameterOption($values)
|
||||
{
|
||||
if ('--' === substr($key, 0, 2))
|
||||
{
|
||||
$this->addLongOption(substr($key, 2), $value);
|
||||
}
|
||||
elseif ('-' === $key[0])
|
||||
{
|
||||
$this->addShortOption(substr($key, 1), $value);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->addArgument($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!is_array($values)) {
|
||||
$values = array($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a short option value.
|
||||
*
|
||||
* @param string $shortcut The short option key
|
||||
* @param mixed $value The value for the option
|
||||
*/
|
||||
protected function addShortOption($shortcut, $value)
|
||||
{
|
||||
if (!$this->definition->hasShortcut($shortcut))
|
||||
{
|
||||
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
foreach ($this->parameters as $k => $v) {
|
||||
if (!is_int($k)) {
|
||||
$v = $k;
|
||||
}
|
||||
|
||||
if (in_array($v, $values)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a long option value.
|
||||
*
|
||||
* @param string $name The long option key
|
||||
* @param mixed $value The value for the option
|
||||
*/
|
||||
protected function addLongOption($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasOption($name))
|
||||
/**
|
||||
* Processes command line arguments.
|
||||
*/
|
||||
protected function parse()
|
||||
{
|
||||
throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
|
||||
foreach ($this->parameters as $key => $value) {
|
||||
if ('--' === substr($key, 0, 2)) {
|
||||
$this->addLongOption(substr($key, 2), $value);
|
||||
} elseif ('-' === $key[0]) {
|
||||
$this->addShortOption(substr($key, 1), $value);
|
||||
} else {
|
||||
$this->addArgument($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$option = $this->definition->getOption($name);
|
||||
|
||||
if (null === $value)
|
||||
/**
|
||||
* Adds a short option value.
|
||||
*
|
||||
* @param string $shortcut The short option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @throws \RuntimeException When option given doesn't exist
|
||||
*/
|
||||
protected function addShortOption($shortcut, $value)
|
||||
{
|
||||
if ($option->isParameterRequired())
|
||||
{
|
||||
throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
|
||||
}
|
||||
if (!$this->definition->hasShortcut($shortcut)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
}
|
||||
|
||||
$value = $option->isParameterOptional() ? $option->getDefault() : true;
|
||||
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
|
||||
}
|
||||
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an argument value.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param mixed $value The value for the argument
|
||||
*/
|
||||
protected function addArgument($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name))
|
||||
/**
|
||||
* Adds a long option value.
|
||||
*
|
||||
* @param string $name The long option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @throws \InvalidArgumentException When option given doesn't exist
|
||||
* @throws \InvalidArgumentException When a required value is missing
|
||||
*/
|
||||
protected function addLongOption($name, $value)
|
||||
{
|
||||
throw new \RuntimeException(sprintf('The "%s" argument does not exist.', $name));
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
$option = $this->definition->getOption($name);
|
||||
|
||||
if (null === $value) {
|
||||
if ($option->isValueRequired()) {
|
||||
throw new \InvalidArgumentException(sprintf('The "--%s" option requires a value.', $name));
|
||||
}
|
||||
|
||||
$value = $option->isValueOptional() ? $option->getDefault() : true;
|
||||
}
|
||||
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
|
||||
$this->arguments[$name] = $value;
|
||||
}
|
||||
/**
|
||||
* Adds an argument value.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param mixed $value The value for the argument
|
||||
*
|
||||
* @throws \InvalidArgumentException When argument given doesn't exist
|
||||
*/
|
||||
protected function addArgument($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
$this->arguments[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
317
lib/vendor/Symfony/Component/Console/Input/Input.php
vendored
317
lib/vendor/Symfony/Component/Console/Input/Input.php
vendored
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Input;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -20,179 +20,180 @@ namespace Symfony\Component\Console\Input;
|
||||
* * `StringInput`: The input is provided as a string
|
||||
* * `ArrayInput`: The input is provided as an array
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
abstract class Input implements InputInterface
|
||||
{
|
||||
protected $definition;
|
||||
protected $options;
|
||||
protected $arguments;
|
||||
protected $interactive = true;
|
||||
protected $definition;
|
||||
protected $options;
|
||||
protected $arguments;
|
||||
protected $interactive = true;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function __construct(InputDefinition $definition = null)
|
||||
{
|
||||
if (null === $definition)
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function __construct(InputDefinition $definition = null)
|
||||
{
|
||||
$this->definition = new InputDefinition();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->bind($definition);
|
||||
$this->validate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the current Input instance with the given arguments and options.
|
||||
*
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function bind(InputDefinition $definition)
|
||||
{
|
||||
$this->arguments = array();
|
||||
$this->options = array();
|
||||
$this->definition = $definition;
|
||||
|
||||
$this->parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes command line arguments.
|
||||
*/
|
||||
abstract protected function parse();
|
||||
|
||||
public function validate()
|
||||
{
|
||||
if (count($this->arguments) < $this->definition->getArgumentRequiredCount())
|
||||
{
|
||||
throw new \RuntimeException('Not enough arguments.');
|
||||
}
|
||||
}
|
||||
|
||||
public function isInteractive()
|
||||
{
|
||||
return $this->interactive;
|
||||
}
|
||||
|
||||
public function setInteractive($interactive)
|
||||
{
|
||||
$this->interactive = (Boolean) $interactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the argument values.
|
||||
*
|
||||
* @return array An array of argument values
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the argument value for a given argument name.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
*
|
||||
* @return mixed The argument value
|
||||
*/
|
||||
public function getArgument($name)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name))
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
if (null === $definition) {
|
||||
$this->definition = new InputDefinition();
|
||||
} else {
|
||||
$this->bind($definition);
|
||||
$this->validate();
|
||||
}
|
||||
}
|
||||
|
||||
return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an argument value by name.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param string $value The argument value
|
||||
*/
|
||||
public function setArgument($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name))
|
||||
/**
|
||||
* Binds the current Input instance with the given arguments and options.
|
||||
*
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function bind(InputDefinition $definition)
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
$this->arguments = array();
|
||||
$this->options = array();
|
||||
$this->definition = $definition;
|
||||
|
||||
$this->parse();
|
||||
}
|
||||
|
||||
$this->arguments[$name] = $value;
|
||||
}
|
||||
/**
|
||||
* Processes command line arguments.
|
||||
*/
|
||||
abstract protected function parse();
|
||||
|
||||
/**
|
||||
* Returns true if an InputArgument object exists by name or position.
|
||||
*
|
||||
* @param string|integer $name The InputArgument name or position
|
||||
*
|
||||
* @return Boolean true if the InputArgument object exists, false otherwise
|
||||
*/
|
||||
public function hasArgument($name)
|
||||
{
|
||||
return $this->definition->hasArgument($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the options values.
|
||||
*
|
||||
* @return array An array of option values
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return array_merge($this->definition->getOptionDefaults(), $this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the option value for a given option name.
|
||||
*
|
||||
* @param string $name The option name
|
||||
*
|
||||
* @return mixed The option value
|
||||
*/
|
||||
public function getOption($name)
|
||||
{
|
||||
if (!$this->definition->hasOption($name))
|
||||
/**
|
||||
* @throws \RuntimeException When not enough arguments are given
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
|
||||
if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) {
|
||||
throw new \RuntimeException('Not enough arguments.');
|
||||
}
|
||||
}
|
||||
|
||||
return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an option value by name.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string $value The option value
|
||||
*/
|
||||
public function setOption($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasOption($name))
|
||||
public function isInteractive()
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
|
||||
return $this->interactive;
|
||||
}
|
||||
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
public function setInteractive($interactive)
|
||||
{
|
||||
$this->interactive = (Boolean) $interactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputOption object exists by name.
|
||||
*
|
||||
* @param string $name The InputOption name
|
||||
*
|
||||
* @return Boolean true if the InputOption object exists, false otherwise
|
||||
*/
|
||||
public function hasOption($name)
|
||||
{
|
||||
return $this->definition->hasOption($name);
|
||||
}
|
||||
/**
|
||||
* Returns the argument values.
|
||||
*
|
||||
* @return array An array of argument values
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the argument value for a given argument name.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
*
|
||||
* @return mixed The argument value
|
||||
*
|
||||
* @throws \InvalidArgumentException When argument given doesn't exist
|
||||
*/
|
||||
public function getArgument($name)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an argument value by name.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param string $value The argument value
|
||||
*
|
||||
* @throws \InvalidArgumentException When argument given doesn't exist
|
||||
*/
|
||||
public function setArgument($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
$this->arguments[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputArgument object exists by name or position.
|
||||
*
|
||||
* @param string|integer $name The InputArgument name or position
|
||||
*
|
||||
* @return Boolean true if the InputArgument object exists, false otherwise
|
||||
*/
|
||||
public function hasArgument($name)
|
||||
{
|
||||
return $this->definition->hasArgument($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the options values.
|
||||
*
|
||||
* @return array An array of option values
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return array_merge($this->definition->getOptionDefaults(), $this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the option value for a given option name.
|
||||
*
|
||||
* @param string $name The option name
|
||||
*
|
||||
* @return mixed The option value
|
||||
*
|
||||
* @throws \InvalidArgumentException When option given doesn't exist
|
||||
*/
|
||||
public function getOption($name)
|
||||
{
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an option value by name.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string $value The option value
|
||||
*
|
||||
* @throws \InvalidArgumentException When option given doesn't exist
|
||||
*/
|
||||
public function setOption($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputOption object exists by name.
|
||||
*
|
||||
* @param string $name The InputOption name
|
||||
*
|
||||
* @return Boolean true if the InputOption object exists, false otherwise
|
||||
*/
|
||||
public function hasOption($name)
|
||||
{
|
||||
return $this->definition->hasOption($name);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Input;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -14,121 +14,115 @@ namespace Symfony\Component\Console\Input;
|
||||
/**
|
||||
* Represents a command line argument.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class InputArgument
|
||||
{
|
||||
const REQUIRED = 1;
|
||||
const OPTIONAL = 2;
|
||||
const IS_ARRAY = 4;
|
||||
const REQUIRED = 1;
|
||||
const OPTIONAL = 2;
|
||||
const IS_ARRAY = 4;
|
||||
|
||||
protected $name;
|
||||
protected $mode;
|
||||
protected $default;
|
||||
protected $description;
|
||||
protected $name;
|
||||
protected $mode;
|
||||
protected $default;
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param integer $mode The argument mode: self::REQUIRED or self::OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (for self::OPTIONAL mode only)
|
||||
*/
|
||||
public function __construct($name, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
if (null === $mode)
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param integer $mode The argument mode: self::REQUIRED or self::OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (for self::OPTIONAL mode only)
|
||||
*
|
||||
* @throws \InvalidArgumentException When argument mode is not valid
|
||||
*/
|
||||
public function __construct($name, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
$mode = self::OPTIONAL;
|
||||
}
|
||||
else if (is_string($mode) || $mode > 7)
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
|
||||
if (null === $mode) {
|
||||
$mode = self::OPTIONAL;
|
||||
} else if (is_string($mode) || $mode > 7) {
|
||||
throw new \InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->mode = $mode;
|
||||
$this->description = $description;
|
||||
|
||||
$this->setDefault($default);
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->mode = $mode;
|
||||
$this->description = $description;
|
||||
|
||||
$this->setDefault($default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the argument name.
|
||||
*
|
||||
* @return string The argument name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the argument is required.
|
||||
*
|
||||
* @return Boolean true if parameter mode is self::REQUIRED, false otherwise
|
||||
*/
|
||||
public function isRequired()
|
||||
{
|
||||
return self::REQUIRED === (self::REQUIRED & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the argument can take multiple values.
|
||||
*
|
||||
* @return Boolean true if mode is self::IS_ARRAY, false otherwise
|
||||
*/
|
||||
public function isArray()
|
||||
{
|
||||
return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value.
|
||||
*
|
||||
* @param mixed $default The default value
|
||||
*/
|
||||
public function setDefault($default = null)
|
||||
{
|
||||
if (self::REQUIRED === $this->mode && null !== $default)
|
||||
/**
|
||||
* Returns the argument name.
|
||||
*
|
||||
* @return string The argument name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
throw new \LogicException('Cannot set a default value except for Parameter::OPTIONAL mode.');
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
if ($this->isArray())
|
||||
/**
|
||||
* Returns true if the argument is required.
|
||||
*
|
||||
* @return Boolean true if parameter mode is self::REQUIRED, false otherwise
|
||||
*/
|
||||
public function isRequired()
|
||||
{
|
||||
if (null === $default)
|
||||
{
|
||||
$default = array();
|
||||
}
|
||||
else if (!is_array($default))
|
||||
{
|
||||
throw new \LogicException('A default value for an array argument must be an array.');
|
||||
}
|
||||
return self::REQUIRED === (self::REQUIRED & $this->mode);
|
||||
}
|
||||
|
||||
$this->default = $default;
|
||||
}
|
||||
/**
|
||||
* Returns true if the argument can take multiple values.
|
||||
*
|
||||
* @return Boolean true if mode is self::IS_ARRAY, false otherwise
|
||||
*/
|
||||
public function isArray()
|
||||
{
|
||||
return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value.
|
||||
*
|
||||
* @return mixed The default value
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
/**
|
||||
* Sets the default value.
|
||||
*
|
||||
* @param mixed $default The default value
|
||||
*
|
||||
* @throws \LogicException When incorrect default value is given
|
||||
*/
|
||||
public function setDefault($default = null)
|
||||
{
|
||||
if (self::REQUIRED === $this->mode && null !== $default) {
|
||||
throw new \LogicException('Cannot set a default value except for Parameter::OPTIONAL mode.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description text.
|
||||
*
|
||||
* @return string The description text
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
if ($this->isArray()) {
|
||||
if (null === $default) {
|
||||
$default = array();
|
||||
} else if (!is_array($default)) {
|
||||
throw new \LogicException('A default value for an array argument must be an array.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->default = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value.
|
||||
*
|
||||
* @return mixed The default value
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description text.
|
||||
*
|
||||
* @return string The description text
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Input;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -18,490 +18,454 @@ namespace Symfony\Component\Console\Input;
|
||||
*
|
||||
* $definition = new InputDefinition(array(
|
||||
* new InputArgument('name', InputArgument::REQUIRED),
|
||||
* new InputOption('foo', 'f', InputOption::PARAMETER_REQUIRED),
|
||||
* new InputOption('foo', 'f', InputOption::VALUE_REQUIRED),
|
||||
* ));
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class InputDefinition
|
||||
{
|
||||
protected $arguments;
|
||||
protected $requiredCount;
|
||||
protected $hasAnArrayArgument = false;
|
||||
protected $hasOptional;
|
||||
protected $options;
|
||||
protected $shortcuts;
|
||||
protected $arguments;
|
||||
protected $requiredCount;
|
||||
protected $hasAnArrayArgument = false;
|
||||
protected $hasOptional;
|
||||
protected $options;
|
||||
protected $shortcuts;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $definition An array of InputArgument and InputOption instance
|
||||
*/
|
||||
public function __construct(array $definition = array())
|
||||
{
|
||||
$this->setDefinition($definition);
|
||||
}
|
||||
|
||||
public function setDefinition(array $definition)
|
||||
{
|
||||
$arguments = array();
|
||||
$options = array();
|
||||
foreach ($definition as $item)
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $definition An array of InputArgument and InputOption instance
|
||||
*/
|
||||
public function __construct(array $definition = array())
|
||||
{
|
||||
if ($item instanceof InputOption)
|
||||
{
|
||||
$options[] = $item;
|
||||
}
|
||||
else
|
||||
{
|
||||
$arguments[] = $item;
|
||||
}
|
||||
$this->setDefinition($definition);
|
||||
}
|
||||
|
||||
$this->setArguments($arguments);
|
||||
$this->setOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the InputArgument objects.
|
||||
*
|
||||
* @param array $arguments An array of InputArgument objects
|
||||
*/
|
||||
public function setArguments($arguments = array())
|
||||
{
|
||||
$this->arguments = array();
|
||||
$this->requiredCount = 0;
|
||||
$this->hasOptional = false;
|
||||
$this->addArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an array of InputArgument objects.
|
||||
*
|
||||
* @param array $arguments An array of InputArgument objects
|
||||
*/
|
||||
public function addArguments($arguments = array())
|
||||
{
|
||||
if (null !== $arguments)
|
||||
public function setDefinition(array $definition)
|
||||
{
|
||||
foreach ($arguments as $argument)
|
||||
{
|
||||
$this->addArgument($argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an InputArgument object.
|
||||
*
|
||||
* @param InputArgument $argument An InputArgument object
|
||||
*/
|
||||
public function addArgument(InputArgument $argument)
|
||||
{
|
||||
if (isset($this->arguments[$argument->getName()]))
|
||||
{
|
||||
throw new \LogicException(sprintf('An argument with name "%s" already exist.', $argument->getName()));
|
||||
}
|
||||
|
||||
if ($this->hasAnArrayArgument)
|
||||
{
|
||||
throw new \LogicException('Cannot add an argument after an array argument.');
|
||||
}
|
||||
|
||||
if ($argument->isRequired() && $this->hasOptional)
|
||||
{
|
||||
throw new \LogicException('Cannot add a required argument after an optional one.');
|
||||
}
|
||||
|
||||
if ($argument->isArray())
|
||||
{
|
||||
$this->hasAnArrayArgument = true;
|
||||
}
|
||||
|
||||
if ($argument->isRequired())
|
||||
{
|
||||
++$this->requiredCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->hasOptional = true;
|
||||
}
|
||||
|
||||
$this->arguments[$argument->getName()] = $argument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InputArgument by name or by position.
|
||||
*
|
||||
* @param string|integer $name The InputArgument name or position
|
||||
*
|
||||
* @return InputArgument An InputArgument object
|
||||
*/
|
||||
public function getArgument($name)
|
||||
{
|
||||
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
|
||||
|
||||
if (!$this->hasArgument($name))
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
return $arguments[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputArgument object exists by name or position.
|
||||
*
|
||||
* @param string|integer $name The InputArgument name or position
|
||||
*
|
||||
* @return Boolean true if the InputArgument object exists, false otherwise
|
||||
*/
|
||||
public function hasArgument($name)
|
||||
{
|
||||
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
|
||||
|
||||
return isset($arguments[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of InputArgument objects.
|
||||
*
|
||||
* @return array An array of InputArgument objects
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of InputArguments.
|
||||
*
|
||||
* @return integer The number of InputArguments
|
||||
*/
|
||||
public function getArgumentCount()
|
||||
{
|
||||
return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of required InputArguments.
|
||||
*
|
||||
* @return integer The number of required InputArguments
|
||||
*/
|
||||
public function getArgumentRequiredCount()
|
||||
{
|
||||
return $this->requiredCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default values.
|
||||
*
|
||||
* @return array An array of default values
|
||||
*/
|
||||
public function getArgumentDefaults()
|
||||
{
|
||||
$values = array();
|
||||
foreach ($this->arguments as $argument)
|
||||
{
|
||||
$values[$argument->getName()] = $argument->getDefault();
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the InputOption objects.
|
||||
*
|
||||
* @param array $options An array of InputOption objects
|
||||
*/
|
||||
public function setOptions($options = array())
|
||||
{
|
||||
$this->options = array();
|
||||
$this->shortcuts = array();
|
||||
$this->addOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an array of InputOption objects.
|
||||
*
|
||||
* @param array $options An array of InputOption objects
|
||||
*/
|
||||
public function addOptions($options = array())
|
||||
{
|
||||
foreach ($options as $option)
|
||||
{
|
||||
$this->addOption($option);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an InputOption object.
|
||||
*
|
||||
* @param InputOption $option An InputOption object
|
||||
*/
|
||||
public function addOption(InputOption $option)
|
||||
{
|
||||
if (isset($this->options[$option->getName()]))
|
||||
{
|
||||
throw new \LogicException(sprintf('An option named "%s" already exist.', $option->getName()));
|
||||
}
|
||||
else if (isset($this->shortcuts[$option->getShortcut()]))
|
||||
{
|
||||
throw new \LogicException(sprintf('An option with shortcut "%s" already exist.', $option->getShortcut()));
|
||||
}
|
||||
|
||||
$this->options[$option->getName()] = $option;
|
||||
if ($option->getShortcut())
|
||||
{
|
||||
$this->shortcuts[$option->getShortcut()] = $option->getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InputOption by name.
|
||||
*
|
||||
* @param string $name The InputOption name
|
||||
*
|
||||
* @return InputOption A InputOption object
|
||||
*/
|
||||
public function getOption($name)
|
||||
{
|
||||
if (!$this->hasOption($name))
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
return $this->options[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputOption object exists by name.
|
||||
*
|
||||
* @param string $name The InputOption name
|
||||
*
|
||||
* @return Boolean true if the InputOption object exists, false otherwise
|
||||
*/
|
||||
public function hasOption($name)
|
||||
{
|
||||
return isset($this->options[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of InputOption objects.
|
||||
*
|
||||
* @return array An array of InputOption objects
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputOption object exists by shortcut.
|
||||
*
|
||||
* @param string $name The InputOption shortcut
|
||||
*
|
||||
* @return Boolean true if the InputOption object exists, false otherwise
|
||||
*/
|
||||
public function hasShortcut($name)
|
||||
{
|
||||
return isset($this->shortcuts[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an InputOption by shortcut.
|
||||
*
|
||||
* @return InputOption An InputOption object
|
||||
*/
|
||||
public function getOptionForShortcut($shortcut)
|
||||
{
|
||||
return $this->getOption($this->shortcutToName($shortcut));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of default values.
|
||||
*
|
||||
* @return array An array of all default values
|
||||
*/
|
||||
public function getOptionDefaults()
|
||||
{
|
||||
$values = array();
|
||||
foreach ($this->options as $option)
|
||||
{
|
||||
$values[$option->getName()] = $option->getDefault();
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the InputOption name given a shortcut.
|
||||
*
|
||||
* @param string $shortcut The shortcut
|
||||
*
|
||||
* @return string The InputOption name
|
||||
*/
|
||||
protected function shortcutToName($shortcut)
|
||||
{
|
||||
if (!isset($this->shortcuts[$shortcut]))
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
}
|
||||
|
||||
return $this->shortcuts[$shortcut];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the synopsis.
|
||||
*
|
||||
* @return string The synopsis
|
||||
*/
|
||||
public function getSynopsis()
|
||||
{
|
||||
$elements = array();
|
||||
foreach ($this->getOptions() as $option)
|
||||
{
|
||||
$shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
|
||||
$elements[] = sprintf('['.($option->isParameterRequired() ? '%s--%s="..."' : ($option->isParameterOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName());
|
||||
}
|
||||
|
||||
foreach ($this->getArguments() as $argument)
|
||||
{
|
||||
$elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : ''));
|
||||
|
||||
if ($argument->isArray())
|
||||
{
|
||||
$elements[] = sprintf('... [%sN]', $argument->getName());
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' ', $elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a textual representation of the InputDefinition.
|
||||
*
|
||||
* @return string A string representing the InputDefinition
|
||||
*/
|
||||
public function asText()
|
||||
{
|
||||
// find the largest option or argument name
|
||||
$max = 0;
|
||||
foreach ($this->getOptions() as $option)
|
||||
{
|
||||
$max = strlen($option->getName()) + 2 > $max ? strlen($option->getName()) + 2 : $max;
|
||||
}
|
||||
foreach ($this->getArguments() as $argument)
|
||||
{
|
||||
$max = strlen($argument->getName()) > $max ? strlen($argument->getName()) : $max;
|
||||
}
|
||||
++$max;
|
||||
|
||||
$text = array();
|
||||
|
||||
if ($this->getArguments())
|
||||
{
|
||||
$text[] = '<comment>Arguments:</comment>';
|
||||
foreach ($this->getArguments() as $argument)
|
||||
{
|
||||
if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault())))
|
||||
{
|
||||
$default = sprintf('<comment> (default: %s)</comment>', is_array($argument->getDefault()) ? str_replace("\n", '', var_export($argument->getDefault(), true)): $argument->getDefault());
|
||||
}
|
||||
else
|
||||
{
|
||||
$default = '';
|
||||
$arguments = array();
|
||||
$options = array();
|
||||
foreach ($definition as $item) {
|
||||
if ($item instanceof InputOption) {
|
||||
$options[] = $item;
|
||||
} else {
|
||||
$arguments[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$text[] = sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $argument->getDescription(), $default);
|
||||
}
|
||||
|
||||
$text[] = '';
|
||||
$this->setArguments($arguments);
|
||||
$this->setOptions($options);
|
||||
}
|
||||
|
||||
if ($this->getOptions())
|
||||
/**
|
||||
* Sets the InputArgument objects.
|
||||
*
|
||||
* @param array $arguments An array of InputArgument objects
|
||||
*/
|
||||
public function setArguments($arguments = array())
|
||||
{
|
||||
$text[] = '<comment>Options:</comment>';
|
||||
$this->arguments = array();
|
||||
$this->requiredCount = 0;
|
||||
$this->hasOptional = false;
|
||||
$this->hasAnArrayArgument = false;
|
||||
$this->addArguments($arguments);
|
||||
}
|
||||
|
||||
foreach ($this->getOptions() as $option)
|
||||
{
|
||||
if ($option->acceptParameter() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault())))
|
||||
{
|
||||
$default = sprintf('<comment> (default: %s)</comment>', is_array($option->getDefault()) ? str_replace("\n", '', print_r($option->getDefault(), true)): $option->getDefault());
|
||||
/**
|
||||
* Add an array of InputArgument objects.
|
||||
*
|
||||
* @param InputArgument[] $arguments An array of InputArgument objects
|
||||
*/
|
||||
public function addArguments($arguments = array())
|
||||
{
|
||||
if (null !== $arguments) {
|
||||
foreach ($arguments as $argument) {
|
||||
$this->addArgument($argument);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$default = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an InputArgument object.
|
||||
*
|
||||
* @param InputArgument $argument An InputArgument object
|
||||
*
|
||||
* @throws \LogicException When incorrect argument is given
|
||||
*/
|
||||
public function addArgument(InputArgument $argument)
|
||||
{
|
||||
if (isset($this->arguments[$argument->getName()])) {
|
||||
throw new \LogicException(sprintf('An argument with name "%s" already exist.', $argument->getName()));
|
||||
}
|
||||
|
||||
$multiple = $option->isArray() ? '<comment> (multiple values allowed)</comment>' : '';
|
||||
$text[] = sprintf(' %-'.$max.'s %s%s%s%s', '<info>--'.$option->getName().'</info>', $option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '', $option->getDescription(), $default, $multiple);
|
||||
}
|
||||
|
||||
$text[] = '';
|
||||
}
|
||||
|
||||
return implode("\n", $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML representation of the InputDefinition.
|
||||
*
|
||||
* @param Boolean $asDom Whether to return a DOM or an XML string
|
||||
*
|
||||
* @return string|DOMDocument An XML string representing the InputDefinition
|
||||
*/
|
||||
public function asXml($asDom = false)
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->formatOutput = true;
|
||||
$dom->appendChild($definitionXML = $dom->createElement('definition'));
|
||||
|
||||
$definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
|
||||
foreach ($this->getArguments() as $argument)
|
||||
{
|
||||
$argumentsXML->appendChild($argumentXML = $dom->createElement('argument'));
|
||||
$argumentXML->setAttribute('name', $argument->getName());
|
||||
$argumentXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
|
||||
$argumentXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
|
||||
$argumentXML->appendChild($descriptionXML = $dom->createElement('description'));
|
||||
$descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
|
||||
|
||||
$argumentXML->appendChild($defaultsXML = $dom->createElement('defaults'));
|
||||
$defaults = is_array($argument->getDefault()) ? $argument->getDefault() : ($argument->getDefault() ? array($argument->getDefault()) : array());
|
||||
foreach ($defaults as $default)
|
||||
{
|
||||
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
|
||||
$defaultXML->appendChild($dom->createTextNode($default));
|
||||
}
|
||||
}
|
||||
|
||||
$definitionXML->appendChild($optionsXML = $dom->createElement('options'));
|
||||
foreach ($this->getOptions() as $option)
|
||||
{
|
||||
$optionsXML->appendChild($optionXML = $dom->createElement('option'));
|
||||
$optionXML->setAttribute('name', '--'.$option->getName());
|
||||
$optionXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
|
||||
$optionXML->setAttribute('accept_parameter', $option->acceptParameter() ? 1 : 0);
|
||||
$optionXML->setAttribute('is_parameter_required', $option->isParameterRequired() ? 1 : 0);
|
||||
$optionXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
|
||||
$optionXML->appendChild($descriptionXML = $dom->createElement('description'));
|
||||
$descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
|
||||
|
||||
if ($option->acceptParameter())
|
||||
{
|
||||
$optionXML->appendChild($defaultsXML = $dom->createElement('defaults'));
|
||||
$defaults = is_array($option->getDefault()) ? $option->getDefault() : ($option->getDefault() ? array($option->getDefault()) : array());
|
||||
foreach ($defaults as $default)
|
||||
{
|
||||
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
|
||||
$defaultXML->appendChild($dom->createTextNode($default));
|
||||
if ($this->hasAnArrayArgument) {
|
||||
throw new \LogicException('Cannot add an argument after an array argument.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($argument->isRequired() && $this->hasOptional) {
|
||||
throw new \LogicException('Cannot add a required argument after an optional one.');
|
||||
}
|
||||
|
||||
if ($argument->isArray()) {
|
||||
$this->hasAnArrayArgument = true;
|
||||
}
|
||||
|
||||
if ($argument->isRequired()) {
|
||||
++$this->requiredCount;
|
||||
} else {
|
||||
$this->hasOptional = true;
|
||||
}
|
||||
|
||||
$this->arguments[$argument->getName()] = $argument;
|
||||
}
|
||||
|
||||
return $asDom ? $dom : $dom->saveXml();
|
||||
}
|
||||
/**
|
||||
* Returns an InputArgument by name or by position.
|
||||
*
|
||||
* @param string|integer $name The InputArgument name or position
|
||||
*
|
||||
* @return InputArgument An InputArgument object
|
||||
*
|
||||
* @throws \InvalidArgumentException When argument given doesn't exist
|
||||
*/
|
||||
public function getArgument($name)
|
||||
{
|
||||
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
|
||||
|
||||
if (!$this->hasArgument($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
return $arguments[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputArgument object exists by name or position.
|
||||
*
|
||||
* @param string|integer $name The InputArgument name or position
|
||||
*
|
||||
* @return Boolean true if the InputArgument object exists, false otherwise
|
||||
*/
|
||||
public function hasArgument($name)
|
||||
{
|
||||
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
|
||||
|
||||
return isset($arguments[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of InputArgument objects.
|
||||
*
|
||||
* @return array An array of InputArgument objects
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of InputArguments.
|
||||
*
|
||||
* @return integer The number of InputArguments
|
||||
*/
|
||||
public function getArgumentCount()
|
||||
{
|
||||
return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of required InputArguments.
|
||||
*
|
||||
* @return integer The number of required InputArguments
|
||||
*/
|
||||
public function getArgumentRequiredCount()
|
||||
{
|
||||
return $this->requiredCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default values.
|
||||
*
|
||||
* @return array An array of default values
|
||||
*/
|
||||
public function getArgumentDefaults()
|
||||
{
|
||||
$values = array();
|
||||
foreach ($this->arguments as $argument) {
|
||||
$values[$argument->getName()] = $argument->getDefault();
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the InputOption objects.
|
||||
*
|
||||
* @param array $options An array of InputOption objects
|
||||
*/
|
||||
public function setOptions($options = array())
|
||||
{
|
||||
$this->options = array();
|
||||
$this->shortcuts = array();
|
||||
$this->addOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an array of InputOption objects.
|
||||
*
|
||||
* @param InputOption[] $options An array of InputOption objects
|
||||
*/
|
||||
public function addOptions($options = array())
|
||||
{
|
||||
foreach ($options as $option) {
|
||||
$this->addOption($option);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an InputOption object.
|
||||
*
|
||||
* @param InputOption $option An InputOption object
|
||||
*
|
||||
* @throws \LogicException When option given already exist
|
||||
*/
|
||||
public function addOption(InputOption $option)
|
||||
{
|
||||
if (isset($this->options[$option->getName()])) {
|
||||
throw new \LogicException(sprintf('An option named "%s" already exist.', $option->getName()));
|
||||
} else if (isset($this->shortcuts[$option->getShortcut()])) {
|
||||
throw new \LogicException(sprintf('An option with shortcut "%s" already exist.', $option->getShortcut()));
|
||||
}
|
||||
|
||||
$this->options[$option->getName()] = $option;
|
||||
if ($option->getShortcut()) {
|
||||
$this->shortcuts[$option->getShortcut()] = $option->getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InputOption by name.
|
||||
*
|
||||
* @param string $name The InputOption name
|
||||
*
|
||||
* @return InputOption A InputOption object
|
||||
*/
|
||||
public function getOption($name)
|
||||
{
|
||||
if (!$this->hasOption($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
return $this->options[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputOption object exists by name.
|
||||
*
|
||||
* @param string $name The InputOption name
|
||||
*
|
||||
* @return Boolean true if the InputOption object exists, false otherwise
|
||||
*/
|
||||
public function hasOption($name)
|
||||
{
|
||||
return isset($this->options[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of InputOption objects.
|
||||
*
|
||||
* @return array An array of InputOption objects
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputOption object exists by shortcut.
|
||||
*
|
||||
* @param string $name The InputOption shortcut
|
||||
*
|
||||
* @return Boolean true if the InputOption object exists, false otherwise
|
||||
*/
|
||||
public function hasShortcut($name)
|
||||
{
|
||||
return isset($this->shortcuts[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an InputOption by shortcut.
|
||||
*
|
||||
* @return InputOption An InputOption object
|
||||
*/
|
||||
public function getOptionForShortcut($shortcut)
|
||||
{
|
||||
return $this->getOption($this->shortcutToName($shortcut));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of default values.
|
||||
*
|
||||
* @return array An array of all default values
|
||||
*/
|
||||
public function getOptionDefaults()
|
||||
{
|
||||
$values = array();
|
||||
foreach ($this->options as $option) {
|
||||
$values[$option->getName()] = $option->getDefault();
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the InputOption name given a shortcut.
|
||||
*
|
||||
* @param string $shortcut The shortcut
|
||||
*
|
||||
* @return string The InputOption name
|
||||
*
|
||||
* @throws \InvalidArgumentException When option given does not exist
|
||||
*/
|
||||
protected function shortcutToName($shortcut)
|
||||
{
|
||||
if (!isset($this->shortcuts[$shortcut])) {
|
||||
throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
}
|
||||
|
||||
return $this->shortcuts[$shortcut];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the synopsis.
|
||||
*
|
||||
* @return string The synopsis
|
||||
*/
|
||||
public function getSynopsis()
|
||||
{
|
||||
$elements = array();
|
||||
foreach ($this->getOptions() as $option) {
|
||||
$shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
|
||||
$elements[] = sprintf('['.($option->isValueRequired() ? '%s--%s="..."' : ($option->isValueOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName());
|
||||
}
|
||||
|
||||
foreach ($this->getArguments() as $argument) {
|
||||
$elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : ''));
|
||||
|
||||
if ($argument->isArray()) {
|
||||
$elements[] = sprintf('... [%sN]', $argument->getName());
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' ', $elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a textual representation of the InputDefinition.
|
||||
*
|
||||
* @return string A string representing the InputDefinition
|
||||
*/
|
||||
public function asText()
|
||||
{
|
||||
// find the largest option or argument name
|
||||
$max = 0;
|
||||
foreach ($this->getOptions() as $option) {
|
||||
$max = strlen($option->getName()) + 2 > $max ? strlen($option->getName()) + 2 : $max;
|
||||
}
|
||||
foreach ($this->getArguments() as $argument) {
|
||||
$max = strlen($argument->getName()) > $max ? strlen($argument->getName()) : $max;
|
||||
}
|
||||
++$max;
|
||||
|
||||
$text = array();
|
||||
|
||||
if ($this->getArguments()) {
|
||||
$text[] = '<comment>Arguments:</comment>';
|
||||
foreach ($this->getArguments() as $argument) {
|
||||
if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) {
|
||||
$default = sprintf('<comment> (default: %s)</comment>', is_array($argument->getDefault()) ? str_replace("\n", '', var_export($argument->getDefault(), true)): $argument->getDefault());
|
||||
} else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$text[] = sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $argument->getDescription(), $default);
|
||||
}
|
||||
|
||||
$text[] = '';
|
||||
}
|
||||
|
||||
if ($this->getOptions()) {
|
||||
$text[] = '<comment>Options:</comment>';
|
||||
|
||||
foreach ($this->getOptions() as $option) {
|
||||
if ($option->acceptValue() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) {
|
||||
$default = sprintf('<comment> (default: %s)</comment>', is_array($option->getDefault()) ? str_replace("\n", '', print_r($option->getDefault(), true)): $option->getDefault());
|
||||
} else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$multiple = $option->isArray() ? '<comment> (multiple values allowed)</comment>' : '';
|
||||
$text[] = sprintf(' %-'.$max.'s %s%s%s%s', '<info>--'.$option->getName().'</info>', $option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '', $option->getDescription(), $default, $multiple);
|
||||
}
|
||||
|
||||
$text[] = '';
|
||||
}
|
||||
|
||||
return implode("\n", $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML representation of the InputDefinition.
|
||||
*
|
||||
* @param Boolean $asDom Whether to return a DOM or an XML string
|
||||
*
|
||||
* @return string|DOMDocument An XML string representing the InputDefinition
|
||||
*/
|
||||
public function asXml($asDom = false)
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->formatOutput = true;
|
||||
$dom->appendChild($definitionXML = $dom->createElement('definition'));
|
||||
|
||||
$definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
|
||||
foreach ($this->getArguments() as $argument) {
|
||||
$argumentsXML->appendChild($argumentXML = $dom->createElement('argument'));
|
||||
$argumentXML->setAttribute('name', $argument->getName());
|
||||
$argumentXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
|
||||
$argumentXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
|
||||
$argumentXML->appendChild($descriptionXML = $dom->createElement('description'));
|
||||
$descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
|
||||
|
||||
$argumentXML->appendChild($defaultsXML = $dom->createElement('defaults'));
|
||||
$defaults = is_array($argument->getDefault()) ? $argument->getDefault() : ($argument->getDefault() ? array($argument->getDefault()) : array());
|
||||
foreach ($defaults as $default) {
|
||||
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
|
||||
$defaultXML->appendChild($dom->createTextNode($default));
|
||||
}
|
||||
}
|
||||
|
||||
$definitionXML->appendChild($optionsXML = $dom->createElement('options'));
|
||||
foreach ($this->getOptions() as $option) {
|
||||
$optionsXML->appendChild($optionXML = $dom->createElement('option'));
|
||||
$optionXML->setAttribute('name', '--'.$option->getName());
|
||||
$optionXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
|
||||
$optionXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
|
||||
$optionXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
|
||||
$optionXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
|
||||
$optionXML->appendChild($descriptionXML = $dom->createElement('description'));
|
||||
$descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
|
||||
|
||||
if ($option->acceptValue()) {
|
||||
$optionXML->appendChild($defaultsXML = $dom->createElement('defaults'));
|
||||
$defaults = is_array($option->getDefault()) ? $option->getDefault() : ($option->getDefault() ? array($option->getDefault()) : array());
|
||||
foreach ($defaults as $default) {
|
||||
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
|
||||
$defaultXML->appendChild($dom->createTextNode($default));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $asDom ? $dom : $dom->saveXml();
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Input;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -14,45 +14,43 @@ namespace Symfony\Component\Console\Input;
|
||||
/**
|
||||
* InputInterface is the interface implemented by all input classes.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
interface InputInterface
|
||||
{
|
||||
/**
|
||||
* Returns the first argument from the raw parameters (not parsed).
|
||||
*
|
||||
* @return string The value of the first argument or null otherwise
|
||||
*/
|
||||
function getFirstArgument();
|
||||
/**
|
||||
* Returns the first argument from the raw parameters (not parsed).
|
||||
*
|
||||
* @return string The value of the first argument or null otherwise
|
||||
*/
|
||||
function getFirstArgument();
|
||||
|
||||
/**
|
||||
* Returns true if the raw parameters (not parsed) contains a value.
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before it has been validated. It must be used carefully.
|
||||
*
|
||||
* @param string $value The value to look for in the raw parameters
|
||||
*
|
||||
* @return Boolean true if the value is contained in the raw parameters
|
||||
*/
|
||||
function hasParameterOption($value);
|
||||
/**
|
||||
* Returns true if the raw parameters (not parsed) contains a value.
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before it has been validated. It must be used carefully.
|
||||
*
|
||||
* @param string $value The value to look for in the raw parameters
|
||||
*
|
||||
* @return Boolean true if the value is contained in the raw parameters
|
||||
*/
|
||||
function hasParameterOption($value);
|
||||
|
||||
/**
|
||||
* Binds the current Input instance with the given arguments and options.
|
||||
*
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
function bind(InputDefinition $definition);
|
||||
/**
|
||||
* Binds the current Input instance with the given arguments and options.
|
||||
*
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
function bind(InputDefinition $definition);
|
||||
|
||||
function validate();
|
||||
function validate();
|
||||
|
||||
function getArguments();
|
||||
function getArguments();
|
||||
|
||||
function getArgument($name);
|
||||
function getArgument($name);
|
||||
|
||||
function getOptions();
|
||||
function getOptions();
|
||||
|
||||
function getOption($name);
|
||||
function getOption($name);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Input;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -14,178 +14,165 @@ namespace Symfony\Component\Console\Input;
|
||||
/**
|
||||
* Represents a command line option.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class InputOption
|
||||
{
|
||||
const PARAMETER_NONE = 1;
|
||||
const PARAMETER_REQUIRED = 2;
|
||||
const PARAMETER_OPTIONAL = 4;
|
||||
const PARAMETER_IS_ARRAY = 8;
|
||||
const VALUE_NONE = 1;
|
||||
const VALUE_REQUIRED = 2;
|
||||
const VALUE_OPTIONAL = 4;
|
||||
const VALUE_IS_ARRAY = 8;
|
||||
|
||||
protected $name;
|
||||
protected $shortcut;
|
||||
protected $mode;
|
||||
protected $default;
|
||||
protected $description;
|
||||
protected $name;
|
||||
protected $shortcut;
|
||||
protected $mode;
|
||||
protected $default;
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string $shortcut The shortcut (can be null)
|
||||
* @param integer $mode The option mode: self::PARAMETER_REQUIRED, self::PARAMETER_NONE or self::PARAMETER_OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (must be null for self::PARAMETER_REQUIRED or self::PARAMETER_NONE)
|
||||
*/
|
||||
public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
if ('--' === substr($name, 0, 2))
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string $shortcut The shortcut (can be null)
|
||||
* @param integer $mode The option mode: One of the VALUE_* constants
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (must be null for self::VALUE_REQUIRED or self::VALUE_NONE)
|
||||
*
|
||||
* @throws \InvalidArgumentException If option mode is invalid or incompatible
|
||||
*/
|
||||
public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
$name = substr($name, 2);
|
||||
if ('--' === substr($name, 0, 2)) {
|
||||
$name = substr($name, 2);
|
||||
}
|
||||
|
||||
if (empty($shortcut)) {
|
||||
$shortcut = null;
|
||||
}
|
||||
|
||||
if (null !== $shortcut) {
|
||||
if ('-' === $shortcut[0]) {
|
||||
$shortcut = substr($shortcut, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $mode) {
|
||||
$mode = self::VALUE_NONE;
|
||||
} else if (!is_int($mode) || $mode > 15) {
|
||||
throw new \InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->shortcut = $shortcut;
|
||||
$this->mode = $mode;
|
||||
$this->description = $description;
|
||||
|
||||
if ($this->isArray() && !$this->acceptValue()) {
|
||||
throw new \InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
|
||||
}
|
||||
|
||||
$this->setDefault($default);
|
||||
}
|
||||
|
||||
if (empty($shortcut))
|
||||
/**
|
||||
* Returns the shortcut.
|
||||
*
|
||||
* @return string The shortcut
|
||||
*/
|
||||
public function getShortcut()
|
||||
{
|
||||
$shortcut = null;
|
||||
return $this->shortcut;
|
||||
}
|
||||
|
||||
if (null !== $shortcut)
|
||||
/**
|
||||
* Returns the name.
|
||||
*
|
||||
* @return string The name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
if ('-' === $shortcut[0])
|
||||
{
|
||||
$shortcut = substr($shortcut, 1);
|
||||
}
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
if (null === $mode)
|
||||
/**
|
||||
* Returns true if the option accepts a value.
|
||||
*
|
||||
* @return Boolean true if value mode is not self::VALUE_NONE, false otherwise
|
||||
*/
|
||||
public function acceptValue()
|
||||
{
|
||||
$mode = self::PARAMETER_NONE;
|
||||
}
|
||||
else if (!is_int($mode) || $mode > 15)
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
|
||||
return $this->isValueRequired() || $this->isValueOptional();
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->shortcut = $shortcut;
|
||||
$this->mode = $mode;
|
||||
$this->description = $description;
|
||||
|
||||
if ($this->isArray() && !$this->acceptParameter())
|
||||
/**
|
||||
* Returns true if the option requires a value.
|
||||
*
|
||||
* @return Boolean true if value mode is self::VALUE_REQUIRED, false otherwise
|
||||
*/
|
||||
public function isValueRequired()
|
||||
{
|
||||
throw new \InvalidArgumentException('Impossible to have an option mode PARAMETER_IS_ARRAY if the option does not accept a parameter.');
|
||||
return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
|
||||
}
|
||||
|
||||
$this->setDefault($default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shortcut.
|
||||
*
|
||||
* @return string The shortcut
|
||||
*/
|
||||
public function getShortcut()
|
||||
{
|
||||
return $this->shortcut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name.
|
||||
*
|
||||
* @return string The name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the option accept a parameter.
|
||||
*
|
||||
* @return Boolean true if parameter mode is not self::PARAMETER_NONE, false otherwise
|
||||
*/
|
||||
public function acceptParameter()
|
||||
{
|
||||
return $this->isParameterRequired() || $this->isParameterOptional();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the option requires a parameter.
|
||||
*
|
||||
* @return Boolean true if parameter mode is self::PARAMETER_REQUIRED, false otherwise
|
||||
*/
|
||||
public function isParameterRequired()
|
||||
{
|
||||
return self::PARAMETER_REQUIRED === (self::PARAMETER_REQUIRED & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the option takes an optional parameter.
|
||||
*
|
||||
* @return Boolean true if parameter mode is self::PARAMETER_OPTIONAL, false otherwise
|
||||
*/
|
||||
public function isParameterOptional()
|
||||
{
|
||||
return self::PARAMETER_OPTIONAL === (self::PARAMETER_OPTIONAL & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the option can take multiple values.
|
||||
*
|
||||
* @return Boolean true if mode is self::PARAMETER_IS_ARRAY, false otherwise
|
||||
*/
|
||||
public function isArray()
|
||||
{
|
||||
return self::PARAMETER_IS_ARRAY === (self::PARAMETER_IS_ARRAY & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value.
|
||||
*
|
||||
* @param mixed $default The default value
|
||||
*/
|
||||
public function setDefault($default = null)
|
||||
{
|
||||
if (self::PARAMETER_NONE === (self::PARAMETER_NONE & $this->mode) && null !== $default)
|
||||
/**
|
||||
* Returns true if the option takes an optional value.
|
||||
*
|
||||
* @return Boolean true if value mode is self::VALUE_OPTIONAL, false otherwise
|
||||
*/
|
||||
public function isValueOptional()
|
||||
{
|
||||
throw new \LogicException('Cannot set a default value when using Option::PARAMETER_NONE mode.');
|
||||
return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
|
||||
}
|
||||
|
||||
if ($this->isArray())
|
||||
/**
|
||||
* Returns true if the option can take multiple values.
|
||||
*
|
||||
* @return Boolean true if mode is self::VALUE_IS_ARRAY, false otherwise
|
||||
*/
|
||||
public function isArray()
|
||||
{
|
||||
if (null === $default)
|
||||
{
|
||||
$default = array();
|
||||
}
|
||||
elseif (!is_array($default))
|
||||
{
|
||||
throw new \LogicException('A default value for an array option must be an array.');
|
||||
}
|
||||
return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
|
||||
}
|
||||
|
||||
$this->default = $this->acceptParameter() ? $default : false;
|
||||
}
|
||||
/**
|
||||
* Sets the default value.
|
||||
*
|
||||
* @param mixed $default The default value
|
||||
*/
|
||||
public function setDefault($default = null)
|
||||
{
|
||||
if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
|
||||
throw new \LogicException('Cannot set a default value when using Option::VALUE_NONE mode.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value.
|
||||
*
|
||||
* @return mixed The default value
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
if ($this->isArray()) {
|
||||
if (null === $default) {
|
||||
$default = array();
|
||||
} elseif (!is_array($default)) {
|
||||
throw new \LogicException('A default value for an array option must be an array.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description text.
|
||||
*
|
||||
* @return string The description text
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
$this->default = $this->acceptValue() ? $default : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value.
|
||||
*
|
||||
* @return mixed The default value
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description text.
|
||||
*
|
||||
* @return string The description text
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Input;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -18,63 +18,54 @@ namespace Symfony\Component\Console\Input;
|
||||
*
|
||||
* $input = new StringInput('foo --bar="foobar"');
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class StringInput extends ArgvInput
|
||||
{
|
||||
const REGEX_STRING = '([^ ]+?)(?: |(?<!\\\\)"|(?<!\\\\)\'|$)';
|
||||
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
|
||||
const REGEX_STRING = '([^ ]+?)(?: |(?<!\\\\)"|(?<!\\\\)\'|$)';
|
||||
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $input An array of parameters from the CLI (in the argv format)
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function __construct($input, InputDefinition $definition = null)
|
||||
{
|
||||
parent::__construct(array(), $definition);
|
||||
|
||||
$this->tokens = $this->tokenize($input);
|
||||
}
|
||||
|
||||
protected function tokenize($input)
|
||||
{
|
||||
$input = preg_replace('/(\r\n|\r|\n|\t)/', ' ', $input);
|
||||
|
||||
$tokens = array();
|
||||
$length = strlen($input);
|
||||
$cursor = 0;
|
||||
while ($cursor < $length)
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $input An array of parameters from the CLI (in the argv format)
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function __construct($input, InputDefinition $definition = null)
|
||||
{
|
||||
if (preg_match('/\s+/A', $input, $match, null, $cursor))
|
||||
{
|
||||
}
|
||||
elseif (preg_match('/([^="\' ]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor))
|
||||
{
|
||||
$tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2)));
|
||||
}
|
||||
elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor))
|
||||
{
|
||||
$tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
|
||||
}
|
||||
elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor))
|
||||
{
|
||||
$tokens[] = stripcslashes($match[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// should never happen
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
parent::__construct(array(), $definition);
|
||||
|
||||
$cursor += strlen($match[0]);
|
||||
$this->tokens = $this->tokenize($input);
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
/**
|
||||
* @throws \InvalidArgumentException When unable to parse input (should never happen)
|
||||
*/
|
||||
protected function tokenize($input)
|
||||
{
|
||||
$input = preg_replace('/(\r\n|\r|\n|\t)/', ' ', $input);
|
||||
|
||||
$tokens = array();
|
||||
$length = strlen($input);
|
||||
$cursor = 0;
|
||||
while ($cursor < $length) {
|
||||
if (preg_match('/\s+/A', $input, $match, null, $cursor)) {
|
||||
} elseif (preg_match('/([^="\' ]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) {
|
||||
$tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2)));
|
||||
} elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) {
|
||||
$tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
|
||||
} elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) {
|
||||
$tokens[] = stripcslashes($match[1]);
|
||||
} else {
|
||||
// should never happen
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$cursor += strlen($match[0]);
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Output;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -22,20 +22,18 @@ namespace Symfony\Component\Console\Output;
|
||||
*
|
||||
* $output = new StreamOutput(fopen('php://stdout', 'w'));
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class ConsoleOutput extends StreamOutput
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
|
||||
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
|
||||
*/
|
||||
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null)
|
||||
{
|
||||
parent::__construct(fopen('php://stdout', 'w'), $verbosity, $decorated);
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
|
||||
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
|
||||
*/
|
||||
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null)
|
||||
{
|
||||
parent::__construct(fopen('php://stdout', 'w'), $verbosity, $decorated);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Output;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -16,19 +16,17 @@ namespace Symfony\Component\Console\Output;
|
||||
*
|
||||
* $output = new NullOutput();
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class NullOutput extends Output
|
||||
{
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string $message A message to write to the output
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
*/
|
||||
public function doWrite($message, $newline)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string $message A message to write to the output
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
*/
|
||||
public function doWrite($message, $newline)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Output;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -20,211 +20,212 @@ namespace Symfony\Component\Console\Output;
|
||||
* * verbose: -v (more output - debug)
|
||||
* * quiet: -q (no output)
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
abstract class Output implements OutputInterface
|
||||
{
|
||||
const VERBOSITY_QUIET = 0;
|
||||
const VERBOSITY_NORMAL = 1;
|
||||
const VERBOSITY_VERBOSE = 2;
|
||||
const VERBOSITY_QUIET = 0;
|
||||
const VERBOSITY_NORMAL = 1;
|
||||
const VERBOSITY_VERBOSE = 2;
|
||||
|
||||
const OUTPUT_NORMAL = 0;
|
||||
const OUTPUT_RAW = 1;
|
||||
const OUTPUT_PLAIN = 2;
|
||||
const OUTPUT_NORMAL = 0;
|
||||
const OUTPUT_RAW = 1;
|
||||
const OUTPUT_PLAIN = 2;
|
||||
|
||||
protected $verbosity;
|
||||
protected $decorated;
|
||||
protected $verbosity;
|
||||
protected $decorated;
|
||||
|
||||
static protected $styles = array(
|
||||
'error' => array('bg' => 'red', 'fg' => 'white'),
|
||||
'info' => array('fg' => 'green'),
|
||||
'comment' => array('fg' => 'yellow'),
|
||||
'question' => array('bg' => 'cyan', 'fg' => 'black'),
|
||||
);
|
||||
static protected $options = array('bold' => 1, 'underscore' => 4, 'blink' => 5, 'reverse' => 7, 'conceal' => 8);
|
||||
static protected $foreground = array('black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'white' => 37);
|
||||
static protected $background = array('black' => 40, 'red' => 41, 'green' => 42, 'yellow' => 43, 'blue' => 44, 'magenta' => 45, 'cyan' => 46, 'white' => 47);
|
||||
static protected $styles = array(
|
||||
'error' => array('bg' => 'red', 'fg' => 'white'),
|
||||
'info' => array('fg' => 'green'),
|
||||
'comment' => array('fg' => 'yellow'),
|
||||
'question' => array('bg' => 'cyan', 'fg' => 'black'),
|
||||
);
|
||||
static protected $options = array('bold' => 1, 'underscore' => 4, 'blink' => 5, 'reverse' => 7, 'conceal' => 8);
|
||||
static protected $foreground = array('black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'white' => 37);
|
||||
static protected $background = array('black' => 40, 'red' => 41, 'green' => 42, 'yellow' => 43, 'blue' => 44, 'magenta' => 45, 'cyan' => 46, 'white' => 47);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
|
||||
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
|
||||
*/
|
||||
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null)
|
||||
{
|
||||
$this->decorated = (Boolean) $decorated;
|
||||
$this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new style.
|
||||
*
|
||||
* @param string $name The style name
|
||||
* @param array $options An array of options
|
||||
*/
|
||||
static public function setStyle($name, $options = array())
|
||||
{
|
||||
static::$styles[strtolower($name)] = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the decorated flag.
|
||||
*
|
||||
* @param Boolean $decorated Whether to decorated the messages or not
|
||||
*/
|
||||
public function setDecorated($decorated)
|
||||
{
|
||||
$this->decorated = (Boolean) $decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the decorated flag.
|
||||
*
|
||||
* @return Boolean true if the output will decorate messages, false otherwise
|
||||
*/
|
||||
public function isDecorated()
|
||||
{
|
||||
return $this->decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the verbosity of the output.
|
||||
*
|
||||
* @param integer $level The level of verbosity
|
||||
*/
|
||||
public function setVerbosity($level)
|
||||
{
|
||||
$this->verbosity = (int) $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current verbosity of the output.
|
||||
*
|
||||
* @return integer The current level of verbosity
|
||||
*/
|
||||
public function getVerbosity()
|
||||
{
|
||||
return $this->verbosity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output and adds a newline at the end.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines of a single string
|
||||
* @param integer $type The type of output
|
||||
*/
|
||||
public function writeln($messages, $type = 0)
|
||||
{
|
||||
$this->write($messages, true, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines of a single string
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
* @param integer $type The type of output
|
||||
*/
|
||||
public function write($messages, $newline = false, $type = 0)
|
||||
{
|
||||
if (self::VERBOSITY_QUIET === $this->verbosity)
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
|
||||
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
|
||||
*/
|
||||
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null)
|
||||
{
|
||||
return;
|
||||
$this->decorated = (Boolean) $decorated;
|
||||
$this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
|
||||
}
|
||||
|
||||
if (!is_array($messages))
|
||||
/**
|
||||
* Sets a new style.
|
||||
*
|
||||
* @param string $name The style name
|
||||
* @param array $options An array of options
|
||||
*/
|
||||
static public function setStyle($name, $options = array())
|
||||
{
|
||||
$messages = array($messages);
|
||||
static::$styles[strtolower($name)] = $options;
|
||||
}
|
||||
|
||||
foreach ($messages as $message)
|
||||
/**
|
||||
* Sets the decorated flag.
|
||||
*
|
||||
* @param Boolean $decorated Whether to decorated the messages or not
|
||||
*/
|
||||
public function setDecorated($decorated)
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case Output::OUTPUT_NORMAL:
|
||||
$message = $this->format($message);
|
||||
break;
|
||||
case Output::OUTPUT_RAW:
|
||||
break;
|
||||
case Output::OUTPUT_PLAIN:
|
||||
$message = strip_tags($this->format($message));
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type));
|
||||
}
|
||||
|
||||
$this->doWrite($message, $newline);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string $message A message to write to the output
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
*/
|
||||
abstract public function doWrite($message, $newline);
|
||||
|
||||
/**
|
||||
* Formats a message according to the given styles.
|
||||
*
|
||||
* @param string $message The message to style
|
||||
*
|
||||
* @return string The styled message
|
||||
*/
|
||||
protected function format($message)
|
||||
{
|
||||
$message = preg_replace_callback('#<([a-z][a-z0-9\-_]+)>#i', array($this, 'replaceStartStyle'), $message);
|
||||
|
||||
return preg_replace_callback('#</([a-z][a-z0-9\-_]+)>#i', array($this, 'replaceEndStyle'), $message);
|
||||
}
|
||||
|
||||
protected function replaceStartStyle($match)
|
||||
{
|
||||
if (!$this->decorated)
|
||||
{
|
||||
return '';
|
||||
$this->decorated = (Boolean) $decorated;
|
||||
}
|
||||
|
||||
if (!isset(static::$styles[strtolower($match[1])]))
|
||||
/**
|
||||
* Gets the decorated flag.
|
||||
*
|
||||
* @return Boolean true if the output will decorate messages, false otherwise
|
||||
*/
|
||||
public function isDecorated()
|
||||
{
|
||||
throw new \InvalidArgumentException(sprintf('Unknown style "%s".', $match[1]));
|
||||
return $this->decorated;
|
||||
}
|
||||
|
||||
$parameters = static::$styles[strtolower($match[1])];
|
||||
$codes = array();
|
||||
|
||||
if (isset($parameters['fg']))
|
||||
/**
|
||||
* Sets the verbosity of the output.
|
||||
*
|
||||
* @param integer $level The level of verbosity
|
||||
*/
|
||||
public function setVerbosity($level)
|
||||
{
|
||||
$codes[] = static::$foreground[$parameters['fg']];
|
||||
$this->verbosity = (int) $level;
|
||||
}
|
||||
|
||||
if (isset($parameters['bg']))
|
||||
/**
|
||||
* Gets the current verbosity of the output.
|
||||
*
|
||||
* @return integer The current level of verbosity
|
||||
*/
|
||||
public function getVerbosity()
|
||||
{
|
||||
$codes[] = static::$background[$parameters['bg']];
|
||||
return $this->verbosity;
|
||||
}
|
||||
|
||||
foreach (static::$options as $option => $value)
|
||||
/**
|
||||
* Writes a message to the output and adds a newline at the end.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines of a single string
|
||||
* @param integer $type The type of output
|
||||
*/
|
||||
public function writeln($messages, $type = 0)
|
||||
{
|
||||
if (isset($parameters[$option]) && $parameters[$option])
|
||||
{
|
||||
$codes[] = $value;
|
||||
}
|
||||
$this->write($messages, true, $type);
|
||||
}
|
||||
|
||||
return "\033[".implode(';', $codes)."m";
|
||||
}
|
||||
|
||||
protected function replaceEndStyle($match)
|
||||
{
|
||||
if (!$this->decorated)
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines of a single string
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
* @param integer $type The type of output
|
||||
*
|
||||
* @throws \InvalidArgumentException When unknown output type is given
|
||||
*/
|
||||
public function write($messages, $newline = false, $type = 0)
|
||||
{
|
||||
return '';
|
||||
if (self::VERBOSITY_QUIET === $this->verbosity) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_array($messages)) {
|
||||
$messages = array($messages);
|
||||
}
|
||||
|
||||
foreach ($messages as $message) {
|
||||
switch ($type) {
|
||||
case Output::OUTPUT_NORMAL:
|
||||
$message = $this->format($message);
|
||||
break;
|
||||
case Output::OUTPUT_RAW:
|
||||
break;
|
||||
case Output::OUTPUT_PLAIN:
|
||||
$message = strip_tags($this->format($message));
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type));
|
||||
}
|
||||
|
||||
$this->doWrite($message, $newline);
|
||||
}
|
||||
}
|
||||
|
||||
return "\033[0m";
|
||||
}
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string $message A message to write to the output
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
*/
|
||||
abstract public function doWrite($message, $newline);
|
||||
|
||||
/**
|
||||
* Formats a message according to the given styles.
|
||||
*
|
||||
* @param string $message The message to style
|
||||
*
|
||||
* @return string The styled message
|
||||
*/
|
||||
protected function format($message)
|
||||
{
|
||||
$message = preg_replace_callback('#<([a-z][a-z0-9\-_=;]+)>#i', array($this, 'replaceStartStyle'), $message);
|
||||
|
||||
return preg_replace_callback('#</([a-z][a-z0-9\-_]*)?>#i', array($this, 'replaceEndStyle'), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException When style is unknown
|
||||
*/
|
||||
protected function replaceStartStyle($match)
|
||||
{
|
||||
if (!$this->decorated) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (isset(static::$styles[strtolower($match[1])])) {
|
||||
$parameters = static::$styles[strtolower($match[1])];
|
||||
} else {
|
||||
// bg=blue;fg=red
|
||||
if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($match[1]), $matches, PREG_SET_ORDER)) {
|
||||
throw new \InvalidArgumentException(sprintf('Unknown style "%s".', $match[1]));
|
||||
}
|
||||
|
||||
$parameters = array();
|
||||
foreach ($matches as $match) {
|
||||
$parameters[$match[1]] = $match[2];
|
||||
}
|
||||
}
|
||||
|
||||
$codes = array();
|
||||
|
||||
if (isset($parameters['fg'])) {
|
||||
$codes[] = static::$foreground[$parameters['fg']];
|
||||
}
|
||||
|
||||
if (isset($parameters['bg'])) {
|
||||
$codes[] = static::$background[$parameters['bg']];
|
||||
}
|
||||
|
||||
foreach (static::$options as $option => $value) {
|
||||
if (isset($parameters[$option]) && $parameters[$option]) {
|
||||
$codes[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return "\033[".implode(';', $codes).'m';
|
||||
}
|
||||
|
||||
protected function replaceEndStyle($match)
|
||||
{
|
||||
if (!$this->decorated) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return "\033[0m";
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Output;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -14,31 +14,32 @@ namespace Symfony\Component\Console\Output;
|
||||
/**
|
||||
* OutputInterface is the interface implemented by all Output classes.
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
interface OutputInterface
|
||||
{
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines of a single string
|
||||
* @param integer $type The type of output
|
||||
*/
|
||||
public function write($messages, $type = 0);
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines of a single string
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
* @param integer $type The type of output
|
||||
*
|
||||
* @throws \InvalidArgumentException When unknown output type is given
|
||||
*/
|
||||
function write($messages, $newline = false, $type = 0);
|
||||
|
||||
/**
|
||||
* Sets the verbosity of the output.
|
||||
*
|
||||
* @param integer $level The level of verbosity
|
||||
*/
|
||||
public function setVerbosity($level);
|
||||
/**
|
||||
* Sets the verbosity of the output.
|
||||
*
|
||||
* @param integer $level The level of verbosity
|
||||
*/
|
||||
function setVerbosity($level);
|
||||
|
||||
/**
|
||||
* Sets the decorated flag.
|
||||
*
|
||||
* @param Boolean $decorated Whether to decorated the messages or not
|
||||
*/
|
||||
public function setDecorated($decorated);
|
||||
/**
|
||||
* Sets the decorated flag.
|
||||
*
|
||||
* @param Boolean $decorated Whether to decorated the messages or not
|
||||
*/
|
||||
function setDecorated($decorated);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Component\Console\Output;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -22,88 +22,84 @@ namespace Symfony\Component\Console\Output;
|
||||
*
|
||||
* $output = new StreamOutput(fopen('/path/to/output.log', 'a', false));
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage console
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class StreamOutput extends Output
|
||||
{
|
||||
protected $stream;
|
||||
protected $stream;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param mixed $stream A stream resource
|
||||
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
|
||||
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
|
||||
*/
|
||||
public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null)
|
||||
{
|
||||
if (!is_resource($stream) || 'stream' !== get_resource_type($stream))
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param mixed $stream A stream resource
|
||||
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
|
||||
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
|
||||
*
|
||||
* @throws \InvalidArgumentException When first argument is not a real stream
|
||||
*/
|
||||
public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null)
|
||||
{
|
||||
throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
|
||||
if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
|
||||
throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
|
||||
}
|
||||
|
||||
$this->stream = $stream;
|
||||
|
||||
if (null === $decorated) {
|
||||
$decorated = $this->hasColorSupport($decorated);
|
||||
}
|
||||
|
||||
parent::__construct($verbosity, $decorated);
|
||||
}
|
||||
|
||||
$this->stream = $stream;
|
||||
|
||||
if (null === $decorated)
|
||||
/**
|
||||
* Gets the stream attached to this StreamOutput instance.
|
||||
*
|
||||
* @return resource A stream resource
|
||||
*/
|
||||
public function getStream()
|
||||
{
|
||||
$decorated = $this->hasColorSupport($decorated);
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
parent::__construct($verbosity, $decorated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the stream attached to this StreamOutput instance.
|
||||
*
|
||||
* @return resource A stream resource
|
||||
*/
|
||||
public function getStream()
|
||||
{
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string $message A message to write to the output
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
*/
|
||||
public function doWrite($message, $newline)
|
||||
{
|
||||
if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : '')))
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string $message A message to write to the output
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
*
|
||||
* @throws \RuntimeException When unable to write output (should never happen)
|
||||
*/
|
||||
public function doWrite($message, $newline)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
// should never happen
|
||||
throw new \RuntimeException('Unable to write output.');
|
||||
// @codeCoverageIgnoreEnd
|
||||
if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) {
|
||||
// @codeCoverageIgnoreStart
|
||||
// should never happen
|
||||
throw new \RuntimeException('Unable to write output.');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the stream supports colorization.
|
||||
*
|
||||
* Colorization is disabled if not supported by the stream:
|
||||
*
|
||||
* - windows without ansicon
|
||||
* - non tty consoles
|
||||
*
|
||||
* @return Boolean true if the stream supports colorization, false otherwise
|
||||
*/
|
||||
protected function hasColorSupport()
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if (DIRECTORY_SEPARATOR == '\\')
|
||||
/**
|
||||
* Returns true if the stream supports colorization.
|
||||
*
|
||||
* Colorization is disabled if not supported by the stream:
|
||||
*
|
||||
* - windows without ansicon
|
||||
* - non tty consoles
|
||||
*
|
||||
* @return Boolean true if the stream supports colorization, false otherwise
|
||||
*/
|
||||
protected function hasColorSupport()
|
||||
{
|
||||
return false !== getenv('ANSICON');
|
||||
// @codeCoverageIgnoreStart
|
||||
if (DIRECTORY_SEPARATOR == '\\') {
|
||||
return false !== getenv('ANSICON');
|
||||
} else {
|
||||
return function_exists('posix_isatty') && @posix_isatty($this->stream);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
else
|
||||
{
|
||||
return function_exists('posix_isatty') && @posix_isatty($this->stream);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
178
lib/vendor/Symfony/Component/Console/Shell.php
vendored
178
lib/vendor/Symfony/Component/Console/Shell.php
vendored
@ -7,7 +7,7 @@ use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
/*
|
||||
* This file is part of the symfony framework.
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
@ -21,118 +21,108 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
* This class only works with a PHP compiled with readline support
|
||||
* (either --with-readline or --with-libedit)
|
||||
*
|
||||
* @package symfony
|
||||
* @subpackage cli
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class Shell
|
||||
{
|
||||
protected $application;
|
||||
protected $history;
|
||||
protected $output;
|
||||
protected $application;
|
||||
protected $history;
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* If there is no readline support for the current PHP executable
|
||||
* a \RuntimeException exception is thrown.
|
||||
*
|
||||
* @param Application $application An application instance
|
||||
*/
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
if (!function_exists('readline'))
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* If there is no readline support for the current PHP executable
|
||||
* a \RuntimeException exception is thrown.
|
||||
*
|
||||
* @param Application $application An application instance
|
||||
*
|
||||
* @throws \RuntimeException When Readline extension is not enabled
|
||||
*/
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
throw new \RuntimeException('Unable to start the shell as the Readline extension is not enabled.');
|
||||
if (!function_exists('readline')) {
|
||||
throw new \RuntimeException('Unable to start the shell as the Readline extension is not enabled.');
|
||||
}
|
||||
|
||||
$this->application = $application;
|
||||
$this->history = getenv('HOME').'/.history_'.$application->getName();
|
||||
$this->output = new ConsoleOutput();
|
||||
}
|
||||
|
||||
$this->application = $application;
|
||||
$this->history = getenv('HOME').'/.history_'.$application->getName();
|
||||
$this->output = new ConsoleOutput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the shell.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->application->setAutoExit(false);
|
||||
$this->application->setCatchExceptions(true);
|
||||
|
||||
readline_read_history($this->history);
|
||||
readline_completion_function(array($this, 'autocompleter'));
|
||||
|
||||
$this->output->writeln($this->getHeader());
|
||||
while (true)
|
||||
/**
|
||||
* Runs the shell.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$command = readline($this->application->getName().' > ');
|
||||
$this->application->setAutoExit(false);
|
||||
$this->application->setCatchExceptions(true);
|
||||
|
||||
if (false === $command)
|
||||
{
|
||||
$this->output->writeln("\n");
|
||||
readline_read_history($this->history);
|
||||
readline_completion_function(array($this, 'autocompleter'));
|
||||
|
||||
break;
|
||||
}
|
||||
$this->output->writeln($this->getHeader());
|
||||
while (true) {
|
||||
$command = readline($this->application->getName().' > ');
|
||||
|
||||
readline_add_history($command);
|
||||
readline_write_history($this->history);
|
||||
if (false === $command) {
|
||||
$this->output->writeln("\n");
|
||||
|
||||
if (0 !== $ret = $this->application->run(new StringInput($command), $this->output))
|
||||
{
|
||||
$this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to return autocompletion for the current entered text.
|
||||
*
|
||||
* @param string $text The last segment of the entered text
|
||||
* @param integer $position The current position
|
||||
*/
|
||||
protected function autocompleter($text, $position)
|
||||
{
|
||||
$info = readline_info();
|
||||
$text = substr($info['line_buffer'], 0, $info['end']);
|
||||
readline_add_history($command);
|
||||
readline_write_history($this->history);
|
||||
|
||||
if ($info['point'] !== $info['end'])
|
||||
{
|
||||
return true;
|
||||
if (0 !== $ret = $this->application->run(new StringInput($command), $this->output)) {
|
||||
$this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// task name?
|
||||
if (false === strpos($text, ' ') || !$text)
|
||||
/**
|
||||
* Tries to return autocompletion for the current entered text.
|
||||
*
|
||||
* @param string $text The last segment of the entered text
|
||||
* @param integer $position The current position
|
||||
*/
|
||||
protected function autocompleter($text, $position)
|
||||
{
|
||||
return array_keys($this->application->getCommands());
|
||||
$info = readline_info();
|
||||
$text = substr($info['line_buffer'], 0, $info['end']);
|
||||
|
||||
if ($info['point'] !== $info['end']) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// task name?
|
||||
if (false === strpos($text, ' ') || !$text) {
|
||||
return array_keys($this->application->all());
|
||||
}
|
||||
|
||||
// options and arguments?
|
||||
try {
|
||||
$command = $this->application->findCommand(substr($text, 0, strpos($text, ' ')));
|
||||
} catch (\Exception $e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$list = array('--help');
|
||||
foreach ($command->getDefinition()->getOptions() as $option) {
|
||||
$list[] = '--'.$option->getName();
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
// options and arguments?
|
||||
try
|
||||
/**
|
||||
* Returns the shell header.
|
||||
*
|
||||
* @return string The header string
|
||||
*/
|
||||
protected function getHeader()
|
||||
{
|
||||
$command = $this->application->findCommand(substr($text, 0, strpos($text, ' ')));
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$list = array('--help');
|
||||
foreach ($command->getDefinition()->getOptions() as $option)
|
||||
{
|
||||
$list[] = '--'.$option->getName();
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shell header.
|
||||
*
|
||||
* @return string The header string
|
||||
*/
|
||||
protected function getHeader()
|
||||
{
|
||||
return <<<EOF
|
||||
return <<<EOF
|
||||
|
||||
Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).
|
||||
|
||||
@ -142,5 +132,5 @@ or <comment>list</comment> to get a list available commands.
|
||||
To exit the shell, type <comment>^D</comment>.
|
||||
|
||||
EOF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,87 +6,96 @@ use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\StreamOutput;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class ApplicationTester
|
||||
{
|
||||
protected $application;
|
||||
protected $display;
|
||||
protected $input;
|
||||
protected $output;
|
||||
protected $application;
|
||||
protected $display;
|
||||
protected $input;
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Application $application A Application instance to test.
|
||||
*/
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the application.
|
||||
*
|
||||
* Available options:
|
||||
*
|
||||
* * interactive: Sets the input interactive flag
|
||||
* * decorated: Sets the output decorated flag
|
||||
* * verbosity: Sets the output verbosity flag
|
||||
*
|
||||
* @param array $input An array of arguments and options
|
||||
* @param array $options An array of options
|
||||
*/
|
||||
public function run(array $input, $options = array())
|
||||
{
|
||||
$this->input = new ArrayInput($input);
|
||||
if (isset($options['interactive']))
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Application $application A Application instance to test.
|
||||
*/
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
$this->input->setInteractive($options['interactive']);
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
|
||||
if (isset($options['decorated']))
|
||||
/**
|
||||
* Executes the application.
|
||||
*
|
||||
* Available options:
|
||||
*
|
||||
* * interactive: Sets the input interactive flag
|
||||
* * decorated: Sets the output decorated flag
|
||||
* * verbosity: Sets the output verbosity flag
|
||||
*
|
||||
* @param array $input An array of arguments and options
|
||||
* @param array $options An array of options
|
||||
*/
|
||||
public function run(array $input, $options = array())
|
||||
{
|
||||
$this->output->setDecorated($options['decorated']);
|
||||
}
|
||||
if (isset($options['verbosity']))
|
||||
{
|
||||
$this->output->setVerbosity($options['verbosity']);
|
||||
$this->input = new ArrayInput($input);
|
||||
if (isset($options['interactive'])) {
|
||||
$this->input->setInteractive($options['interactive']);
|
||||
}
|
||||
|
||||
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
|
||||
if (isset($options['decorated'])) {
|
||||
$this->output->setDecorated($options['decorated']);
|
||||
}
|
||||
if (isset($options['verbosity'])) {
|
||||
$this->output->setVerbosity($options['verbosity']);
|
||||
}
|
||||
|
||||
$ret = $this->application->run($this->input, $this->output);
|
||||
|
||||
rewind($this->output->getStream());
|
||||
|
||||
return $this->display = stream_get_contents($this->output->getStream());
|
||||
}
|
||||
|
||||
$ret = $this->application->run($this->input, $this->output);
|
||||
/**
|
||||
* Gets the display returned by the last execution of the application.
|
||||
*
|
||||
* @return string The display
|
||||
*/
|
||||
public function getDisplay()
|
||||
{
|
||||
return $this->display;
|
||||
}
|
||||
|
||||
rewind($this->output->getStream());
|
||||
/**
|
||||
* Gets the input instance used by the last execution of the application.
|
||||
*
|
||||
* @return InputInterface The current input instance
|
||||
*/
|
||||
public function getInput()
|
||||
{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
return $this->display = stream_get_contents($this->output->getStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display returned by the last execution of the application.
|
||||
*
|
||||
* @return string The display
|
||||
*/
|
||||
public function getDisplay()
|
||||
{
|
||||
return $this->display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input instance used by the last execution of the application.
|
||||
*
|
||||
* @return InputInterface The current input instance
|
||||
*/
|
||||
public function getInput()
|
||||
{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the output instance used by the last execution of the application.
|
||||
*
|
||||
* @return OutputInterface The current output instance
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
/**
|
||||
* Gets the output instance used by the last execution of the application.
|
||||
*
|
||||
* @return OutputInterface The current output instance
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
}
|
||||
|
@ -6,87 +6,96 @@ use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\StreamOutput;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class CommandTester
|
||||
{
|
||||
protected $command;
|
||||
protected $display;
|
||||
protected $input;
|
||||
protected $output;
|
||||
protected $command;
|
||||
protected $display;
|
||||
protected $input;
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Command $command A Command instance to test.
|
||||
*/
|
||||
public function __construct(Command $command)
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command.
|
||||
*
|
||||
* Available options:
|
||||
*
|
||||
* * interactive: Sets the input interactive flag
|
||||
* * decorated: Sets the output decorated flag
|
||||
* * verbosity: Sets the output verbosity flag
|
||||
*
|
||||
* @param array $input An array of arguments and options
|
||||
* @param array $options An array of options
|
||||
*/
|
||||
public function execute(array $input, array $options = array())
|
||||
{
|
||||
$this->input = new ArrayInput(array_merge($input, array('command' => $this->command->getFullName())));
|
||||
if (isset($options['interactive']))
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Command $command A Command instance to test.
|
||||
*/
|
||||
public function __construct(Command $command)
|
||||
{
|
||||
$this->input->setInteractive($options['interactive']);
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
|
||||
if (isset($options['decorated']))
|
||||
/**
|
||||
* Executes the command.
|
||||
*
|
||||
* Available options:
|
||||
*
|
||||
* * interactive: Sets the input interactive flag
|
||||
* * decorated: Sets the output decorated flag
|
||||
* * verbosity: Sets the output verbosity flag
|
||||
*
|
||||
* @param array $input An array of arguments and options
|
||||
* @param array $options An array of options
|
||||
*/
|
||||
public function execute(array $input, array $options = array())
|
||||
{
|
||||
$this->output->setDecorated($options['decorated']);
|
||||
}
|
||||
if (isset($options['verbosity']))
|
||||
{
|
||||
$this->output->setVerbosity($options['verbosity']);
|
||||
$this->input = new ArrayInput($input);
|
||||
if (isset($options['interactive'])) {
|
||||
$this->input->setInteractive($options['interactive']);
|
||||
}
|
||||
|
||||
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
|
||||
if (isset($options['decorated'])) {
|
||||
$this->output->setDecorated($options['decorated']);
|
||||
}
|
||||
if (isset($options['verbosity'])) {
|
||||
$this->output->setVerbosity($options['verbosity']);
|
||||
}
|
||||
|
||||
$ret = $this->command->run($this->input, $this->output);
|
||||
|
||||
rewind($this->output->getStream());
|
||||
|
||||
return $this->display = stream_get_contents($this->output->getStream());
|
||||
}
|
||||
|
||||
$ret = $this->command->run($this->input, $this->output);
|
||||
/**
|
||||
* Gets the display returned by the last execution of the command.
|
||||
*
|
||||
* @return string The display
|
||||
*/
|
||||
public function getDisplay()
|
||||
{
|
||||
return $this->display;
|
||||
}
|
||||
|
||||
rewind($this->output->getStream());
|
||||
/**
|
||||
* Gets the input instance used by the last execution of the command.
|
||||
*
|
||||
* @return InputInterface The current input instance
|
||||
*/
|
||||
public function getInput()
|
||||
{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
return $this->display = stream_get_contents($this->output->getStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display returned by the last execution of the command.
|
||||
*
|
||||
* @return string The display
|
||||
*/
|
||||
public function getDisplay()
|
||||
{
|
||||
return $this->display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input instance used by the last execution of the command.
|
||||
*
|
||||
* @return InputInterface The current input instance
|
||||
*/
|
||||
public function getInput()
|
||||
{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the output instance used by the last execution of the command.
|
||||
*
|
||||
* @return OutputInterface The current output instance
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
/**
|
||||
* Gets the output instance used by the last execution of the command.
|
||||
*
|
||||
* @return OutputInterface The current output instance
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
}
|
||||
|
2
lib/vendor/doctrine-common
vendored
2
lib/vendor/doctrine-common
vendored
@ -1 +1 @@
|
||||
Subproject commit 3b5123434e979c7adfd42061484b5a8f10a3431b
|
||||
Subproject commit 9eb66b7cf90919ff64281f7e476530fd879cefe4
|
2
lib/vendor/doctrine-dbal
vendored
2
lib/vendor/doctrine-dbal
vendored
@ -1 +1 @@
|
||||
Subproject commit ce1e5f0f9c4f2e8894e1d2036ab11cc0597dd0a4
|
||||
Subproject commit e97fbbf755ea7bc5d575d71778501a73f72a4ecb
|
@ -8,7 +8,7 @@ namespace Doctrine\Tests\Models\Company;
|
||||
class CompanyFixContract extends CompanyContract
|
||||
{
|
||||
/**
|
||||
* @column(type="integer", nullable=true)
|
||||
* @column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
private $fixPrice = 0;
|
||||
|
@ -7,13 +7,13 @@ namespace Doctrine\Tests\Models\Company;
|
||||
class CompanyFlexContract extends CompanyContract
|
||||
{
|
||||
/**
|
||||
* @column(type="integer", nullable=true)
|
||||
* @column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
private $hoursWorked = 0;
|
||||
|
||||
/**
|
||||
* @column(type="integer", nullable=true)
|
||||
* @column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
private $pricePerHour = 0;
|
||||
|
@ -8,7 +8,7 @@ namespace Doctrine\Tests\Models\Company;
|
||||
class CompanyFlexUltraContract extends CompanyFlexContract
|
||||
{
|
||||
/**
|
||||
* @column(type="integer", nullable=true)
|
||||
* @column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
private $maxPrice = 0;
|
||||
|
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\Models\DirectoryTree;
|
||||
|
||||
/**
|
||||
* @MappedSuperclass
|
||||
*/
|
||||
abstract class AbstractContentItem
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer") @GeneratedValue
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="Directory")
|
||||
*/
|
||||
protected $parentDirectory;
|
||||
|
||||
/** @column(type="string") */
|
||||
protected $name;
|
||||
|
||||
public function __construct(Directory $parentDir = null)
|
||||
{
|
||||
$this->parentDirectory = $parentDir;
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getParent()
|
||||
{
|
||||
return $this->parentDirectory;
|
||||
}
|
||||
}
|
41
tests/Doctrine/Tests/Models/DirectoryTree/Directory.php
Normal file
41
tests/Doctrine/Tests/Models/DirectoryTree/Directory.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\Models\DirectoryTree;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class Directory extends AbstractContentItem
|
||||
{
|
||||
/**
|
||||
* @Column(type="string")
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
46
tests/Doctrine/Tests/Models/DirectoryTree/File.php
Normal file
46
tests/Doctrine/Tests/Models/DirectoryTree/File.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
|
||||
namespace Doctrine\Tests\Models\DirectoryTree;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="`file`")
|
||||
*/
|
||||
class File extends AbstractContentItem
|
||||
{
|
||||
/** @Column(type="string") */
|
||||
protected $extension = "html";
|
||||
|
||||
public function __construct(Directory $parent = null)
|
||||
{
|
||||
parent::__construct($parent);
|
||||
}
|
||||
|
||||
public function getExtension()
|
||||
{
|
||||
return $this->extension;
|
||||
}
|
||||
|
||||
public function setExtension($ext)
|
||||
{
|
||||
$this->extension = $ext;
|
||||
}
|
||||
}
|
@ -73,8 +73,8 @@ class ECommerceCategory
|
||||
public function removeProduct(ECommerceProduct $product)
|
||||
{
|
||||
$removed = $this->products->removeElement($product);
|
||||
if ($removed !== null) {
|
||||
$removed->removeCategory($this);
|
||||
if ($removed) {
|
||||
$product->removeCategory($this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,8 +114,8 @@ class ECommerceCategory
|
||||
public function removeChild(ECommerceCategory $child)
|
||||
{
|
||||
$removed = $this->children->removeElement($child);
|
||||
if ($removed !== null) {
|
||||
$removed->removeParent();
|
||||
if ($removed) {
|
||||
$child->removeParent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,11 +112,10 @@ class ECommerceProduct
|
||||
public function removeFeature(ECommerceFeature $feature)
|
||||
{
|
||||
$removed = $this->features->removeElement($feature);
|
||||
if ($removed !== null) {
|
||||
$removed->removeProduct();
|
||||
return true;
|
||||
if ($removed) {
|
||||
$feature->removeProduct();
|
||||
}
|
||||
return false;
|
||||
return $removed;
|
||||
}
|
||||
|
||||
public function addCategory(ECommerceCategory $category)
|
||||
@ -130,8 +129,8 @@ class ECommerceProduct
|
||||
public function removeCategory(ECommerceCategory $category)
|
||||
{
|
||||
$removed = $this->categories->removeElement($category);
|
||||
if ($removed !== null) {
|
||||
$removed->removeProduct($this);
|
||||
if ($removed) {
|
||||
$category->removeProduct($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,16 @@ class EntityManagerTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->_em = $this->_getTestEntityManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-899
|
||||
*/
|
||||
public function testIsOpen()
|
||||
{
|
||||
$this->assertTrue($this->_em->isOpen());
|
||||
$this->_em->close();
|
||||
$this->assertFalse($this->_em->isOpen());
|
||||
}
|
||||
|
||||
public function testGetConnection()
|
||||
{
|
||||
$this->assertType('\Doctrine\DBAL\Connection', $this->_em->getConnection());
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\ORM\Tools\SchemaTool;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
||||
use Doctrine\Tests\Models\CMS\CmsAddress;
|
||||
@ -263,7 +264,111 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->refresh($user);
|
||||
$this->assertEquals('developer', $user->status);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-833
|
||||
*/
|
||||
public function testRefreshResetsCollection()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Guilherme';
|
||||
$user->username = 'gblanco';
|
||||
$user->status = 'developer';
|
||||
|
||||
// Add a phonenumber
|
||||
$ph1 = new CmsPhonenumber;
|
||||
$ph1->phonenumber = "12345";
|
||||
$user->addPhonenumber($ph1);
|
||||
|
||||
// Add a phonenumber
|
||||
$ph2 = new CmsPhonenumber;
|
||||
$ph2->phonenumber = "54321";
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->persist($ph1);
|
||||
$this->_em->persist($ph2);
|
||||
$this->_em->flush();
|
||||
|
||||
$user->addPhonenumber($ph2);
|
||||
|
||||
$this->assertEquals(2, count($user->phonenumbers));
|
||||
$this->_em->refresh($user);
|
||||
|
||||
$this->assertEquals(1, count($user->phonenumbers));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-833
|
||||
*/
|
||||
public function testDqlRefreshResetsCollection()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Guilherme';
|
||||
$user->username = 'gblanco';
|
||||
$user->status = 'developer';
|
||||
|
||||
// Add a phonenumber
|
||||
$ph1 = new CmsPhonenumber;
|
||||
$ph1->phonenumber = "12345";
|
||||
$user->addPhonenumber($ph1);
|
||||
|
||||
// Add a phonenumber
|
||||
$ph2 = new CmsPhonenumber;
|
||||
$ph2->phonenumber = "54321";
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->persist($ph1);
|
||||
$this->_em->persist($ph2);
|
||||
$this->_em->flush();
|
||||
|
||||
$user->addPhonenumber($ph2);
|
||||
|
||||
$this->assertEquals(2, count($user->phonenumbers));
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1";
|
||||
$user = $this->_em->createQuery($dql)
|
||||
->setParameter(1, $user->id)
|
||||
->setHint(Query::HINT_REFRESH, true)
|
||||
->getSingleResult();
|
||||
|
||||
$this->assertEquals(1, count($user->phonenumbers));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-833
|
||||
*/
|
||||
public function testCreateEntityOfProxy()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Guilherme';
|
||||
$user->username = 'gblanco';
|
||||
$user->status = 'developer';
|
||||
|
||||
// Add a phonenumber
|
||||
$ph1 = new CmsPhonenumber;
|
||||
$ph1->phonenumber = "12345";
|
||||
$user->addPhonenumber($ph1);
|
||||
|
||||
// Add a phonenumber
|
||||
$ph2 = new CmsPhonenumber;
|
||||
$ph2->phonenumber = "54321";
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->persist($ph1);
|
||||
$this->_em->persist($ph2);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$userId = $user->id;
|
||||
$user = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $user->id);
|
||||
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1";
|
||||
$user = $this->_em->createQuery($dql)
|
||||
->setParameter(1, $userId)
|
||||
->getSingleResult();
|
||||
|
||||
$this->assertEquals(1, count($user->phonenumbers));
|
||||
}
|
||||
|
||||
public function testAddToCollectionDoesNotInitialize()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
|
@ -353,4 +353,61 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals($manager->getId(), $dqlManager->getId());
|
||||
$this->assertEquals($person->getId(), $dqlManager->getSpouse()->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-817
|
||||
*/
|
||||
public function testFindByAssociation()
|
||||
{
|
||||
$manager = new CompanyManager();
|
||||
$manager->setName('gblanco');
|
||||
$manager->setSalary(1234);
|
||||
$manager->setTitle('Awesome!');
|
||||
$manager->setDepartment('IT');
|
||||
|
||||
$person = new CompanyPerson();
|
||||
$person->setName('spouse');
|
||||
|
||||
$manager->setSpouse($person);
|
||||
|
||||
$this->_em->persist($manager);
|
||||
$this->_em->persist($person);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyManager');
|
||||
$pmanager = $repos->findOneBy(array('spouse' => $person->getId()));
|
||||
|
||||
$this->assertEquals($manager->getId(), $pmanager->getId());
|
||||
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyPerson');
|
||||
$pmanager = $repos->findOneBy(array('spouse' => $person->getId()));
|
||||
|
||||
$this->assertEquals($manager->getId(), $pmanager->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-834
|
||||
*/
|
||||
public function testGetReferenceEntityWithSubclasses()
|
||||
{
|
||||
$manager = new CompanyManager();
|
||||
$manager->setName('gblanco');
|
||||
$manager->setSalary(1234);
|
||||
$manager->setTitle('Awesome!');
|
||||
$manager->setDepartment('IT');
|
||||
|
||||
$this->_em->persist($manager);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$ref = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyPerson', $manager->getId());
|
||||
$this->assertNotType('Doctrine\ORM\Proxy\Proxy', $ref, "Cannot Request a proxy from a class that has subclasses.");
|
||||
$this->assertType('Doctrine\Tests\Models\Company\CompanyPerson', $ref);
|
||||
$this->assertType('Doctrine\Tests\Models\Company\CompanyEmployee', $ref, "Direct fetch of the reference has to load the child class Emplyoee directly.");
|
||||
$this->_em->clear();
|
||||
|
||||
$ref = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyManager', $manager->getId());
|
||||
$this->assertType('Doctrine\ORM\Proxy\Proxy', $ref, "A proxy can be generated only if no subclasses exists for the requested reference.");
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$user->status = 'developer';
|
||||
|
||||
$ph1 = new CmsPhonenumber;
|
||||
$ph1->phonenumber = 1234;
|
||||
$ph1->phonenumber = "1234";
|
||||
$user->addPhonenumber($ph1);
|
||||
|
||||
$this->_em->persist($user);
|
||||
@ -68,24 +68,36 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
unset($user);
|
||||
|
||||
$user = unserialize($serialized);
|
||||
|
||||
$this->assertEquals(1, count($user->getPhonenumbers()), "Pre-Condition: 1 Phonenumber");
|
||||
|
||||
$ph2 = new CmsPhonenumber;
|
||||
$ph2->phonenumber = 56789;
|
||||
$ph2->phonenumber = "56789";
|
||||
$user->addPhonenumber($ph2);
|
||||
$this->assertEquals(2, count($user->getPhonenumbers()));
|
||||
$oldPhonenumbers = $user->getPhonenumbers();
|
||||
$this->assertEquals(2, count($oldPhonenumbers), "Pre-Condition: 2 Phonenumbers");
|
||||
$this->assertFalse($this->_em->contains($user));
|
||||
|
||||
$this->_em->persist($ph2);
|
||||
|
||||
|
||||
// Merge back in
|
||||
$user = $this->_em->merge($user); // merge cascaded to phonenumbers
|
||||
$this->assertType('Doctrine\Tests\Models\CMS\CmsUser', $user->phonenumbers[0]->user);
|
||||
$this->assertType('Doctrine\Tests\Models\CMS\CmsUser', $user->phonenumbers[1]->user);
|
||||
$im = $this->_em->getUnitOfWork()->getIdentityMap();
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertTrue($this->_em->contains($user));
|
||||
$this->assertEquals(2, count($user->getPhonenumbers()));
|
||||
$this->assertTrue($this->_em->contains($user), "Failed to assert that merged user is contained inside EntityManager persistence context.");
|
||||
$phonenumbers = $user->getPhonenumbers();
|
||||
$this->assertTrue($this->_em->contains($phonenumbers[0]));
|
||||
$this->assertTrue($this->_em->contains($phonenumbers[1]));
|
||||
$this->assertNotSame($oldPhonenumbers, $phonenumbers, "Merge should replace the Detached Collection with a new PersistentCollection.");
|
||||
$this->assertEquals(2, count($phonenumbers), "Failed to assert that two phonenumbers are contained in the merged users phonenumber collection.");
|
||||
|
||||
$this->assertType('Doctrine\Tests\Models\CMS\CmsPhonenumber', $phonenumbers[1]);
|
||||
$this->assertTrue($this->_em->contains($phonenumbers[1]), "Failed to assert that second phonenumber in collection is contained inside EntityManager persistence context.");
|
||||
|
||||
$this->assertType('Doctrine\Tests\Models\CMS\CmsPhonenumber', $phonenumbers[0]);
|
||||
$this->assertTrue($this->_em->getUnitOfWork()->isInIdentityMap($phonenumbers[0]));
|
||||
$this->assertTrue($this->_em->contains($phonenumbers[0]), "Failed to assert that first phonenumber in collection is contained inside EntityManager persistence context.");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,8 +117,8 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
} catch (\Exception $expected) {}
|
||||
}
|
||||
|
||||
public function testUninitializedLazyAssociationsAreIgnoredOnMerge() {
|
||||
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
|
||||
public function testUninitializedLazyAssociationsAreIgnoredOnMerge()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Guilherme';
|
||||
$user->username = 'gblanco';
|
||||
@ -136,5 +148,49 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertFalse($managedAddress2->user === $detachedAddress2->user);
|
||||
$this->assertFalse($managedAddress2->user->__isInitialized__);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-822
|
||||
*/
|
||||
public function testUseDetachedEntityAsQueryParameter()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Guilherme';
|
||||
$user->username = 'gblanco';
|
||||
$user->status = 'developer';
|
||||
|
||||
$this->_em->persist($user);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->detach($user);
|
||||
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1";
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$query->setParameter(1, $user);
|
||||
|
||||
$newUser = $query->getSingleResult();
|
||||
|
||||
$this->assertType('Doctrine\Tests\Models\CMS\CmsUser', $newUser);
|
||||
$this->assertEquals('gblanco', $newUser->username);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-920
|
||||
*/
|
||||
public function testDetachManagedUnpersistedEntity()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Guilherme';
|
||||
$user->username = 'gblanco';
|
||||
$user->status = 'developer';
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->detach($user);
|
||||
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertFalse($this->_em->contains($user));
|
||||
$this->assertFalse($this->_em->getUnitOfWork()->isInIdentityMap($user));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
||||
use Doctrine\Tests\Models\CMS\CmsAddress;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
@ -19,7 +20,8 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testBasicFinders() {
|
||||
public function loadFixture()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Roman';
|
||||
$user->username = 'romanb';
|
||||
@ -38,35 +40,58 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
unset($user2);
|
||||
$this->_em->clear();
|
||||
|
||||
return $user1Id;
|
||||
}
|
||||
|
||||
public function testBasicFind()
|
||||
{
|
||||
$user1Id = $this->loadFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$user = $repos->find($user1Id);
|
||||
$this->assertTrue($user instanceof CmsUser);
|
||||
$this->assertEquals('Roman', $user->name);
|
||||
$this->assertEquals('freak', $user->status);
|
||||
}
|
||||
|
||||
$this->_em->clear();
|
||||
public function testFindByField()
|
||||
{
|
||||
$user1Id = $this->loadFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$users = $repos->findBy(array('status' => 'dev'));
|
||||
$this->assertEquals(1, count($users));
|
||||
$this->assertTrue($users[0] instanceof CmsUser);
|
||||
$this->assertEquals('Guilherme', $users[0]->name);
|
||||
$this->assertEquals('dev', $users[0]->status);
|
||||
}
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
public function testFindFieldByMagicCall()
|
||||
{
|
||||
$user1Id = $this->loadFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$users = $repos->findByStatus('dev');
|
||||
$this->assertEquals(1, count($users));
|
||||
$this->assertTrue($users[0] instanceof CmsUser);
|
||||
$this->assertEquals('Guilherme', $users[0]->name);
|
||||
$this->assertEquals('dev', $users[0]->status);
|
||||
|
||||
$this->_em->clear();
|
||||
}
|
||||
|
||||
public function testFindAll()
|
||||
{
|
||||
$user1Id = $this->loadFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$users = $repos->findAll();
|
||||
$this->assertEquals(2, count($users));
|
||||
}
|
||||
|
||||
$this->_em->clear();
|
||||
public function testFindByAlias()
|
||||
{
|
||||
$user1Id = $this->loadFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$this->_em->getConfiguration()->addEntityNamespace('CMS', 'Doctrine\Tests\Models\CMS');
|
||||
|
||||
@ -74,8 +99,12 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$users = $repos->findAll();
|
||||
$this->assertEquals(2, count($users));
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->_em->getConfiguration()->setEntityNamespaces(array());
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,5 +179,116 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->setExpectedException('Doctrine\ORM\OptimisticLockException');
|
||||
$this->_em->find('Doctrine\Tests\Models\Cms\CmsUser', $userId, \Doctrine\DBAL\LockMode::OPTIMISTIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-819
|
||||
*/
|
||||
public function testFindMagicCallByNullValue()
|
||||
{
|
||||
$this->loadFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$this->setExpectedException('Doctrine\ORM\ORMException');
|
||||
$users = $repos->findByStatus(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-819
|
||||
*/
|
||||
public function testInvalidMagicCall()
|
||||
{
|
||||
$this->setExpectedException('BadMethodCallException');
|
||||
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$repos->foo();
|
||||
}
|
||||
|
||||
public function loadAssociatedFixture()
|
||||
{
|
||||
$address = new CmsAddress();
|
||||
$address->city = "Berlin";
|
||||
$address->country = "Germany";
|
||||
$address->street = "Foostreet";
|
||||
$address->zip = "12345";
|
||||
|
||||
$user = new CmsUser();
|
||||
$user->name = 'Roman';
|
||||
$user->username = 'romanb';
|
||||
$user->status = 'freak';
|
||||
$user->setAddress($address);
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->persist($address);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
return array($user->id, $address->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-817
|
||||
*/
|
||||
public function testFindByAssociationKey_ExceptionOnInverseSide()
|
||||
{
|
||||
list($userId, $addressId) = $this->loadAssociatedFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$this->setExpectedException('Doctrine\ORM\ORMException', "You cannot search for the association field 'Doctrine\Tests\Models\CMS\CmsUser#address', because it is the inverse side of an association. Find methods only work on owning side associations.");
|
||||
$user = $repos->findBy(array('address' => $addressId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-817
|
||||
*/
|
||||
public function testFindOneByAssociationKey()
|
||||
{
|
||||
list($userId, $addressId) = $this->loadAssociatedFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
$address = $repos->findOneBy(array('user' => $userId));
|
||||
|
||||
$this->assertType('Doctrine\Tests\Models\CMS\CmsAddress', $address);
|
||||
$this->assertEquals($addressId, $address->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-817
|
||||
*/
|
||||
public function testFindByAssociationKey()
|
||||
{
|
||||
list($userId, $addressId) = $this->loadAssociatedFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
$addresses = $repos->findBy(array('user' => $userId));
|
||||
|
||||
$this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsAddress', $addresses);
|
||||
$this->assertEquals(1, count($addresses));
|
||||
$this->assertEquals($addressId, $addresses[0]->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-817
|
||||
*/
|
||||
public function testFindAssociationByMagicCall()
|
||||
{
|
||||
list($userId, $addressId) = $this->loadAssociatedFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
$addresses = $repos->findByUser($userId);
|
||||
|
||||
$this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsAddress', $addresses);
|
||||
$this->assertEquals(1, count($addresses));
|
||||
$this->assertEquals($addressId, $addresses[0]->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-817
|
||||
*/
|
||||
public function testFindOneAssociationByMagicCall()
|
||||
{
|
||||
list($userId, $addressId) = $this->loadAssociatedFixture();
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
$address = $repos->findOneByUser($userId);
|
||||
|
||||
$this->assertType('Doctrine\Tests\Models\CMS\CmsAddress', $address);
|
||||
$this->assertEquals($addressId, $address->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,20 @@ class OptimisticTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testMultipleFlushesDoIncrementalUpdates()
|
||||
{
|
||||
$test = new OptimisticStandard();
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$test->name = 'test' . $i;
|
||||
$this->_em->persist($test);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertType('int', $test->getVersion());
|
||||
$this->assertEquals($i + 1, $test->getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
public function testStandardInsertSetsInitialVersionValue()
|
||||
{
|
||||
$test = new OptimisticStandard();
|
||||
@ -107,6 +121,7 @@ class OptimisticTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->persist($test);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertType('int', $test->getVersion());
|
||||
$this->assertEquals(1, $test->getVersion());
|
||||
|
||||
return $test;
|
||||
@ -139,10 +154,13 @@ class OptimisticTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
$test = new OptimisticTimestamp();
|
||||
$test->name = 'Testing';
|
||||
|
||||
$this->assertNull($test->version, "Pre-Condition");
|
||||
|
||||
$this->_em->persist($test);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertTrue(strtotime($test->version) > 0);
|
||||
$this->assertType('DateTime', $test->version);
|
||||
|
||||
return $test;
|
||||
}
|
||||
|
@ -247,6 +247,34 @@ class ManyToManyBasicAssociationTest extends \Doctrine\Tests\OrmFunctionalTestCa
|
||||
$this->assertEquals(0, count($newUser->getGroups()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-839
|
||||
*/
|
||||
public function testWorkWithDqlHydratedEmptyCollection()
|
||||
{
|
||||
$user = $this->addCmsUserGblancoWithGroups(0);
|
||||
$group = new CmsGroup();
|
||||
$group->name = "Developers0";
|
||||
$this->_em->persist($group);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$newUser = $this->_em->createQuery('SELECT u, g FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.groups g WHERE u.id = ?1')
|
||||
->setParameter(1, $user->getId())
|
||||
->getSingleResult();
|
||||
$this->assertEquals(0, count($newUser->groups));
|
||||
$this->assertType('array', $newUser->groups->getMapping());
|
||||
|
||||
$newUser->addGroup($group);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$newUser = $this->_em->find(get_class($user), $user->getId());
|
||||
$this->assertEquals(1, count($newUser->groups));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $groupCount
|
||||
* @return CmsUser
|
||||
|
@ -12,100 +12,35 @@ require_once __DIR__ . '/../../TestInit.php';
|
||||
class MappedSuperclassTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp() {
|
||||
$this->useModelSet('directorytree');
|
||||
parent::setUp();
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\EntitySubClass'),
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
// Swallow all exceptions. We do not test the schema tool here.
|
||||
}
|
||||
}
|
||||
|
||||
public function testCRUD()
|
||||
{
|
||||
$e = new EntitySubClass;
|
||||
$e->setId(1);
|
||||
$e->setName('Roman');
|
||||
$e->setMapped1(42);
|
||||
$e->setMapped2('bar');
|
||||
|
||||
$this->_em->persist($e);
|
||||
$root = new \Doctrine\Tests\Models\DirectoryTree\Directory();
|
||||
$root->setName('Root');
|
||||
$root->setPath('/root');
|
||||
|
||||
$directory = new \Doctrine\Tests\Models\DirectoryTree\Directory($root);
|
||||
$directory->setName('TestA');
|
||||
$directory->setPath('/root/dir');
|
||||
|
||||
$file = new \Doctrine\Tests\Models\DirectoryTree\File($directory);
|
||||
$file->setName('test-b.html');
|
||||
|
||||
$this->_em->persist($root);
|
||||
$this->_em->persist($directory);
|
||||
$this->_em->persist($file);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$e2 = $this->_em->find('Doctrine\Tests\ORM\Functional\EntitySubClass', 1);
|
||||
$this->assertEquals(1, $e2->getId());
|
||||
$this->assertEquals('Roman', $e2->getName());
|
||||
$this->assertNull($e2->getMappedRelated1());
|
||||
$this->assertEquals(42, $e2->getMapped1());
|
||||
$this->assertEquals('bar', $e2->getMapped2());
|
||||
|
||||
$cleanFile = $this->_em->find(get_class($file), $file->getId());
|
||||
|
||||
$this->assertType('Doctrine\Tests\Models\DirectoryTree\Directory', $cleanFile->getParent());
|
||||
$this->assertEquals($directory->getId(), $cleanFile->getParent()->getId());
|
||||
$this->assertType('Doctrine\Tests\Models\DirectoryTree\Directory', $cleanFile->getParent()->getParent());
|
||||
$this->assertEquals($root->getId(), $cleanFile->getParent()->getParent()->getId());
|
||||
}
|
||||
}
|
||||
|
||||
/** @MappedSuperclass */
|
||||
class MappedSuperclassBase {
|
||||
/** @Column(type="integer") */
|
||||
private $mapped1;
|
||||
/** @Column(type="string") */
|
||||
private $mapped2;
|
||||
/**
|
||||
* @OneToOne(targetEntity="MappedSuperclassRelated1")
|
||||
* @JoinColumn(name="related1_id", referencedColumnName="id")
|
||||
*/
|
||||
private $mappedRelated1;
|
||||
private $transient;
|
||||
|
||||
public function setMapped1($val) {
|
||||
$this->mapped1 = $val;
|
||||
}
|
||||
|
||||
public function getMapped1() {
|
||||
return $this->mapped1;
|
||||
}
|
||||
|
||||
public function setMapped2($val) {
|
||||
$this->mapped2 = $val;
|
||||
}
|
||||
|
||||
public function getMapped2() {
|
||||
return $this->mapped2;
|
||||
}
|
||||
|
||||
public function getMappedRelated1() {
|
||||
return $this->mappedRelated1;
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class MappedSuperclassRelated1 {
|
||||
/** @Id @Column(type="integer") */
|
||||
private $id;
|
||||
/** @Column(type="string") */
|
||||
private $name;
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class EntitySubClass extends MappedSuperclassBase {
|
||||
/** @Id @Column(type="integer") */
|
||||
private $id;
|
||||
/** @Column(type="string") */
|
||||
private $name;
|
||||
|
||||
public function setName($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setId($id) {
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function getId() {
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
|
||||
|
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