3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15 * This software consists of voluntary contributions made by many individuals
16 * and is licensed under the LGPL. For more information, see
17 * <http://www.doctrine-project.org>.
23 require_once 'phar://'.__FILE__.'/Doctrine/Common/ClassLoader.php';
25 $classLoader = new \Doctrine\Common\ClassLoader('Doctrine\Common', 'phar://'.__FILE__);
26 $classLoader->register();
28 $classLoader = new \Doctrine\Common\ClassLoader('Doctrine\DBAL', 'phar://'.__FILE__);
29 $classLoader->register();
31 $classLoader = new \Doctrine\Common\ClassLoader('Symfony', 'phar://'.__FILE__);
32 $classLoader->register();
34 $helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
35 'dialog' => new \Symfony\Component\Console\Helper\DialogHelper(),
38 $cli = new \Symfony\Component\Console\Application('Doctrine Migrations', \Doctrine\DBAL\Migrations\MigrationsVersion::VERSION);
39 $cli->setCatchExceptions(true);
40 $cli->setHelperSet($helperSet);
41 $cli->addCommands(array(
42 // Migrations Commands
43 new \Doctrine\DBAL\Migrations\Tools\Console\Command\DiffCommand(),
44 new \Doctrine\DBAL\Migrations\Tools\Console\Command\ExecuteCommand(),
45 new \Doctrine\DBAL\Migrations\Tools\Console\Command\GenerateCommand(),
46 new \Doctrine\DBAL\Migrations\Tools\Console\Command\MigrateCommand(),
47 new \Doctrine\DBAL\Migrations\Tools\Console\Command\StatusCommand(),
48 new \Doctrine\DBAL\Migrations\Tools\Console\Command\VersionCommand()
51 $input = file_exists('migrations-input.php')
52 ? include('migrations-input.php')
55 $output = file_exists('migrations-output.php')
56 ? include('migrations-output.php')
59 $cli->run($input, $output);
61 __HALT_COMPILER(); ?>
\r
62 \83,
\0\0¤
\0\0\0\11\0\0\0\ 1\0\0\0\0\0\0\0\0\0;
\0\0\0Doctrine/DBAL/Migrations/IrreversibleMigrationException.php¨
\ 5\0\0\99ÈÏL¨
\ 5\0\0\82üÊܶ
\ 1\0\0\0\0\0\04
\0\0\0Doctrine/DBAL/Migrations/AbortMigrationException.phpm
\0\0\0\99ÈÏLm
\0\0\0°ß
\ e\9c¶
\ 1\0\0\0\0\0\03
\0\0\0Doctrine/DBAL/Migrations/SkipMigrationException.phpl
\0\0\0\99ÈÏLl
\0\0\0\16\1dTŶ
\ 1\0\0\0\0\0\0.
\0\0\0Doctrine/DBAL/Migrations/AbstractMigration.phpå
\11\0\0\99ÈÏLå
\11\0\0¢
\9dé`¶
\ 1\0\0\0\0\0\0/
\0\0\0Doctrine/DBAL/Migrations/MigrationException.phpÈ
\0\0\99ÈÏLÈ
\0\0(Shz¶
\ 1\0\0\0\0\0\0&
\0\0\0Doctrine/DBAL/Migrations/Migration.php
\16\0\0\99ÈÏL
\16\0\0Í~®«¶
\ 1\0\0\0\0\0\08
\0\0\0Doctrine/DBAL/Migrations/Configuration/Configuration.php"7
\0\0\99ÈÏL"7
\0\0\15pë
\90¶
\ 1\0\0\0\0\0\0;
\0\0\0Doctrine/DBAL/Migrations/Configuration/XmlConfiguration.php
\9b \0\0\99ÈÏL
\9b \0\0ëZ÷
\1d¶
\ 1\0\0\0\0\0\0<
\0\0\0Doctrine/DBAL/Migrations/Configuration/YamlConfiguration.php¢
\0\0\99ÈÏL¢
\0\0>x7¾¶
\ 1\0\0\0\0\0\0D
\0\0\0Doctrine/DBAL/Migrations/Configuration/AbstractFileConfiguration.php
\v\0\0\99ÈÏL
\v\0\0\9fMÿ
\17¶
\ 1\0\0\0\0\0\0)
\0\0\0Doctrine/DBAL/Migrations/OutputWriter.php
\ 3\a\0\0\99ÈÏL
\ 3\a\0\04
\97£4¶
\ 1\0\0\0\0\0\0$
\0\0\0Doctrine/DBAL/Migrations/Version.phpÏ&
\0\0\99ÈÏLÏ&
\0\0v
\8cM}¶
\ 1\0\0\0\0\0\0.
\0\0\0Doctrine/DBAL/Migrations/MigrationsVersion.php8
\ 4\0\0\99ÈÏL8
\ 4\0\0¢
\11R£¶
\ 1\0\0\0\0\0\0>
\0\0\0Doctrine/DBAL/Migrations/Tools/Console/Command/DiffCommand.phpÌ
\ f\0\0\99ÈÏLÌ
\ f\0\0£4&
\16¶
\ 1\0\0\0\0\0\0B
\0\0\0Doctrine/DBAL/Migrations/Tools/Console/Command/AbstractCommand.phpâ
\15\0\0\99ÈÏLâ
\15\0\0*T\j¶
\ 1\0\0\0\0\0\0B
\0\0\0Doctrine/DBAL/Migrations/Tools/Console/Command/GenerateCommand.phpã
\ f\0\0\99ÈÏLã
\ f\0\0\ 1~Ò
\1a¶
\ 1\0\0\0\0\0\0A
\0\0\0Doctrine/DBAL/Migrations/Tools/Console/Command/VersionCommand.php
\a\10\0\0\99ÈÏL
\a\10\0\0í±
\13§¶
\ 1\0\0\0\0\0\0A
\0\0\0Doctrine/DBAL/Migrations/Tools/Console/Command/ExecuteCommand.php
\96\10\0\0\99ÈÏL
\96\10\0\0U
\11üI¶
\ 1\0\0\0\0\0\0@
\0\0\0Doctrine/DBAL/Migrations/Tools/Console/Command/StatusCommand.php÷
\15\0\0\99ÈÏL÷
\15\0\0ñe
\8f-¶
\ 1\0\0\0\0\0\0A
\0\0\0Doctrine/DBAL/Migrations/Tools/Console/Command/MigrateCommand.php7
\12\0\0\99ÈÏL7
\12\0\0a±é¹¶
\ 1\0\0\0\0\0\0\1f\0\0\0Doctrine/DBAL/DBALException.php
\f
64 \0\0\8c^Ñ<¶
\ 1\0\0\0\0\0\0)
\0\0\0Doctrine/DBAL/Driver/PDOOracle/Driver.php¤
66 \0\0ýós&¶
\ 1\0\0\0\0\0\0-
\0\0\0Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php
\ 3\r\0\0\99ÈÏL
\ 3\r\0\0<t
\96\0¶
\ 1\0\0\0\0\0\0,
\0\0\0Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php®.
\0\0\99ÈÏL®.
\0\0Á
\e¥3¶
\ 1\0\0\0\0\0\0,
\0\0\0Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php7
\ 4\0\0\99ÈÏL7
\ 4\0\0Ç~Þò¶
\ 1\0\0\0\0\0\0)
\0\0\0Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php®
\ e\0\0\99ÈÏL®
\ e\0\0üh
\83$¶
\ 1\0\0\0\0\0\0%
\0\0\0Doctrine/DBAL/Driver/PDOStatement.php
\v\ 5\0\0\99ÈÏL
\v\ 5\0\0\87F
\17Á¶
\ 1\0\0\0\0\0\0(
\0\0\0Doctrine/DBAL/Driver/PDOMsSql/Driver.phpÒ
\0\0\99ÈÏLÒ
\0\0\81kX)¶
\ 1\0\0\0\0\0\0,
\0\0\0Doctrine/DBAL/Driver/PDOMsSql/Connection.php|
\ 6\0\0\99ÈÏL|
\ 6\0\0P{1
\13¶
\ 1\0\0\0\0\0\0"
\0\0\0Doctrine/DBAL/Driver/Statement.php
\9b%
\0\0\99ÈÏL
\9b%
\0\0,¿i
\80¶
\ 1\0\0\0\0\0\0(
\0\0\0Doctrine/DBAL/Driver/PDOPgSql/Driver.php
\8c\ 6\0\0\99ÈÏL
\8c\ 6\0\0§
\7f\9cZ¶
\ 1\0\0\0\0\0\0&
\0\0\0Doctrine/DBAL/Driver/PDOConnection.php
\12\ 6\0\0\99ÈÏL
\12\ 6\0\0Q0
\12Ô¶
\ 1\0\0\0\0\0\0&
\0\0\0Doctrine/DBAL/Driver/PDOIbm/Driver.phpN
\ f\0\0\99ÈÏLN
\ f\0\0SPuo¶
\ 1\0\0\0\0\0\0(
\0\0\0Doctrine/DBAL/Driver/PDOMySql/Driver.php?
\v\0\0\99ÈÏL?
\v\0\0£°¤¿¶
\ 1\0\0\0\0\0\0)
\0\0\0Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php¬
\0\0\99ÈÏL¬
\0\0·
\15ܪ¶
\ 1\0\0\0\0\0\0)
\0\0\0Doctrine/DBAL/Driver/PDOSqlite/Driver.php§
\ e\0\0\99ÈÏL§
\ e\0\0ÓÖV
\80¶
\ 1\0\0\0\0\0\0+
\0\0\0Doctrine/DBAL/Driver/OCI8/OCI8Exception.php«
\ 4\0\0\99ÈÏL«
\ 4\0\0J¢Ù®¶
\ 1\0\0\0\0\0\0$
\0\0\0Doctrine/DBAL/Driver/OCI8/Driver.php?
\v\0\0\99ÈÏL?
\v\0\0ó
\ fÀ»¶
\ 1\0\0\0\0\0\0+
\0\0\0Doctrine/DBAL/Driver/OCI8/OCI8Statement.php
\ 4\e\0\0\99ÈÏL
\ 4\e\0\0µR
\14¦¶
\ 1\0\0\0\0\0\0,
\0\0\0Doctrine/DBAL/Driver/OCI8/OCI8Connection.php
\13\ f\0\0\99ÈÏL
\13\ f\0\0Ïç
\88\13¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/DBAL/Driver/Connection.phpé
\ 5\0\0\99ÈÏLé
\ 5\0\0\8fkVǦ
\ 1\0\0\0\0\0\0\18\0\0\0Doctrine/DBAL/Events.phpù
\ 4\0\0\99ÈÏLù
\ 4\0\0Â
\0p
\13¶
\ 1\0\0\0\0\0\0\1f\0\0\0Doctrine/DBAL/DriverManager.phpË
\17\0\0\99ÈÏLË
\17\0\0dÄ< ¶
\ 1\0\0\0\0\0\0\1f\0\0\0Doctrine/DBAL/Configuration.phpp
\b\0\0\99ÈÏLp
\b\0\0¦êMo¶
\ 1\0\0\0\0\0\0\e\0\0\0Doctrine/DBAL/Statement.php
\ 4\1d\0\0\99ÈÏL
\ 4\1d\0\0uÒËÛ¶
\ 1\0\0\0\0\0\0+
\0\0\0Doctrine/DBAL/Schema/MySqlSchemaManager.php:
\19\0\0\99ÈÏL:
\19\0\0#÷r
\80¶
\ 1\0\0\0\0\0\00
\0\0\0Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php
\97$
\0\0\99ÈÏL
\97$
\0\0ÔÛ
\8bó¶
\ 1\0\0\0\0\0\0\1d\0\0\0Doctrine/DBAL/Schema/View.phpF
\ 6\0\0\99ÈÏLF
\ 6\0\0\8d.ú±¶
\ 1\0\0\0\0\0\0)
\0\0\0Doctrine/DBAL/Schema/DB2SchemaManager.php=
\19\0\0\99ÈÏL=
\19\0\0Ó
\93\17Ȧ
\ 1\0\0\0\0\0\0,
\0\0\0Doctrine/DBAL/Schema/SqliteSchemaManager.php÷
\16\0\0\99ÈÏL÷
\16\0\0\1f\7fU´¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/DBAL/Schema/Comparator.phpÁ3
\0\0\99ÈÏLÁ3
\0\0\8eÖÜ
67 ¶
\ 1\0\0\0\0\0\0\1e\0\0\0Doctrine/DBAL/Schema/Index.php
\80\14\0\0\99ÈÏL
\80\14\0\0Ô&o!¶
\ 1\0\0\0\0\0\0.
\0\0\0Doctrine/DBAL/Schema/AbstractSchemaManager.phpKV
\0\0\99ÈÏLKV
\0\0,:
\b\89¶
\ 1\0\0\0\0\0\0&
\0\0\0Doctrine/DBAL/Schema/AbstractAsset.phpþ
\f\0\0\99ÈÏLþ
\f\0\0 T
\1eK¶
\ 1\0\0\0\0\0\0%
\0\0\0Doctrine/DBAL/Schema/SchemaConfig.phpC
\b\0\0\99ÈÏLC
\b\0\0Ù>ƶ
\ 1\0\0\0\0\0\0\1f\0\0\0Doctrine/DBAL/Schema/Column.php§
\1c\0\0\99ÈÏL§
\1c\0\0+W
\8a\92¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/DBAL/Schema/Constraint.phpO
\ 5\0\0\99ÈÏLO
\ 5\0\0\82:
\87¦¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/DBAL/Schema/SchemaDiff.phpÿ
\14\0\0\99ÈÏLÿ
\14\0\0~'
\9a׶
\ 1\0\0\0\0\0\0\1f\0\0\0Doctrine/DBAL/Schema/Schema.php3"
\0\0\99ÈÏL3"
\0\0"
\ e$V¶
\ 1\0\0\0\0\0\0+
\0\0\0Doctrine/DBAL/Schema/MsSqlSchemaManager.php!
\16\0\0\99ÈÏL!
\16\0\0\85@á
\84¶
\ 1\0\0\0\0\0\0(
\0\0\0Doctrine/DBAL/Schema/Visitor/Visitor.php*
\0\0\99ÈÏL*
\0\0D
\9di&¶
\ 1\0\0\0\0\0\09
\0\0\0Doctrine/DBAL/Schema/Visitor/CreateSchemaSqlCollector.phpj
\ f\0\0\99ÈÏLj
\ f\0\0à
\12妦
\ 1\0\0\0\0\0\07
\0\0\0Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php¡
\ e\0\0\99ÈÏL¡
\ e\0\00ý
\aé¶
\ 1\0\0\0\0\0\0-
\0\0\0Doctrine/DBAL/Schema/ForeignKeyConstraint.phpÚ
\ e\0\0\99ÈÏLÚ
\ e\0\0}
\8fW¼¶
\ 1\0\0\0\0\0\0\1e\0\0\0Doctrine/DBAL/Schema/Table.php`C
\0\0\99ÈÏL`C
\0\0\ 6ï»P¶
\ 1\0\0\0\0\0\0"
\0\0\0Doctrine/DBAL/Schema/TableDiff.php^
\ e\0\0\99ÈÏL^
\ e\0\0Ê
\16\12¶
\ 1\0\0\0\0\0\0,
\0\0\0Doctrine/DBAL/Schema/OracleSchemaManager.php6$
\0\0\99ÈÏL6$
\0\0äÍ
\1cG¶
\ 1\0\0\0\0\0\0!
\0\0\0Doctrine/DBAL/Schema/Sequence.php
\92\b\0\0\99ÈÏL
\92\b\0\0LöÜk¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/DBAL/Schema/ColumnDiff.php
\1d\a\0\0\99ÈÏL
\1d\a\0\0ûÏ'
\8b¶
\ 1\0\0\0\0\0\0(
\0\0\0Doctrine/DBAL/Schema/SchemaException.phpt
\ f\0\0\99ÈÏLt
\ f\0\0ή!
\86¶
\ 1\0\0\0\0\0\0\1a\0\0\0Doctrine/DBAL/LockMode.phpä
\ 5\0\0\99ÈÏLä
\ 5\0\0jWW̶
\ 1\0\0\0\0\0\0\18\0\0\0Doctrine/DBAL/Driver.php=
69 \0\01
\eô]¶
\ 1\0\0\0\0\0\0.
\0\0\0Doctrine/DBAL/Platforms/PostgreSqlPlatform.php Y
\0\0\99ÈÏL Y
\0\0®
\8cv¡¶
\ 1\0\0\0\0\0\0)
\0\0\0Doctrine/DBAL/Platforms/MsSqlPlatform.php
\97M
\0\0\99ÈÏL
\97M
\0\0¼å>0¶
\ 1\0\0\0\0\0\0*
\0\0\0Doctrine/DBAL/Platforms/OraclePlatform.php
\83V
\0\0\99ÈÏL
\83V
\0\0|
\1fª
\9d¶
\ 1\0\0\0\0\0\0'
\0\0\0Doctrine/DBAL/Platforms/DB2Platform.php
\eA
\0\0\99ÈÏL
\eA
\0\0\E1߶
\ 1\0\0\0\0\0\0)
\0\0\0Doctrine/DBAL/Platforms/MySqlPlatform.php
\9dM
\0\0\99ÈÏL
\9dM
\0\0¥
\936¶
\ 1\0\0\0\0\0\0,
\0\0\0Doctrine/DBAL/Platforms/AbstractPlatform.phpýî
\0\0\99ÈÏLýî
\0\0X
\9aò
\88¶
\ 1\0\0\0\0\0\0*
\0\0\0Doctrine/DBAL/Platforms/SqlitePlatform.phpF8
\0\0\99ÈÏLF8
\0\0E
\1f\rT¶
\ 1\0\0\0\0\0\0\1d\0\0\0Doctrine/DBAL/README.markdown
\0\0\0\0\99ÈÏL
\0\0\0\0\0\0\0\0¶
\ 1\0\0\0\0\0\0\19\0\0\0Doctrine/DBAL/Version.phpó
\a\0\0\99ÈÏLó
\a\0\0\ 5|!
\92¶
\ 1\0\0\0\0\0\0%
\0\0\0Doctrine/DBAL/ConnectionException.php
\0\b\0\0\99ÈÏL
\0\b\0\0¾óíC¶
\ 1\0\0\0\0\0\0\1c\0\0\0Doctrine/DBAL/Connection.php£{
\0\0\99ÈÏL£{
\0\0÷ªË
\1f¶
\ 1\0\0\0\0\0\0'
\0\0\0Doctrine/DBAL/Logging/EchoSQLLogger.phpN
\a\0\0\99ÈÏLN
\a\0\0¾
\13N¦
\ 1\0\0\0\0\0\0$
\0\0\0Doctrine/DBAL/Logging/DebugStack.php
\9f\b\0\0\99ÈÏL
\9f\b\0\0}
\ 2ª
\12¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/DBAL/Logging/SQLLogger.php§
\a\0\0\99ÈÏL§
\a\0\05õ
\90 ¶
\ 1\0\0\0\0\0\05
\0\0\0Doctrine/DBAL/Tools/Console/Command/ImportCommand.php
\1c\12\0\0\99ÈÏL
\1c\12\0\0G:
\8d¨¶
\ 1\0\0\0\0\0\05
\0\0\0Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php/
\f\0\0\99ÈÏL/
\f\0\0÷Ï9R¶
\ 1\0\0\0\0\0\07
\0\0\0Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.phpv
\b\0\0\99ÈÏLv
\b\0\04
\18ás¶
\ 1\0\0\0\0\0\0'
\0\0\0Doctrine/DBAL/Types/VarDateTimeType.phpÔ
\b\0\0\99ÈÏLÔ
\b\0\0wá3ì¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/DBAL/Types/IntegerType.phpª
\ 6\0\0\99ÈÏLª
\ 6\0\0 l6
\92¶
\ 1\0\0\0\0\0\0 \0\0\0Doctrine/DBAL/Types/DateType.phpÊ
\a\0\0\99ÈÏLÊ
\a\0\0òEÇe¶
\ 1\0\0\0\0\0\0\1c\0\0\0Doctrine/DBAL/Types/Type.php
\ 6\1c\0\0\99ÈÏL
\ 6\1c\0\0Â,do¶
\ 1\0\0\0\0\0\0!
\0\0\0Doctrine/DBAL/Types/FloatType.phpz
\a\0\0\99ÈÏLz
\a\0\0~[e
\91¶
\ 1\0\0\0\0\0\0$
\0\0\0Doctrine/DBAL/Types/SmallIntType.php
\85\ 6\0\0\99ÈÏL
\85\ 6\0\0G9#k¶
\ 1\0\0\0\0\0\0"
\0\0\0Doctrine/DBAL/Types/BigIntType.phpû
\ 5\0\0\99ÈÏLû
\ 5\0\0>
\1e\9fõ¶
\ 1\0\0\0\0\0\0"
\0\0\0Doctrine/DBAL/Types/StringType.phpY
\ 6\0\0\99ÈÏLY
\ 6\0\0(¤.G¶
\ 1\0\0\0\0\0\0"
\0\0\0Doctrine/DBAL/Types/ObjectType.phpñ
\ 3\0\0\99ÈÏLñ
\ 3\0\0M(
\ 3\1d¶
\ 1\0\0\0\0\0\0&
\0\0\0Doctrine/DBAL/Types/DateTimeTzType.php
\7f\f\0\0\99ÈÏL
\7f\f\0\0\96ç}
\10¶
\ 1\0\0\0\0\0\0+
\0\0\0Doctrine/DBAL/Types/ConversionException.php±
\a\0\0\99ÈÏL±
\a\0\0¢Gf[¶
\ 1\0\0\0\0\0\0$
\0\0\0Doctrine/DBAL/Types/DateTimeType.phpë
\a\0\0\99ÈÏLë
\a\0\0\ 3ìÝ
\81¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/DBAL/Types/DecimalType.php
\1f\ 6\0\0\99ÈÏL
\1f\ 6\0\0\9cµ
\a\91¶
\ 1\0\0\0\0\0\0 \0\0\0Doctrine/DBAL/Types/TextType.php
\7f\a\0\0\99ÈÏL
\7f\a\0\0ªúæ@¶
\ 1\0\0\0\0\0\0!
\0\0\0Doctrine/DBAL/Types/ArrayType.phpÊ
\a\0\0\99ÈÏLÊ
\a\0\0§´ùï¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/DBAL/Types/BooleanType.php
\10\a\0\0\99ÈÏL
\10\a\0\0\9f<4
\89¶
\ 1\0\0\0\0\0\0 \0\0\0Doctrine/DBAL/Types/TimeType.php5
\b\0\0\99ÈÏL5
\b\0\0Ù»
\11¶
\ 1\0\0\0\0\0\0+
\0\0\0Doctrine/DBAL/Event/ConnectionEventArgs.phpõ
\b\0\0\99ÈÏLõ
\b\0\0\ 1±5
\90¶
\ 1\0\0\0\0\0\02
\0\0\0Doctrine/DBAL/Event/Listeners/MysqlSessionInit.phpO
\0\0\99ÈÏLO
\0\0¤â¿9¶
\ 1\0\0\0\0\0\03
\0\0\0Doctrine/DBAL/Event/Listeners/OracleSessionInit.php
\98\v\0\0\99ÈÏL
\98\v\0\01?
\91\16¶
\ 1\0\0\0\0\0\0\1d\0\0\0Doctrine/Common/EventArgs.php#
71 \0\0to·
\a¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/Common/CommonException.phpq
\ 4\0\0\99ÈÏLq
\ 4\0\0(|
\1ck¶
\ 1\0\0\0\0\0\00
\0\0\0Doctrine/Common/Annotations/AnnotationReader.php
\b"
\0\0\99ÈÏL
\b"
\0\0
72 6
\13ÿ¶
\ 1\0\0\0\0\0\03
\0\0\0Doctrine/Common/Annotations/AnnotationException.php
\90\a\0\0\99ÈÏL
\90\a\0\0ø=?
\8b¶
\ 1\0\0\0\0\0\0&
\0\0\0Doctrine/Common/Annotations/Parser.php£=
\0\0\99ÈÏL£=
\0\03¾
\9aS¶
\ 1\0\0\0\0\0\0%
\0\0\0Doctrine/Common/Annotations/Lexer.phpª
\12\0\0\99ÈÏLª
\12\0\0Snôÿ¶
\ 1\0\0\0\0\0\0*
\0\0\0Doctrine/Common/Annotations/Annotation.phpö
\0\0\99ÈÏLö
\0\0@ãÔ
\18¶
\ 1\0\0\0\0\0\0\1f\0\0\0Doctrine/Common/ClassLoader.php
\ f"
\0\0\99ÈÏL
\ f"
\0\0\9b:à@¶
\ 1\0\0\0\0\0\0/
\0\0\0Doctrine/Common/Collections/ArrayCollection.php .
\0\0\99ÈÏL .
\0\0ùj
\eë¶
\ 1\0\0\0\0\0\0*
\0\0\0Doctrine/Common/Collections/Collection.phpZ
\0\0\99ÈÏLZ
\0\0\9f´
\80\80¶
\ 1\0\0\0\0\0\0\e\0\0\0Doctrine/Common/Version.phpõ
\a\0\0\99ÈÏLõ
\a\0\0¸Ó/\¶
\ 1\0\0\0\0\0\0%
\0\0\0Doctrine/Common/Cache/XcacheCache.phpç
\v\0\0\99ÈÏLç
\v\0\0&
\ 22Ͷ
\ 1\0\0\0\0\0\0$
\0\0\0Doctrine/Common/Cache/ArrayCache.php'
\0\0\99ÈÏL'
\0\0ï::b¶
\ 1\0\0\0\0\0\0'
\0\0\0Doctrine/Common/Cache/MemcacheCache.phpû
\f\0\0\99ÈÏLû
\f\0\0rü6
\80¶
\ 1\0\0\0\0\0\0\1f\0\0\0Doctrine/Common/Cache/Cache.php
\13
74 \0\0±Ó\O¶
\ 1\0\0\0\0\0\0"
\0\0\0Doctrine/Common/Cache/ApcCache.phpA
\0\0\99ÈÏLA
\0\0Y
\84Á*¶
\ 1\0\0\0\0\0\0'
\0\0\0Doctrine/Common/Cache/AbstractCache.php1
\18\0\0\99ÈÏL1
\18\0\0L»
\8d0¶
\ 1\0\0\0\0\0\0\1e\0\0\0Doctrine/Common/Util/Debug.php
\ 2\13\0\0\99ÈÏL
\ 2\13\0\0Í;º`¶
\ 1\0\0\0\0\0\0"
\0\0\0Doctrine/Common/Util/Inflector.php;
76 \0\0;%ë
\90¶
\ 1\0\0\0\0\0\0)
\0\0\0Doctrine/Common/NotifyPropertyChanged.phpª
\ 6\0\0\99ÈÏLª
\ 6\0\0\1aÃnF¶
\ 1\0\0\0\0\0\0+
\0\0\0Doctrine/Common/PropertyChangedListener.php
\89\a\0\0\99ÈÏL
\89\a\0\0©ï
\86î¶
\ 1\0\0\0\0\0\0 \0\0\0Doctrine/Common/EventManager.php,
\13\0\0\99ÈÏL,
\13\0\0Ñg]F¶
\ 1\0\0\0\0\0\0\19\0\0\0Doctrine/Common/Lexer.phpK
\e\0\0\99ÈÏLK
\e\0\0NÁã
\ 1¶
\ 1\0\0\0\0\0\0#
\0\0\0Doctrine/Common/EventSubscriber.php
\ 5\a\0\0\99ÈÏL
\ 5\a\0\0iJÛ
\17¶
\ 1\0\0\0\0\0\0\1f\0\0\0Symfony/Component/Yaml/Yaml.php
\9e\v\0\0\99ÈÏL
\9e\v\0\0!
\88¯
\13¶
\ 1\0\0\0\0\0\0!
\0\0\0Symfony/Component/Yaml/Dumper.php
\1c\ 6\0\0\99ÈÏL
\1c\ 6\0\0Ã
\82ßê¶
\ 1\0\0\0\0\0\0*
\0\0\0Symfony/Component/Yaml/ParserException.php
\ f\ 2\0\0\99ÈÏL
\ f\ 2\0\0§³À9¶
\ 1\0\0\0\0\0\0$
\0\0\0Symfony/Component/Yaml/Exception.php
78 \ 2\0\0\ 1WGQ¶
\ 1\0\0\0\0\0\0!
\0\0\0Symfony/Component/Yaml/Inline.php *
\0\0\99ÈÏL *
\0\0:¬
\1fÚ¶
\ 1\0\0\0\0\0\0!
\0\0\0Symfony/Component/Yaml/Parser.php
\90?
\0\0\99ÈÏL
\90?
\0\0í|#ɶ
\ 1\0\0\0\0\0\01
\0\0\0Symfony/Component/Console/Command/ListCommand.php¢
\a\0\0\99ÈÏL¢
\a\0\0ý[¯¤¶
\ 1\0\0\0\0\0\01
\0\0\0Symfony/Component/Console/Command/HelpCommand.phpi
\b\0\0\99ÈÏLi
\b\0\0LÇUí¶
\ 1\0\0\0\0\0\0-
\0\0\0Symfony/Component/Console/Command/Command.phpR8
\0\0\99ÈÏLR8
\0\0\9a¾Dj¶
\ 1\0\0\0\0\0\02
\0\0\0Symfony/Component/Console/Output/ConsoleOutput.phpi
\ 4\0\0\99ÈÏLi
\ 4\0\0Üw*ë¶
\ 1\0\0\0\0\0\04
\0\0\0Symfony/Component/Console/Output/OutputInterface.php¶
\ 4\0\0\99ÈÏL¶
\ 4\0\0ïÛw
\r¶
\ 1\0\0\0\0\0\01
\0\0\0Symfony/Component/Console/Output/StreamOutput.php
\ 3\f\0\0\99ÈÏL
\ 3\f\0\0¿
\9dÐJ¶
\ 1\0\0\0\0\0\0+
\0\0\0Symfony/Component/Console/Output/Output.phpí
\1a\0\0\99ÈÏLí
\1a\0\0Èvs
\r¶
\ 1\0\0\0\0\0\0/
\0\0\0Symfony/Component/Console/Output/NullOutput.phpÕ
\ 2\0\0\99ÈÏLÕ
\ 2\0\0æ1Éê¶
\ 1\0\0\0\0\0\0#
\0\0\0Symfony/Component/Console/Shell.php!
\ f\0\0\99ÈÏL!
\ f\0\0É
\96\ e\9e¶
\ 1\0\0\0\0\0\04
\0\0\0Symfony/Component/Console/Helper/FormatterHelper.php
\ 1 \0\0\99ÈÏL
\ 1 \0\0\10g ø¶
\ 1\0\0\0\0\0\0.
\0\0\0Symfony/Component/Console/Helper/HelperSet.php
\7f \0\0\99ÈÏL
\7f \0\0\14ïÑǶ
\ 1\0\0\0\0\0\0+
\0\0\0Symfony/Component/Console/Helper/Helper.php¿
\ 3\0\0\99ÈÏL¿
\ 3\0\0³
\10憦
\ 1\0\0\0\0\0\04
\0\0\0Symfony/Component/Console/Helper/HelperInterface.php±
\ 3\0\0\99ÈÏL±
\ 3\0\0×ñf
\r¶
\ 1\0\0\0\0\0\01
\0\0\0Symfony/Component/Console/Helper/DialogHelper.php
\94\f\0\0\99ÈÏL
\94\f\0\03Ü.϶
\ 1\0\0\0\0\0\0)
\0\0\0Symfony/Component/Console/Application.php
\89[
\0\0\99ÈÏL
\89[
\0\0¸Nªâ¶
\ 1\0\0\0\0\0\06
\0\0\0Symfony/Component/Console/Tester/ApplicationTester.phpb
80 \0\0ôé*
\19¶
\ 1\0\0\0\0\0\02
\0\0\0Symfony/Component/Console/Tester/CommandTester.php8
82 \0\0µÕ¥®¶
\ 1\0\0\0\0\0\0)
\0\0\0Symfony/Component/Console/Input/Input.php~
\15\0\0\99ÈÏL~
\15\0\0)ª
\97[¶
\ 1\0\0\0\0\0\0.
\0\0\0Symfony/Component/Console/Input/ArrayInput.php
\v\12\0\0\99ÈÏL
\v\12\0\0¿glt¶
\ 1\0\0\0\0\0\0/
\0\0\0Symfony/Component/Console/Input/InputOption.phpA
\13\0\0\99ÈÏLA
\13\0\0ÁÁÇ6¶
\ 1\0\0\0\0\0\03
\0\0\0Symfony/Component/Console/Input/InputDefinition.phpE<
\0\0\99ÈÏLE<
\0\0\84.
\ fú¶
\ 1\0\0\0\0\0\02
\0\0\0Symfony/Component/Console/Input/InputInterface.php¸
\ 5\0\0\99ÈÏL¸
\ 5\0\0\
\85)-¶
\ 1\0\0\0\0\0\0-
\0\0\0Symfony/Component/Console/Input/ArgvInput.php
\89\1d\0\0\99ÈÏL
\89\1d\0\0¥
\eM°¶
\ 1\0\0\0\0\0\0/
\0\0\0Symfony/Component/Console/Input/StringInput.phpÍ
\0\0\99ÈÏLÍ
\0\0g¸kd¶
\ 1\0\0\0\0\0\01
\0\0\0Symfony/Component/Console/Input/InputArgument.phpË
\f\0\0\99ÈÏLË
\f\0\0]×TP¶
\ 1\0\0\0\0\0\0<?php
86 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
87 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
88 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
89 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
90 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
91 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
92 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
93 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
94 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
95 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
96 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
98 * This software consists of voluntary contributions made by many individuals
99 * and is licensed under the LGPL. For more information, see
100 * <http://www.doctrine-project.org>.
103 namespace Doctrine\DBAL\Migrations;
106 * Exception to be thrown in the down() methods of migrations that signifies it
107 * is an irreversible migration and stops execution.
109 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
110 * @link www.doctrine-project.org
112 * @version $Revision$
113 * @author Jonathan H. Wage <jonwage@gmail.com>
115 class IrreversibleMigrationException extends \Exception
119 namespace Doctrine\DBAL\Migrations;
121 class AbortMigrationException extends MigrationException
126 namespace Doctrine\DBAL\Migrations;
128 class SkipMigrationException extends MigrationException
135 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
136 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
137 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
138 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
139 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
140 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
141 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
142 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
143 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
144 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
145 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
147 * This software consists of voluntary contributions made by many individuals
148 * and is licensed under the LGPL. For more information, see
149 * <http://www.doctrine-project.org>.
152 namespace Doctrine\DBAL\Migrations;
154 use Doctrine\DBAL\Schema\Schema,
155 Doctrine\DBAL\Migrations\Configuration\Configuration,
156 Doctrine\DBAL\Migrations\Version;
159 * Abstract class for individual migrations to extend from.
161 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
162 * @link www.doctrine-project.org
164 * @version $Revision$
165 * @author Jonathan H. Wage <jonwage@gmail.com>
167 abstract class AbstractMigration
169 /** The Migrations Configuration instance for this migration */
170 protected $_configuration;
172 /** The OutputWriter object instance used for outputting information */
173 protected $_outputWriter;
175 /** The Doctrine\DBAL\Connection instance we are migrating */
176 protected $_connection;
178 /** Reference to the SchemaManager instance referened by $_connection */
181 /** Reference to the DatabasePlatform instance referenced by $_conection */
182 protected $_platform;
184 /** Reference to the Version instance representing this migration */
187 public function __construct(Version $version)
189 $this->_configuration = $version->getConfiguration();
190 $this->_outputWriter = $this->_configuration->getOutputWriter();
191 $this->_connection = $this->_configuration->getConnection();
192 $this->_sm = $this->_connection->getSchemaManager();
193 $this->_platform = $this->_connection->getDatabasePlatform();
194 $this->_version = $version;
197 abstract public function up(Schema $schema);
198 abstract public function down(Schema $schema);
200 protected function _addSql($sql)
202 return $this->_version->addSql($sql);
205 protected function _write($message)
207 $this->_outputWriter->write($message);
210 protected function _throwIrreversibleMigrationException($message = null)
212 if ($message === null) {
213 $message = 'This migration is irreversible and cannot be reverted.';
215 throw new IrreversibleMigrationException($message);
219 * Print a warning message if the condition evalutes to TRUE.
221 * @param bool $condition
222 * @param string $message
224 public function warnIf($condition, $message = '')
226 $message = (strlen($message)) ? $message : 'Unknown Reason';
228 if ($condition === true) {
229 $this->_outputWriter->write(' <warning>Warning during ' . $this->_version->getExecutionState() . ': ' . $message . '</warning>');
234 * Abort the migration if the condition evalutes to TRUE.
236 * @param bool $condition
237 * @param string $message
239 public function abortIf($condition, $message = '')
241 $message = (strlen($message)) ? $message : 'Unknown Reason';
243 if ($condition === true) {
244 throw new AbortMigrationException($message);
249 * Skip this migration (but not the next ones) if condition evalutes to TRUE.
251 * @param bool $condition
252 * @param string $message
254 public function skipIf($condition, $message = '')
256 $message = (strlen($message)) ? $message : 'Unknown Reason';
258 if ($condition === true) {
259 throw new SkipMigrationException($message);
263 public function preUp(Schema $schema)
267 public function postUp(Schema $schema)
271 public function preDown(Schema $schema)
275 public function postDown(Schema $schema)
282 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
283 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
284 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
285 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
286 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
287 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
288 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
289 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
290 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
291 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
292 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
294 * This software consists of voluntary contributions made by many individuals
295 * and is licensed under the LGPL. For more information, see
296 * <http://www.doctrine-project.org>.
299 namespace Doctrine\DBAL\Migrations;
302 * Class for Migrations specific exceptions
304 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
305 * @link www.doctrine-project.org
307 * @version $Revision$
308 * @author Jonathan H. Wage <jonwage@gmail.com>
310 class MigrationException extends \Exception
312 public static function migrationsNamespaceRequired()
314 return new self('Migrations namespace must be configured in order to use Doctrine migrations.', 2);
317 public static function migrationsDirectoryRequired()
319 return new self('Migrations directory must be configured in order to use Doctrine migrations.', 3);
322 public static function noMigrationsToExecute()
324 return new self('Could not find any migrations to execute.', 4);
327 public static function unknownMigrationVersion($version)
329 return new self(sprintf('Could not find migration version %s', $version), 5);
332 public static function alreadyAtVersion($version)
334 return new self(sprintf('Database is already at version %s', $version), 6);
337 public static function duplicateMigrationVersion($version, $class)
339 return new self(sprintf('Migration version %s already registered with class %s', $version, $class), 7);
342 public static function configurationFileAlreadyLoaded()
344 return new self(sprintf('Migrations configuration file already loaded'), 8);
351 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
352 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
353 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
354 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
355 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
356 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
357 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
358 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
359 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
360 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
361 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
363 * This software consists of voluntary contributions made by many individuals
364 * and is licensed under the LGPL. For more information, see
365 * <http://www.doctrine-project.org>.
368 namespace Doctrine\DBAL\Migrations;
370 use Doctrine\DBAL\Migrations\Configuration\Configuration,
371 Doctrine\DBAL\Schema\Schema;
374 * Class for running migrations to the current version or a manually specified version.
376 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
377 * @link www.doctrine-project.org
379 * @version $Revision$
380 * @author Jonathan H. Wage <jonwage@gmail.com>
384 /** The Doctrine\DBAL\Connection instance we are migrating */
385 private $_connection;
387 /** The OutputWriter object instance used for outputting information */
388 private $_outputWriter;
391 * Construct a Migration instance
393 * @param Configuration $configuration A migration Configuration instance
395 public function __construct(Configuration $configuration)
397 $this->_configuration = $configuration;
398 $this->_outputWriter = $configuration->getOutputWriter();
402 * Get the array of versions and SQL queries that would be executed for
403 * each version but do not execute anything.
405 * @param string $to The version to migrate to.
406 * @return array $sql The array of SQL queries.
408 public function getSql($to = null)
410 return $this->migrate($to, true);
414 * Write a migration SQL file to the given path
416 * @param string $path The path to write the migration SQL file.
417 * @param string $to The version to migrate to.
418 * @return bool $written
420 public function writeSqlFile($path, $to = null)
422 $sql = $this->getSql($to);
424 $from = $this->_configuration->getCurrentVersion();
426 $to = $this->_configuration->getLatestVersion();
429 $string = sprintf("# Doctrine Migration File Generated on %s\n", date('Y-m-d H:m:s'));
430 $string .= sprintf("# Migrating from %s to %s\n", $from, $to);
432 foreach ($sql as $version => $queries) {
433 $string .= "\n# Version " . $version . "\n";
434 foreach ($queries as $query) {
435 $string .= $query . ";\n";
439 $path = realpath($path);
440 $path = $path . '/doctrine_migration_' . date('YmdHis') . '.sql';
443 $this->_outputWriter->write("\n".sprintf('Writing migration file to "<info>%s</info>"', $path));
445 return file_put_contents($path, $string);
449 * Run a migration to the current version or the given target version.
451 * @param string $to The version to migrate to.
452 * @param string $dryRun Whether or not to make this a dry run and not execute anything.
453 * @return array $sql The array of migration sql statements
454 * @throws MigrationException
456 public function migrate($to = null, $dryRun = false)
459 $to = $this->_configuration->getLatestVersion();
462 $from = $this->_configuration->getCurrentVersion();
463 $from = (string) $from;
466 $migrations = $this->_configuration->getMigrations();
467 if ( ! isset($migrations[$to]) && $to > 0) {
468 throw MigrationException::unknownMigrationVersion($to);
472 throw MigrationException::alreadyAtVersion($to);
475 $direction = $from > $to ? 'down' : 'up';
476 $migrations = $this->_configuration->getMigrationsToExecute($direction, $to);
478 if ($dryRun === false) {
479 $this->_outputWriter->write(sprintf('Migrating <info>%s</info> to <comment>%s</comment> from <comment>%s</comment>', $direction, $to, $from));
481 $this->_outputWriter->write(sprintf('Executing dry run of migration <info>%s</info> to <comment>%s</comment> from <comment>%s</comment>', $direction, $to, $from));
484 if (empty($migrations)) {
485 throw MigrationException::noMigrationsToExecute();
490 foreach ($migrations as $version) {
491 $versionSql = $version->execute($direction, $dryRun);
492 $sql[$version->getVersion()] = $versionSql;
493 $time += $version->getTime();
496 $this->_outputWriter->write("\n <comment>------------------------</comment>\n");
497 $this->_outputWriter->write(sprintf(" <info>++</info> finished in %s", $time));
498 $this->_outputWriter->write(sprintf(" <info>++</info> %s migrations executed", count($migrations)));
499 $this->_outputWriter->write(sprintf(" <info>++</info> %s sql queries", count($sql, true) - count($sql)));
508 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
509 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
510 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
511 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
512 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
513 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
514 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
515 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
516 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
517 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
518 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
520 * This software consists of voluntary contributions made by many individuals
521 * and is licensed under the LGPL. For more information, see
522 * <http://www.doctrine-project.org>.
525 namespace Doctrine\DBAL\Migrations\Configuration;
527 use Doctrine\DBAL\Connection,
528 Doctrine\DBAL\Migrations\MigrationException,
529 Doctrine\DBAL\Migrations\Version,
530 Doctrine\DBAL\Migrations\OutputWriter,
531 Doctrine\DBAL\Schema\Table,
532 Doctrine\DBAL\Schema\Column,
533 Doctrine\DBAL\Types\Type;
536 * Default Migration Configurtion object used for configuring an instance of
537 * the Migration class. Set the connection, version table name, register migration
538 * classes/versions, etc.
540 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
541 * @link www.doctrine-project.org
543 * @version $Revision$
544 * @author Jonathan H. Wage <jonwage@gmail.com>
548 /** Name of this set of migrations */
551 /** Flag for whether or not the migration table has been created */
552 private $_migrationTableCreated = false;
554 /** Connection instance to use for migrations */
555 private $_connection;
557 /** OutputWriter instance for writing output during migrations */
558 private $_outputWriter;
560 /** The migration table name to track versions in */
561 private $_migrationsTableName = 'doctrine_migration_versions';
563 /** The path to a directory where new migration classes will be written */
564 private $_migrationsDirectory;
566 /** Namespace the migration classes live in */
567 private $_migrationsNamespace;
569 /** Array of the registered migrations */
570 private $_migrations = array();
573 * Construct a migration configuration object.
575 * @param Connection $connection A Connection instance
576 * @param OutputWriter $outputWriter A OutputWriter instance
578 public function __construct(Connection $connection, OutputWriter $outputWriter = null)
580 $this->_connection = $connection;
581 if ($outputWriter === null) {
582 $outputWriter = new OutputWriter();
584 $this->_outputWriter = $outputWriter;
588 * Validation that this instance has all the required properties configured
591 * @throws MigrationException
593 public function validate()
595 if ( ! $this->_migrationsNamespace) {
596 throw MigrationException::migrationsNamespaceRequired();
598 if ( ! $this->_migrationsDirectory) {
599 throw MigrationException::migrationsDirectoryRequired();
604 * Set the name of this set of migrations
606 * @param string $name The name of this set of migrations
608 public function setName($name)
610 $this->_name = $name;
614 * Returns the name of this set of migrations
616 * @return string $name The name of this set of migrations
618 public function getName()
624 * Returns the OutputWriter instance
626 * @return OutputWriter $outputWriter The OutputWriter instance
628 public function getOutputWriter()
630 return $this->_outputWriter;
634 * Returns a timestamp version as a formatted date
636 * @param string $version
637 * @return string $formattedVersion The formatted version
639 public function formatVersion($version)
641 return sprintf('%s-%s-%s %s:%s:%s',
642 substr($version, 0, 4),
643 substr($version, 4, 2),
644 substr($version, 6, 2),
645 substr($version, 8, 2),
646 substr($version, 10, 2),
647 substr($version, 12, 2)
652 * Returns the Connection instance
654 * @return Connection $connection The Connection instance
656 public function getConnection()
658 return $this->_connection;
662 * Set the migration table name
664 * @param string $tableName The migration table name
666 public function setMigrationsTableName($tableName)
668 $this->_migrationsTableName = $tableName;
672 * Returns the migration table name
674 * @return string $migrationsTableName The migration table name
676 public function getMigrationsTableName()
678 return $this->_migrationsTableName;
682 * Set the new migrations directory where new migration classes are generated
684 * @param string $migrationsDirectory The new migrations directory
686 public function setMigrationsDirectory($migrationsDirectory)
688 $this->_migrationsDirectory = $migrationsDirectory;
692 * Returns the new migrations directory where new migration classes are generated
694 * @return string $migrationsDirectory The new migrations directory
696 public function getMigrationsDirectory()
698 return $this->_migrationsDirectory;
702 * Set the migrations namespace
704 * @param string $migrationsNamespace The migrations namespace
706 public function setMigrationsNamespace($migrationsNamespace)
708 $this->_migrationsNamespace = $migrationsNamespace;
712 * Returns the migrations namespace
714 * @return string $migrationsNamespace The migrations namespace
716 public function getMigrationsNamespace()
718 return $this->_migrationsNamespace;
722 * Register migrations from a given directory. Recursively finds all files
723 * with the pattern VersionYYYYMMDDHHMMSS.php as the filename and registers
724 * them as migrations.
726 * @param string $path The root directory to where some migration classes live.
727 * @return $migrations The array of migrations registered.
729 public function registerMigrationsFromDirectory($path)
731 $path = realpath($path);
732 $path = rtrim($path, '/');
733 $files = glob($path . '/Version*.php');
735 foreach ($files as $file) {
737 $info = pathinfo($file);
738 $version = substr($info['filename'], 7);
739 $class = $this->_migrationsNamespace . '\\' . $info['filename'];
740 $versions[] = $this->registerMigration($version, $class);
746 * Register a single migration version to be executed by a AbstractMigration
749 * @param string $version The version of the migration in the format YYYYMMDDHHMMSS.
750 * @param string $class The migration class to execute for the version.
752 public function registerMigration($version, $class)
754 $version = (string) $version;
755 $class = (string) $class;
756 if (isset($this->_migrations[$version])) {
757 throw MigrationException::duplicateMigrationVersion($version, get_class($this->_migrations[$version]));
759 $version = new Version($this, $version, $class);
760 $this->_migrations[$version->getVersion()] = $version;
761 ksort($this->_migrations);
766 * Register an array of migrations. Each key of the array is the version and
767 * the value is the migration class name.
770 * @param array $migrations
773 public function registerMigrations(array $migrations)
776 foreach ($migrations as $version => $class) {
777 $versions[] = $this->registerMigration($version, $class);
783 * Get the array of registered migration versions.
785 * @return array $migrations
787 public function getMigrations()
789 return $this->_migrations;
793 * Returns the Version instance for a given version in the format YYYYMMDDHHMMSS.
795 * @param string $version The version string in the format YYYYMMDDHHMMSS.
796 * @return Version $version
797 * @throws MigrationException $exception Throws exception if migration version does not exist.
799 public function getVersion($version)
801 if ( ! isset($this->_migrations[$version])) {
802 MigrationException::unknownMigrationVersion($version);
804 return $this->_migrations[$version];
808 * Check if a version exists.
810 * @param string $version
811 * @return bool $exists
813 public function hasVersion($version)
815 return isset($this->_migrations[$version]) ? true : false;
819 * Check if a version has been migrated or not yet
821 * @param Version $version
822 * @return bool $migrated
824 public function hasVersionMigrated(Version $version)
826 $this->createMigrationTable();
828 $version = $this->_connection->fetchColumn("SELECT version FROM " . $this->_migrationsTableName . " WHERE version = '" . $version->getVersion() . "'");
829 return $version !== false ? true : false;
833 * Returns the current migrated version from the versions table.
835 * @return bool $currentVersion
837 public function getCurrentVersion()
839 $this->createMigrationTable();
841 $result = $this->_connection->fetchColumn("SELECT version FROM " . $this->_migrationsTableName . " ORDER BY version DESC LIMIT 1");
842 return $result !== false ? (string) $result : '0';
846 * Returns the total number of executed migration versions
848 * @return integer $count
850 public function getNumberOfExecutedMigrations()
852 $this->createMigrationTable();
854 $result = $this->_connection->fetchColumn("SELECT COUNT(version) FROM " . $this->_migrationsTableName);
855 return $result !== false ? $result : 0;
859 * Returns the total number of available migration versions
861 * @return integer $count
863 public function getNumberOfAvailableMigrations()
865 return count($this->_migrations);
869 * Returns the latest available migration version.
871 * @return string $version The version string in the format YYYYMMDDHHMMSS.
873 public function getLatestVersion()
875 $versions = array_keys($this->_migrations);
876 $latest = end($versions);
877 return $latest !== false ? (string) $latest : '0';
881 * Create the migration table to track migrations with.
883 * @return bool $created Whether or not the table was created.
885 public function createMigrationTable()
889 if ($this->_migrationTableCreated) {
893 $schema = $this->_connection->getSchemaManager()->createSchema();
894 if ( ! $schema->hasTable($this->_migrationsTableName)) {
896 'version' => new Column('version', Type::getType('string'), array('length' => 14)),
898 $table = new Table($this->_migrationsTableName, $columns);
899 $table->setPrimaryKey(array('version'));
900 $this->_connection->getSchemaManager()->createTable($table);
902 $this->_migrationTableCreated = true;
910 * Returns the array of migrations to executed based on the given direction
911 * and target version number.
913 * @param string $direction The direction we are migrating.
914 * @param string $to The version to migrate to.
915 * @return array $migrations The array of migrations we can execute.
917 public function getMigrationsToExecute($direction, $to)
919 if ($direction === 'down') {
920 $allVersions = array_reverse(array_keys($this->_migrations));
921 $classes = array_reverse(array_values($this->_migrations));
922 $allVersions = array_combine($allVersions, $classes);
924 $allVersions = $this->_migrations;
927 foreach ($allVersions as $version) {
928 if ($this->_shouldExecuteMigration($direction, $version, $to)) {
929 $versions[$version->getVersion()] = $version;
936 * Check if we should execute a migration for a given direction and target
939 * @param string $direction The direction we are migrating.
940 * @param Version $version The Version instance to check.
941 * @param string $to The version we are migrating to.
944 private function _shouldExecuteMigration($direction, Version $version, $to)
946 if ($direction === 'down') {
947 if ( ! $this->hasVersionMigrated($version)) {
950 return $version->getVersion() > $to ? true : false;
951 } else if ($direction === 'up') {
952 if ($this->hasVersionMigrated($version)) {
955 return $version->getVersion() <= $to ? true : false;
962 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
963 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
964 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
965 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
966 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
967 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
968 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
969 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
970 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
971 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
972 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
974 * This software consists of voluntary contributions made by many individuals
975 * and is licensed under the LGPL. For more information, see
976 * <http://www.doctrine-project.org>.
979 namespace Doctrine\DBAL\Migrations\Configuration;
982 * Load migration configuration information from a XML configuration file.
984 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
985 * @link www.doctrine-project.org
987 * @version $Revision$
988 * @author Jonathan H. Wage <jonwage@gmail.com>
990 class XmlConfiguration extends AbstractFileConfiguration
995 protected function _load($file)
997 $xml = simplexml_load_file($file);
998 if (isset($xml->name)) {
999 $this->setName((string) $xml->name);
1001 if (isset($xml->table['name'])) {
1002 $this->setMigrationsTableName((string) $xml->table['name']);
1004 if (isset($xml->{'migrations-namespace'})) {
1005 $this->setMigrationsNamespace((string) $xml->{'migrations-namespace'});
1007 if (isset($xml->{'migrations-directory'})) {
1008 $migrationsDirectory = $this->_getDirectoryRelativeToFile($file, (string) $xml->{'migrations-directory'});
1009 $this->setMigrationsDirectory($migrationsDirectory);
1010 $this->registerMigrationsFromDirectory($migrationsDirectory);
1012 if (isset($xml->migrations->migration)) {
1013 foreach ($xml->migrations->migration as $migration) {
1014 $this->registerMigration((string) $migration['version'], (string) $migration['class']);
1022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1023 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1024 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1025 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1026 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1027 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1028 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1029 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1030 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1032 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1034 * This software consists of voluntary contributions made by many individuals
1035 * and is licensed under the LGPL. For more information, see
1036 * <http://www.doctrine-project.org>.
1039 namespace Doctrine\DBAL\Migrations\Configuration;
1041 use Symfony\Component\Yaml\Yaml;
1044 * Load migration configuration information from a YAML configuration file.
1046 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1047 * @link www.doctrine-project.org
1049 * @version $Revision$
1050 * @author Jonathan H. Wage <jonwage@gmail.com>
1052 class YamlConfiguration extends AbstractFileConfiguration
1057 protected function _load($file)
1059 $array = Yaml::load($file);
1061 if (isset($array['name'])) {
1062 $this->setName($array['name']);
1064 if (isset($array['table_name'])) {
1065 $this->setMigrationsTableName($array['table_name']);
1067 if (isset($array['migrations_namespace'])) {
1068 $this->setMigrationsNamespace($array['migrations_namespace']);
1070 if (isset($array['migrations_directory'])) {
1071 $migrationsDirectory = $this->_getDirectoryRelativeToFile($file, $array['migrations_directory']);
1072 $this->setMigrationsDirectory($migrationsDirectory);
1073 $this->registerMigrationsFromDirectory($migrationsDirectory);
1075 if (isset($array['migrations']) && is_array($array['migrations'])) {
1076 foreach ($array['migrations'] as $migration) {
1077 $this->registerMigration($migration['version'], $migration['class']);
1086 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1087 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1088 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1089 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1090 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1091 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1092 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1093 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1094 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1095 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1096 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1098 * This software consists of voluntary contributions made by many individuals
1099 * and is licensed under the LGPL. For more information, see
1100 * <http://www.doctrine-project.org>.
1103 namespace Doctrine\DBAL\Migrations\Configuration;
1105 use Doctrine\DBAL\Migrations\MigrationsException;
1108 * Abstract Migration Configuration class for loading configuration information
1109 * from a configuration file (xml or yml).
1111 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1112 * @link www.doctrine-project.org
1114 * @version $Revision$
1115 * @author Jonathan H. Wage <jonwage@gmail.com>
1117 abstract class AbstractFileConfiguration extends Configuration
1119 /** The configuration file used to load configuration information */
1122 /** Whether or not the configuration file has been loaded yet or not */
1123 private $_loaded = false;
1126 * Load the information from the passed configuration file
1128 * @param string $file The path to the configuration file
1130 * @throws MigrationException $exception Throws exception if configuration file was already loaded
1132 public function load($file)
1134 if ($this->_loaded) {
1135 throw MigrationsException::configurationFileAlreadyLoaded();
1137 if (file_exists($path = getcwd() . '/' . $file)) {
1140 $this->_file = $file;
1141 $this->_load($file);
1142 $this->_loaded = true;
1145 protected function _getDirectoryRelativeToFile($file, $input)
1147 $path = realpath(dirname($file) . '/' . $input);
1148 if ($path !== false) {
1151 $directory = $input;
1156 public function getFile()
1158 return $this->_file;
1162 * Abstract method that each file configuration driver must implement to
1163 * load the given configuration file whether it be xml, yaml, etc. or something
1166 * @param string $file The path to a configuration file.
1168 abstract protected function _load($file);
1173 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1174 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1175 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1176 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1177 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1178 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1179 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1180 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1181 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1182 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1183 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1185 * This software consists of voluntary contributions made by many individuals
1186 * and is licensed under the LGPL. For more information, see
1187 * <http://www.doctrine-project.org>.
1190 namespace Doctrine\DBAL\Migrations;
1193 * Simple class for outputting information from migrations.
1195 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1196 * @link www.doctrine-project.org
1198 * @version $Revision$
1199 * @author Jonathan H. Wage <jonwage@gmail.com>
1205 public function __construct(\Closure $closure = null)
1207 if ($closure === null) {
1208 $closure = function($message) {};
1210 $this->_closure = $closure;
1214 * Write output using the configured closure.
1216 * @param string $message The message to write.
1218 public function write($message)
1220 $closure = $this->_closure;
1227 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1228 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1229 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1230 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1231 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1232 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1233 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1234 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1235 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1236 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1237 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1239 * This software consists of voluntary contributions made by many individuals
1240 * and is licensed under the LGPL. For more information, see
1241 * <http://www.doctrine-project.org>.
1244 namespace Doctrine\DBAL\Migrations;
1246 use Doctrine\DBAL\Migrations\Configuration\Configuration,
1247 Doctrine\DBAL\Schema\Schema;
1250 * Class which wraps a migration version and allows execution of the
1251 * individual migration version up or down method.
1253 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1254 * @link www.doctrine-project.org
1256 * @version $Revision$
1257 * @author Jonathan H. Wage <jonwage@gmail.com>
1261 const STATE_NONE = 0;
1262 const STATE_PRE = 1;
1263 const STATE_EXEC = 2;
1264 const STATE_POST = 3;
1267 * The Migrations Configuration instance for this migration
1269 * @var Configuration
1271 private $_configuration;
1274 * The OutputWriter object instance used for outputting information
1278 private $_outputWriter;
1281 * The version in timestamp format (YYYYMMDDHHMMSS)
1288 * @var AbstractSchemaManager
1293 * @var AbstractPlatform
1298 * The migration instance for this version
1300 * @var AbstractMigration
1302 private $_migration;
1307 private $_connection;
1314 /** The array of collected SQL statements for this version */
1315 private $_sql = array();
1317 /** The time in seconds that this migration version took to execute */
1323 private $_state = self::STATE_NONE;
1325 public function __construct(Configuration $configuration, $version, $class)
1327 $this->_configuration = $configuration;
1328 $this->_outputWriter = $configuration->getOutputWriter();
1329 $this->_version = $version;
1330 $this->_class = $class;
1331 $this->_connection = $configuration->getConnection();
1332 $this->_sm = $this->_connection->getSchemaManager();
1333 $this->_platform = $this->_connection->getDatabasePlatform();
1334 $this->_migration = new $class($this);
1338 * Returns the string version in the format YYYYMMDDHHMMSS
1340 * @return string $version
1342 public function getVersion()
1344 return $this->_version;
1348 * Returns the Migrations Configuration object instance
1350 * @return Configuration $configuration
1352 public function getConfiguration()
1354 return $this->_configuration;
1358 * Check if this version has been migrated or not.
1363 public function isMigrated()
1365 return $this->_configuration->hasVersionMigrated($this);
1368 public function markMigrated()
1370 $this->_configuration->createMigrationTable();
1371 $this->_connection->executeQuery("INSERT INTO " . $this->_configuration->getMigrationsTableName() . " (version) VALUES (?)", array($this->_version));
1374 public function markNotMigrated()
1376 $this->_configuration->createMigrationTable();
1377 $this->_connection->executeQuery("DELETE FROM " . $this->_configuration->getMigrationsTableName() . " WHERE version = '$this->_version'");
1381 * Add some SQL queries to this versions migration
1386 public function addSql($sql)
1388 if (is_array($sql)) {
1389 foreach ($sql as $query) {
1390 $this->_sql[] = $query;
1393 $this->_sql[] = $sql;
1398 * Write a migration SQL file to the given path
1400 * @param string $path The path to write the migration SQL file.
1401 * @param string $direction The direction to execute.
1402 * @return bool $written
1404 public function writeSqlFile($path, $direction = 'up')
1406 $queries = $this->execute($direction, true);
1408 $string = sprintf("# Doctrine Migration File Generated on %s\n", date('Y-m-d H:m:s'));
1410 $string .= "\n# Version " . $this->_version . "\n";
1411 foreach ($queries as $query) {
1412 $string .= $query . ";\n";
1414 if (is_dir($path)) {
1415 $path = realpath($path);
1416 $path = $path . '/doctrine_migration_' . date('YmdHis') . '.sql';
1419 $this->_outputWriter->write("\n".sprintf('Writing migration file to "<info>%s</info>"', $path));
1421 return file_put_contents($path, $string);
1425 * Execute this migration version up or down and and return the SQL.
1427 * @param string $direction The direction to execute the migration.
1428 * @param string $dryRun Whether to not actually execute the migration SQL and just do a dry run.
1429 * @return array $sql
1430 * @throws Exception when migration fails
1432 public function execute($direction, $dryRun = false)
1434 $this->_sql = array();
1436 $this->_connection->beginTransaction();
1439 $start = microtime(true);
1441 $this->_state = self::STATE_PRE;
1442 $fromSchema = $this->_sm->createSchema();
1443 $this->_migration->{'pre' . ucfirst($direction)}($fromSchema);
1445 if ($direction === 'up') {
1446 $this->_outputWriter->write("\n" . sprintf(' <info>++</info> migrating <comment>%s</comment>', $this->_version) . "\n");
1448 $this->_outputWriter->write("\n" . sprintf(' <info>--</info> reverting <comment>%s</comment>', $this->_version) . "\n");
1451 $this->_state = self::STATE_EXEC;
1453 $toSchema = clone $fromSchema;
1454 $this->_migration->$direction($toSchema);
1455 $this->addSql($fromSchema->getMigrateToSql($toSchema, $this->_platform));
1457 if ($dryRun === false) {
1459 $count = count($this->_sql);
1460 foreach ($this->_sql as $query) {
1461 $this->_outputWriter->write(' <comment>-></comment> ' . $query);
1462 $this->_connection->executeQuery($query);
1465 if ($direction === 'up') {
1466 $this->markMigrated();
1468 $this->markNotMigrated();
1471 $this->_outputWriter->write(sprintf('<error>Migration %s was executed but did not result in any SQL statements.</error>', $this->_version));
1474 foreach ($this->_sql as $query) {
1475 $this->_outputWriter->write(' <comment>-></comment> ' . $query);
1479 $this->_state = self::STATE_POST;
1480 $this->_migration->{'post' . ucfirst($direction)}($toSchema);
1482 $end = microtime(true);
1483 $this->_time = round($end - $start, 2);
1484 if ($direction === 'up') {
1485 $this->_outputWriter->write(sprintf("\n <info>++</info> migrated (%ss)", $this->_time));
1487 $this->_outputWriter->write(sprintf("\n <info>--</info> reverted (%ss)", $this->_time));
1490 $this->_connection->commit();
1493 } catch(SkipMigrationException $e) {
1494 $this->_connection->rollback();
1496 // now mark it as migrated
1497 if ($direction === 'up') {
1498 $this->markMigrated();
1500 $this->markNotMigrated();
1503 $this->_outputWriter->write(sprintf("\n <info>SS</info> skipped (Reason: %s)", $e->getMessage()));
1504 } catch (\Exception $e) {
1506 $this->_outputWriter->write(sprintf(
1507 '<error>Migration %s failed during %s. Error %s</error>',
1508 $this->_version, $this->getExecutionState(), $e->getMessage()
1511 $this->_connection->rollback();
1513 $this->_state = self::STATE_NONE;
1516 $this->_state = self::STATE_NONE;
1519 public function getExecutionState()
1521 switch($this->_state) {
1522 case self::STATE_PRE:
1523 return 'Pre-Checks';
1524 case self::STATE_POST:
1525 return 'Post-Checks';
1526 case self::STATE_EXEC:
1534 * Returns the time this migration version took to execute
1536 * @return integer $time The time this migration version took to execute
1538 public function getTime()
1540 return $this->_time;
1543 public function __toString()
1545 return $this->_version;
1550 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1551 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1552 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1553 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1554 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1555 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1556 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1557 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1558 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1559 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1560 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1562 * This software consists of voluntary contributions made by many individuals
1563 * and is licensed under the LGPL. For more information, see
1564 * <http://www.doctrine-project.org>.
1568 namespace Doctrine\DBAL\Migrations;
1570 class MigrationsVersion
1572 const VERSION = '2.0.0-DEV';
1577 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1578 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1579 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1580 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1581 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1582 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1583 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1584 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1585 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1586 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1587 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1589 * This software consists of voluntary contributions made by many individuals
1590 * and is licensed under the LGPL. For more information, see
1591 * <http://www.doctrine-project.org>.
1594 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
1596 use Symfony\Component\Console\Input\InputInterface,
1597 Symfony\Component\Console\Output\OutputInterface,
1598 Symfony\Component\Console\Input\InputArgument,
1599 Symfony\Component\Console\Input\InputOption,
1600 Doctrine\ORM\Tools\SchemaTool,
1601 Doctrine\DBAL\Migrations\Configuration\Configuration;
1604 * Command for generate migration classes by comparing your current database schema
1605 * to your mapping information.
1607 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1608 * @link www.doctrine-project.org
1610 * @version $Revision$
1611 * @author Jonathan Wage <jonwage@gmail.com>
1613 class DiffCommand extends GenerateCommand
1615 protected function configure()
1617 parent::configure();
1620 ->setName('migrations:diff')
1621 ->setDescription('Generate a migration by comparing your current database to your mapping information.')
1623 The <info>%command.name%</info> command generates a migration by comparing your current database to your mapping information:
1625 <info>%command.full_name%</info>
1627 You can optionally specify a <comment>--editor-cmd</comment> option to open the generated file in your favorite editor:
1629 <info>%command.full_name% --editor-cmd=mate</info>
1635 public function execute(InputInterface $input, OutputInterface $output)
1637 $configuration = $this->_getMigrationConfiguration($input, $output);
1639 $em = $this->getHelper('em')->getEntityManager();
1640 $conn = $em->getConnection();
1641 $platform = $conn->getDatabasePlatform();
1642 $metadata = $em->getMetadataFactory()->getAllMetadata();
1644 if (empty($metadata)) {
1645 $output->writeln('No mapping information to process.', 'ERROR');
1649 $tool = new SchemaTool($em);
1651 $fromSchema = $conn->getSchemaManager()->createSchema();
1652 $toSchema = $tool->getSchemaFromMetadata($metadata);
1653 $up = $this->_buildCodeFromSql($configuration, $fromSchema->getMigrateToSql($toSchema, $platform));
1654 $down = $this->_buildCodeFromSql($configuration, $fromSchema->getMigrateFromSql($toSchema, $platform));
1656 if ( ! $up && ! $down) {
1657 $output->writeln('No changes detected in your mapping information.', 'ERROR');
1661 $version = date('YmdHis');
1662 $path = $this->_generateMigration($configuration, $input, $version, $up, $down);
1664 $output->writeln(sprintf('Generated new migration class to "<info>%s</info>" from schema differences.', $path));
1667 private function _buildCodeFromSql(Configuration $configuration, array $sql)
1670 foreach ($sql as $query) {
1671 if (strpos($query, $configuration->getMigrationsTableName()) !== false) {
1674 $code[] = "\$this->_addSql('" . $query . "');";
1676 return implode("\n", $code);
1683 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1684 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1685 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1686 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1687 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1688 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1689 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1690 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1691 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1692 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1693 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1695 * This software consists of voluntary contributions made by many individuals
1696 * and is licensed under the LGPL. For more information, see
1697 * <http://www.doctrine-project.org>.
1700 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
1702 use Symfony\Component\Console\Command\Command,
1703 Symfony\Component\Console\Input\InputInterface,
1704 Symfony\Component\Console\Output\OutputInterface,
1705 Symfony\Component\Console\Input\InputOption,
1706 Doctrine\DBAL\Migrations\Migration,
1707 Doctrine\DBAL\Migrations\MigrationException,
1708 Doctrine\DBAL\Migrations\OutputWriter,
1709 Doctrine\DBAL\Migrations\Configuration\Configuration,
1710 Doctrine\DBAL\Migrations\Configuration\YamlConfiguration,
1711 Doctrine\DBAL\Migrations\Configuration\XmlConfiguration;
1714 * CLI Command for adding and deleting migration versions from the version table.
1716 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1717 * @link www.doctrine-project.org
1719 * @version $Revision$
1720 * @author Jonathan Wage <jonwage@gmail.com>
1722 abstract class AbstractCommand extends Command
1724 protected $_configuration;
1726 protected function configure()
1728 $this->addOption('configuration', null, InputOption::PARAMETER_OPTIONAL, 'The path to a migrations configuration file.');
1729 $this->addOption('db-configuration', null, InputOption::PARAMETER_OPTIONAL, 'The path to a database connection configuration file.');
1732 protected function _outputHeader(Configuration $configuration, OutputInterface $output)
1734 $name = $configuration->getName();
1735 $name = $name ? $name : 'Doctrine Database Migrations';
1736 $name = str_repeat(' ', 20) . $name . str_repeat(' ', 20);
1737 $output->writeln('<question>' . str_repeat(' ', strlen($name)) . '</question>');
1738 $output->writeln('<question>' . $name . '</question>');
1739 $output->writeln('<question>' . str_repeat(' ', strlen($name)) . '</question>');
1740 $output->writeln('');
1744 * @param InputInterface $input
1745 * @param OutputInterface $output
1746 * @return Configuration
1748 protected function _getMigrationConfiguration(InputInterface $input, OutputInterface $output)
1750 if ( ! $this->_configuration) {
1751 $outputWriter = new OutputWriter(function($message) use ($output) {
1752 return $output->writeln($message);
1755 if ($this->application->getHelperSet()->has('db')) {
1756 $conn = $this->getHelper('db')->getConnection();
1757 } else if($input->getOption('db-configuration')) {
1758 if (!file_exists($input->getOption('db-configuration'))) {
1759 throw new \InvalidArgumentException("The specified connection file is a valid file.");
1762 $params = include($input->getOption('db-configuration'));
1763 if (!is_array($params)) {
1764 throw new \InvalidArgumentException('The connection file has to return an array with database configuration parameters.');
1766 $conn = \Doctrine\DBAL\DriverManager::getConnection($params);
1767 } else if (file_exists('migrations-db.php')) {
1768 $params = include("migrations-db.php");
1769 if (!is_array($params)) {
1770 throw new \InvalidArgumentException('The connection file has to return an array with database configuration parameters.');
1772 $conn = \Doctrine\DBAL\DriverManager::getConnection($params);
1774 throw new \InvalidArgumentException('You have to specify a --db-configuration file or pass a Database Connection as a dependency to the Migrations.');
1777 if ($input->getOption('configuration')) {
1778 $info = pathinfo($input->getOption('configuration'));
1779 $class = $info['extension'] === 'xml' ? 'Doctrine\DBAL\Migrations\Configuration\XmlConfiguration' : 'Doctrine\DBAL\Migrations\Configuration\YamlConfiguration';
1780 $configuration = new $class($conn, $outputWriter);
1781 $configuration->load($input->getOption('configuration'));
1782 } else if (file_exists('migrations.xml')) {
1783 $configuration = new XmlConfiguration($conn, $outputWriter);
1784 $configuration->load('migrations.xml');
1785 } else if (file_exists('migrations.yml')) {
1786 $configuration = new YamlConfiguration($conn, $outputWriter);
1787 $configuration->load('migrations.yml');
1789 $configuration = new Configuration($conn, $outputWriter);
1791 $this->_configuration = $configuration;
1793 return $this->_configuration;
1800 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1801 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1802 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1803 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1804 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1805 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1806 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1807 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1808 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1809 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1810 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1812 * This software consists of voluntary contributions made by many individuals
1813 * and is licensed under the LGPL. For more information, see
1814 * <http://www.doctrine-project.org>.
1817 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
1819 use Symfony\Component\Console\Input\InputInterface,
1820 Symfony\Component\Console\Output\OutputInterface,
1821 Symfony\Component\Console\Input\InputArgument,
1822 Symfony\Component\Console\Input\InputOption,
1823 Doctrine\DBAL\Migrations\MigrationException,
1824 Doctrine\DBAL\Migrations\Configuration\Configuration;
1827 * Command for generating new blank migration classes
1829 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1830 * @link www.doctrine-project.org
1832 * @version $Revision$
1833 * @author Jonathan Wage <jonwage@gmail.com>
1835 class GenerateCommand extends AbstractCommand
1837 private static $_template =
1840 namespace <namespace>;
1842 use Doctrine\DBAL\Migrations\AbstractMigration,
1843 Doctrine\DBAL\Schema\Schema;
1845 class Version<version> extends AbstractMigration
1847 public function up(Schema $schema)
1852 public function down(Schema $schema)
1858 protected function configure()
1861 ->setName('migrations:generate')
1862 ->setDescription('Generate a blank migration class.')
1863 ->addOption('editor-cmd', null, InputOption::PARAMETER_OPTIONAL, 'Open file with this command upon creation.')
1865 The <info>%command.name%</info> command generates a blank migration class:
1867 <info>%command.full_name%</info>
1869 You can optionally specify a <comment>--editor-cmd</comment> option to open the generated file in your favorite editor:
1871 <info>%command.full_name% --editor-cmd=mate</info>
1875 parent::configure();
1878 public function execute(InputInterface $input, OutputInterface $output)
1880 $configuration = $this->_getMigrationConfiguration($input, $output);
1882 $version = date('YmdHis');
1883 $path = $this->_generateMigration($configuration, $input, $version);
1885 $output->writeln(sprintf('Generated new migration class to "<info>%s</info>"', $path));
1888 protected function _generateMigration(Configuration $configuration, InputInterface $input, $version, $up = null, $down = null)
1890 $placeHolders = array(
1896 $replacements = array(
1897 $configuration->getMigrationsNamespace(),
1899 $up ? " " . implode("\n ", explode("\n", $up)) : null,
1900 $down ? " " . implode("\n ", explode("\n", $down)) : null
1902 $code = str_replace($placeHolders, $replacements, self::$_template);
1903 $dir = $configuration->getMigrationsDirectory();
1904 $dir = $dir ? $dir : getcwd();
1905 $dir = rtrim($dir, '/');
1906 $path = $dir . '/Version' . $version . '.php';
1908 file_put_contents($path, $code);
1910 if ($editorCmd = $input->getOption('editor-cmd'))
1912 shell_exec($editorCmd . ' ' . escapeshellarg($path));
1922 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1923 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1924 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1925 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1926 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1927 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1928 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1929 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1930 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1931 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1932 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1934 * This software consists of voluntary contributions made by many individuals
1935 * and is licensed under the LGPL. For more information, see
1936 * <http://www.doctrine-project.org>.
1939 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
1941 use Symfony\Component\Console\Input\InputInterface,
1942 Symfony\Component\Console\Output\OutputInterface,
1943 Symfony\Component\Console\Input\InputArgument,
1944 Symfony\Component\Console\Input\InputOption,
1945 Doctrine\DBAL\Migrations\Migration,
1946 Doctrine\DBAL\Migrations\MigrationException,
1947 Doctrine\DBAL\Migrations\Configuration\Configuration,
1948 Doctrine\DBAL\Migrations\Configuration\YamlConfiguration,
1949 Doctrine\DBAL\Migrations\Configuration\XmlConfiguration;
1952 * Command for manually adding and deleting migration versions from the version table.
1954 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1955 * @link www.doctrine-project.org
1957 * @version $Revision$
1958 * @author Jonathan Wage <jonwage@gmail.com>
1960 class VersionCommand extends AbstractCommand
1962 protected function configure()
1965 ->setName('migrations:version')
1966 ->setDescription('Manually add and delete migration versions from the version table.')
1967 ->addArgument('version', InputArgument::REQUIRED, 'The version to add or delete.', null)
1968 ->addOption('add', null, InputOption::PARAMETER_NONE, 'Add the specified version.')
1969 ->addOption('delete', null, InputOption::PARAMETER_NONE, 'Delete the specified version.')
1971 The <info>%command.name%</info> command allows you to manually add and delete migration versions from the version table:
1973 <info>%command.full_name% YYYYMMDDHHMMSS --add</info>
1975 If you want to delete a version you can use the <comment>--delete</comment> option:
1977 <info>%command.full_name% YYYYMMDDHHMMSS --delete</info>
1981 parent::configure();
1984 public function execute(InputInterface $input, OutputInterface $output)
1986 $configuration = $this->_getMigrationConfiguration($input, $output);
1987 $migration = new Migration($configuration);
1989 if ($input->getOption('add') === false && $input->getOption('delete') === false) {
1990 throw new \InvalidArgumentException('You must specify whether you want to --add or --delete the specified version.');
1993 $version = $input->getArgument('version');
1994 $markMigrated = $input->getOption('add') ? true : false;
1996 if ( ! $configuration->hasVersion($version)) {
1997 throw MigrationException::unknownMigrationVersion($version);
2000 $version = $configuration->getVersion($version);
2001 if ($markMigrated && $configuration->hasVersionMigrated($version)) {
2002 throw new \InvalidArgumentException(sprintf('The version "%s" already exists in the version table.', $version));
2005 if ( ! $markMigrated && ! $configuration->hasVersionMigrated($version)) {
2006 throw new \InvalidArgumentException(sprintf('The version "%s" does not exists in the version table.', $version));
2009 if ($markMigrated) {
2010 $version->markMigrated();
2012 $version->markNotMigrated();
2020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2021 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2022 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2023 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2024 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2025 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2026 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2027 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2028 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2029 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2030 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2032 * This software consists of voluntary contributions made by many individuals
2033 * and is licensed under the LGPL. For more information, see
2034 * <http://www.doctrine-project.org>.
2037 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
2039 use Symfony\Component\Console\Input\InputInterface,
2040 Symfony\Component\Console\Output\OutputInterface,
2041 Symfony\Component\Console\Input\InputArgument,
2042 Symfony\Component\Console\Input\InputOption,
2043 Doctrine\DBAL\Migrations\Migration,
2044 Doctrine\DBAL\Migrations\Configuration\Configuration,
2045 Doctrine\DBAL\Migrations\Configuration\YamlConfiguration,
2046 Doctrine\DBAL\Migrations\Configuration\XmlConfiguration;
2049 * Command for executing single migrations up or down manually.
2051 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
2052 * @link www.doctrine-project.org
2054 * @version $Revision$
2055 * @author Jonathan Wage <jonwage@gmail.com>
2057 class ExecuteCommand extends AbstractCommand
2059 protected function configure()
2062 ->setName('migrations:execute')
2063 ->setDescription('Execute a single migration version up or down manually.')
2064 ->addArgument('version', InputArgument::REQUIRED, 'The version to execute.', null)
2065 ->addOption('write-sql', null, InputOption::PARAMETER_NONE, 'The path to output the migration SQL file instead of executing it.')
2066 ->addOption('dry-run', null, InputOption::PARAMETER_NONE, 'Execute the migration as a dry run.')
2067 ->addOption('up', null, InputOption::PARAMETER_NONE, 'Execute the migration down.')
2068 ->addOption('down', null, InputOption::PARAMETER_NONE, 'Execute the migration down.')
2070 The <info>%command.name%</info> command executes a single migration version up or down manually:
2072 <info>%command.full_name% YYYYMMDDHHMMSS</info>
2074 If no <comment>--up</comment> or <comment>--down</comment> option is specified it defaults to up:
2076 <info>%command.full_name% YYYYMMDDHHMMSS --down</info>
2078 You can also execute the migration as a <comment>--dry-run</comment>:
2080 <info>%command.full_name% YYYYMMDDHHMMSS --dry-run</info>
2082 Or you can output the would be executed SQL statements to a file with <comment>--write-sql</comment>:
2084 <info>%command.full_name% YYYYMMDDHHMMSS --write-sql</info>
2088 parent::configure();
2091 public function execute(InputInterface $input, OutputInterface $output)
2093 $version = $input->getArgument('version');
2094 $direction = $input->getOption('down') ? 'down' : 'up';
2096 $configuration = $this->_getMigrationConfiguration($input, $output);
2097 $version = $configuration->getVersion($version);
2099 if ($path = $input->getOption('write-sql')) {
2100 $path = is_bool($path) ? getcwd() : $path;
2101 $version->writeSqlFile($path, $direction);
2103 $confirmation = $this->getHelper('dialog')->askConfirmation($output, '<question>WARNING! You are about to execute a database migration that could result in schema changes and data lost. Are you sure you wish to continue? (y/n)</question>', 'y');
2104 if ($confirmation === true) {
2105 $version->execute($direction, $input->getOption('dry-run') ? true : false);
2107 $output->writeln('<error>Migration cancelled!</error>');
2116 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2117 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2118 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2119 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2120 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2121 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2122 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2123 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2124 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2125 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2126 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2128 * This software consists of voluntary contributions made by many individuals
2129 * and is licensed under the LGPL. For more information, see
2130 * <http://www.doctrine-project.org>.
2133 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
2135 use Symfony\Component\Console\Input\InputInterface,
2136 Symfony\Component\Console\Output\OutputInterface,
2137 Symfony\Component\Console\Input\InputArgument,
2138 Symfony\Component\Console\Input\InputOption,
2139 Doctrine\DBAL\Migrations\Migration,
2140 Doctrine\DBAL\Migrations\MigrationException,
2141 Doctrine\DBAL\Migrations\Configuration\Configuration,
2142 Doctrine\DBAL\Migrations\Configuration\YamlConfiguration,
2143 Doctrine\DBAL\Migrations\Configuration\XmlConfiguration;
2146 * Command to view the status of a set of migrations.
2148 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
2149 * @link www.doctrine-project.org
2151 * @version $Revision$
2152 * @author Jonathan Wage <jonwage@gmail.com>
2154 class StatusCommand extends AbstractCommand
2156 protected function configure()
2159 ->setName('migrations:status')
2160 ->setDescription('View the status of a set of migrations.')
2161 ->addOption('show-versions', null, InputOption::PARAMETER_NONE, 'This will display a list of all available migrations and their status')
2163 The <info>%command.name%</info> command outputs the status of a set of migrations:
2165 <info>%command.full_name%</info>
2167 You can output a list of all available migrations and their status with <comment>--show-versions</comment>:
2169 <info>%command.full_name% --show-versions</info>
2173 parent::configure();
2176 public function execute(InputInterface $input, OutputInterface $output)
2178 $configuration = $this->_getMigrationConfiguration($input, $output);
2180 $currentVersion = $configuration->getCurrentVersion();
2181 if ($currentVersion) {
2182 $currentVersionFormatted = $configuration->formatVersion($currentVersion) . ' (<comment>'.$currentVersion.'</comment>)';
2184 $currentVersionFormatted = 0;
2186 $latestVersion = $configuration->getLatestVersion();
2187 if ($latestVersion) {
2188 $latestVersionFormatted = $configuration->formatVersion($latestVersion) . ' (<comment>'.$latestVersion.'</comment>)';
2190 $latestVersionFormatted = 0;
2192 $executedMigrations = $configuration->getNumberOfExecutedMigrations();
2193 $availableMigrations = $configuration->getNumberOfAvailableMigrations();
2194 $newMigrations = $availableMigrations - $executedMigrations;
2196 $output->writeln("\n <info>==</info> Configuration\n");
2199 'Name' => $configuration->getName() ? $configuration->getName() : 'Doctrine Database Migrations',
2200 'Database Driver' => $configuration->getConnection()->getDriver()->getName(),
2201 'Database Name' => $configuration->getConnection()->getDatabase(),
2202 'Configuration Source' => $configuration instanceof \Doctrine\DBAL\Migrations\Configuration\AbstractFileConfiguration ? $configuration->getFile() : 'manually configured',
2203 'Version Table Name' => $configuration->getMigrationsTableName(),
2204 'Migrations Namespace' => $configuration->getMigrationsNamespace(),
2205 'Migrations Directory' => $configuration->getMigrationsDirectory(),
2206 'Current Version' => $currentVersionFormatted,
2207 'Latest Version' => $latestVersionFormatted,
2208 'Executed Migrations' => $executedMigrations,
2209 'Available Migrations' => $availableMigrations,
2210 'New Migrations' => $newMigrations > 0 ? '<question>' . $newMigrations . '</question>' : $newMigrations
2212 foreach ($info as $name => $value) {
2213 $output->writeln(' <comment>>></comment> ' . $name . ': ' . str_repeat(' ', 50 - strlen($name)) . $value);
2216 $showVersions = $input->getOption('show-versions') ? true : false;
2217 if ($showVersions === true) {
2218 if ($migrations = $configuration->getMigrations()) {
2219 $output->writeln("\n <info>==</info> Migration Versions\n");
2220 foreach ($migrations as $version) {
2221 $isMigrated = $version->isMigrated();
2222 $status = $isMigrated ? '<info>migrated</info>' : '<error>not migrated</error>';
2223 $output->writeln(' <comment>>></comment> ' . $configuration->formatVersion($version->getVersion()) . ' (<comment>' . $version->getVersion() . '</comment>)' . str_repeat(' ', 30 - strlen($name)) . $status);
2233 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2234 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2235 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2236 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2237 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2238 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2239 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2240 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2241 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2242 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2243 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2245 * This software consists of voluntary contributions made by many individuals
2246 * and is licensed under the LGPL. For more information, see
2247 * <http://www.doctrine-project.org>.
2250 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
2252 use Symfony\Component\Console\Input\InputInterface,
2253 Symfony\Component\Console\Output\OutputInterface,
2254 Symfony\Component\Console\Input\InputArgument,
2255 Symfony\Component\Console\Input\InputOption,
2256 Doctrine\DBAL\Migrations\Migration,
2257 Doctrine\DBAL\Migrations\Configuration\Configuration,
2258 Doctrine\DBAL\Migrations\Configuration\YamlConfiguration,
2259 Doctrine\DBAL\Migrations\Configuration\XmlConfiguration;
2262 * Command for executing a migration to a specified version or the latest available version.
2264 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
2265 * @link www.doctrine-project.org
2267 * @version $Revision$
2268 * @author Jonathan Wage <jonwage@gmail.com>
2270 class MigrateCommand extends AbstractCommand
2272 protected function configure()
2275 ->setName('migrations:migrate')
2276 ->setDescription('Execute a migration to a specified version or the latest available version.')
2277 ->addArgument('version', InputArgument::OPTIONAL, 'The version to migrate to.', null)
2278 ->addOption('write-sql', null, InputOption::PARAMETER_NONE, 'The path to output the migration SQL file instead of executing it.')
2279 ->addOption('dry-run', null, InputOption::PARAMETER_NONE, 'Execute the migration as a dry run.')
2281 The <info>%command.name%</info> command executes a migration to a specified version or the latest available version:
2283 <info>%command.full_name%</info>
2285 You can optionally manually specify the version you wish to migrate to:
2287 <info>%command.full_name% YYYYMMDDHHMMSS</info>
2289 You can also execute the migration as a <comment>--dry-run</comment>:
2291 <info>%command.full_name% YYYYMMDDHHMMSS --dry-run</info>
2293 Or you can output the would be executed SQL statements to a file with <comment>--write-sql</comment>:
2295 <info>%command.full_name% YYYYMMDDHHMMSS --write-sql</info>
2297 You can also execute the migration without a warning message wich you need to interact with:
2299 <info>%command.full_name% --no-interaction</info>
2304 parent::configure();
2307 public function execute(InputInterface $input, OutputInterface $output)
2309 $version = $input->getArgument('version');
2311 $configuration = $this->_getMigrationConfiguration($input, $output);
2312 $migration = new Migration($configuration);
2314 $this->_outputHeader($configuration, $output);
2316 if ($path = $input->getOption('write-sql')) {
2317 $path = is_bool($path) ? getcwd() : $path;
2318 $migration->writeSqlFile($path, $version);
2320 $dryRun = $input->getOption('dry-run') ? true : false;
2321 if ($dryRun === true) {
2322 $migration->migrate($version, true);
2324 $noInteraction = $input->getOption('no-interaction') ? true : false;
2325 if ($noInteraction === true) {
2326 $migration->migrate($version, $dryRun);
2328 $confirmation = $this->getHelper('dialog')->askConfirmation($output, '<question>WARNING! You are about to execute a database migration that could result in schema changes and data lost. Are you sure you wish to continue? (y/n)</question>', 'y');
2329 if ($confirmation === true) {
2330 $migration->migrate($version, $dryRun);
2332 $output->writeln('<error>Migration cancelled!</error>');
2341 namespace Doctrine\DBAL;
2343 class DBALException extends \Exception
2345 public static function notSupported($method)
2347 return new self("Operation '$method' is not supported by platform.");
2350 public static function invalidPlatformSpecified()
2353 "Invalid 'platform' option specified, need to give an instance of ".
2354 "\Doctrine\DBAL\Platforms\AbstractPlatform.");
2357 public static function invalidPdoInstance()
2360 "The 'pdo' option was used in DriverManager::getConnection() but no ".
2361 "instance of PDO was given."
2365 public static function driverRequired()
2367 return new self("The options 'driver' or 'driverClass' are mandatory if no PDO ".
2368 "instance is given to DriverManager::getConnection().");
2371 public static function unknownDriver($unknownDriverName, array $knownDrivers)
2373 return new self("The given 'driver' ".$unknownDriverName." is unknown, ".
2374 "Doctrine currently supports only the following drivers: ".implode(", ", $knownDrivers));
2377 public static function invalidWrapperClass($wrapperClass)
2379 return new self("The given 'wrapperClass' ".$wrapperClass." has to be a ".
2380 "subtype of \Doctrine\DBAL\Connection.");
2383 public static function invalidDriverClass($driverClass)
2385 return new self("The given 'driverClass' ".$driverClass." has to implement the ".
2386 "\Doctrine\DBAL\Driver interface.");
2390 * @param string $tableName
2391 * @return DBALException
2393 public static function invalidTableName($tableName)
2395 return new self("Invalid table name specified: ".$tableName);
2399 * @param string $tableName
2400 * @return DBALException
2402 public static function noColumnsSpecifiedForTable($tableName)
2404 return new self("No columns specified for table ".$tableName);
2407 public static function limitOffsetInvalid()
2409 return new self("Invalid Offset in Limit Query, it has to be larger or equal to 0.");
2412 public static function typeExists($name)
2414 return new self('Type '.$name.' already exists.');
2417 public static function unknownColumnType($name)
2419 return new self('Unknown column type '.$name.' requested.');
2422 public static function typeNotFound($name)
2424 return new self('Type to be overwritten '.$name.' does not exist.');
2430 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2431 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2432 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2433 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2434 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2435 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2436 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2437 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2438 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2439 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2440 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2442 * This software consists of voluntary contributions made by many individuals
2443 * and is licensed under the LGPL. For more information, see
2444 * <http://www.doctrine-project.org>.
2447 namespace Doctrine\DBAL\Driver\PDOOracle;
2449 use Doctrine\DBAL\Platforms;
2451 class Driver implements \Doctrine\DBAL\Driver
2453 public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
2455 return new \Doctrine\DBAL\Driver\PDOConnection(
2456 $this->_constructPdoDsn($params),
2464 * Constructs the Oracle PDO DSN.
2466 * @return string The DSN.
2468 private function _constructPdoDsn(array $params)
2471 if (isset($params['host'])) {
2472 $dsn .= 'dbname=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)' .
2473 '(HOST=' . $params['host'] . ')';
2475 if (isset($params['port'])) {
2476 $dsn .= '(PORT=' . $params['port'] . ')';
2478 $dsn .= '(PORT=1521)';
2481 $dsn .= '))(CONNECT_DATA=(SID=' . $params['dbname'] . ')))';
2483 $dsn .= 'dbname=' . $params['dbname'];
2486 if (isset($params['charset'])) {
2487 $dsn .= ';charset=' . $params['charset'];
2493 public function getDatabasePlatform()
2495 return new \Doctrine\DBAL\Platforms\OraclePlatform();
2498 public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
2500 return new \Doctrine\DBAL\Schema\OracleSchemaManager($conn);
2503 public function getName()
2505 return 'pdo_oracle';
2508 public function getDatabase(\Doctrine\DBAL\Connection $conn)
2510 $params = $conn->getParams();
2511 return $params['user'];
2517 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2518 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2519 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2520 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2521 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2522 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2523 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2524 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2525 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2526 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2527 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2529 * This software consists of voluntary contributions made by many individuals
2530 * and is licensed under the LGPL. For more information, see
2531 * <http://www.doctrine-project.org>.
2534 namespace Doctrine\DBAL\Driver\IBMDB2;
2536 class DB2Connection implements \Doctrine\DBAL\Driver\Connection
2538 private $_conn = null;
2540 public function __construct(array $params, $username, $password, $driverOptions = array())
2542 $isPersistant = (isset($params['persistent']) && $params['persistent'] == true);
2544 if ($isPersistant) {
2545 $this->_conn = db2_pconnect($params['dbname'], $username, $password, $driverOptions);
2547 $this->_conn = db2_connect($params['dbname'], $username, $password, $driverOptions);
2549 if (!$this->_conn) {
2550 throw new DB2Exception(db2_conn_errormsg());
2554 function prepare($sql)
2556 $stmt = @db2_prepare($this->_conn, $sql);
2558 throw new DB2Exception(db2_stmt_errormsg());
2560 return new DB2Statement($stmt);
2565 $args = func_get_args();
2567 $stmt = $this->prepare($sql);
2572 function quote($input, $type=\PDO::PARAM_STR)
2574 $input = db2_escape_string($input);
2575 if ($type == \PDO::PARAM_INT ) {
2578 return "'".$input."'";
2582 function exec($statement)
2584 $stmt = $this->prepare($statement);
2586 return $stmt->rowCount();
2589 function lastInsertId($name = null)
2591 return db2_last_insert_id($this->_conn);
2594 function beginTransaction()
2596 db2_autocommit($this->_conn, DB2_AUTOCOMMIT_OFF);
2601 if (!db2_commit($this->_conn)) {
2602 throw new DB2Exception(db2_conn_errormsg($this->_conn));
2604 db2_autocommit($this->_conn, DB2_AUTOCOMMIT_ON);
2609 if (!db2_rollback($this->_conn)) {
2610 throw new DB2Exception(db2_conn_errormsg($this->_conn));
2612 db2_autocommit($this->_conn, DB2_AUTOCOMMIT_ON);
2615 function errorCode()
2617 return db2_conn_error($this->_conn);
2620 function errorInfo()
2623 0 => db2_conn_errormsg($this->_conn),
2624 1 => $this->errorCode(),
2631 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2632 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2633 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2634 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2635 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2636 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2637 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2638 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2639 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2640 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2641 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2643 * This software consists of voluntary contributions made by many individuals
2644 * and is licensed under the LGPL. For more information, see
2645 * <http://www.doctrine-project.org>.
2648 namespace Doctrine\DBAL\Driver\IBMDB2;
2650 class DB2Statement implements \Doctrine\DBAL\Driver\Statement
2652 private $_stmt = null;
2654 private $_bindParam = array();
2657 * DB2_BINARY, DB2_CHAR, DB2_DOUBLE, or DB2_LONG
2660 static private $_typeMap = array(
2661 \PDO::PARAM_INT => DB2_LONG,
2662 \PDO::PARAM_STR => DB2_CHAR,
2665 public function __construct($stmt)
2667 $this->_stmt = $stmt;
2671 * Binds a value to a corresponding named or positional
2672 * placeholder in the SQL statement that was used to prepare the statement.
2674 * @param mixed $param Parameter identifier. For a prepared statement using named placeholders,
2675 * this will be a parameter name of the form :name. For a prepared statement
2676 * using question mark placeholders, this will be the 1-indexed position of the parameter
2678 * @param mixed $value The value to bind to the parameter.
2679 * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants.
2681 * @return boolean Returns TRUE on success or FALSE on failure.
2683 function bindValue($param, $value, $type = null)
2685 return $this->bindParam($param, $value, $type);
2689 * Binds a PHP variable to a corresponding named or question mark placeholder in the
2690 * SQL statement that was use to prepare the statement. Unlike PDOStatement->bindValue(),
2691 * the variable is bound as a reference and will only be evaluated at the time
2692 * that PDOStatement->execute() is called.
2694 * Most parameters are input parameters, that is, parameters that are
2695 * used in a read-only fashion to build up the query. Some drivers support the invocation
2696 * of stored procedures that return data as output parameters, and some also as input/output
2697 * parameters that both send in data and are updated to receive it.
2699 * @param mixed $param Parameter identifier. For a prepared statement using named placeholders,
2700 * this will be a parameter name of the form :name. For a prepared statement
2701 * using question mark placeholders, this will be the 1-indexed position of the parameter
2703 * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter.
2705 * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. To return
2706 * an INOUT parameter from a stored procedure, use the bitwise OR operator to set the
2707 * PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter.
2708 * @return boolean Returns TRUE on success or FALSE on failure.
2710 function bindParam($column, &$variable, $type = null)
2712 $this->_bindParam[$column] =& $variable;
2714 if ($type && isset(self::$_typeMap[$type])) {
2715 $type = self::$_typeMap[$type];
2720 if (!db2_bind_param($this->_stmt, $column, "variable", DB2_PARAM_IN, $type)) {
2721 throw new DB2Exception(db2_stmt_errormsg());
2727 * Closes the cursor, enabling the statement to be executed again.
2729 * @return boolean Returns TRUE on success or FALSE on failure.
2731 function closeCursor()
2733 if (!$this->_stmt) {
2737 $this->_bindParam = array();
2738 db2_free_result($this->_stmt);
2739 $ret = db2_free_stmt($this->_stmt);
2740 $this->_stmt = false;
2746 * Returns the number of columns in the result set
2748 * @return integer Returns the number of columns in the result set represented
2749 * by the PDOStatement object. If there is no result set,
2750 * this method should return 0.
2752 function columnCount()
2754 if (!$this->_stmt) {
2757 return db2_num_fields($this->_stmt);
2762 * Fetch the SQLSTATE associated with the last operation on the statement handle
2764 * @see Doctrine_Adapter_Interface::errorCode()
2765 * @return string error code string
2767 function errorCode()
2769 return db2_stmt_error();
2774 * Fetch extended error information associated with the last operation on the statement handle
2776 * @see Doctrine_Adapter_Interface::errorInfo()
2777 * @return array error info array
2779 function errorInfo()
2782 0 => db2_stmt_errormsg(),
2783 1 => db2_stmt_error(),
2788 * Executes a prepared statement
2790 * If the prepared statement included parameter markers, you must either:
2791 * call PDOStatement->bindParam() to bind PHP variables to the parameter markers:
2792 * bound variables pass their value as input and receive the output value,
2793 * if any, of their associated parameter markers or pass an array of input-only
2797 * @param array $params An array of values with as many elements as there are
2798 * bound parameters in the SQL statement being executed.
2799 * @return boolean Returns TRUE on success or FALSE on failure.
2801 function execute($params = null)
2803 if (!$this->_stmt) {
2808 if ($params !== null) {
2809 $retval = @db2_execute($this->_stmt, $params);
2811 $retval = @db2_execute($this->_stmt);
2813 if ($params === null) {
2814 ksort($this->_bindParam);
2815 $params = array_values($this->_bindParam);
2817 $retval = @db2_execute($this->_stmt, $params);
2819 if ($retval === false) {
2820 throw new DB2Exception(db2_stmt_errormsg());
2828 * @see Query::HYDRATE_* constants
2829 * @param integer $fetchStyle Controls how the next row will be returned to the caller.
2830 * This value must be one of the Query::HYDRATE_* constants,
2831 * defaulting to Query::HYDRATE_BOTH
2833 * @param integer $cursorOrientation For a PDOStatement object representing a scrollable cursor,
2834 * this value determines which row will be returned to the caller.
2835 * This value must be one of the Query::HYDRATE_ORI_* constants, defaulting to
2836 * Query::HYDRATE_ORI_NEXT. To request a scrollable cursor for your
2837 * PDOStatement object,
2838 * you must set the PDO::ATTR_CURSOR attribute to Doctrine::CURSOR_SCROLL when you
2839 * prepare the SQL statement with Doctrine_Adapter_Interface->prepare().
2841 * @param integer $cursorOffset For a PDOStatement object representing a scrollable cursor for which the
2842 * $cursorOrientation parameter is set to Query::HYDRATE_ORI_ABS, this value specifies
2843 * the absolute number of the row in the result set that shall be fetched.
2845 * For a PDOStatement object representing a scrollable cursor for
2846 * which the $cursorOrientation parameter is set to Query::HYDRATE_ORI_REL, this value
2847 * specifies the row to fetch relative to the cursor position before
2848 * PDOStatement->fetch() was called.
2852 function fetch($fetchStyle = \PDO::FETCH_BOTH)
2854 switch ($fetchStyle) {
2855 case \PDO::FETCH_BOTH:
2856 return db2_fetch_both($this->_stmt);
2857 case \PDO::FETCH_ASSOC:
2858 return db2_fetch_assoc($this->_stmt);
2859 case \PDO::FETCH_NUM:
2860 return db2_fetch_array($this->_stmt);
2862 throw new DB2Exception("Given Fetch-Style " . $fetchStyle . " is not supported.");
2867 * Returns an array containing all of the result set rows
2869 * @param integer $fetchStyle Controls how the next row will be returned to the caller.
2870 * This value must be one of the Query::HYDRATE_* constants,
2871 * defaulting to Query::HYDRATE_BOTH
2873 * @param integer $columnIndex Returns the indicated 0-indexed column when the value of $fetchStyle is
2874 * Query::HYDRATE_COLUMN. Defaults to 0.
2878 function fetchAll($fetchStyle = \PDO::FETCH_BOTH)
2881 while ($row = $this->fetch($fetchStyle)) {
2889 * Returns a single column from the next row of a
2890 * result set or FALSE if there are no more rows.
2892 * @param integer $columnIndex 0-indexed number of the column you wish to retrieve from the row. If no
2893 * value is supplied, PDOStatement->fetchColumn()
2894 * fetches the first column.
2896 * @return string returns a single column in the next row of a result set.
2898 function fetchColumn($columnIndex = 0)
2900 $row = $this->fetch(\PDO::FETCH_NUM);
2901 if ($row && isset($row[$columnIndex])) {
2902 return $row[$columnIndex];
2909 * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement
2910 * executed by the corresponding object.
2912 * If the last SQL statement executed by the associated Statement object was a SELECT statement,
2913 * some databases may return the number of rows returned by that statement. However,
2914 * this behaviour is not guaranteed for all databases and should not be
2915 * relied on for portable applications.
2917 * @return integer Returns the number of rows.
2921 return (@db2_num_rows($this->_stmt))?:0;
2928 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2929 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2930 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2931 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2932 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2933 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2934 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2935 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2936 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2937 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2938 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2940 * This software consists of voluntary contributions made by many individuals
2941 * and is licensed under the LGPL. For more information, see
2942 * <http://www.doctrine-project.org>.
2945 namespace Doctrine\DBAL\Driver\IBMDB2;
2947 class DB2Exception extends \Exception
2952 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2953 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2954 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2955 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2956 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2957 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2958 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2959 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2960 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2961 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2962 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2964 * This software consists of voluntary contributions made by many individuals
2965 * and is licensed under the LGPL. For more information, see
2966 * <http://www.doctrine-project.org>.
2969 namespace Doctrine\DBAL\Driver\IBMDB2;
2971 use Doctrine\DBAL\Driver,
2972 Doctrine\DBAL\Connection;
2978 * @author Benjamin Eberlei <kontakt@beberlei.de>
2980 class DB2Driver implements Driver
2983 * Attempts to create a connection with the database.
2985 * @param array $params All connection parameters passed by the user.
2986 * @param string $username The username to use when connecting.
2987 * @param string $password The password to use when connecting.
2988 * @param array $driverOptions The driver options to use when connecting.
2989 * @return Doctrine\DBAL\Driver\Connection The database connection.
2991 public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
2993 if ( !isset($params['schema']) ) {
2997 if ($params['host'] !== 'localhost' && $params['host'] != '127.0.0.1') {
2998 // if the host isn't localhost, use extended connection params
2999 $params['dbname'] = 'DRIVER={IBM DB2 ODBC DRIVER}' .
3000 ';DATABASE=' . $params['dbname'] .
3001 ';HOSTNAME=' . $params['host'] .
3002 ';PORT=' . $params['port'] .
3003 ';PROTOCOL=' . $params['protocol'] .
3004 ';UID=' . $username .
3005 ';PWD=' . $password .';';
3010 return new DB2Connection($params, $username, $password, $driverOptions);
3014 * Gets the DatabasePlatform instance that provides all the metadata about
3015 * the platform this driver connects to.
3017 * @return Doctrine\DBAL\Platforms\AbstractPlatform The database platform.
3019 public function getDatabasePlatform()
3021 return new \Doctrine\DBAL\Platforms\DB2Platform;
3025 * Gets the SchemaManager that can be used to inspect and change the underlying
3026 * database schema of the platform this driver connects to.
3028 * @param Doctrine\DBAL\Connection $conn
3029 * @return Doctrine\DBAL\SchemaManager
3031 public function getSchemaManager(Connection $conn)
3033 return new \Doctrine\DBAL\Schema\DB2SchemaManager($conn);
3037 * Gets the name of the driver.
3039 * @return string The name of the driver.
3041 public function getName()
3047 * Get the name of the database connected to for this driver.
3049 * @param Doctrine\DBAL\Connection $conn
3050 * @return string $database
3052 public function getDatabase(\Doctrine\DBAL\Connection $conn)
3054 $params = $conn->getParams();
3055 return $params['dbname'];
3060 * $Id: Interface.php 3882 2008-02-22 18:11:35Z jwage $
3062 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3063 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3064 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3065 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3066 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3067 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3068 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3069 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3070 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3071 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3072 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3074 * This software consists of voluntary contributions made by many individuals
3075 * and is licensed under the LGPL. For more information, see
3076 * <http://www.doctrine-project.org>.
3079 namespace Doctrine\DBAL\Driver;
3082 * The PDO implementation of the Statement interface.
3083 * Used by all PDO-based drivers.
3087 class PDOStatement extends \PDOStatement implements Statement
3089 private function __construct() {}
3094 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3095 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3096 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3097 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3098 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3099 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3100 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3101 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3102 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3103 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3104 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3106 * This software consists of voluntary contributions made by many individuals
3107 * and is licensed under the LGPL. For more information, see
3108 * <http://www.doctrine-project.org>.
3111 namespace Doctrine\DBAL\Driver\PDOMsSql;
3114 * The PDO-based MsSql driver.
3118 class Driver implements \Doctrine\DBAL\Driver
3120 public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3122 return new Connection(
3123 $this->_constructPdoDsn($params),
3131 * Constructs the MsSql PDO DSN.
3133 * @return string The DSN.
3135 private function _constructPdoDsn(array $params)
3137 // TODO: This might need to be revisted once we have access to a mssql server
3139 if (isset($params['host'])) {
3140 $dsn .= 'host=' . $params['host'] . ';';
3142 if (isset($params['port'])) {
3143 $dsn .= 'port=' . $params['port'] . ';';
3145 if (isset($params['dbname'])) {
3146 $dsn .= 'dbname=' . $params['dbname'] . ';';
3153 public function getDatabasePlatform()
3155 return new \Doctrine\DBAL\Platforms\MsSqlPlatform();
3158 public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
3160 return new \Doctrine\DBAL\Schema\MsSqlSchemaManager($conn);
3163 public function getName()
3168 public function getDatabase(\Doctrine\DBAL\Connection $conn)
3170 $params = $conn->getParams();
3171 return $params['dbname'];
3177 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3178 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3179 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3180 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3181 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3182 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3183 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3184 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3185 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3186 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3187 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3189 * This software consists of voluntary contributions made by many individuals
3190 * and is licensed under the LGPL. For more information, see
3191 * <http://www.doctrine-project.org>.
3194 namespace Doctrine\DBAL\Driver\PDOMsSql;
3197 * MsSql Connection implementation.
3201 class Connection extends \PDO implements \Doctrine\DBAL\Driver\Connection
3204 * Performs the rollback.
3208 public function rollback()
3210 $this->exec('ROLLBACK TRANSACTION');
3214 * Performs the commit.
3218 public function commit()
3220 $this->exec('COMMIT TRANSACTION');
3224 * Begins a database transaction.
3228 public function beginTransaction()
3230 $this->exec('BEGIN TRANSACTION');
3236 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3237 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3238 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3239 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3240 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3241 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3242 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3243 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3244 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3245 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3246 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3248 * This software consists of voluntary contributions made by many individuals
3249 * and is licensed under the LGPL. For more information, see
3250 * <http://www.doctrine-project.org>.
3253 namespace Doctrine\DBAL\Driver;
3258 * Statement interface.
3259 * Drivers must implement this interface.
3261 * This resembles (a subset of) the PDOStatement interface.
3263 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
3264 * @author Roman Borschel <roman@code-factory.org>
3265 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
3266 * @link www.doctrine-project.org
3268 * @version $Revision$
3273 * Binds a value to a corresponding named or positional
3274 * placeholder in the SQL statement that was used to prepare the statement.
3276 * @param mixed $param Parameter identifier. For a prepared statement using named placeholders,
3277 * this will be a parameter name of the form :name. For a prepared statement
3278 * using question mark placeholders, this will be the 1-indexed position of the parameter
3280 * @param mixed $value The value to bind to the parameter.
3281 * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants.
3283 * @return boolean Returns TRUE on success or FALSE on failure.
3285 function bindValue($param, $value, $type = null);
3288 * Binds a PHP variable to a corresponding named or question mark placeholder in the
3289 * SQL statement that was use to prepare the statement. Unlike PDOStatement->bindValue(),
3290 * the variable is bound as a reference and will only be evaluated at the time
3291 * that PDOStatement->execute() is called.
3293 * Most parameters are input parameters, that is, parameters that are
3294 * used in a read-only fashion to build up the query. Some drivers support the invocation
3295 * of stored procedures that return data as output parameters, and some also as input/output
3296 * parameters that both send in data and are updated to receive it.
3298 * @param mixed $param Parameter identifier. For a prepared statement using named placeholders,
3299 * this will be a parameter name of the form :name. For a prepared statement
3300 * using question mark placeholders, this will be the 1-indexed position of the parameter
3302 * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter.
3304 * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. To return
3305 * an INOUT parameter from a stored procedure, use the bitwise OR operator to set the
3306 * PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter.
3307 * @return boolean Returns TRUE on success or FALSE on failure.
3309 function bindParam($column, &$variable, $type = null);
3312 * Closes the cursor, enabling the statement to be executed again.
3314 * @return boolean Returns TRUE on success or FALSE on failure.
3316 function closeCursor();
3320 * Returns the number of columns in the result set
3322 * @return integer Returns the number of columns in the result set represented
3323 * by the PDOStatement object. If there is no result set,
3324 * this method should return 0.
3326 function columnCount();
3330 * Fetch the SQLSTATE associated with the last operation on the statement handle
3332 * @see Doctrine_Adapter_Interface::errorCode()
3333 * @return string error code string
3335 function errorCode();
3339 * Fetch extended error information associated with the last operation on the statement handle
3341 * @see Doctrine_Adapter_Interface::errorInfo()
3342 * @return array error info array
3344 function errorInfo();
3347 * Executes a prepared statement
3349 * If the prepared statement included parameter markers, you must either:
3350 * call PDOStatement->bindParam() to bind PHP variables to the parameter markers:
3351 * bound variables pass their value as input and receive the output value,
3352 * if any, of their associated parameter markers or pass an array of input-only
3356 * @param array $params An array of values with as many elements as there are
3357 * bound parameters in the SQL statement being executed.
3358 * @return boolean Returns TRUE on success or FALSE on failure.
3360 function execute($params = null);
3365 * @see Query::HYDRATE_* constants
3366 * @param integer $fetchStyle Controls how the next row will be returned to the caller.
3367 * This value must be one of the Query::HYDRATE_* constants,
3368 * defaulting to Query::HYDRATE_BOTH
3370 * @param integer $cursorOrientation For a PDOStatement object representing a scrollable cursor,
3371 * this value determines which row will be returned to the caller.
3372 * This value must be one of the Query::HYDRATE_ORI_* constants, defaulting to
3373 * Query::HYDRATE_ORI_NEXT. To request a scrollable cursor for your
3374 * PDOStatement object,
3375 * you must set the PDO::ATTR_CURSOR attribute to Doctrine::CURSOR_SCROLL when you
3376 * prepare the SQL statement with Doctrine_Adapter_Interface->prepare().
3378 * @param integer $cursorOffset For a PDOStatement object representing a scrollable cursor for which the
3379 * $cursorOrientation parameter is set to Query::HYDRATE_ORI_ABS, this value specifies
3380 * the absolute number of the row in the result set that shall be fetched.
3382 * For a PDOStatement object representing a scrollable cursor for
3383 * which the $cursorOrientation parameter is set to Query::HYDRATE_ORI_REL, this value
3384 * specifies the row to fetch relative to the cursor position before
3385 * PDOStatement->fetch() was called.
3389 function fetch($fetchStyle = PDO::FETCH_BOTH);
3392 * Returns an array containing all of the result set rows
3394 * @param integer $fetchStyle Controls how the next row will be returned to the caller.
3395 * This value must be one of the Query::HYDRATE_* constants,
3396 * defaulting to Query::HYDRATE_BOTH
3398 * @param integer $columnIndex Returns the indicated 0-indexed column when the value of $fetchStyle is
3399 * Query::HYDRATE_COLUMN. Defaults to 0.
3403 function fetchAll($fetchStyle = PDO::FETCH_BOTH);
3407 * Returns a single column from the next row of a
3408 * result set or FALSE if there are no more rows.
3410 * @param integer $columnIndex 0-indexed number of the column you wish to retrieve from the row. If no
3411 * value is supplied, PDOStatement->fetchColumn()
3412 * fetches the first column.
3414 * @return string returns a single column in the next row of a result set.
3416 function fetchColumn($columnIndex = 0);
3420 * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement
3421 * executed by the corresponding object.
3423 * If the last SQL statement executed by the associated Statement object was a SELECT statement,
3424 * some databases may return the number of rows returned by that statement. However,
3425 * this behaviour is not guaranteed for all databases and should not be
3426 * relied on for portable applications.
3428 * @return integer Returns the number of rows.
3430 function rowCount();
3433 namespace Doctrine\DBAL\Driver\PDOPgSql;
3435 use Doctrine\DBAL\Platforms;
3438 * Driver that connects through pdo_pgsql.
3442 class Driver implements \Doctrine\DBAL\Driver
3445 * Attempts to connect to the database and returns a driver connection on success.
3447 * @return Doctrine\DBAL\Driver\Connection
3449 public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3451 return new \Doctrine\DBAL\Driver\PDOConnection(
3452 $this->_constructPdoDsn($params),
3460 * Constructs the Postgres PDO DSN.
3462 * @return string The DSN.
3464 private function _constructPdoDsn(array $params)
3467 if (isset($params['host'])) {
3468 $dsn .= 'host=' . $params['host'] . ' ';
3470 if (isset($params['port'])) {
3471 $dsn .= 'port=' . $params['port'] . ' ';
3473 if (isset($params['dbname'])) {
3474 $dsn .= 'dbname=' . $params['dbname'] . ' ';
3480 public function getDatabasePlatform()
3482 return new \Doctrine\DBAL\Platforms\PostgreSqlPlatform();
3485 public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
3487 return new \Doctrine\DBAL\Schema\PostgreSqlSchemaManager($conn);
3490 public function getName()
3495 public function getDatabase(\Doctrine\DBAL\Connection $conn)
3497 $params = $conn->getParams();
3498 return $params['dbname'];
3504 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3505 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3506 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3507 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3508 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3509 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3510 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3511 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3512 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3513 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3514 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3516 * This software consists of voluntary contributions made by many individuals
3517 * and is licensed under the LGPL. For more information, see
3518 * <http://www.doctrine-project.org>.
3521 namespace Doctrine\DBAL\Driver;
3526 * PDO implementation of the Connection interface.
3527 * Used by all PDO-based drivers.
3531 class PDOConnection extends PDO implements Connection
3533 public function __construct($dsn, $user = null, $password = null, array $options = null)
3535 parent::__construct($dsn, $user, $password, $options);
3536 $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('Doctrine\DBAL\Driver\PDOStatement', array()));
3537 $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
3543 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3544 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3545 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3546 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3547 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3548 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3549 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3550 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3551 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3552 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3553 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3555 * This software consists of voluntary contributions made by many individuals
3556 * and is licensed under the LGPL. For more information, see
3557 * <http://www.doctrine-project.org>.
3560 namespace Doctrine\DBAL\Driver\PDOIbm;
3562 use Doctrine\DBAL\Connection;
3565 * Driver for the PDO IBM extension
3567 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
3568 * @link www.doctrine-project.com
3570 * @version $Revision$
3571 * @author Benjamin Eberlei <kontakt@beberlei.de>
3572 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
3573 * @author Jonathan Wage <jonwage@gmail.com>
3574 * @author Roman Borschel <roman@code-factory.org>
3576 class Driver implements \Doctrine\DBAL\Driver
3579 * Attempts to establish a connection with the underlying driver.
3581 * @param array $params
3582 * @param string $username
3583 * @param string $password
3584 * @param array $driverOptions
3585 * @return Doctrine\DBAL\Driver\Connection
3587 public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3589 $conn = new \Doctrine\DBAL\Driver\PDOConnection(
3590 $this->_constructPdoDsn($params),
3599 * Constructs the MySql PDO DSN.
3601 * @return string The DSN.
3603 private function _constructPdoDsn(array $params)
3606 if (isset($params['host'])) {
3607 $dsn .= 'HOSTNAME=' . $params['host'] . ';';
3609 if (isset($params['port'])) {
3610 $dsn .= 'PORT=' . $params['port'] . ';';
3612 $dsn .= 'PROTOCOL=TCPIP;';
3613 if (isset($params['dbname'])) {
3614 $dsn .= 'DATABASE=' . $params['dbname'] . ';';
3621 * Gets the DatabasePlatform instance that provides all the metadata about
3622 * the platform this driver connects to.
3624 * @return Doctrine\DBAL\Platforms\AbstractPlatform The database platform.
3626 public function getDatabasePlatform()
3628 return new \Doctrine\DBAL\Platforms\DB2Platform;
3632 * Gets the SchemaManager that can be used to inspect and change the underlying
3633 * database schema of the platform this driver connects to.
3635 * @param Doctrine\DBAL\Connection $conn
3636 * @return Doctrine\DBAL\SchemaManager
3638 public function getSchemaManager(Connection $conn)
3640 return new \Doctrine\DBAL\Schema\DB2SchemaManager($conn);
3644 * Gets the name of the driver.
3646 * @return string The name of the driver.
3648 public function getName()
3654 * Get the name of the database connected to for this driver.
3656 * @param Doctrine\DBAL\Connection $conn
3657 * @return string $database
3659 public function getDatabase(\Doctrine\DBAL\Connection $conn)
3661 $params = $conn->getParams();
3662 return $params['dbname'];
3666 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3667 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3668 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3669 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3670 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3671 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3672 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3673 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3674 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3675 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3676 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3678 * This software consists of voluntary contributions made by many individuals
3679 * and is licensed under the LGPL. For more information, see
3680 * <http://www.doctrine-project.org>.
3683 namespace Doctrine\DBAL\Driver\PDOMySql;
3685 use Doctrine\DBAL\Connection;
3692 class Driver implements \Doctrine\DBAL\Driver
3695 * Attempts to establish a connection with the underlying driver.
3697 * @param array $params
3698 * @param string $username
3699 * @param string $password
3700 * @param array $driverOptions
3701 * @return Doctrine\DBAL\Driver\Connection
3703 public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3705 $conn = new \Doctrine\DBAL\Driver\PDOConnection(
3706 $this->_constructPdoDsn($params),
3715 * Constructs the MySql PDO DSN.
3717 * @return string The DSN.
3719 private function _constructPdoDsn(array $params)
3722 if (isset($params['host'])) {
3723 $dsn .= 'host=' . $params['host'] . ';';
3725 if (isset($params['port'])) {
3726 $dsn .= 'port=' . $params['port'] . ';';
3728 if (isset($params['dbname'])) {
3729 $dsn .= 'dbname=' . $params['dbname'] . ';';
3731 if (isset($params['unix_socket'])) {
3732 $dsn .= 'unix_socket=' . $params['unix_socket'] . ';';
3738 public function getDatabasePlatform()
3740 return new \Doctrine\DBAL\Platforms\MySqlPlatform();
3743 public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
3745 return new \Doctrine\DBAL\Schema\MySqlSchemaManager($conn);
3748 public function getName()
3753 public function getDatabase(\Doctrine\DBAL\Connection $conn)
3755 $params = $conn->getParams();
3756 return $params['dbname'];
3762 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3763 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3764 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3765 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3766 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3767 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3768 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3769 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3770 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3771 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3772 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3774 * This software consists of voluntary contributions made by many individuals
3775 * and is licensed under the LGPL. For more information, see
3776 * <http://www.doctrine-project.org>.
3779 namespace Doctrine\DBAL\Driver\PDOSqlsrv;
3782 * The PDO-based Sqlsrv driver.
3786 class Driver implements \Doctrine\DBAL\Driver
3788 public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3790 return new \Doctrine\DBAL\Driver\PDOConnection(
3791 $this->_constructPdoDsn($params),
3799 * Constructs the Sqlsrv PDO DSN.
3801 * @return string The DSN.
3803 private function _constructPdoDsn(array $params)
3805 $dsn = 'sqlsrv:server=';
3807 if (isset($params['host'])) {
3808 $dsn .= $params['host'];
3811 if (isset($params['port']) && !empty($params['port'])) {
3812 $dsn .= ',' . $params['port'];
3815 if (isset($params['dbname'])) {
3816 $dsn .= ';Database=' . $params['dbname'];
3823 public function getDatabasePlatform()
3825 return new \Doctrine\DBAL\Platforms\MsSqlPlatform();
3828 public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
3830 return new \Doctrine\DBAL\Schema\MsSqlSchemaManager($conn);
3833 public function getName()
3835 return 'pdo_sqlsrv';
3838 public function getDatabase(\Doctrine\DBAL\Connection $conn)
3840 $params = $conn->getParams();
3841 return $params['dbname'];
3845 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3846 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3847 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3848 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3849 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3850 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3851 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3852 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3853 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3854 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3855 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3857 * This software consists of voluntary contributions made by many individuals
3858 * and is licensed under the LGPL. For more information, see
3859 * <http://www.doctrine-project.org>.
3862 namespace Doctrine\DBAL\Driver\PDOSqlite;
3865 * The PDO Sqlite driver.
3869 class Driver implements \Doctrine\DBAL\Driver
3874 protected $_userDefinedFunctions = array(
3875 'sqrt' => array('callback' => array('Doctrine\DBAL\Platforms\SqlitePlatform', 'udfSqrt'), 'numArgs' => 1),
3876 'mod' => array('callback' => array('Doctrine\DBAL\Platforms\SqlitePlatform', 'udfMod'), 'numArgs' => 2),
3877 'locate' => array('callback' => array('Doctrine\DBAL\Platforms\SqlitePlatform', 'udfLocate'), 'numArgs' => -1),
3881 * Tries to establish a database connection to SQLite.
3883 * @param array $params
3884 * @param string $username
3885 * @param string $password
3886 * @param array $driverOptions
3887 * @return Connection
3889 public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3891 if (isset($driverOptions['userDefinedFunctions'])) {
3892 $this->_userDefinedFunctions = array_merge(
3893 $this->_userDefinedFunctions, $driverOptions['userDefinedFunctions']);
3894 unset($driverOptions['userDefinedFunctions']);
3897 $pdo = new \Doctrine\DBAL\Driver\PDOConnection(
3898 $this->_constructPdoDsn($params),
3904 foreach ($this->_userDefinedFunctions AS $fn => $data) {
3905 $pdo->sqliteCreateFunction($fn, $data['callback'], $data['numArgs']);
3912 * Constructs the Sqlite PDO DSN.
3914 * @return string The DSN.
3917 protected function _constructPdoDsn(array $params)
3920 if (isset($params['path'])) {
3921 $dsn .= $params['path'];
3922 } else if (isset($params['memory'])) {
3930 * Gets the database platform that is relevant for this driver.
3932 public function getDatabasePlatform()
3934 return new \Doctrine\DBAL\Platforms\SqlitePlatform();
3938 * Gets the schema manager that is relevant for this driver.
3940 * @param Doctrine\DBAL\Connection $conn
3941 * @return Doctrine\DBAL\Schema\SqliteSchemaManager
3943 public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
3945 return new \Doctrine\DBAL\Schema\SqliteSchemaManager($conn);
3948 public function getName()
3950 return 'pdo_sqlite';
3953 public function getDatabase(\Doctrine\DBAL\Connection $conn)
3955 $params = $conn->getParams();
3956 return isset($params['path']) ? $params['path'] : null;
3962 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3963 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3964 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3965 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3966 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3967 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3968 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3969 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3970 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3971 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3972 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3974 * This software consists of voluntary contributions made by many individuals
3975 * and is licensed under the LGPL. For more information, see
3976 * <http://www.doctrine-project.org>.
3979 namespace Doctrine\DBAL\Driver\OCI8;
3981 class OCI8Exception extends \Exception
3983 static public function fromErrorInfo($error)
3985 return new self($error['message'], $error['code']);
3992 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3993 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3994 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3995 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3996 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3997 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3998 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3999 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4000 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4001 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4002 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4004 * This software consists of voluntary contributions made by many individuals
4005 * and is licensed under the LGPL. For more information, see
4006 * <http://www.doctrine-project.org>.
4009 namespace Doctrine\DBAL\Driver\OCI8;
4011 use Doctrine\DBAL\Platforms;
4014 * A Doctrine DBAL driver for the Oracle OCI8 PHP extensions.
4016 * @author Roman Borschel <roman@code-factory.org>
4019 class Driver implements \Doctrine\DBAL\Driver
4021 public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
4023 return new OCI8Connection(
4026 $this->_constructDsn($params)
4031 * Constructs the Oracle DSN.
4033 * @return string The DSN.
4035 private function _constructDsn(array $params)
4038 if (isset($params['host'])) {
4039 $dsn .= '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)' .
4040 '(HOST=' . $params['host'] . ')';
4042 if (isset($params['port'])) {
4043 $dsn .= '(PORT=' . $params['port'] . ')';
4045 $dsn .= '(PORT=1521)';
4049 if (isset($params['dbname'])) {
4050 $dsn .= '(CONNECT_DATA=(SID=' . $params['dbname'] . ')';
4054 $dsn .= $params['dbname'];
4057 if (isset($params['charset'])) {
4058 $dsn .= ';charset=' . $params['charset'];
4064 public function getDatabasePlatform()
4066 return new \Doctrine\DBAL\Platforms\OraclePlatform();
4069 public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
4071 return new \Doctrine\DBAL\Schema\OracleSchemaManager($conn);
4074 public function getName()
4079 public function getDatabase(\Doctrine\DBAL\Connection $conn)
4081 $params = $conn->getParams();
4082 return $params['user'];
4086 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4087 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4088 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4089 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4090 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4091 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4092 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4093 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4094 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4095 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4096 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4098 * This software consists of voluntary contributions made by many individuals
4099 * and is licensed under the LGPL. For more information, see
4100 * <http://www.doctrine-project.org>.
4103 namespace Doctrine\DBAL\Driver\OCI8;
4108 * The OCI8 implementation of the Statement interface.
4111 * @author Roman Borschel <roman@code-factory.org>
4113 class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
4115 /** Statement handle. */
4117 private static $_PARAM = ':param';
4118 private static $fetchStyleMap = array(
4119 PDO::FETCH_BOTH => OCI_BOTH,
4120 PDO::FETCH_ASSOC => OCI_ASSOC,
4121 PDO::FETCH_NUM => OCI_NUM
4123 private $_paramMap = array();
4126 * Creates a new OCI8Statement that uses the given connection handle and SQL statement.
4128 * @param resource $dbh The connection handle.
4129 * @param string $statement The SQL statement.
4131 public function __construct($dbh, $statement)
4133 list($statement, $paramMap) = self::convertPositionalToNamedPlaceholders($statement);
4134 $this->_sth = oci_parse($dbh, $statement);
4135 $this->_paramMap = $paramMap;
4139 * Convert positional (?) into named placeholders (:param<num>)
4141 * Oracle does not support positional parameters, hence this method converts all
4142 * positional parameters into artificially named parameters. Note that this conversion
4143 * is not perfect. All question marks (?) in the original statement are treated as
4144 * placeholders and converted to a named parameter.
4146 * The algorithm uses a state machine with two possible states: InLiteral and NotInLiteral.
4147 * Question marks inside literal strings are therefore handled correctly by this method.
4148 * This comes at a cost, the whole sql statement has to be looped over.
4150 * @todo extract into utility class in Doctrine\DBAL\Util namespace
4151 * @todo review and test for lost spaces. we experienced missing spaces with oci8 in some sql statements.
4152 * @param string $statement The SQL statement to convert.
4155 static public function convertPositionalToNamedPlaceholders($statement)
4158 $inLiteral = false; // a valid query never starts with quotes
4159 $stmtLen = strlen($statement);
4160 $paramMap = array();
4161 for ($i = 0; $i < $stmtLen; $i++) {
4162 if ($statement[$i] == '?' && !$inLiteral) {
4163 // real positional parameter detected
4164 $paramMap[$count] = ":param$count";
4165 $len = strlen($paramMap[$count]);
4166 $statement = substr_replace($statement, ":param$count", $i, 1);
4167 $i += $len-1; // jump ahead
4168 $stmtLen = strlen($statement); // adjust statement length
4170 } else if ($statement[$i] == "'" || $statement[$i] == '"') {
4171 $inLiteral = ! $inLiteral; // switch state!
4175 return array($statement, $paramMap);
4181 public function bindValue($param, $value, $type = null)
4183 return $this->bindParam($param, $value, $type);
4189 public function bindParam($column, &$variable, $type = null)
4191 $column = isset($this->_paramMap[$column]) ? $this->_paramMap[$column] : $column;
4193 return oci_bind_by_name($this->_sth, $column, $variable);
4197 * Closes the cursor, enabling the statement to be executed again.
4199 * @return boolean Returns TRUE on success or FALSE on failure.
4201 public function closeCursor()
4203 return oci_free_statement($this->_sth);
4209 public function columnCount()
4211 return oci_num_fields($this->_sth);
4217 public function errorCode()
4219 $error = oci_error($this->_sth);
4220 if ($error !== false) {
4221 $error = $error['code'];
4229 public function errorInfo()
4231 return oci_error($this->_sth);
4237 public function execute($params = null)
4240 $hasZeroIndex = isset($params[0]);
4241 foreach ($params as $key => $val) {
4242 if ($hasZeroIndex && is_numeric($key)) {
4243 $this->bindValue($key + 1, $val);
4245 $this->bindValue($key, $val);
4250 $ret = @oci_execute($this->_sth, OCI_DEFAULT);
4252 throw OCI8Exception::fromErrorInfo($this->errorInfo());
4260 public function fetch($fetchStyle = PDO::FETCH_BOTH)
4262 if ( ! isset(self::$fetchStyleMap[$fetchStyle])) {
4263 throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle);
4266 return oci_fetch_array($this->_sth, self::$fetchStyleMap[$fetchStyle] | OCI_RETURN_NULLS | OCI_RETURN_LOBS);
4272 public function fetchAll($fetchStyle = PDO::FETCH_BOTH)
4274 if ( ! isset(self::$fetchStyleMap[$fetchStyle])) {
4275 throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle);
4279 oci_fetch_all($this->_sth, $result, 0, -1,
4280 self::$fetchStyleMap[$fetchStyle] | OCI_RETURN_NULLS | OCI_FETCHSTATEMENT_BY_ROW | OCI_RETURN_LOBS);
4288 public function fetchColumn($columnIndex = 0)
4290 $row = oci_fetch_array($this->_sth, OCI_NUM | OCI_RETURN_NULLS | OCI_RETURN_LOBS);
4291 return $row[$columnIndex];
4297 public function rowCount()
4299 return oci_num_rows($this->_sth);
4303 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4304 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4305 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4306 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4307 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4308 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4309 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4310 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4311 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4312 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4313 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4315 * This software consists of voluntary contributions made by many individuals
4316 * and is licensed under the LGPL. For more information, see
4317 * <http://www.doctrine-project.org>.
4320 namespace Doctrine\DBAL\Driver\OCI8;
4323 * OCI8 implementation of the Connection interface.
4327 class OCI8Connection implements \Doctrine\DBAL\Driver\Connection
4332 * Create a Connection to an Oracle Database using oci8 extension.
4334 * @param string $username
4335 * @param string $password
4338 public function __construct($username, $password, $db)
4340 $this->_dbh = @oci_connect($username, $password, $db);
4342 throw new OCI8Exception($this->errorInfo());
4347 * Create a non-executed prepared statement.
4349 * @param string $prepareString
4350 * @return OCI8Statement
4352 public function prepare($prepareString)
4354 return new OCI8Statement($this->_dbh, $prepareString);
4358 * @param string $sql
4359 * @return OCI8Statement
4361 public function query()
4363 $args = func_get_args();
4365 //$fetchMode = $args[1];
4366 $stmt = $this->prepare($sql);
4372 * Quote input value.
4374 * @param mixed $input
4375 * @param int $type PDO::PARAM*
4378 public function quote($input, $type=\PDO::PARAM_STR)
4380 return is_numeric($input) ? $input : "'$input'";
4385 * @param string $statement
4388 public function exec($statement)
4390 $stmt = $this->prepare($statement);
4392 return $stmt->rowCount();
4395 public function lastInsertId($name = null)
4397 //TODO: throw exception or support sequences?
4401 * Start a transactiom
4403 * Oracle has to explicitly set the autocommit mode off. That means
4404 * after connection, a commit or rollback there is always automatically
4405 * opened a new transaction.
4409 public function beginTransaction()
4415 * @throws OCI8Exception
4418 public function commit()
4420 if (!oci_commit($this->_dbh)) {
4421 throw OCI8Exception::fromErrorInfo($this->errorInfo());
4427 * @throws OCI8Exception
4430 public function rollBack()
4432 if (!oci_rollback($this->_dbh)) {
4433 throw OCI8Exception::fromErrorInfo($this->errorInfo());
4438 public function errorCode()
4440 $error = oci_error($this->_dbh);
4441 if ($error !== false) {
4442 $error = $error['code'];
4447 public function errorInfo()
4449 return oci_error($this->_dbh);
4453 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4454 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4455 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4456 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4457 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4458 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4459 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4460 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4461 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4462 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4463 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4465 * This software consists of voluntary contributions made by many individuals
4466 * and is licensed under the LGPL. For more information, see
4467 * <http://www.doctrine-project.org>.
4470 namespace Doctrine\DBAL\Driver;
4473 * Connection interface.
4474 * Driver connections must implement this interface.
4476 * This resembles (a subset of) the PDO interface.
4480 interface Connection
4482 function prepare($prepareString);
4484 function quote($input, $type=\PDO::PARAM_STR);
4485 function exec($statement);
4486 function lastInsertId($name = null);
4487 function beginTransaction();
4489 function rollBack();
4490 function errorCode();
4491 function errorInfo();
4496 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4497 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4498 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4499 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4500 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4501 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4502 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4503 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4504 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4505 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4506 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4508 * This software consists of voluntary contributions made by many individuals
4509 * and is licensed under the LGPL. For more information, see
4510 * <http://www.doctrine-project.org>.
4513 namespace Doctrine\DBAL;
4516 * Container for all DBAL events.
4518 * This class cannot be instantiated.
4520 * @author Roman Borschel <roman@code-factory.org>
4525 private function __construct() {}
4527 const postConnect = 'postConnect';
4532 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4533 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4534 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4535 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4536 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4537 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4538 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4539 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4540 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4541 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4542 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4544 * This software consists of voluntary contributions made by many individuals
4545 * and is licensed under the LGPL. For more information, see
4546 * <http://www.doctrine-project.org>.
4549 namespace Doctrine\DBAL;
4551 use Doctrine\Common\EventManager;
4554 * Factory for creating Doctrine\DBAL\Connection instances.
4556 * @author Roman Borschel <roman@code-factory.org>
4559 final class DriverManager
4562 * List of supported drivers and their mappings to the driver classes.
4565 * @todo REMOVE. Users should directly supply class names instead.
4567 private static $_driverMap = array(
4568 'pdo_mysql' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
4569 'pdo_sqlite' => 'Doctrine\DBAL\Driver\PDOSqlite\Driver',
4570 'pdo_pgsql' => 'Doctrine\DBAL\Driver\PDOPgSql\Driver',
4571 'pdo_oci' => 'Doctrine\DBAL\Driver\PDOOracle\Driver',
4572 'pdo_mssql' => 'Doctrine\DBAL\Driver\PDOMsSql\Driver',
4573 'oci8' => 'Doctrine\DBAL\Driver\OCI8\Driver',
4574 'ibm_db2' => 'Doctrine\DBAL\Driver\IBMDB2\DB2Driver',
4575 'pdo_ibm' => 'Doctrine\DBAL\Driver\PDOIbm\Driver',
4576 'pdo_sqlsrv' => 'Doctrine\DBAL\Driver\PDOSqlsrv\Driver',
4579 /** Private constructor. This class cannot be instantiated. */
4580 private function __construct() { }
4583 * Creates a connection object based on the specified parameters.
4584 * This method returns a Doctrine\DBAL\Connection which wraps the underlying
4585 * driver connection.
4587 * $params must contain at least one of the following.
4589 * Either 'driver' with one of the following values:
4596 * OR 'driverClass' that contains the full class name (with namespace) of the
4597 * driver class to instantiate.
4599 * Other (optional) parameters:
4601 * <b>user (string)</b>:
4602 * The username to use when connecting.
4604 * <b>password (string)</b>:
4605 * The password to use when connecting.
4607 * <b>driverOptions (array)</b>:
4608 * Any additional driver-specific options for the driver. These are just passed
4609 * through to the driver.
4612 * You can pass an existing PDO instance through this parameter. The PDO
4613 * instance will be wrapped in a Doctrine\DBAL\Connection.
4615 * <b>wrapperClass</b>:
4616 * You may specify a custom wrapper class through the 'wrapperClass'
4617 * parameter but this class MUST inherit from Doctrine\DBAL\Connection.
4619 * @param array $params The parameters.
4620 * @param Doctrine\DBAL\Configuration The configuration to use.
4621 * @param Doctrine\Common\EventManager The event manager to use.
4622 * @return Doctrine\DBAL\Connection
4624 public static function getConnection(
4626 Configuration $config = null,
4627 EventManager $eventManager = null)
4629 // create default config and event manager, if not set
4631 $config = new Configuration();
4633 if ( ! $eventManager) {
4634 $eventManager = new EventManager();
4637 // check for existing pdo object
4638 if (isset($params['pdo']) && ! $params['pdo'] instanceof \PDO) {
4639 throw DBALException::invalidPdoInstance();
4640 } else if (isset($params['pdo'])) {
4641 $params['pdo']->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
4642 $params['driver'] = 'pdo_' . $params['pdo']->getAttribute(\PDO::ATTR_DRIVER_NAME);
4644 self::_checkParams($params);
4646 if (isset($params['driverClass'])) {
4647 $className = $params['driverClass'];
4649 $className = self::$_driverMap[$params['driver']];
4652 $driver = new $className();
4654 $wrapperClass = 'Doctrine\DBAL\Connection';
4655 if (isset($params['wrapperClass'])) {
4656 if (is_subclass_of($params['wrapperClass'], $wrapperClass)) {
4657 $wrapperClass = $params['wrapperClass'];
4659 throw DBALException::invalidWrapperClass($params['wrapperClass']);
4663 return new $wrapperClass($params, $driver, $config, $eventManager);
4667 * Checks the list of parameters.
4669 * @param array $params
4671 private static function _checkParams(array $params)
4673 // check existance of mandatory parameters
4676 if ( ! isset($params['driver']) && ! isset($params['driverClass'])) {
4677 throw DBALException::driverRequired();
4680 // check validity of parameters
4683 if ( isset($params['driver']) && ! isset(self::$_driverMap[$params['driver']])) {
4684 throw DBALException::unknownDriver($params['driver'], array_keys(self::$_driverMap));
4687 if (isset($params['driverClass']) && ! in_array('Doctrine\DBAL\Driver', class_implements($params['driverClass'], true))) {
4688 throw DBALException::invalidDriverClass($params['driverClass']);
4693 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4694 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4695 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4696 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4697 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4698 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4699 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4700 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4701 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4702 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4703 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4705 * This software consists of voluntary contributions made by many individuals
4706 * and is licensed under the LGPL. For more information, see
4707 * <http://www.doctrine-project.org>.
4710 namespace Doctrine\DBAL;
4712 use Doctrine\DBAL\Logging\SQLLogger;
4715 * Configuration container for the Doctrine DBAL.
4718 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
4719 * @author Jonathan Wage <jonwage@gmail.com>
4720 * @author Roman Borschel <roman@code-factory.org>
4721 * @internal When adding a new configuration option just write a getter/setter
4722 * pair and add the option to the _attributes array with a proper default value.
4727 * The attributes that are contained in the configuration.
4728 * Values are default values.
4732 protected $_attributes = array();
4735 * Sets the SQL logger to use. Defaults to NULL which means SQL logging is disabled.
4737 * @param SQLLogger $logger
4739 public function setSQLLogger(SQLLogger $logger)
4741 $this->_attributes['sqlLogger'] = $logger;
4745 * Gets the SQL logger that is used.
4749 public function getSQLLogger()
4751 return isset($this->_attributes['sqlLogger']) ?
4752 $this->_attributes['sqlLogger'] : null;
4758 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4759 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4760 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4761 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4762 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4763 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4764 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4765 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4766 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4767 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4768 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4770 * This software consists of voluntary contributions made by many individuals
4771 * and is licensed under the LGPL. For more information, see
4772 * <http://www.doctrine-project.org>.
4775 namespace Doctrine\DBAL;
4778 Doctrine\DBAL\Types\Type,
4779 Doctrine\DBAL\Driver\Statement as DriverStatement;
4782 * A thin wrapper around a Doctrine\DBAL\Driver\Statement that adds support
4783 * for logging, DBAL mapping types, etc.
4785 * @author Roman Borschel <roman@code-factory.org>
4788 class Statement implements DriverStatement
4791 * @var string The SQL statement.
4795 * @var array The bound parameters.
4797 private $_params = array();
4799 * @var Doctrine\DBAL\Driver\Statement The underlying driver statement.
4803 * @var Doctrine\DBAL\Platforms\AbstractPlatform The underlying database platform.
4807 * @var Doctrine\DBAL\Connection The connection this statement is bound to and executed on.
4812 * Creates a new <tt>Statement</tt> for the given SQL and <tt>Connection</tt>.
4814 * @param string $sql The SQL of the statement.
4815 * @param Doctrine\DBAL\Connection The connection on which the statement should be executed.
4817 public function __construct($sql, Connection $conn)
4820 $this->_stmt = $conn->getWrappedConnection()->prepare($sql);
4821 $this->_conn = $conn;
4822 $this->_platform = $conn->getDatabasePlatform();
4826 * Binds a parameter value to the statement.
4828 * The value can optionally be bound with a PDO binding type or a DBAL mapping type.
4829 * If bound with a DBAL mapping type, the binding type is derived from the mapping
4830 * type and the value undergoes the conversion routines of the mapping type before
4833 * @param $name The name or position of the parameter.
4834 * @param $value The value of the parameter.
4835 * @param mixed $type Either a PDO binding type or a DBAL mapping type name or instance.
4836 * @return boolean TRUE on success, FALSE on failure.
4838 public function bindValue($name, $value, $type = null)
4840 $this->_params[$name] = $value;
4841 if ($type !== null) {
4842 if (is_string($type)) {
4843 $type = Type::getType($type);
4845 if ($type instanceof Type) {
4846 $value = $type->convertToDatabaseValue($value, $this->_platform);
4847 $bindingType = $type->getBindingType();
4849 $bindingType = $type; // PDO::PARAM_* constants
4851 return $this->_stmt->bindValue($name, $value, $bindingType);
4853 return $this->_stmt->bindValue($name, $value);
4858 * Binds a parameter to a value by reference.
4860 * Binding a parameter by reference does not support DBAL mapping types.
4862 * @param string $name The name or position of the parameter.
4863 * @param mixed $value The reference to the variable to bind
4864 * @param integer $type The PDO binding type.
4865 * @return boolean TRUE on success, FALSE on failure.
4867 public function bindParam($name, &$var, $type = PDO::PARAM_STR)
4869 return $this->_stmt->bindParam($name, $var, $type);
4873 * Executes the statement with the currently bound parameters.
4875 * @return boolean TRUE on success, FALSE on failure.
4877 public function execute($params = null)
4879 $hasLogger = $this->_conn->getConfiguration()->getSQLLogger();
4881 $this->_conn->getConfiguration()->getSQLLogger()->startQuery($this->_sql, $this->_params);
4884 $stmt = $this->_stmt->execute($params);
4887 $this->_conn->getConfiguration()->getSQLLogger()->stopQuery();
4889 $this->_params = array();
4894 * Closes the cursor, freeing the database resources used by this statement.
4896 * @return boolean TRUE on success, FALSE on failure.
4898 public function closeCursor()
4900 return $this->_stmt->closeCursor();
4904 * Returns the number of columns in the result set.
4908 public function columnCount()
4910 return $this->_stmt->columnCount();
4914 * Fetches the SQLSTATE associated with the last operation on the statement.
4918 public function errorCode()
4920 return $this->_stmt->errorCode();
4924 * Fetches extended error information associated with the last operation on the statement.
4928 public function errorInfo()
4930 return $this->_stmt->errorInfo();
4934 * Fetches the next row from a result set.
4936 * @param integer $fetchStyle
4937 * @return mixed The return value of this function on success depends on the fetch type.
4938 * In all cases, FALSE is returned on failure.
4940 public function fetch($fetchStyle = PDO::FETCH_BOTH)
4942 return $this->_stmt->fetch($fetchStyle);
4946 * Returns an array containing all of the result set rows.
4948 * @param integer $fetchStyle
4949 * @param integer $columnIndex
4950 * @return array An array containing all of the remaining rows in the result set.
4952 public function fetchAll($fetchStyle = PDO::FETCH_BOTH, $columnIndex = 0)
4954 if ($columnIndex != 0) {
4955 return $this->_stmt->fetchAll($fetchStyle, $columnIndex);
4957 return $this->_stmt->fetchAll($fetchStyle);
4961 * Returns a single column from the next row of a result set.
4963 * @param integer $columnIndex
4964 * @return mixed A single column from the next row of a result set or FALSE if there are no more rows.
4966 public function fetchColumn($columnIndex = 0)
4968 return $this->_stmt->fetchColumn($columnIndex);
4972 * Returns the number of rows affected by the last execution of this statement.
4974 * @return integer The number of affected rows.
4976 public function rowCount()
4978 return $this->_stmt->rowCount();
4982 * Gets the wrapped driver statement.
4984 * @return Doctrine\DBAL\Driver\Statement
4986 public function getWrappedStatement()
4988 return $this->_stmt;
4992 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4993 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4994 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4995 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4996 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4997 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4998 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4999 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5000 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5001 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5002 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5004 * This software consists of voluntary contributions made by many individuals
5005 * and is licensed under the LGPL. For more information, see
5006 * <http://www.doctrine-project.org>.
5009 namespace Doctrine\DBAL\Schema;
5012 * Schema manager for the MySql RDBMS.
5014 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
5015 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
5016 * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
5017 * @author Roman Borschel <roman@code-factory.org>
5018 * @author Benjamin Eberlei <kontakt@beberlei.de>
5019 * @version $Revision$
5022 class MySqlSchemaManager extends AbstractSchemaManager
5024 protected function _getPortableViewDefinition($view)
5026 return new View($view['TABLE_NAME'], $view['VIEW_DEFINITION']);
5029 protected function _getPortableTableDefinition($table)
5031 return array_shift($table);
5034 protected function _getPortableUserDefinition($user)
5037 'user' => $user['User'],
5038 'password' => $user['Password'],
5042 protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
5044 foreach($tableIndexes AS $k => $v) {
5045 $v = array_change_key_case($v, CASE_LOWER);
5046 if($v['key_name'] == 'PRIMARY') {
5047 $v['primary'] = true;
5049 $v['primary'] = false;
5051 $tableIndexes[$k] = $v;
5054 return parent::_getPortableTableIndexesList($tableIndexes, $tableName);
5057 protected function _getPortableSequenceDefinition($sequence)
5059 return end($sequence);
5062 protected function _getPortableDatabaseDefinition($database)
5064 return $database['Database'];
5068 * Gets a portable column definition.
5070 * The database type is mapped to a corresponding Doctrine mapping type.
5072 * @param $tableColumn
5075 protected function _getPortableTableColumnDefinition($tableColumn)
5077 $tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
5079 $dbType = strtolower($tableColumn['type']);
5080 $dbType = strtok($dbType, '(), ');
5081 if (isset($tableColumn['length'])) {
5082 $length = $tableColumn['length'];
5085 $length = strtok('(), ');
5086 $decimal = strtok('(), ') ? strtok('(), '):null;
5089 $unsigned = $fixed = null;
5091 if ( ! isset($tableColumn['name'])) {
5092 $tableColumn['name'] = '';
5098 $type = $this->_platform->getDoctrineTypeMapping($dbType);
5108 if(preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['type'], $match)) {
5109 $precision = $match[1];
5131 $length = ((int) $length == 0) ? null : (int) $length;
5134 'length' => $length,
5135 'unsigned' => (bool) $unsigned,
5136 'fixed' => (bool) $fixed
5140 'length' => $length,
5141 'unsigned' => (bool)$unsigned,
5142 'fixed' => (bool)$fixed,
5143 'default' => $tableColumn['default'],
5144 'notnull' => (bool) ($tableColumn['null'] != 'YES'),
5146 'precision' => null,
5147 'autoincrement' => (bool) (strpos($tableColumn['extra'], 'auto_increment') !== false),
5150 if ($scale !== null && $precision !== null) {
5151 $options['scale'] = $scale;
5152 $options['precision'] = $precision;
5155 return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options);
5158 public function _getPortableTableForeignKeyDefinition($tableForeignKey)
5160 $tableForeignKey = array_change_key_case($tableForeignKey, CASE_LOWER);
5162 if (!isset($tableForeignKey['delete_rule']) || $tableForeignKey['delete_rule'] == "RESTRICT") {
5163 $tableForeignKey['delete_rule'] = null;
5165 if (!isset($tableForeignKey['update_rule']) || $tableForeignKey['update_rule'] == "RESTRICT") {
5166 $tableForeignKey['update_rule'] = null;
5169 return new ForeignKeyConstraint(
5170 (array)$tableForeignKey['column_name'],
5171 $tableForeignKey['referenced_table_name'],
5172 (array)$tableForeignKey['referenced_column_name'],
5173 $tableForeignKey['constraint_name'],
5175 'onUpdate' => $tableForeignKey['update_rule'],
5176 'onDelete' => $tableForeignKey['delete_rule'],
5183 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5184 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5185 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
5186 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
5187 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5188 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
5189 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5190 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5191 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5192 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5193 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5195 * This software consists of voluntary contributions made by many individuals
5196 * and is licensed under the LGPL. For more information, see
5197 * <http://www.doctrine-project.org>.
5200 namespace Doctrine\DBAL\Schema;
5205 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
5206 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
5207 * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
5208 * @author Benjamin Eberlei <kontakt@beberlei.de>
5209 * @version $Revision$
5212 class PostgreSqlSchemaManager extends AbstractSchemaManager
5215 protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
5220 if (preg_match('(ON UPDATE ([a-zA-Z0-9]+))', $tableForeignKey['condef'], $match)) {
5221 $onUpdate = $match[1];
5223 if (preg_match('(ON DELETE ([a-zA-Z0-9]+))', $tableForeignKey['condef'], $match)) {
5224 $onDelete = $match[1];
5227 if (preg_match('/FOREIGN KEY \((.+)\) REFERENCES (.+)\((.+)\)/', $tableForeignKey['condef'], $values)) {
5228 $localColumns = array_map('trim', explode(",", $values[1]));
5229 $foreignColumns = array_map('trim', explode(",", $values[3]));
5230 $foreignTable = $values[2];
5233 return new ForeignKeyConstraint(
5234 $localColumns, $foreignTable, $foreignColumns, $tableForeignKey['conname'],
5235 array('onUpdate' => $onUpdate, 'onDelete' => $onDelete)
5239 public function dropDatabase($database)
5241 $params = $this->_conn->getParams();
5242 $params["dbname"] = "postgres";
5243 $tmpPlatform = $this->_platform;
5244 $tmpConn = $this->_conn;
5246 $this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params);
5247 $this->_platform = $this->_conn->getDatabasePlatform();
5249 parent::dropDatabase($database);
5251 $this->_platform = $tmpPlatform;
5252 $this->_conn = $tmpConn;
5255 public function createDatabase($database)
5257 $params = $this->_conn->getParams();
5258 $params["dbname"] = "postgres";
5259 $tmpPlatform = $this->_platform;
5260 $tmpConn = $this->_conn;
5262 $this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params);
5263 $this->_platform = $this->_conn->getDatabasePlatform();
5265 parent::createDatabase($database);
5267 $this->_platform = $tmpPlatform;
5268 $this->_conn = $tmpConn;
5271 protected function _getPortableTriggerDefinition($trigger)
5273 return $trigger['trigger_name'];
5276 protected function _getPortableViewDefinition($view)
5278 return new View($view['viewname'], $view['definition']);
5281 protected function _getPortableUserDefinition($user)
5284 'user' => $user['usename'],
5285 'password' => $user['passwd']
5289 protected function _getPortableTableDefinition($table)
5291 return $table['table_name'];
5295 * @license New BSD License
5296 * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
5297 * @param array $tableIndexes
5298 * @param string $tableName
5301 protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
5304 foreach ($tableIndexes AS $row) {
5305 $colNumbers = explode(' ', $row['indkey']);
5306 $colNumbersSql = 'IN (' . join(' ,', $colNumbers) . ' )';
5307 $columnNameSql = "SELECT attnum, attname FROM pg_attribute
5308 WHERE attrelid={$row['indrelid']} AND attnum $colNumbersSql ORDER BY attnum ASC;";
5310 $stmt = $this->_conn->executeQuery($columnNameSql);
5311 $indexColumns = $stmt->fetchAll();
5313 // required for getting the order of the columns right.
5314 foreach ($colNumbers AS $colNum) {
5315 foreach ($indexColumns as $colRow) {
5316 if ($colNum == $colRow['attnum']) {
5318 'key_name' => $row['relname'],
5319 'column_name' => trim($colRow['attname']),
5320 'non_unique' => !$row['indisunique'],
5321 'primary' => $row['indisprimary']
5327 return parent::_getPortableTableIndexesList($buffer);
5330 protected function _getPortableDatabaseDefinition($database)
5332 return $database['datname'];
5335 protected function _getPortableSequenceDefinition($sequence)
5337 $data = $this->_conn->fetchAll('SELECT min_value, increment_by FROM ' . $sequence['relname']);
5338 return new Sequence($sequence['relname'], $data[0]['increment_by'], $data[0]['min_value']);
5341 protected function _getPortableTableColumnDefinition($tableColumn)
5343 $tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
5345 if (strtolower($tableColumn['type']) === 'varchar') {
5346 // get length from varchar definition
5347 $length = preg_replace('~.*\(([0-9]*)\).*~', '$1', $tableColumn['complete_type']);
5348 $tableColumn['length'] = $length;
5353 $autoincrement = false;
5354 if (preg_match("/^nextval\('(.*)'(::.*)?\)$/", $tableColumn['default'], $matches)) {
5355 $tableColumn['sequence'] = $matches[1];
5356 $tableColumn['default'] = null;
5357 $autoincrement = true;
5360 if (stripos($tableColumn['default'], 'NULL') === 0) {
5361 $tableColumn['default'] = null;
5364 $length = (isset($tableColumn['length'])) ? $tableColumn['length'] : null;
5365 if ($length == '-1' && isset($tableColumn['atttypmod'])) {
5366 $length = $tableColumn['atttypmod'] - 4;
5368 if ((int) $length <= 0) {
5374 if (!isset($tableColumn['name'])) {
5375 $tableColumn['name'] = '';
5381 if ($this->_platform->hasDoctrineTypeMappingFor($tableColumn['type'])) {
5382 $dbType = strtolower($tableColumn['type']);
5384 $dbType = strtolower($tableColumn['domain_type']);
5385 $tableColumn['complete_type'] = $tableColumn['domain_complete_type'];
5388 $type = $this->_platform->getDoctrineTypeMapping($dbType);
5423 case 'double precision':
5428 if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['complete_type'], $match)) {
5429 $precision = $match[1];
5440 'length' => $length,
5441 'notnull' => (bool) $tableColumn['isnotnull'],
5442 'default' => $tableColumn['default'],
5443 'primary' => (bool) ($tableColumn['pri'] == 't'),
5444 'precision' => $precision,
5447 'unsigned' => false,
5448 'autoincrement' => $autoincrement,
5451 return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options);
5458 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5459 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5460 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
5461 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
5462 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5463 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
5464 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5465 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5466 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5467 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5468 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5470 * This software consists of voluntary contributions made by many individuals
5471 * and is licensed under the LGPL. For more information, see
5472 * <http://www.doctrine-project.org>.
5475 namespace Doctrine\DBAL\Schema;
5478 * Representation of a Database View
5480 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
5481 * @link www.doctrine-project.com
5483 * @version $Revision$
5484 * @author Benjamin Eberlei <kontakt@beberlei.de>
5486 class View extends AbstractAsset
5493 public function __construct($name, $sql)
5495 $this->_setName($name);
5502 public function getSql()
5510 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5511 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5512 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
5513 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
5514 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5515 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
5516 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5517 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5518 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5519 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5520 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5522 * This software consists of voluntary contributions made by many individuals
5523 * and is licensed under the LGPL. For more information, see
5524 * <http://www.doctrine-project.org>.
5527 namespace Doctrine\DBAL\Schema;
5530 * IBM Db2 Schema Manager
5532 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
5533 * @link www.doctrine-project.com
5535 * @version $Revision$
5536 * @author Benjamin Eberlei <kontakt@beberlei.de>
5538 class DB2SchemaManager extends AbstractSchemaManager
5541 * Return a list of all tables in the current database
5543 * Apparently creator is the schema not the user who created it:
5544 * {@link http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.sqlref/db2z_sysibmsystablestable.htm}
5548 public function listTableNames()
5550 $sql = $this->_platform->getListTablesSQL();
5551 $sql .= " AND CREATOR = UPPER('".$this->_conn->getUsername()."')";
5553 $tables = $this->_conn->fetchAll($sql);
5555 return $this->_getPortableTablesList($tables);
5560 * Get Table Column Definition
5562 * @param array $tableColumn
5565 protected function _getPortableTableColumnDefinition($tableColumn)
5567 $tableColumn = array_change_key_case($tableColumn, \CASE_LOWER);
5575 $type = $this->_platform->getDoctrineTypeMapping($tableColumn['typename']);
5577 switch (strtolower($tableColumn['typename'])) {
5579 $length = $tableColumn['length'];
5583 $length = $tableColumn['length'];
5587 $length = $tableColumn['length'];
5592 $scale = $tableColumn['scale'];
5593 $precision = $tableColumn['length'];
5598 'length' => $length,
5599 'unsigned' => (bool)$unsigned,
5600 'fixed' => (bool)$fixed,
5601 'default' => ($tableColumn['default'] == "NULL") ? null : $tableColumn['default'],
5602 'notnull' => (bool) ($tableColumn['nulls'] == 'N'),
5604 'precision' => null,
5605 'platformOptions' => array(),
5608 if ($scale !== null && $precision !== null) {
5609 $options['scale'] = $scale;
5610 $options['precision'] = $precision;
5613 return new Column($tableColumn['colname'], \Doctrine\DBAL\Types\Type::getType($type), $options);
5616 protected function _getPortableTablesList($tables)
5618 $tableNames = array();
5619 foreach ($tables AS $tableRow) {
5620 $tableRow = array_change_key_case($tableRow, \CASE_LOWER);
5621 $tableNames[] = $tableRow['name'];
5626 protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
5628 $tableIndexRows = array();
5630 foreach($tableIndexes AS $indexKey => $data) {
5631 $data = array_change_key_case($data, \CASE_LOWER);
5632 $unique = ($data['uniquerule'] == "D") ? false : true;
5633 $primary = ($data['uniquerule'] == "P");
5635 $indexName = strtolower($data['name']);
5637 $keyName = 'primary';
5639 $keyName = $indexName;
5642 $indexes[$keyName] = new Index($indexName, explode("+", ltrim($data['colnames'], '+')), $unique, $primary);
5648 protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
5650 $tableForeignKey = array_change_key_case($tableForeignKey, CASE_LOWER);
5652 $tableForeignKey['deleterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['deleterule']);
5653 $tableForeignKey['updaterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['updaterule']);
5655 return new ForeignKeyConstraint(
5656 array_map('trim', (array)$tableForeignKey['fkcolnames']),
5657 $tableForeignKey['reftbname'],
5658 array_map('trim', (array)$tableForeignKey['pkcolnames']),
5659 $tableForeignKey['relname'],
5661 'onUpdate' => $tableForeignKey['updaterule'],
5662 'onDelete' => $tableForeignKey['deleterule'],
5667 protected function _getPortableForeignKeyRuleDef($def)
5671 } else if ($def == "N") {
5677 protected function _getPortableViewDefinition($view)
5679 $view = array_change_key_case($view, \CASE_LOWER);
5680 // sadly this still segfaults on PDO_IBM, see http://pecl.php.net/bugs/bug.php?id=17199
5681 //$view['text'] = (is_resource($view['text']) ? stream_get_contents($view['text']) : $view['text']);
5682 if (!is_resource($view['text'])) {
5683 $pos = strpos($view['text'], ' AS ');
5684 $sql = substr($view['text'], $pos+4);
5689 return new View($view['name'], $sql);
5693 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5694 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5695 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
5696 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
5697 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5698 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
5699 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5700 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5701 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5702 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5703 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5705 * This software consists of voluntary contributions made by many individuals
5706 * and is licensed under the LGPL. For more information, see
5707 * <http://www.doctrine-project.org>.
5710 namespace Doctrine\DBAL\Schema;
5713 * SqliteSchemaManager
5715 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
5716 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
5717 * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
5718 * @author Jonathan H. Wage <jonwage@gmail.com>
5719 * @version $Revision$
5722 class SqliteSchemaManager extends AbstractSchemaManager
5729 public function dropDatabase($database)
5731 if (file_exists($database)) {
5741 public function createDatabase($database)
5743 $params = $this->_conn->getParams();
5744 $driver = $params['driver'];
5746 'driver' => $driver,
5749 $conn = \Doctrine\DBAL\DriverManager::getConnection($options);
5754 protected function _getPortableTableDefinition($table)
5756 return $table['name'];
5760 * @license New BSD License
5761 * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
5762 * @param array $tableIndexes
5763 * @param string $tableName
5766 protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
5768 $indexBuffer = array();
5771 $stmt = $this->_conn->executeQuery( "PRAGMA TABLE_INFO ('$tableName')" );
5772 $indexArray = $stmt->fetchAll(\PDO::FETCH_ASSOC);
5773 foreach($indexArray AS $indexColumnRow) {
5774 if($indexColumnRow['pk'] == "1") {
5775 $indexBuffer[] = array(
5776 'key_name' => 'primary',
5778 'non_unique' => false,
5779 'column_name' => $indexColumnRow['name']
5784 // fetch regular indexes
5785 foreach($tableIndexes AS $tableIndex) {
5786 $keyName = $tableIndex['name'];
5788 $idx['key_name'] = $keyName;
5789 $idx['primary'] = false;
5790 $idx['non_unique'] = $tableIndex['unique']?false:true;
5792 $stmt = $this->_conn->executeQuery( "PRAGMA INDEX_INFO ( '{$keyName}' )" );
5793 $indexArray = $stmt->fetchAll(\PDO::FETCH_ASSOC);
5795 foreach ( $indexArray as $indexColumnRow ) {
5796 $idx['column_name'] = $indexColumnRow['name'];
5797 $indexBuffer[] = $idx;
5801 return parent::_getPortableTableIndexesList($indexBuffer, $tableName);
5804 protected function _getPortableTableIndexDefinition($tableIndex)
5807 'name' => $tableIndex['name'],
5808 'unique' => (bool) $tableIndex['unique']
5812 protected function _getPortableTableColumnDefinition($tableColumn)
5814 $e = explode('(', $tableColumn['type']);
5815 $tableColumn['type'] = $e[0];
5817 $length = trim($e[1], ')');
5818 $tableColumn['length'] = $length;
5821 $dbType = strtolower($tableColumn['type']);
5822 $length = isset($tableColumn['length']) ? $tableColumn['length'] : null;
5823 $unsigned = (boolean) isset($tableColumn['unsigned']) ? $tableColumn['unsigned'] : false;
5825 $type = $this->_platform->getDoctrineTypeMapping($dbType);
5826 $default = $tableColumn['dflt_value'];
5827 if ($default == 'NULL') {
5830 $notnull = (bool) $tableColumn['notnull'];
5832 if ( ! isset($tableColumn['name'])) {
5833 $tableColumn['name'] = '';
5848 list($precision, $scale) = array_map('trim', explode(', ', $tableColumn['length']));
5854 'length' => $length,
5855 'unsigned' => (bool) $unsigned,
5857 'notnull' => $notnull,
5858 'default' => $default,
5859 'precision' => $precision,
5861 'autoincrement' => (bool) $tableColumn['pk'],
5864 return new Column($tableColumn['name'], \Doctrine\DBAL\Types\Type::getType($type), $options);
5867 protected function _getPortableViewDefinition($view)
5869 return new View($view['name'], $view['sql']);
5873 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5874 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5875 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
5876 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
5877 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5878 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
5879 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5880 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5881 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5882 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5883 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5885 * This software consists of voluntary contributions made by many individuals
5886 * and is licensed under the LGPL. For more information, see
5887 * <http://www.doctrine-project.org>.
5890 namespace Doctrine\DBAL\Schema;
5893 * Compare to Schemas and return an instance of SchemaDiff
5895 * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
5896 * @license http://ez.no/licenses/new_bsd New BSD License
5897 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
5898 * @link www.doctrine-project.org
5900 * @version $Revision$
5901 * @author Benjamin Eberlei <kontakt@beberlei.de>
5906 * @param Schema $fromSchema
5907 * @param Schema $toSchema
5908 * @return SchemaDiff
5910 static public function compareSchemas( Schema $fromSchema, Schema $toSchema )
5913 return $c->compare($fromSchema, $toSchema);
5917 * Returns a SchemaDiff object containing the differences between the schemas $fromSchema and $toSchema.
5919 * The returned diferences are returned in such a way that they contain the
5920 * operations to change the schema stored in $fromSchema to the schema that is
5921 * stored in $toSchema.
5923 * @param Schema $fromSchema
5924 * @param Schema $toSchema
5926 * @return SchemaDiff
5928 public function compare(Schema $fromSchema, Schema $toSchema)
5930 $diff = new SchemaDiff();
5932 $foreignKeysToTable = array();
5934 foreach ( $toSchema->getTables() AS $tableName => $table ) {
5935 if ( !$fromSchema->hasTable($tableName) ) {
5936 $diff->newTables[$tableName] = $table;
5938 $tableDifferences = $this->diffTable( $fromSchema->getTable($tableName), $table );
5939 if ( $tableDifferences !== false ) {
5940 $diff->changedTables[$tableName] = $tableDifferences;
5945 /* Check if there are tables removed */
5946 foreach ( $fromSchema->getTables() AS $tableName => $table ) {
5947 if ( !$toSchema->hasTable($tableName) ) {
5948 $diff->removedTables[$tableName] = $table;
5951 // also remember all foreign keys that point to a specific table
5952 foreach ($table->getForeignKeys() AS $foreignKey) {
5953 $foreignTable = strtolower($foreignKey->getForeignTableName());
5954 if (!isset($foreignKeysToTable[$foreignTable])) {
5955 $foreignKeysToTable[$foreignTable] = array();
5957 $foreignKeysToTable[$foreignTable][] = $foreignKey;
5961 foreach ($diff->removedTables AS $tableName => $table) {
5962 if (isset($foreignKeysToTable[$tableName])) {
5963 $diff->orphanedForeignKeys = array_merge($diff->orphanedForeignKeys, $foreignKeysToTable[$tableName]);
5967 foreach ( $toSchema->getSequences() AS $sequenceName => $sequence) {
5968 if (!$fromSchema->hasSequence($sequenceName)) {
5969 $diff->newSequences[] = $sequence;
5971 if ($this->diffSequence($sequence, $fromSchema->getSequence($sequenceName))) {
5972 $diff->changedSequences[] = $fromSchema->getSequence($sequenceName);
5977 foreach ($fromSchema->getSequences() AS $sequenceName => $sequence) {
5978 if (!$toSchema->hasSequence($sequenceName)) {
5979 $diff->removedSequences[] = $sequence;
5988 * @param Sequence $sequence1
5989 * @param Sequence $sequence2
5991 public function diffSequence(Sequence $sequence1, Sequence $sequence2)
5993 if($sequence1->getAllocationSize() != $sequence2->getAllocationSize()) {
5997 if($sequence1->getInitialValue() != $sequence2->getInitialValue()) {
6005 * Returns the difference between the tables $table1 and $table2.
6007 * If there are no differences this method returns the boolean false.
6009 * @param Table $table1
6010 * @param Table $table2
6012 * @return bool|TableDiff
6014 public function diffTable(Table $table1, Table $table2)
6017 $tableDifferences = new TableDiff($table1->getName());
6019 $table1Columns = $table1->getColumns();
6020 $table2Columns = $table2->getColumns();
6022 /* See if all the fields in table 1 exist in table 2 */
6023 foreach ( $table2Columns as $columnName => $column ) {
6024 if ( !$table1->hasColumn($columnName) ) {
6025 $tableDifferences->addedColumns[$columnName] = $column;
6029 /* See if there are any removed fields in table 2 */
6030 foreach ( $table1Columns as $columnName => $column ) {
6031 if ( !$table2->hasColumn($columnName) ) {
6032 $tableDifferences->removedColumns[$columnName] = $column;
6036 foreach ( $table1Columns as $columnName => $column ) {
6037 if ( $table2->hasColumn($columnName) ) {
6038 $changedProperties = $this->diffColumn( $column, $table2->getColumn($columnName) );
6039 if (count($changedProperties) ) {
6040 $columnDiff = new ColumnDiff($column->getName(), $table2->getColumn($columnName), $changedProperties);
6041 $tableDifferences->changedColumns[$column->getName()] = $columnDiff;
6047 $this->detectColumnRenamings($tableDifferences);
6049 $table1Indexes = $table1->getIndexes();
6050 $table2Indexes = $table2->getIndexes();
6052 foreach ($table2Indexes AS $index2Name => $index2Definition) {
6053 foreach ($table1Indexes AS $index1Name => $index1Definition) {
6054 if ($this->diffIndex($index1Definition, $index2Definition) === false) {
6055 unset($table1Indexes[$index1Name]);
6056 unset($table2Indexes[$index2Name]);
6058 if ($index1Name == $index2Name) {
6059 $tableDifferences->changedIndexes[$index2Name] = $table2Indexes[$index2Name];
6060 unset($table1Indexes[$index1Name]);
6061 unset($table2Indexes[$index2Name]);
6068 foreach ($table1Indexes AS $index1Name => $index1Definition) {
6069 $tableDifferences->removedIndexes[$index1Name] = $index1Definition;
6073 foreach ($table2Indexes AS $index2Name => $index2Definition) {
6074 $tableDifferences->addedIndexes[$index2Name] = $index2Definition;
6078 $fromFkeys = $table1->getForeignKeys();
6079 $toFkeys = $table2->getForeignKeys();
6081 foreach ($fromFkeys AS $key1 => $constraint1) {
6082 foreach ($toFkeys AS $key2 => $constraint2) {
6083 if($this->diffForeignKey($constraint1, $constraint2) === false) {
6084 unset($fromFkeys[$key1]);
6085 unset($toFkeys[$key2]);
6087 if (strtolower($constraint1->getName()) == strtolower($constraint2->getName())) {
6088 $tableDifferences->changedForeignKeys[] = $constraint2;
6090 unset($fromFkeys[$key1]);
6091 unset($toFkeys[$key2]);
6097 foreach ($fromFkeys AS $key1 => $constraint1) {
6098 $tableDifferences->removedForeignKeys[] = $constraint1;
6102 foreach ($toFkeys AS $key2 => $constraint2) {
6103 $tableDifferences->addedForeignKeys[] = $constraint2;
6107 return $changes ? $tableDifferences : false;
6111 * Try to find columns that only changed their name, rename operations maybe cheaper than add/drop
6112 * however ambiguouties between different possibilites should not lead to renaming at all.
6114 * @param TableDiff $tableDifferences
6116 private function detectColumnRenamings(TableDiff $tableDifferences)
6118 $renameCandidates = array();
6119 foreach ($tableDifferences->addedColumns AS $addedColumnName => $addedColumn) {
6120 foreach ($tableDifferences->removedColumns AS $removedColumnName => $removedColumn) {
6121 if (count($this->diffColumn($addedColumn, $removedColumn)) == 0) {
6122 $renameCandidates[$addedColumn->getName()][] = array($removedColumn, $addedColumn);
6127 foreach ($renameCandidates AS $candidate => $candidateColumns) {
6128 if (count($candidateColumns) == 1) {
6129 list($removedColumn, $addedColumn) = $candidateColumns[0];
6131 $tableDifferences->renamedColumns[$removedColumn->getName()] = $addedColumn;
6132 unset($tableDifferences->addedColumns[$addedColumnName]);
6133 unset($tableDifferences->removedColumns[$removedColumnName]);
6139 * @param ForeignKeyConstraint $key1
6140 * @param ForeignKeyConstraint $key2
6143 public function diffForeignKey(ForeignKeyConstraint $key1, ForeignKeyConstraint $key2)
6145 if (array_map('strtolower', $key1->getLocalColumns()) != array_map('strtolower', $key2->getLocalColumns())) {
6149 if (array_map('strtolower', $key1->getForeignColumns()) != array_map('strtolower', $key2->getForeignColumns())) {
6153 if ($key1->onUpdate() != $key2->onUpdate()) {
6157 if ($key1->onDelete() != $key2->onDelete()) {
6165 * Returns the difference between the fields $field1 and $field2.
6167 * If there are differences this method returns $field2, otherwise the
6170 * @param Column $column1
6171 * @param Column $column2
6175 public function diffColumn(Column $column1, Column $column2)
6177 $changedProperties = array();
6178 if ( $column1->getType() != $column2->getType() ) {
6179 $changedProperties[] = 'type';
6182 if ($column1->getNotnull() != $column2->getNotnull()) {
6183 $changedProperties[] = 'notnull';
6186 if ($column1->getDefault() != $column2->getDefault()) {
6187 $changedProperties[] = 'default';
6190 if ($column1->getUnsigned() != $column2->getUnsigned()) {
6191 $changedProperties[] = 'unsigned';
6194 if ($column1->getType() instanceof \Doctrine\DBAL\Types\StringType) {
6195 if ($column1->getLength() != $column2->getLength()) {
6196 $changedProperties[] = 'length';
6199 if ($column1->getFixed() != $column2->getFixed()) {
6200 $changedProperties[] = 'fixed';
6204 if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) {
6205 if ($column1->getPrecision() != $column2->getPrecision()) {
6206 $changedProperties[] = 'precision';
6208 if ($column1->getScale() != $column2->getScale()) {
6209 $changedProperties[] = 'scale';
6213 if ($column1->getAutoincrement() != $column2->getAutoincrement()) {
6214 $changedProperties[] = 'autoincrement';
6217 return $changedProperties;
6221 * Finds the difference between the indexes $index1 and $index2.
6223 * Compares $index1 with $index2 and returns $index2 if there are any
6224 * differences or false in case there are no differences.
6226 * @param Index $index1
6227 * @param Index $index2
6230 public function diffIndex(Index $index1, Index $index2)
6232 if ($index1->isFullfilledBy($index2) && $index2->isFullfilledBy($index1)) {
6240 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6241 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6242 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6243 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
6244 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
6245 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6246 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
6247 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
6248 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6249 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
6250 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6252 * This software consists of voluntary contributions made by many individuals
6253 * and is licensed under the LGPL. For more information, see
6254 * <http://www.doctrine-project.org>.
6257 namespace Doctrine\DBAL\Schema;
6259 use Doctrine\DBAL\Schema\Visitor\Visitor;
6261 class Index extends AbstractAsset implements Constraint
6266 protected $_columns;
6271 protected $_isUnique = false;
6276 protected $_isPrimary = false;
6279 * @param string $indexName
6280 * @param array $column
6281 * @param bool $isUnique
6282 * @param bool $isPrimary
6284 public function __construct($indexName, array $columns, $isUnique=false, $isPrimary=false)
6286 $isUnique = ($isPrimary)?true:$isUnique;
6288 $this->_setName($indexName);
6289 $this->_isUnique = $isUnique;
6290 $this->_isPrimary = $isPrimary;
6292 foreach($columns AS $column) {
6293 $this->_addColumn($column);
6298 * @param string $column
6300 protected function _addColumn($column)
6302 if(is_string($column)) {
6303 $this->_columns[] = strtolower($column);
6305 throw new \InvalidArgumentException("Expecting a string as Index Column");
6312 public function getColumns()
6314 return $this->_columns;
6320 public function isUnique()
6322 return $this->_isUnique;
6328 public function isPrimary()
6330 return $this->_isPrimary;
6334 * @param string $columnName
6338 public function hasColumnAtPosition($columnName, $pos=0)
6340 $columnName = strtolower($columnName);
6341 $indexColumns = \array_map('strtolower', $this->getColumns());
6342 return \array_search($columnName, $indexColumns) === $pos;
6346 * Check if this index exactly spans the given column names in the correct order.
6348 * @param array $columnNames
6351 public function spansColumns(array $columnNames)
6353 $sameColumns = true;
6354 for ($i = 0; $i < count($this->_columns); $i++) {
6355 if (!isset($columnNames[$i]) || strtolower($this->_columns[$i]) != strtolower($columnNames[$i])) {
6356 $sameColumns = false;
6359 return $sameColumns;
6363 * Check if the other index already fullfills all the indexing and constraint needs of the current one.
6365 * @param Index $other
6368 public function isFullfilledBy(Index $other)
6370 // allow the other index to be equally large only. It being larger is an option
6371 // but it creates a problem with scenarios of the kind PRIMARY KEY(foo,bar) UNIQUE(foo)
6372 if (count($other->getColumns()) != count($this->getColumns())) {
6376 // Check if columns are the same, and even in the same order
6377 $sameColumns = $this->spansColumns($other->getColumns());
6380 if (!$this->isUnique() && !$this->isPrimary()) {
6381 // this is a special case: If the current key is neither primary or unique, any uniqe or
6382 // primary key will always have the same effect for the index and there cannot be any constraint
6383 // overlaps. This means a primary or unique index can always fullfill the requirements of just an
6384 // index that has no constraints.
6386 } else if ($other->isPrimary() != $this->isPrimary()) {
6388 } else if ($other->isUnique() != $this->isUnique()) {
6397 * Detect if the other index is a non-unique, non primary index that can be overwritten by this one.
6399 * @param Index $other
6402 public function overrules(Index $other)
6404 if ($other->isPrimary() || $other->isUnique()) {
6408 if ($this->spansColumns($other->getColumns()) && ($this->isPrimary() || $this->isUnique())) {
6415 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6416 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6417 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6418 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
6419 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
6420 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6421 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
6422 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
6423 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6424 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
6425 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6427 * This software consists of voluntary contributions made by many individuals
6428 * and is licensed under the LGPL. For more information, see
6429 * <http://www.doctrine-project.org>.
6432 namespace Doctrine\DBAL\Schema;
6434 use Doctrine\DBAL\Types;
6435 use Doctrine\DBAL\DBALException;
6436 use Doctrine\DBAL\Platforms\AbstractPlatform;
6439 * Base class for schema managers. Schema managers are used to inspect and/or
6440 * modify the database schema/structure.
6442 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
6443 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
6444 * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
6445 * @author Roman Borschel <roman@code-factory.org>
6446 * @author Jonathan H. Wage <jonwage@gmail.com>
6447 * @author Benjamin Eberlei <kontakt@beberlei.de>
6448 * @version $Revision$
6451 abstract class AbstractSchemaManager
6454 * Holds instance of the Doctrine connection for this schema manager
6456 * @var \Doctrine\DBAL\Connection
6461 * Holds instance of the database platform used for this schema manager
6463 * @var \Doctrine\DBAL\Platforms\AbstractPlatform
6465 protected $_platform;
6468 * Constructor. Accepts the Connection instance to manage the schema for
6470 * @param \Doctrine\DBAL\Connection $conn
6472 public function __construct(\Doctrine\DBAL\Connection $conn)
6474 $this->_conn = $conn;
6475 $this->_platform = $this->_conn->getDatabasePlatform();
6479 * Return associated platform.
6481 * @return \Doctrine\DBAL\Platform\AbstractPlatform
6483 public function getDatabasePlatform()
6485 return $this->_platform;
6489 * Try any method on the schema manager. Normally a method throws an
6490 * exception when your DBMS doesn't support it or if an error occurs.
6491 * This method allows you to try and method on your SchemaManager
6492 * instance and will return false if it does not work or is not supported.
6495 * $result = $sm->tryMethod('dropView', 'view_name');
6500 public function tryMethod()
6502 $args = func_get_args();
6505 $args = array_values($args);
6508 return call_user_func_array(array($this, $method), $args);
6509 } catch (\Exception $e) {
6515 * List the available databases for this connection
6517 * @return array $databases
6519 public function listDatabases()
6521 $sql = $this->_platform->getListDatabasesSQL();
6523 $databases = $this->_conn->fetchAll($sql);
6525 return $this->_getPortableDatabasesList($databases);
6529 * List the available sequences for this connection
6531 * @return Sequence[]
6533 public function listSequences($database = null)
6535 if (is_null($database)) {
6536 $database = $this->_conn->getDatabase();
6538 $sql = $this->_platform->getListSequencesSQL($database);
6540 $sequences = $this->_conn->fetchAll($sql);
6542 return $this->_getPortableSequencesList($sequences);
6546 * List the columns for a given table.
6548 * In contrast to other libraries and to the old version of Doctrine,
6549 * this column definition does try to contain the 'primary' field for
6550 * the reason that it is not portable accross different RDBMS. Use
6551 * {@see listTableIndexes($tableName)} to retrieve the primary key
6552 * of a table. We're a RDBMS specifies more details these are held
6553 * in the platformDetails array.
6555 * @param string $table The name of the table.
6558 public function listTableColumns($table)
6560 $sql = $this->_platform->getListTableColumnsSQL($table);
6562 $tableColumns = $this->_conn->fetchAll($sql);
6564 return $this->_getPortableTableColumnList($tableColumns);
6568 * List the indexes for a given table returning an array of Index instances.
6570 * Keys of the portable indexes list are all lower-cased.
6572 * @param string $table The name of the table
6573 * @return Index[] $tableIndexes
6575 public function listTableIndexes($table)
6577 $sql = $this->_platform->getListTableIndexesSQL($table);
6579 $tableIndexes = $this->_conn->fetchAll($sql);
6581 return $this->_getPortableTableIndexesList($tableIndexes, $table);
6585 * Return true if all the given tables exist.
6587 * @param array $tableNames
6590 public function tablesExist($tableNames)
6592 $tableNames = array_map('strtolower', (array)$tableNames);
6593 return count($tableNames) == count(\array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
6598 * Return a list of all tables in the current database
6602 public function listTableNames()
6604 $sql = $this->_platform->getListTablesSQL();
6606 $tables = $this->_conn->fetchAll($sql);
6608 return $this->_getPortableTablesList($tables);
6612 * List the tables for this connection
6616 public function listTables()
6618 $tableNames = $this->listTableNames();
6621 foreach ($tableNames AS $tableName) {
6622 $tables[] = $this->listTableDetails($tableName);
6629 * @param string $tableName
6632 public function listTableDetails($tableName)
6634 $columns = $this->listTableColumns($tableName);
6635 $foreignKeys = array();
6636 if ($this->_platform->supportsForeignKeyConstraints()) {
6637 $foreignKeys = $this->listTableForeignKeys($tableName);
6639 $indexes = $this->listTableIndexes($tableName);
6641 return new Table($tableName, $columns, $indexes, $foreignKeys, false, array());
6645 * List the views this connection has
6649 public function listViews()
6651 $database = $this->_conn->getDatabase();
6652 $sql = $this->_platform->getListViewsSQL($database);
6653 $views = $this->_conn->fetchAll($sql);
6655 return $this->_getPortableViewsList($views);
6659 * List the foreign keys for the given table
6661 * @param string $table The name of the table
6662 * @return ForeignKeyConstraint[]
6664 public function listTableForeignKeys($table, $database = null)
6666 if (is_null($database)) {
6667 $database = $this->_conn->getDatabase();
6669 $sql = $this->_platform->getListTableForeignKeysSQL($table, $database);
6670 $tableForeignKeys = $this->_conn->fetchAll($sql);
6672 return $this->_getPortableTableForeignKeysList($tableForeignKeys);
6675 /* drop*() Methods */
6680 * NOTE: You can not drop the database this SchemaManager is currently connected to.
6682 * @param string $database The name of the database to drop
6684 public function dropDatabase($database)
6686 $this->_execSql($this->_platform->getDropDatabaseSQL($database));
6690 * Drop the given table
6692 * @param string $table The name of the table to drop
6694 public function dropTable($table)
6696 $this->_execSql($this->_platform->getDropTableSQL($table));
6700 * Drop the index from the given table
6702 * @param Index|string $index The name of the index
6703 * @param string|Table $table The name of the table
6705 public function dropIndex($index, $table)
6707 if($index instanceof Index) {
6708 $index = $index->getName();
6711 $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
6715 * Drop the constraint from the given table
6717 * @param Constraint $constraint
6718 * @param string $table The name of the table
6720 public function dropConstraint(Constraint $constraint, $table)
6722 $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
6726 * Drops a foreign key from a table.
6728 * @param ForeignKeyConstraint|string $table The name of the table with the foreign key.
6729 * @param Table|string $name The name of the foreign key.
6730 * @return boolean $result
6732 public function dropForeignKey($foreignKey, $table)
6734 $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
6738 * Drops a sequence with a given name.
6740 * @param string $name The name of the sequence to drop.
6742 public function dropSequence($name)
6744 $this->_execSql($this->_platform->getDropSequenceSQL($name));
6750 * @param string $name The name of the view
6751 * @return boolean $result
6753 public function dropView($name)
6755 $this->_execSql($this->_platform->getDropViewSQL($name));
6758 /* create*() Methods */
6761 * Creates a new database.
6763 * @param string $database The name of the database to create.
6765 public function createDatabase($database)
6767 $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
6771 * Create a new table.
6773 * @param Table $table
6774 * @param int $createFlags
6776 public function createTable(Table $table)
6778 $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
6779 $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
6783 * Create a new sequence
6785 * @param Sequence $sequence
6786 * @throws Doctrine\DBAL\ConnectionException if something fails at database level
6788 public function createSequence($sequence)
6790 $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
6794 * Create a constraint on a table
6796 * @param Constraint $constraint
6797 * @param string|Table $table
6799 public function createConstraint(Constraint $constraint, $table)
6801 $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table));
6805 * Create a new index on a table
6807 * @param Index $index
6808 * @param string $table name of the table on which the index is to be created
6810 public function createIndex(Index $index, $table)
6812 $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
6816 * Create a new foreign key
6818 * @param ForeignKeyConstraint $foreignKey ForeignKey instance
6819 * @param string|Table $table name of the table on which the foreign key is to be created
6821 public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
6823 $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
6831 public function createView(View $view)
6833 $this->_execSql($this->_platform->getCreateViewSQL($view->getName(), $view->getSql()));
6836 /* dropAndCreate*() Methods */
6839 * Drop and create a constraint
6841 * @param Constraint $constraint
6842 * @param string $table
6843 * @see dropConstraint()
6844 * @see createConstraint()
6846 public function dropAndCreateConstraint(Constraint $constraint, $table)
6848 $this->tryMethod('dropConstraint', $constraint, $table);
6849 $this->createConstraint($constraint, $table);
6853 * Drop and create a new index on a table
6855 * @param string|Table $table name of the table on which the index is to be created
6856 * @param Index $index
6858 public function dropAndCreateIndex(Index $index, $table)
6860 $this->tryMethod('dropIndex', $index->getName(), $table);
6861 $this->createIndex($index, $table);
6865 * Drop and create a new foreign key
6867 * @param ForeignKeyConstraint $foreignKey associative array that defines properties of the foreign key to be created.
6868 * @param string|Table $table name of the table on which the foreign key is to be created
6870 public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
6872 $this->tryMethod('dropForeignKey', $foreignKey, $table);
6873 $this->createForeignKey($foreignKey, $table);
6877 * Drop and create a new sequence
6879 * @param Sequence $sequence
6880 * @throws Doctrine\DBAL\ConnectionException if something fails at database level
6882 public function dropAndCreateSequence(Sequence $sequence)
6884 $this->tryMethod('createSequence', $seqName, $start, $allocationSize);
6885 $this->createSequence($seqName, $start, $allocationSize);
6889 * Drop and create a new table.
6891 * @param Table $table
6893 public function dropAndCreateTable(Table $table)
6895 $this->tryMethod('dropTable', $table->getName());
6896 $this->createTable($table);
6900 * Drop and creates a new database.
6902 * @param string $database The name of the database to create.
6904 public function dropAndCreateDatabase($database)
6906 $this->tryMethod('dropDatabase', $database);
6907 $this->createDatabase($database);
6911 * Drop and create a new view
6915 public function dropAndCreateView(View $view)
6917 $this->tryMethod('dropView', $view->getName());
6918 $this->createView($view);
6921 /* alterTable() Methods */
6924 * Alter an existing tables schema
6926 * @param TableDiff $tableDiff
6928 public function alterTable(TableDiff $tableDiff)
6930 $queries = $this->_platform->getAlterTableSQL($tableDiff);
6931 if (is_array($queries) && count($queries)) {
6932 foreach ($queries AS $ddlQuery) {
6933 $this->_execSql($ddlQuery);
6939 * Rename a given table to another name
6941 * @param string $name The current name of the table
6942 * @param string $newName The new name of the table
6944 public function renameTable($name, $newName)
6946 $tableDiff = new TableDiff($name);
6947 $tableDiff->newName = $newName;
6948 $this->alterTable($tableDiff);
6952 * Methods for filtering return values of list*() methods to convert
6953 * the native DBMS data definition to a portable Doctrine definition
6956 protected function _getPortableDatabasesList($databases)
6959 foreach ($databases as $key => $value) {
6960 if ($value = $this->_getPortableDatabaseDefinition($value)) {
6967 protected function _getPortableDatabaseDefinition($database)
6972 protected function _getPortableFunctionsList($functions)
6975 foreach ($functions as $key => $value) {
6976 if ($value = $this->_getPortableFunctionDefinition($value)) {
6983 protected function _getPortableFunctionDefinition($function)
6988 protected function _getPortableTriggersList($triggers)
6991 foreach ($triggers as $key => $value) {
6992 if ($value = $this->_getPortableTriggerDefinition($value)) {
6999 protected function _getPortableTriggerDefinition($trigger)
7004 protected function _getPortableSequencesList($sequences)
7007 foreach ($sequences as $key => $value) {
7008 if ($value = $this->_getPortableSequenceDefinition($value)) {
7016 * @param array $sequence
7019 protected function _getPortableSequenceDefinition($sequence)
7021 throw DBALException::notSupported('Sequences');
7025 * Independent of the database the keys of the column list result are lowercased.
7027 * The name of the created column instance however is kept in its case.
7029 * @param array $tableColumns
7032 protected function _getPortableTableColumnList($tableColumns)
7035 foreach ($tableColumns as $key => $column) {
7036 if ($column = $this->_getPortableTableColumnDefinition($column)) {
7037 $name = strtolower($column->getName());
7038 $list[$name] = $column;
7045 * Get Table Column Definition
7047 * @param array $tableColumn
7050 abstract protected function _getPortableTableColumnDefinition($tableColumn);
7053 * Aggregate and group the index results according to the required data result.
7055 * @param array $tableIndexRows
7056 * @param string $tableName
7059 protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null)
7062 foreach($tableIndexRows AS $tableIndex) {
7063 $indexName = $keyName = $tableIndex['key_name'];
7064 if($tableIndex['primary']) {
7065 $keyName = 'primary';
7067 $keyName = strtolower($keyName);
7069 if(!isset($result[$keyName])) {
7070 $result[$keyName] = array(
7071 'name' => $indexName,
7072 'columns' => array($tableIndex['column_name']),
7073 'unique' => $tableIndex['non_unique'] ? false : true,
7074 'primary' => $tableIndex['primary'],
7077 $result[$keyName]['columns'][] = $tableIndex['column_name'];
7082 foreach($result AS $indexKey => $data) {
7083 $indexes[$indexKey] = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']);
7089 protected function _getPortableTablesList($tables)
7092 foreach ($tables as $key => $value) {
7093 if ($value = $this->_getPortableTableDefinition($value)) {
7100 protected function _getPortableTableDefinition($table)
7105 protected function _getPortableUsersList($users)
7108 foreach ($users as $key => $value) {
7109 if ($value = $this->_getPortableUserDefinition($value)) {
7116 protected function _getPortableUserDefinition($user)
7121 protected function _getPortableViewsList($views)
7124 foreach ($views as $key => $value) {
7125 if ($view = $this->_getPortableViewDefinition($value)) {
7126 $viewName = strtolower($view->getName());
7127 $list[$viewName] = $view;
7133 protected function _getPortableViewDefinition($view)
7138 protected function _getPortableTableForeignKeysList($tableForeignKeys)
7141 foreach ($tableForeignKeys as $key => $value) {
7142 if ($value = $this->_getPortableTableForeignKeyDefinition($value)) {
7149 protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
7151 return $tableForeignKey;
7154 protected function _execSql($sql)
7156 foreach ((array) $sql as $query) {
7157 $this->_conn->executeUpdate($query);
7162 * Create a schema instance for the current database.
7166 public function createSchema()
7168 $sequences = array();
7169 if($this->_platform->supportsSequences()) {
7170 $sequences = $this->listSequences();
7172 $tables = $this->listTables();
7174 return new Schema($tables, $sequences, $this->createSchemaConfig());
7178 * Create the configuration for this schema.
7180 * @return SchemaConfig
7182 public function createSchemaConfig()
7184 $schemaConfig = new SchemaConfig();
7185 $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
7187 return $schemaConfig;
7193 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
7194 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7195 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7196 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7197 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
7198 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
7199 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
7200 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
7201 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7202 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7203 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7205 * This software consists of voluntary contributions made by many individuals
7206 * and is licensed under the LGPL. For more information, see
7207 * <http://www.doctrine-project.org>.
7210 namespace Doctrine\DBAL\Schema;
7213 * The abstract asset allows to reset the name of all assets without publishing this to the public userland.
7215 * This encapsulation hack is necessary to keep a consistent state of the database schema. Say we have a list of tables
7216 * array($tableName => Table($tableName)); if you want to rename the table, you have to make sure
7218 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7219 * @link www.doctrine-project.org
7221 * @version $Revision$
7222 * @author Benjamin Eberlei <kontakt@beberlei.de>
7224 abstract class AbstractAsset
7232 * Set name of this asset
7234 * @param string $name
7236 protected function _setName($name)
7238 $this->_name = $name;
7242 * Return name of this schema asset.
7246 public function getName()
7248 return $this->_name;
7252 * Generate an identifier from a list of column names obeying a certain string length.
7254 * This is especially important for Oracle, since it does not allow identifiers larger than 30 chars,
7255 * however building idents automatically for foreign keys, composite keys or such can easily create
7258 * @param array $columnNames
7259 * @param string $postfix
7260 * @param int $maxSize
7263 protected function _generateIdentifierName($columnNames, $postfix='', $maxSize=30)
7265 $columnCount = count($columnNames);
7266 $postfixLen = strlen($postfix);
7267 $parts = array_map(function($columnName) use($columnCount, $postfixLen, $maxSize) {
7268 return substr($columnName, -floor(($maxSize-$postfixLen)/$columnCount - 1));
7270 $parts[] = $postfix;
7272 $identifier = trim(implode("_", $parts), '_');
7273 // using implicit schema support of DB2 and Postgres there might be dots in the auto-generated
7274 // identifier names which can easily be replaced by underscores.
7275 $identifier = str_replace(".", "_", $identifier);
7277 if (is_numeric(substr($identifier, 0, 1))) {
7278 $identifier = "i" . substr($identifier, 0, strlen($identifier)-1);
7285 * $Id: Schema.php 6876 2009-12-06 23:11:35Z beberlei $
7287 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
7288 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7289 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7290 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7291 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
7292 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
7293 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
7294 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
7295 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7296 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7297 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7299 * This software consists of voluntary contributions made by many individuals
7300 * and is licensed under the LGPL. For more information, see
7301 * <http://www.doctrine-project.org>.
7304 namespace Doctrine\DBAL\Schema;
7307 * Configuration for a Schema
7309 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7310 * @link www.doctrine-project.org
7312 * @version $Revision$
7313 * @author Benjamin Eberlei <kontakt@beberlei.de>
7320 protected $_hasExplicitForeignKeyIndexes = false;
7325 protected $_maxIdentifierLength = 63;
7330 public function hasExplicitForeignKeyIndexes()
7332 return $this->_hasExplicitForeignKeyIndexes;
7338 public function setExplicitForeignKeyIndexes($flag)
7340 $this->_hasExplicitForeignKeyIndexes = (bool)$flag;
7344 * @param int $length
7346 public function setMaxIdentifierLength($length)
7348 $this->_maxIdentifierLength = (int)$length;
7354 public function getMaxIdentifierLength()
7356 return $this->_maxIdentifierLength;
7360 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
7361 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7362 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7363 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7364 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
7365 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
7366 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
7367 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
7368 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7369 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7370 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7372 * This software consists of voluntary contributions made by many individuals
7373 * and is licensed under the LGPL. For more information, see
7374 * <http://www.doctrine-project.org>.
7377 namespace Doctrine\DBAL\Schema;
7379 use \Doctrine\DBAL\Types\Type;
7380 use Doctrine\DBAL\Schema\Visitor\Visitor;
7383 * Object representation of a database column
7385 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7386 * @link www.doctrine-project.org
7388 * @version $Revision$
7389 * @author Benjamin Eberlei <kontakt@beberlei.de>
7391 class Column extends AbstractAsset
7394 * @var \Doctrine\DBAL\Types\Type
7401 protected $_length = null;
7406 protected $_precision = 0;
7411 protected $_scale = 0;
7416 protected $_unsigned = false;
7421 protected $_fixed = false;
7426 protected $_notnull = true;
7431 protected $_default = null;
7436 protected $_autoincrement = false;
7441 protected $_platformOptions = array();
7446 protected $_columnDefinition = null;
7449 * Create a new Column
7451 * @param string $columnName
7452 * @param Doctrine\DBAL\Types\Type $type
7453 * @param int $length
7454 * @param bool $notNull
7455 * @param mixed $default
7456 * @param bool $unsigned
7457 * @param bool $fixed
7458 * @param int $precision
7460 * @param array $platformOptions
7462 public function __construct($columnName, Type $type, array $options=array())
7464 $this->_setName($columnName);
7465 $this->setType($type);
7466 $this->setOptions($options);
7470 * @param array $options
7473 public function setOptions(array $options)
7475 foreach ($options AS $name => $value) {
7476 $method = "set".$name;
7477 if (method_exists($this, $method)) {
7478 $this->$method($value);
7488 public function setType(Type $type)
7490 $this->_type = $type;
7495 * @param int $length
7498 public function setLength($length)
7500 if($length !== null) {
7501 $this->_length = (int)$length;
7503 $this->_length = null;
7509 * @param int $precision
7512 public function setPrecision($precision)
7514 $this->_precision = (int)$precision;
7522 public function setScale($scale)
7524 $this->_scale = $scale;
7530 * @param bool $unsigned
7533 public function setUnsigned($unsigned)
7535 $this->_unsigned = (bool)$unsigned;
7541 * @param bool $fixed
7544 public function setFixed($fixed)
7546 $this->_fixed = (bool)$fixed;
7551 * @param bool $notnull
7554 public function setNotnull($notnull)
7556 $this->_notnull = (bool)$notnull;
7562 * @param mixed $default
7565 public function setDefault($default)
7567 $this->_default = $default;
7573 * @param array $platformOptions
7576 public function setPlatformOptions(array $platformOptions)
7578 $this->_platformOptions = $platformOptions;
7584 * @param string $name
7585 * @param mixed $value
7588 public function setPlatformOption($name, $value)
7590 $this->_platformOptions[$name] = $value;
7599 public function setColumnDefinition($value)
7601 $this->_columnDefinition = $value;
7605 public function getType()
7607 return $this->_type;
7610 public function getLength()
7612 return $this->_length;
7615 public function getPrecision()
7617 return $this->_precision;
7620 public function getScale()
7622 return $this->_scale;
7625 public function getUnsigned()
7627 return $this->_unsigned;
7630 public function getFixed()
7632 return $this->_fixed;
7635 public function getNotnull()
7637 return $this->_notnull;
7640 public function getDefault()
7642 return $this->_default;
7645 public function getPlatformOptions()
7647 return $this->_platformOptions;
7650 public function hasPlatformOption($name)
7652 return isset($this->_platformOptions[$name]);
7655 public function getPlatformOption($name)
7657 return $this->_platformOptions[$name];
7660 public function getColumnDefinition()
7662 return $this->_columnDefinition;
7665 public function getAutoincrement()
7667 return $this->_autoincrement;
7670 public function setAutoincrement($flag)
7672 $this->_autoincrement = $flag;
7677 * @param Visitor $visitor
7679 public function visit(\Doctrine\DBAL\Schema\Visitor $visitor)
7681 $visitor->accept($this);
7687 public function toArray()
7689 return array_merge(array(
7690 'name' => $this->_name,
7691 'type' => $this->_type,
7692 'default' => $this->_default,
7693 'notnull' => $this->_notnull,
7694 'length' => $this->_length,
7695 'precision' => $this->_precision,
7696 'scale' => $this->_scale,
7697 'fixed' => $this->_fixed,
7698 'unsigned' => $this->_unsigned,
7699 'autoincrement' => $this->_autoincrement,
7700 'columnDefinition' => $this->_columnDefinition,
7701 ), $this->_platformOptions);
7707 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
7708 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7709 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7710 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7711 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
7712 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
7713 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
7714 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
7715 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7716 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7717 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7719 * This software consists of voluntary contributions made by many individuals
7720 * and is licensed under the LGPL. For more information, see
7721 * <http://www.doctrine-project.org>.
7724 namespace Doctrine\DBAL\Schema;
7727 * Marker interface for contraints
7729 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7730 * @link www.doctrine-project.org
7732 * @version $Revision$
7733 * @author Benjamin Eberlei <kontakt@beberlei.de>
7735 interface Constraint
7737 public function getName();
7739 public function getColumns();
7742 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
7743 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7744 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7745 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7746 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
7747 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
7748 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
7749 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
7750 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7751 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7752 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7754 * This software consists of voluntary contributions made by many individuals
7755 * and is licensed under the LGPL. For more information, see
7756 * <http://www.doctrine-project.org>.
7759 namespace Doctrine\DBAL\Schema;
7761 use \Doctrine\DBAL\Platforms\AbstractPlatform;
7766 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7767 * @link www.doctrine-project.org
7768 * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
7769 * @license http://ez.no/licenses/new_bsd New BSD License
7771 * @version $Revision$
7772 * @author Benjamin Eberlei <kontakt@beberlei.de>
7779 * @var array(string=>ezcDbSchemaTable)
7781 public $newTables = array();
7784 * All changed tables
7786 * @var array(string=>ezcDbSchemaTableDiff)
7788 public $changedTables = array();
7791 * All removed tables
7793 * @var array(string=>Table)
7795 public $removedTables = array();
7800 public $newSequences = array();
7805 public $changedSequences = array();
7810 public $removedSequences = array();
7815 public $orphanedForeignKeys = array();
7818 * Constructs an SchemaDiff object.
7820 * @param array(string=>Table) $newTables
7821 * @param array(string=>TableDiff) $changedTables
7822 * @param array(string=>bool) $removedTables
7824 public function __construct($newTables = array(), $changedTables = array(), $removedTables = array())
7826 $this->newTables = $newTables;
7827 $this->changedTables = $changedTables;
7828 $this->removedTables = $removedTables;
7832 * The to save sql mode ensures that the following things don't happen:
7834 * 1. Tables are deleted
7835 * 2. Sequences are deleted
7836 * 3. Foreign Keys which reference tables that would otherwise be deleted.
7838 * This way it is ensured that assets are deleted which might not be relevant to the metadata schema at all.
7840 * @param AbstractPlatform $platform
7843 public function toSaveSql(AbstractPlatform $platform)
7845 return $this->_toSql($platform, true);
7849 * @param AbstractPlatform $platform
7852 public function toSql(AbstractPlatform $platform)
7854 return $this->_toSql($platform, false);
7858 * @param AbstractPlatform $platform
7859 * @param bool $saveMode
7862 protected function _toSql(AbstractPlatform $platform, $saveMode = false)
7866 if ($platform->supportsForeignKeyConstraints() && $saveMode == false) {
7867 foreach ($this->orphanedForeignKeys AS $orphanedForeignKey) {
7868 $sql[] = $platform->getDropForeignKeySQL($orphanedForeignKey, $orphanedForeignKey->getLocalTableName());
7872 if ($platform->supportsSequences() == true) {
7873 foreach ($this->changedSequences AS $sequence) {
7874 $sql[] = $platform->getDropSequenceSQL($sequence);
7875 $sql[] = $platform->getCreateSequenceSQL($sequence);
7878 if ($saveMode === false) {
7879 foreach ($this->removedSequences AS $sequence) {
7880 $sql[] = $platform->getDropSequenceSQL($sequence);
7884 foreach ($this->newSequences AS $sequence) {
7885 $sql[] = $platform->getCreateSequenceSQL($sequence);
7889 $foreignKeySql = array();
7890 foreach ($this->newTables AS $table) {
7893 $platform->getCreateTableSQL($table, AbstractPlatform::CREATE_INDEXES)
7896 if ($platform->supportsForeignKeyConstraints()) {
7897 foreach ($table->getForeignKeys() AS $foreignKey) {
7898 $foreignKeySql[] = $platform->getCreateForeignKeySQL($foreignKey, $table);
7902 $sql = array_merge($sql, $foreignKeySql);
7904 if ($saveMode === false) {
7905 foreach ($this->removedTables AS $table) {
7906 $sql[] = $platform->getDropTableSQL($table);
7910 foreach ($this->changedTables AS $tableDiff) {
7911 $sql = array_merge($sql, $platform->getAlterTableSQL($tableDiff));
7920 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
7921 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7922 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7923 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7924 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
7925 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
7926 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
7927 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
7928 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7929 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7930 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7932 * This software consists of voluntary contributions made by many individuals
7933 * and is licensed under the LGPL. For more information, see
7934 * <http://www.doctrine-project.org>.
7937 namespace Doctrine\DBAL\Schema;
7939 use Doctrine\DBAL\Schema\Visitor\CreateSchemaSqlCollector;
7940 use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector;
7941 use Doctrine\DBAL\Schema\Visitor\Visitor;
7944 * Object representation of a database schema
7946 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7947 * @link www.doctrine-project.org
7949 * @version $Revision$
7950 * @author Benjamin Eberlei <kontakt@beberlei.de>
7952 class Schema extends AbstractAsset
7957 protected $_tables = array();
7962 protected $_sequences = array();
7967 protected $_schemaConfig = false;
7970 * @param array $tables
7971 * @param array $sequences
7972 * @param array $views
7973 * @param array $triggers
7974 * @param SchemaConfig $schemaConfig
7976 public function __construct(array $tables=array(), array $sequences=array(), SchemaConfig $schemaConfig=null)
7978 if ($schemaConfig == null) {
7979 $schemaConfig = new SchemaConfig();
7981 $this->_schemaConfig = $schemaConfig;
7983 foreach ($tables AS $table) {
7984 $this->_addTable($table);
7986 foreach ($sequences AS $sequence) {
7987 $this->_addSequence($sequence);
7994 public function hasExplicitForeignKeyIndexes()
7996 return $this->_schemaConfig->hasExplicitForeignKeyIndexes();
8000 * @param Table $table
8002 protected function _addTable(Table $table)
8004 $tableName = strtolower($table->getName());
8005 if(isset($this->_tables[$tableName])) {
8006 throw SchemaException::tableAlreadyExists($tableName);
8009 $this->_tables[$tableName] = $table;
8010 $table->setSchemaConfig($this->_schemaConfig);
8014 * @param Sequence $sequence
8016 protected function _addSequence(Sequence $sequence)
8018 $seqName = strtolower($sequence->getName());
8019 if (isset($this->_sequences[$seqName])) {
8020 throw SchemaException::sequenceAlreadyExists($seqName);
8022 $this->_sequences[$seqName] = $sequence;
8026 * Get all tables of this schema.
8030 public function getTables()
8032 return $this->_tables;
8036 * @param string $tableName
8039 public function getTable($tableName)
8041 $tableName = strtolower($tableName);
8042 if (!isset($this->_tables[$tableName])) {
8043 throw SchemaException::tableDoesNotExist($tableName);
8046 return $this->_tables[$tableName];
8050 * Does this schema have a table with the given name?
8052 * @param string $tableName
8055 public function hasTable($tableName)
8057 $tableName = strtolower($tableName);
8058 return isset($this->_tables[$tableName]);
8062 * @param string $sequenceName
8065 public function hasSequence($sequenceName)
8067 $sequenceName = strtolower($sequenceName);
8068 return isset($this->_sequences[$sequenceName]);
8072 * @throws SchemaException
8073 * @param string $sequenceName
8074 * @return Doctrine\DBAL\Schema\Sequence
8076 public function getSequence($sequenceName)
8078 $sequenceName = strtolower($sequenceName);
8079 if(!$this->hasSequence($sequenceName)) {
8080 throw SchemaException::sequenceDoesNotExist($sequenceName);
8082 return $this->_sequences[$sequenceName];
8086 * @return Doctrine\DBAL\Schema\Sequence[]
8088 public function getSequences()
8090 return $this->_sequences;
8094 * Create a new table
8096 * @param string $tableName
8099 public function createTable($tableName)
8101 $table = new Table($tableName);
8102 $this->_addTable($table);
8109 * @param string $oldTableName
8110 * @param string $newTableName
8113 public function renameTable($oldTableName, $newTableName)
8115 $table = $this->getTable($oldTableName);
8116 $table->_setName($newTableName);
8118 $this->dropTable($oldTableName);
8119 $this->_addTable($table);
8124 * Drop a table from the schema.
8126 * @param string $tableName
8129 public function dropTable($tableName)
8131 $tableName = strtolower($tableName);
8132 $table = $this->getTable($tableName);
8133 unset($this->_tables[$tableName]);
8138 * Create a new sequence
8140 * @param string $sequenceName
8141 * @param int $allocationSize
8142 * @param int $initialValue
8145 public function createSequence($sequenceName, $allocationSize=1, $initialValue=1)
8147 $seq = new Sequence($sequenceName, $allocationSize, $initialValue);
8148 $this->_addSequence($seq);
8153 * @param string $sequenceName
8156 public function dropSequence($sequenceName)
8158 $sequenceName = strtolower($sequenceName);
8159 unset($this->_sequences[$sequenceName]);
8164 * Return an array of necessary sql queries to create the schema on the given platform.
8166 * @param AbstractPlatform $platform
8169 public function toSql(\Doctrine\DBAL\Platforms\AbstractPlatform $platform)
8171 $sqlCollector = new CreateSchemaSqlCollector($platform);
8172 $this->visit($sqlCollector);
8174 return $sqlCollector->getQueries();
8178 * Return an array of necessary sql queries to drop the schema on the given platform.
8180 * @param AbstractPlatform $platform
8183 public function toDropSql(\Doctrine\DBAL\Platforms\AbstractPlatform $platform)
8185 $dropSqlCollector = new DropSchemaSqlCollector($platform);
8186 $this->visit($dropSqlCollector);
8188 return $dropSqlCollector->getQueries();
8192 * @param Schema $toSchema
8193 * @param AbstractPlatform $platform
8195 public function getMigrateToSql(Schema $toSchema, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
8197 $comparator = new Comparator();
8198 $schemaDiff = $comparator->compare($this, $toSchema);
8199 return $schemaDiff->toSql($platform);
8203 * @param Schema $fromSchema
8204 * @param AbstractPlatform $platform
8206 public function getMigrateFromSql(Schema $fromSchema, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
8208 $comparator = new Comparator();
8209 $schemaDiff = $comparator->compare($fromSchema, $this);
8210 return $schemaDiff->toSql($platform);
8214 * @param Visitor $visitor
8216 public function visit(Visitor $visitor)
8218 $visitor->acceptSchema($this);
8220 foreach ($this->_tables AS $table) {
8221 $table->visit($visitor);
8223 foreach ($this->_sequences AS $sequence) {
8224 $sequence->visit($visitor);
8229 * Cloning a Schema triggers a deep clone of all related assets.
8233 public function __clone()
8235 foreach ($this->_tables AS $k => $table) {
8236 $this->_tables[$k] = clone $table;
8238 foreach ($this->_sequences AS $k => $sequence) {
8239 $this->_sequences[$k] = clone $sequence;
8245 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
8246 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
8247 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8248 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8249 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8250 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
8251 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
8252 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
8253 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8254 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
8255 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8257 * This software consists of voluntary contributions made by many individuals
8258 * and is licensed under the LGPL. For more information, see
8259 * <http://www.phpdoctrine.org>.
8262 namespace Doctrine\DBAL\Schema;
8267 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
8268 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
8269 * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
8270 * @author Juozas Kaziukenas <juozas@juokaz.com>
8271 * @version $Revision$
8274 class MsSqlSchemaManager extends AbstractSchemaManager
8280 protected function _getPortableTableColumnDefinition($tableColumn)
8282 $dbType = strtolower($tableColumn['TYPE_NAME']);
8284 $autoincrement = false;
8285 if (stripos($dbType, 'identity')) {
8286 $dbType = trim(str_ireplace('identity', '', $dbType));
8287 $autoincrement = true;
8291 $unsigned = $fixed = null;
8293 if (!isset($tableColumn['name'])) {
8294 $tableColumn['name'] = '';
8297 $default = $tableColumn['COLUMN_DEF'];
8299 while ($default != ($default2 = preg_replace("/^\((.*)\)$/", '$1', $default))) {
8300 $default = $default2;
8303 $length = (int) $tableColumn['LENGTH'];
8305 $type = $this->_platform->getDoctrineTypeMapping($dbType);
8308 if ($tableColumn['LENGTH'] == '1') {
8310 if (preg_match('/^(is|has)/', $tableColumn['name'])) {
8311 $type = array_reverse($type);
8324 // Unicode data requires 2 bytes per character
8325 $length = $length / 2;
8330 'length' => ($length == 0 || !in_array($type, array('text', 'string'))) ? null : $length,
8331 'unsigned' => (bool) $unsigned,
8332 'fixed' => (bool) $fixed,
8333 'default' => $default !== 'NULL' ? $default : null,
8334 'notnull' => (bool) ($tableColumn['IS_NULLABLE'] != 'YES'),
8335 'scale' => $tableColumn['SCALE'],
8336 'precision' => $tableColumn['PRECISION'],
8337 'autoincrement' => $autoincrement,
8340 return new Column($tableColumn['COLUMN_NAME'], \Doctrine\DBAL\Types\Type::getType($type), $options);
8346 protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null)
8349 foreach ($tableIndexRows AS $tableIndex) {
8350 $indexName = $keyName = $tableIndex['index_name'];
8351 if (strpos($tableIndex['index_description'], 'primary key') !== false) {
8352 $keyName = 'primary';
8354 $keyName = strtolower($keyName);
8356 $result[$keyName] = array(
8357 'name' => $indexName,
8358 'columns' => explode(', ', $tableIndex['index_keys']),
8359 'unique' => strpos($tableIndex['index_description'], 'unique') !== false,
8360 'primary' => strpos($tableIndex['index_description'], 'primary key') !== false,
8365 foreach ($result AS $indexKey => $data) {
8366 $indexes[$indexKey] = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']);
8375 public function _getPortableTableForeignKeyDefinition($tableForeignKey)
8377 return new ForeignKeyConstraint(
8378 (array) $tableForeignKey['ColumnName'],
8379 $tableForeignKey['ReferenceTableName'],
8380 (array) $tableForeignKey['ReferenceColumnName'],
8381 $tableForeignKey['ForeignKey'],
8383 'onUpdate' => str_replace('_', ' ', $tableForeignKey['update_referential_action_desc']),
8384 'onDelete' => str_replace('_', ' ', $tableForeignKey['delete_referential_action_desc']),
8392 protected function _getPortableTableDefinition($table)
8394 return $table['name'];
8400 protected function _getPortableDatabaseDefinition($database)
8402 return $database['name'];
8408 protected function _getPortableViewDefinition($view)
8411 return new View($view['name'], null);
8418 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
8419 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
8420 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8421 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8422 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8423 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
8424 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
8425 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
8426 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8427 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
8428 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8430 * This software consists of voluntary contributions made by many individuals
8431 * and is licensed under the LGPL. For more information, see
8432 * <http://www.doctrine-project.org>.
8435 namespace Doctrine\DBAL\Schema\Visitor;
8437 use Doctrine\DBAL\Platforms\AbstractPlatform,
8438 Doctrine\DBAL\Schema\Table,
8439 Doctrine\DBAL\Schema\Schema,
8440 Doctrine\DBAL\Schema\Column,
8441 Doctrine\DBAL\Schema\ForeignKeyConstraint,
8442 Doctrine\DBAL\Schema\Constraint,
8443 Doctrine\DBAL\Schema\Sequence,
8444 Doctrine\DBAL\Schema\Index;
8447 * Schema Visitor used for Validation or Generation purposes.
8449 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
8450 * @link www.doctrine-project.org
8452 * @version $Revision$
8453 * @author Benjamin Eberlei <kontakt@beberlei.de>
8458 * @param Schema $schema
8460 public function acceptSchema(Schema $schema);
8463 * @param Table $table
8465 public function acceptTable(Table $table);
8468 * @param Column $column
8470 public function acceptColumn(Table $table, Column $column);
8473 * @param Table $localTable
8474 * @param ForeignKeyConstraint $fkConstraint
8476 public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint);
8479 * @param Table $table
8480 * @param Index $index
8482 public function acceptIndex(Table $table, Index $index);
8485 * @param Sequence $sequence
8487 public function acceptSequence(Sequence $sequence);
8492 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
8493 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
8494 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8495 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8496 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8497 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
8498 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
8499 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
8500 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8501 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
8502 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8504 * This software consists of voluntary contributions made by many individuals
8505 * and is licensed under the LGPL. For more information, see
8506 * <http://www.doctrine-project.org>.
8509 namespace Doctrine\DBAL\Schema\Visitor;
8511 use Doctrine\DBAL\Platforms\AbstractPlatform,
8512 Doctrine\DBAL\Schema\Table,
8513 Doctrine\DBAL\Schema\Schema,
8514 Doctrine\DBAL\Schema\Column,
8515 Doctrine\DBAL\Schema\ForeignKeyConstraint,
8516 Doctrine\DBAL\Schema\Constraint,
8517 Doctrine\DBAL\Schema\Sequence,
8518 Doctrine\DBAL\Schema\Index;
8520 class CreateSchemaSqlCollector implements Visitor
8525 private $_createTableQueries = array();
8530 private $_createSequenceQueries = array();
8535 private $_createFkConstraintQueries = array();
8539 * @var \Doctrine\DBAL\Platforms\AbstractPlatform
8541 private $_platform = null;
8544 * @param AbstractPlatform $platform
8546 public function __construct(AbstractPlatform $platform)
8548 $this->_platform = $platform;
8552 * @param Schema $schema
8554 public function acceptSchema(Schema $schema)
8560 * Generate DDL Statements to create the accepted table with all its dependencies.
8562 * @param Table $table
8564 public function acceptTable(Table $table)
8566 $this->_createTableQueries = array_merge($this->_createTableQueries,
8567 $this->_platform->getCreateTableSQL($table)
8571 public function acceptColumn(Table $table, Column $column)
8577 * @param Table $localTable
8578 * @param ForeignKeyConstraint $fkConstraint
8580 public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint)
8582 // Append the foreign key constraints SQL
8583 if ($this->_platform->supportsForeignKeyConstraints()) {
8584 $this->_createFkConstraintQueries = array_merge($this->_createFkConstraintQueries,
8585 (array) $this->_platform->getCreateForeignKeySQL($fkConstraint, $localTable->getName())
8591 * @param Table $table
8592 * @param Index $index
8594 public function acceptIndex(Table $table, Index $index)
8600 * @param Sequence $sequence
8602 public function acceptSequence(Sequence $sequence)
8604 $this->_createSequenceQueries = array_merge(
8605 $this->_createSequenceQueries, (array)$this->_platform->getCreateSequenceSQL($sequence)
8612 public function resetQueries()
8614 $this->_createTableQueries = array();
8615 $this->_createSequenceQueries = array();
8616 $this->_createFkConstraintQueries = array();
8620 * Get all queries collected so far.
8624 public function getQueries()
8627 $this->_createTableQueries,
8628 $this->_createSequenceQueries,
8629 $this->_createFkConstraintQueries
8636 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
8637 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
8638 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8639 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8640 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8641 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
8642 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
8643 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
8644 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8645 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
8646 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8648 * This software consists of voluntary contributions made by many individuals
8649 * and is licensed under the LGPL. For more information, see
8650 * <http://www.doctrine-project.org>.
8653 namespace Doctrine\DBAL\Schema\Visitor;
8655 use Doctrine\DBAL\Platforms\AbstractPlatform,
8656 Doctrine\DBAL\Schema\Table,
8657 Doctrine\DBAL\Schema\Schema,
8658 Doctrine\DBAL\Schema\Column,
8659 Doctrine\DBAL\Schema\ForeignKeyConstraint,
8660 Doctrine\DBAL\Schema\Constraint,
8661 Doctrine\DBAL\Schema\Sequence,
8662 Doctrine\DBAL\Schema\Index;
8665 * Gather SQL statements that allow to completly drop the current schema.
8667 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
8668 * @link www.doctrine-project.org
8670 * @version $Revision$
8671 * @author Benjamin Eberlei <kontakt@beberlei.de>
8673 class DropSchemaSqlCollector implements Visitor
8678 private $_constraints = array();
8683 private $_sequences = array();
8688 private $_tables = array();
8692 * @var \Doctrine\DBAL\Platforms\AbstractPlatform
8694 private $_platform = null;
8697 * @param AbstractPlatform $platform
8699 public function __construct(AbstractPlatform $platform)
8701 $this->_platform = $platform;
8705 * @param Schema $schema
8707 public function acceptSchema(Schema $schema)
8713 * @param Table $table
8715 public function acceptTable(Table $table)
8717 $this->_tables[] = $this->_platform->getDropTableSQL($table->getName());
8721 * @param Column $column
8723 public function acceptColumn(Table $table, Column $column)
8729 * @param Table $localTable
8730 * @param ForeignKeyConstraint $fkConstraint
8732 public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint)
8734 if (strlen($fkConstraint->getName()) == 0) {
8735 throw SchemaException::namedForeignKeyRequired($localTable, $fkConstraint);
8738 $this->_constraints[] = $this->_platform->getDropForeignKeySQL($fkConstraint->getName(), $localTable->getName());
8742 * @param Table $table
8743 * @param Index $index
8745 public function acceptIndex(Table $table, Index $index)
8751 * @param Sequence $sequence
8753 public function acceptSequence(Sequence $sequence)
8755 $this->_sequences[] = $this->_platform->getDropSequenceSQL($sequence->getName());
8761 public function clearQueries()
8763 $this->_constraints = $this->_sequences = $this->_tables = array();
8769 public function getQueries()
8771 return array_merge($this->_constraints, $this->_tables, $this->_sequences);
8778 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
8779 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
8780 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8781 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8782 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8783 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
8784 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
8785 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
8786 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8787 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
8788 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8790 * This software consists of voluntary contributions made by many individuals
8791 * and is licensed under the LGPL. For more information, see
8792 * <http://www.doctrine-project.org>.
8795 namespace Doctrine\DBAL\Schema;
8797 use Doctrine\DBAL\Schema\Visitor\Visitor;
8799 class ForeignKeyConstraint extends AbstractAsset implements Constraint
8804 protected $_localTable;
8809 protected $_localColumnNames;
8814 protected $_foreignTableName;
8819 protected $_foreignColumnNames;
8824 protected $_cascade = '';
8829 protected $_options;
8833 * @param array $localColumnNames
8834 * @param string $foreignTableName
8835 * @param array $foreignColumnNames
8836 * @param string $cascade
8837 * @param string|null $name
8839 public function __construct(array $localColumnNames, $foreignTableName, array $foreignColumnNames, $name=null, array $options=array())
8841 $this->_setName($name);
8842 $this->_localColumnNames = $localColumnNames;
8843 $this->_foreignTableName = $foreignTableName;
8844 $this->_foreignColumnNames = $foreignColumnNames;
8845 $this->_options = $options;
8851 public function getLocalTableName()
8853 return $this->_localTable->getName();
8857 * @param Table $table
8859 public function setLocalTable(Table $table)
8861 $this->_localTable = $table;
8867 public function getLocalColumns()
8869 return $this->_localColumnNames;
8872 public function getColumns()
8874 return $this->_localColumnNames;
8880 public function getForeignTableName()
8882 return $this->_foreignTableName;
8888 public function getForeignColumns()
8890 return $this->_foreignColumnNames;
8893 public function hasOption($name)
8895 return isset($this->_options[$name]);
8898 public function getOption($name)
8900 return $this->_options[$name];
8904 * Foreign Key onUpdate status
8906 * @return string|null
8908 public function onUpdate()
8910 return $this->_onEvent('onUpdate');
8914 * Foreign Key onDelete status
8916 * @return string|null
8918 public function onDelete()
8920 return $this->_onEvent('onDelete');
8924 * @param string $event
8925 * @return string|null
8927 private function _onEvent($event)
8929 if (isset($this->_options[$event])) {
8930 $onEvent = strtoupper($this->_options[$event]);
8931 if (!in_array($onEvent, array('NO ACTION', 'RESTRICT'))) {
8942 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
8943 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
8944 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8945 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8946 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8947 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
8948 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
8949 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
8950 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8951 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
8952 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8954 * This software consists of voluntary contributions made by many individuals
8955 * and is licensed under the LGPL. For more information, see
8956 * <http://www.doctrine-project.org>.
8959 namespace Doctrine\DBAL\Schema;
8961 use Doctrine\DBAL\Types\Type;
8962 use Doctrine\DBAL\Schema\Visitor\Visitor;
8963 use Doctrine\DBAL\DBALException;
8966 * Object Representation of a table
8968 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
8969 * @link www.doctrine-project.org
8971 * @version $Revision$
8972 * @author Benjamin Eberlei <kontakt@beberlei.de>
8974 class Table extends AbstractAsset
8979 protected $_name = null;
8984 protected $_columns = array();
8989 protected $_indexes = array();
8994 protected $_primaryKeyName = false;
8999 protected $_fkConstraints = array();
9004 protected $_options = array();
9009 protected $_schemaConfig = null;
9013 * @param string $tableName
9014 * @param array $columns
9015 * @param array $indexes
9016 * @param array $fkConstraints
9017 * @param int $idGeneratorType
9018 * @param array $options
9020 public function __construct($tableName, array $columns=array(), array $indexes=array(), array $fkConstraints=array(), $idGeneratorType = 0, array $options=array())
9022 if (strlen($tableName) == 0) {
9023 throw DBALException::invalidTableName($tableName);
9026 $this->_setName($tableName);
9027 $this->_idGeneratorType = $idGeneratorType;
9029 foreach ($columns AS $column) {
9030 $this->_addColumn($column);
9033 foreach ($indexes AS $idx) {
9034 $this->_addIndex($idx);
9037 foreach ($fkConstraints AS $constraint) {
9038 $this->_addForeignKeyConstraint($constraint);
9041 $this->_options = $options;
9045 * @param SchemaConfig $schemaConfig
9047 public function setSchemaConfig(SchemaConfig $schemaConfig)
9049 $this->_schemaConfig = $schemaConfig;
9055 protected function _getMaxIdentifierLength()
9057 if ($this->_schemaConfig instanceof SchemaConfig) {
9058 return $this->_schemaConfig->getMaxIdentifierLength();
9067 * @param array $columns
9068 * @param string $indexName
9071 public function setPrimaryKey(array $columns, $indexName = false)
9073 $primaryKey = $this->_createIndex($columns, $indexName ?: "primary", true, true);
9075 foreach ($columns AS $columnName) {
9076 $column = $this->getColumn($columnName);
9077 $column->setNotnull(true);
9084 * @param array $columnNames
9085 * @param string $indexName
9088 public function addIndex(array $columnNames, $indexName = null)
9090 if($indexName == null) {
9091 $indexName = $this->_generateIdentifierName(
9092 array_merge(array($this->getName()), $columnNames), "idx", $this->_getMaxIdentifierLength()
9096 return $this->_createIndex($columnNames, $indexName, false, false);
9101 * @param array $columnNames
9102 * @param string $indexName
9105 public function addUniqueIndex(array $columnNames, $indexName = null)
9107 if ($indexName == null) {
9108 $indexName = $this->_generateIdentifierName(
9109 array_merge(array($this->getName()), $columnNames), "uniq", $this->_getMaxIdentifierLength()
9113 return $this->_createIndex($columnNames, $indexName, true, false);
9117 * Check if an index begins in the order of the given columns.
9119 * @param array $columnsNames
9122 public function columnsAreIndexed(array $columnsNames)
9124 foreach ($this->getIndexes() AS $index) {
9125 /* @var $index Index */
9126 if ($index->spansColumns($columnsNames)) {
9135 * @param array $columnNames
9136 * @param string $indexName
9137 * @param bool $isUnique
9138 * @param bool $isPrimary
9141 private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary)
9143 if (preg_match('(([^a-zA-Z0-9_]+))', $indexName)) {
9144 throw SchemaException::indexNameInvalid($indexName);
9147 foreach ($columnNames AS $columnName => $indexColOptions) {
9148 if (is_numeric($columnName) && is_string($indexColOptions)) {
9149 $columnName = $indexColOptions;
9152 if ( ! $this->hasColumn($columnName)) {
9153 throw SchemaException::columnDoesNotExist($columnName, $this->_name);
9156 $this->_addIndex(new Index($indexName, $columnNames, $isUnique, $isPrimary));
9161 * @param string $columnName
9162 * @param string $columnType
9163 * @param array $options
9166 public function addColumn($columnName, $typeName, array $options=array())
9168 $column = new Column($columnName, Type::getType($typeName), $options);
9170 $this->_addColumn($column);
9177 * @param string $oldColumnName
9178 * @param string $newColumnName
9181 public function renameColumn($oldColumnName, $newColumnName)
9183 $column = $this->getColumn($oldColumnName);
9184 $this->dropColumn($oldColumnName);
9186 $column->_setName($newColumnName);
9191 * Change Column Details
9193 * @param string $columnName
9194 * @param array $options
9197 public function changeColumn($columnName, array $options)
9199 $column = $this->getColumn($columnName);
9200 $column->setOptions($options);
9205 * Drop Column from Table
9207 * @param string $columnName
9210 public function dropColumn($columnName)
9212 $columnName = strtolower($columnName);
9213 $column = $this->getColumn($columnName);
9214 unset($this->_columns[$columnName]);
9220 * Add a foreign key constraint
9222 * Name is inferred from the local columns
9224 * @param Table $foreignTable
9225 * @param array $localColumns
9226 * @param array $foreignColumns
9227 * @param array $options
9230 public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array())
9232 $name = $this->_generateIdentifierName(array_merge((array)$this->getName(), $localColumnNames), "fk", $this->_getMaxIdentifierLength());
9233 return $this->addNamedForeignKeyConstraint($name, $foreignTable, $localColumnNames, $foreignColumnNames, $options);
9237 * Add a foreign key constraint
9239 * Name is to be generated by the database itsself.
9241 * @param Table $foreignTable
9242 * @param array $localColumns
9243 * @param array $foreignColumns
9244 * @param array $options
9247 public function addUnnamedForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array())
9249 return $this->addNamedForeignKeyConstraint(null, $foreignTable, $localColumnNames, $foreignColumnNames, $options);
9253 * Add a foreign key constraint with a given name
9255 * @param string $name
9256 * @param Table $foreignTable
9257 * @param array $localColumns
9258 * @param array $foreignColumns
9259 * @param array $options
9262 public function addNamedForeignKeyConstraint($name, $foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array())
9264 if ($foreignTable instanceof Table) {
9265 $foreignTableName = $foreignTable->getName();
9267 foreach ($foreignColumnNames AS $columnName) {
9268 if ( ! $foreignTable->hasColumn($columnName)) {
9269 throw SchemaException::columnDoesNotExist($columnName, $foreignTable->getName());
9273 $foreignTableName = $foreignTable;
9276 foreach ($localColumnNames AS $columnName) {
9277 if ( ! $this->hasColumn($columnName)) {
9278 throw SchemaException::columnDoesNotExist($columnName, $this->_name);
9282 $constraint = new ForeignKeyConstraint(
9283 $localColumnNames, $foreignTableName, $foreignColumnNames, $name, $options
9285 $this->_addForeignKeyConstraint($constraint);
9291 * @param string $name
9292 * @param string $value
9295 public function addOption($name, $value)
9297 $this->_options[$name] = $value;
9302 * @param Column $column
9304 protected function _addColumn(Column $column)
9306 $columnName = $column->getName();
9307 $columnName = strtolower($columnName);
9309 if (isset($this->_columns[$columnName])) {
9310 throw SchemaException::columnAlreadyExists($this->getName(), $columnName);
9313 $this->_columns[$columnName] = $column;
9317 * Add index to table
9319 * @param Index $indexCandidate
9322 protected function _addIndex(Index $indexCandidate)
9324 // check for duplicates
9325 foreach ($this->_indexes AS $existingIndex) {
9326 if ($indexCandidate->isFullfilledBy($existingIndex)) {
9331 $indexName = $indexCandidate->getName();
9332 $indexName = strtolower($indexName);
9334 if (isset($this->_indexes[$indexName]) || ($this->_primaryKeyName != false && $indexCandidate->isPrimary())) {
9335 throw SchemaException::indexAlreadyExists($indexName, $this->_name);
9338 // remove overruled indexes
9339 foreach ($this->_indexes AS $idxKey => $existingIndex) {
9340 if ($indexCandidate->overrules($existingIndex)) {
9341 unset($this->_indexes[$idxKey]);
9345 if ($indexCandidate->isPrimary()) {
9346 $this->_primaryKeyName = $indexName;
9349 $this->_indexes[$indexName] = $indexCandidate;
9354 * @param ForeignKeyConstraint $constraint
9356 protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint)
9358 $constraint->setLocalTable($this);
9360 if(strlen($constraint->getName())) {
9361 $name = $constraint->getName();
9363 $name = $this->_generateIdentifierName(
9364 array_merge((array)$this->getName(), $constraint->getLocalColumns()), "fk", $this->_getMaxIdentifierLength()
9367 $name = strtolower($name);
9369 $this->_fkConstraints[$name] = $constraint;
9370 // add an explicit index on the foreign key columns. If there is already an index that fullfils this requirements drop the request.
9371 // In the case of __construct calling this method during hydration from schema-details all the explicitly added indexes
9372 // lead to duplicates. This creates compuation overhead in this case, however no duplicate indexes are ever added (based on columns).
9373 $this->addIndex($constraint->getColumns());
9377 * Does Table have a foreign key constraint with the given name?
9379 * @param string $constraintName
9382 public function hasForeignKey($constraintName)
9384 $constraintName = strtolower($constraintName);
9385 return isset($this->_fkConstraints[$constraintName]);
9389 * @param string $constraintName
9390 * @return ForeignKeyConstraint
9392 public function getForeignKey($constraintName)
9394 $constraintName = strtolower($constraintName);
9395 if(!$this->hasForeignKey($constraintName)) {
9396 throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name);
9399 return $this->_fkConstraints[$constraintName];
9405 public function getColumns()
9407 $columns = $this->_columns;
9412 if ($this->hasIndex($this->_primaryKeyName)) {
9413 $pkCols = $this->getPrimaryKey()->getColumns();
9415 foreach ($this->getForeignKeys() AS $fk) {
9416 /* @var $fk ForeignKeyConstraint */
9417 $fkCols = array_merge($fkCols, $fk->getColumns());
9419 $colNames = array_unique(array_merge($pkCols, $fkCols, array_keys($columns)));
9421 uksort($columns, function($a, $b) use($colNames) {
9422 return (array_search($a, $colNames) >= array_search($b, $colNames));
9429 * Does this table have a column with the given name?
9431 * @param string $columnName
9434 public function hasColumn($columnName)
9436 $columnName = strtolower($columnName);
9437 return isset($this->_columns[$columnName]);
9441 * Get a column instance
9443 * @param string $columnName
9446 public function getColumn($columnName)
9448 $columnName = strtolower($columnName);
9449 if (!$this->hasColumn($columnName)) {
9450 throw SchemaException::columnDoesNotExist($columnName, $this->_name);
9453 return $this->_columns[$columnName];
9459 public function getPrimaryKey()
9461 return $this->getIndex($this->_primaryKeyName);
9465 * @param string $indexName
9468 public function hasIndex($indexName)
9470 $indexName = strtolower($indexName);
9471 return (isset($this->_indexes[$indexName]));
9475 * @param string $indexName
9478 public function getIndex($indexName)
9480 $indexName = strtolower($indexName);
9481 if (!$this->hasIndex($indexName)) {
9482 throw SchemaException::indexDoesNotExist($indexName, $this->_name);
9484 return $this->_indexes[$indexName];
9490 public function getIndexes()
9492 return $this->_indexes;
9500 public function getForeignKeys()
9502 return $this->_fkConstraints;
9505 public function hasOption($name)
9507 return isset($this->_options[$name]);
9510 public function getOption($name)
9512 return $this->_options[$name];
9515 public function getOptions()
9517 return $this->_options;
9521 * @param Visitor $visitor
9523 public function visit(Visitor $visitor)
9525 $visitor->acceptTable($this);
9527 foreach ($this->getColumns() AS $column) {
9528 $visitor->acceptColumn($this, $column);
9531 foreach ($this->getIndexes() AS $index) {
9532 $visitor->acceptIndex($this, $index);
9535 foreach ($this->getForeignKeys() AS $constraint) {
9536 $visitor->acceptForeignKey($this, $constraint);
9541 * Clone of a Table triggers a deep clone of all affected assets
9543 public function __clone()
9545 foreach ($this->_columns AS $k => $column) {
9546 $this->_columns[$k] = clone $column;
9548 foreach ($this->_indexes AS $k => $index) {
9549 $this->_indexes[$k] = clone $index;
9551 foreach ($this->_fkConstraints AS $k => $fk) {
9552 $this->_fkConstraints[$k] = clone $fk;
9553 $this->_fkConstraints[$k]->setLocalTable($this);
9560 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
9561 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9562 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
9563 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9564 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9565 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9566 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
9567 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
9568 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9569 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
9570 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9572 * This software consists of voluntary contributions made by many individuals
9573 * and is licensed under the LGPL. For more information, see
9574 * <http://www.doctrine-project.org>.
9577 namespace Doctrine\DBAL\Schema;
9582 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
9583 * @link www.doctrine-project.org
9584 * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
9585 * @license http://ez.no/licenses/new_bsd New BSD License
9587 * @version $Revision$
9588 * @author Benjamin Eberlei <kontakt@beberlei.de>
9595 public $name = null;
9600 public $newName = false;
9605 * @var array(string=>Column)
9607 public $addedColumns;
9610 * All changed fields
9612 * @var array(string=>Column)
9614 public $changedColumns = array();
9617 * All removed fields
9619 * @var array(string=>bool)
9621 public $removedColumns = array();
9624 * Columns that are only renamed from key to column instance name.
9626 * @var array(string=>Column)
9628 public $renamedColumns = array();
9633 * @var array(string=>Index)
9635 public $addedIndexes = array();
9638 * All changed indexes
9640 * @var array(string=>Index)
9642 public $changedIndexes = array();
9645 * All removed indexes
9647 * @var array(string=>bool)
9649 public $removedIndexes = array();
9652 * All added foreign key definitions
9656 public $addedForeignKeys = array();
9659 * All changed foreign keys
9663 public $changedForeignKeys = array();
9666 * All removed foreign keys
9670 public $removedForeignKeys = array();
9673 * Constructs an TableDiff object.
9675 * @param array(string=>Column) $addedColumns
9676 * @param array(string=>Column) $changedColumns
9677 * @param array(string=>bool) $removedColumns
9678 * @param array(string=>Index) $addedIndexes
9679 * @param array(string=>Index) $changedIndexes
9680 * @param array(string=>bool) $removedIndexes
9682 public function __construct($tableName, $addedColumns = array(),
9683 $changedColumns = array(), $removedColumns = array(), $addedIndexes = array(),
9684 $changedIndexes = array(), $removedIndexes = array())
9686 $this->name = $tableName;
9687 $this->addedColumns = $addedColumns;
9688 $this->changedColumns = $changedColumns;
9689 $this->removedColumns = $removedColumns;
9690 $this->addedIndexes = $addedIndexes;
9691 $this->changedIndexes = $changedIndexes;
9692 $this->removedIndexes = $removedIndexes;
9698 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
9699 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9700 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
9701 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9702 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9703 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9704 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
9705 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
9706 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9707 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
9708 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9710 * This software consists of voluntary contributions made by many individuals
9711 * and is licensed under the LGPL. For more information, see
9712 * <http://www.phpdoctrine.org>.
9715 namespace Doctrine\DBAL\Schema;
9718 * Oracle Schema Manager
9720 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
9721 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
9722 * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
9723 * @author Benjamin Eberlei <kontakt@beberlei.de>
9724 * @version $Revision$
9727 class OracleSchemaManager extends AbstractSchemaManager
9729 protected function _getPortableViewDefinition($view)
9731 $view = \array_change_key_case($view, CASE_LOWER);
9733 return new View($view['view_name'], $view['text']);
9736 protected function _getPortableUserDefinition($user)
9738 $user = \array_change_key_case($user, CASE_LOWER);
9741 'user' => $user['username'],
9745 protected function _getPortableTableDefinition($table)
9747 $table = \array_change_key_case($table, CASE_LOWER);
9749 return $table['table_name'];
9753 * @license New BSD License
9754 * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
9755 * @param array $tableIndexes
9756 * @param string $tableName
9759 protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
9761 $indexBuffer = array();
9762 foreach ( $tableIndexes as $tableIndex ) {
9763 $tableIndex = \array_change_key_case($tableIndex, CASE_LOWER);
9765 $keyName = strtolower($tableIndex['name']);
9767 if ( strtolower($tableIndex['is_primary']) == "p" ) {
9768 $keyName = 'primary';
9769 $buffer['primary'] = true;
9770 $buffer['non_unique'] = false;
9772 $buffer['primary'] = false;
9773 $buffer['non_unique'] = ( $tableIndex['is_unique'] == 0 ) ? true : false;
9775 $buffer['key_name'] = $keyName;
9776 $buffer['column_name'] = $tableIndex['column_name'];
9777 $indexBuffer[] = $buffer;
9779 return parent::_getPortableTableIndexesList($indexBuffer, $tableName);
9782 protected function _getPortableTableColumnDefinition($tableColumn)
9784 $tableColumn = \array_change_key_case($tableColumn, CASE_LOWER);
9786 $dbType = strtolower($tableColumn['data_type']);
9787 if(strpos($dbType, "timestamp(") === 0) {
9788 if (strpos($dbType, "WITH TIME ZONE")) {
9789 $dbType = "timestamptz";
9791 $dbType = "timestamp";
9796 $length = $unsigned = $fixed = null;
9797 if ( ! empty($tableColumn['data_length'])) {
9798 $length = $tableColumn['data_length'];
9801 if ( ! isset($tableColumn['column_name'])) {
9802 $tableColumn['column_name'] = '';
9805 if (stripos($tableColumn['data_default'], 'NULL') !== null) {
9806 $tableColumn['data_default'] = null;
9812 $type = $this->_platform->getDoctrineTypeMapping($dbType);
9815 // @todo this sucks for the mapping stuff, is this deterministic maybe?
9816 if($tableColumn['data_scale'] > 0) {
9817 $precision = $tableColumn['data_precision'];
9818 $scale = $tableColumn['data_scale'];
9819 if ($precision == 0 && $scale == 1) {
9828 case 'binary_integer':
9845 $precision = $tableColumn['data_precision'];
9846 $scale = $tableColumn['data_scale'];
9866 'notnull' => (bool) ($tableColumn['nullable'] === 'N'),
9867 'fixed' => (bool) $fixed,
9868 'unsigned' => (bool) $unsigned,
9869 'default' => $tableColumn['data_default'],
9870 'length' => $length,
9871 'precision' => $precision,
9873 'platformDetails' => array(),
9876 return new Column($tableColumn['column_name'], \Doctrine\DBAL\Types\Type::getType($type), $options);
9879 protected function _getPortableTableForeignKeysList($tableForeignKeys)
9882 foreach ($tableForeignKeys as $key => $value) {
9883 $value = \array_change_key_case($value, CASE_LOWER);
9884 if (!isset($list[$value['constraint_name']])) {
9885 if ($value['delete_rule'] == "NO ACTION") {
9886 $value['delete_rule'] = null;
9889 $list[$value['constraint_name']] = array(
9890 'name' => $value['constraint_name'],
9892 'foreign' => array(),
9893 'foreignTable' => $value['references_table'],
9894 'onDelete' => $value['delete_rule'],
9897 $list[$value['constraint_name']]['local'][$value['position']] = $value['local_column'];
9898 $list[$value['constraint_name']]['foreign'][$value['position']] = $value['foreign_column'];
9902 foreach($list AS $constraint) {
9903 $result[] = new ForeignKeyConstraint(
9904 array_values($constraint['local']), $constraint['foreignTable'],
9905 array_values($constraint['foreign']), $constraint['name'],
9906 array('onDelete' => $constraint['onDelete'])
9913 protected function _getPortableSequenceDefinition($sequence)
9915 $sequence = \array_change_key_case($sequence, CASE_LOWER);
9916 return new Sequence($sequence['sequence_name'], $sequence['increment_by'], $sequence['min_value']);
9919 protected function _getPortableFunctionDefinition($function)
9921 $function = \array_change_key_case($function, CASE_LOWER);
9922 return $function['name'];
9925 protected function _getPortableDatabaseDefinition($database)
9927 $database = \array_change_key_case($database, CASE_LOWER);
9928 return $database['username'];
9931 public function createDatabase($database = null)
9933 if (is_null($database)) {
9934 $database = $this->_conn->getDatabase();
9937 $params = $this->_conn->getParams();
9938 $username = $database;
9939 $password = $params['password'];
9941 $query = 'CREATE USER ' . $username . ' IDENTIFIED BY ' . $password;
9942 $result = $this->_conn->executeUpdate($query);
9944 $query = 'GRANT CREATE SESSION, CREATE TABLE, UNLIMITED TABLESPACE, CREATE SEQUENCE, CREATE TRIGGER TO ' . $username;
9945 $result = $this->_conn->executeUpdate($query);
9950 public function dropAutoincrement($table)
9952 $sql = $this->_platform->getDropAutoincrementSql($table);
9953 foreach ($sql as $query) {
9954 $this->_conn->executeUpdate($query);
9960 public function dropTable($name)
9962 $this->dropAutoincrement($name);
9964 return parent::dropTable($name);
9970 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
9971 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9972 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
9973 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9974 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9975 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9976 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
9977 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
9978 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9979 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
9980 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9982 * This software consists of voluntary contributions made by many individuals
9983 * and is licensed under the LGPL. For more information, see
9984 * <http://www.doctrine-project.org>.
9987 namespace Doctrine\DBAL\Schema;
9989 use Doctrine\DBAL\Schema\Visitor\Visitor;
9992 * Sequence Structure
9994 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
9995 * @link www.doctrine-project.org
9997 * @version $Revision$
9998 * @author Benjamin Eberlei <kontakt@beberlei.de>
10000 class Sequence extends AbstractAsset
10005 protected $_allocationSize = 1;
10010 protected $_initialValue = 1;
10014 * @param string $name
10015 * @param int $allocationSize
10016 * @param int $initialValue
10018 public function __construct($name, $allocationSize=1, $initialValue=1)
10020 $this->_setName($name);
10021 $this->_allocationSize = (is_numeric($allocationSize))?$allocationSize:1;
10022 $this->_initialValue = (is_numeric($initialValue))?$initialValue:1;
10025 public function getAllocationSize()
10027 return $this->_allocationSize;
10030 public function getInitialValue()
10032 return $this->_initialValue;
10036 * @param Visitor $visitor
10038 public function visit(Visitor $visitor)
10040 $visitor->acceptSequence($this);
10047 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10048 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10049 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
10050 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
10051 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10052 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10053 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10054 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
10055 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10056 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
10057 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10059 * This software consists of voluntary contributions made by many individuals
10060 * and is licensed under the LGPL. For more information, see
10061 * <http://www.doctrine-project.org>.
10064 namespace Doctrine\DBAL\Schema;
10067 * Represent the change of a column
10069 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
10070 * @link www.doctrine-project.org
10072 * @version $Revision$
10073 * @author Benjamin Eberlei <kontakt@beberlei.de>
10077 public $oldColumnName;
10087 public $changedProperties = array();
10089 public function __construct($oldColumnName, Column $column, array $changedProperties = array())
10091 $this->oldColumnName = $oldColumnName;
10092 $this->column = $column;
10093 $this->changedProperties = $changedProperties;
10096 public function hasChanged($propertyName)
10098 return in_array($propertyName, $this->changedProperties);
10102 namespace Doctrine\DBAL\Schema;
10104 class SchemaException extends \Doctrine\DBAL\DBALException
10106 const TABLE_DOESNT_EXIST = 10;
10107 const TABLE_ALREADY_EXISTS = 20;
10108 const COLUMN_DOESNT_EXIST = 30;
10109 const COLUMN_ALREADY_EXISTS = 40;
10110 const INDEX_DOESNT_EXIST = 50;
10111 const INDEX_ALREADY_EXISTS = 60;
10112 const SEQUENCE_DOENST_EXIST = 70;
10113 const SEQUENCE_ALREADY_EXISTS = 80;
10114 const INDEX_INVALID_NAME = 90;
10115 const FOREIGNKEY_DOESNT_EXIST = 100;
10118 * @param string $tableName
10119 * @return SchemaException
10121 static public function tableDoesNotExist($tableName)
10123 return new self("There is no table with name '".$tableName."' in the schema.", self::TABLE_DOESNT_EXIST);
10127 * @param string $indexName
10128 * @return SchemaException
10130 static public function indexNameInvalid($indexName)
10132 return new self("Invalid index-name $indexName given, has to be [a-zA-Z0-9_]", self::INDEX_INVALID_NAME);
10136 * @param string $indexName
10137 * @return SchemaException
10139 static public function indexDoesNotExist($indexName, $table)
10141 return new self("Index '$indexName' does not exist on table '$table'.", self::INDEX_DOESNT_EXIST);
10145 * @param string $indexName
10146 * @return SchemaException
10148 static public function indexAlreadyExists($indexName, $table)
10150 return new self("An index with name '$indexName' was already defined on table '$table'.", self::INDEX_ALREADY_EXISTS);
10154 * @param string $columnName
10155 * @return SchemaException
10157 static public function columnDoesNotExist($columnName, $table)
10159 return new self("There is no column with name '$columnName' on table '$table'.", self::COLUMN_DOESNT_EXIST);
10164 * @param string $tableName
10165 * @return SchemaException
10167 static public function tableAlreadyExists($tableName)
10169 return new self("The table with name '".$tableName."' already exists.", self::TABLE_ALREADY_EXISTS);
10174 * @param string $tableName
10175 * @param string $columnName
10176 * @return SchemaException
10178 static public function columnAlreadyExists($tableName, $columnName)
10181 "The column '".$columnName."' on table '".$tableName."' already exists.", self::COLUMN_ALREADY_EXISTS
10186 * @param string $sequenceName
10187 * @return SchemaException
10189 static public function sequenceAlreadyExists($sequenceName)
10191 return new self("The sequence '".$sequenceName."' already exists.", self::SEQUENCE_ALREADY_EXISTS);
10195 * @param string $sequenceName
10196 * @return SchemaException
10198 static public function sequenceDoesNotExist($sequenceName)
10200 return new self("There exists no sequence with the name '".$sequenceName."'.", self::SEQUENCE_DOENST_EXIST);
10204 * @param string $fkName
10205 * @return SchemaException
10207 static public function foreignKeyDoesNotExist($fkName, $table)
10209 return new self("There exists no foreign key with the name '$fkName' on table '$table'.", self::FOREIGNKEY_DOESNT_EXIST);
10212 static public function namedForeignKeyRequired(Table $localTable, ForeignKeyConstraint $foreignKey)
10215 "The performed schema operation on ".$localTable->getName()." requires a named foreign key, ".
10216 "but the given foreign key from (".implode(", ", $foreignKey->getColumns()).") onto foreign table ".
10217 "'".$foreignKey->getForeignTableName()."' (".implode(", ", $foreignKey->getForeignColumns()).") is currently ".
10222 static public function alterTableChangeNotSupported($changeName) {
10223 return new self ("Alter table change not supported, given '$changeName'");
10229 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10230 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10231 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
10232 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
10233 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10234 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10235 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10236 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
10237 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10238 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
10239 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10241 * This software consists of voluntary contributions made by many individuals
10242 * and is licensed under the LGPL. For more information, see
10243 * <http://www.doctrine-project.org>.
10246 namespace Doctrine\DBAL;
10249 * Contains all DBAL LockModes
10251 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
10252 * @link www.doctrine-project.com
10254 * @version $Revision$
10255 * @author Benjamin Eberlei <kontakt@beberlei.de>
10256 * @author Roman Borschel <roman@code-factory.org>
10261 const OPTIMISTIC = 1;
10262 const PESSIMISTIC_READ = 2;
10263 const PESSIMISTIC_WRITE = 4;
10265 final private function __construct() { }
10268 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10269 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10270 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
10271 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
10272 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10273 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10274 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10275 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
10276 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10277 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
10278 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10280 * This software consists of voluntary contributions made by many individuals
10281 * and is licensed under the LGPL. For more information, see
10282 * <http://www.doctrine-project.org>.
10285 namespace Doctrine\DBAL;
10288 * Driver interface.
10289 * Interface that all DBAL drivers must implement.
10296 * Attempts to create a connection with the database.
10298 * @param array $params All connection parameters passed by the user.
10299 * @param string $username The username to use when connecting.
10300 * @param string $password The password to use when connecting.
10301 * @param array $driverOptions The driver options to use when connecting.
10302 * @return Doctrine\DBAL\Driver\Connection The database connection.
10304 public function connect(array $params, $username = null, $password = null, array $driverOptions = array());
10307 * Gets the DatabasePlatform instance that provides all the metadata about
10308 * the platform this driver connects to.
10310 * @return Doctrine\DBAL\Platforms\AbstractPlatform The database platform.
10312 public function getDatabasePlatform();
10315 * Gets the SchemaManager that can be used to inspect and change the underlying
10316 * database schema of the platform this driver connects to.
10318 * @param Doctrine\DBAL\Connection $conn
10319 * @return Doctrine\DBAL\SchemaManager
10321 public function getSchemaManager(Connection $conn);
10324 * Gets the name of the driver.
10326 * @return string The name of the driver.
10328 public function getName();
10331 * Get the name of the database connected to for this driver.
10333 * @param Doctrine\DBAL\Connection $conn
10334 * @return string $database
10336 public function getDatabase(Connection $conn);
10339 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10340 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10341 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
10342 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
10343 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10344 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10345 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10346 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
10347 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10348 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
10349 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10351 * This software consists of voluntary contributions made by many individuals
10352 * and is licensed under the LGPL. For more information, see
10353 * <http://www.doctrine-project.org>.
10356 namespace Doctrine\DBAL\Platforms;
10358 use Doctrine\DBAL\Schema\TableDiff,
10359 Doctrine\DBAL\Schema\Table;
10362 * PostgreSqlPlatform.
10365 * @author Roman Borschel <roman@code-factory.org>
10366 * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
10367 * @author Benjamin Eberlei <kontakt@beberlei.de>
10368 * @todo Rename: PostgreSQLPlatform
10370 class PostgreSqlPlatform extends AbstractPlatform
10373 * Returns part of a string.
10375 * Note: Not SQL92, but common functionality.
10377 * @param string $value the target $value the string or the string column.
10378 * @param int $from extract from this characeter.
10379 * @param int $len extract this amount of characters.
10380 * @return string sql that extracts part of a string.
10383 public function getSubstringExpression($value, $from, $len = null)
10385 if ($len === null) {
10386 return 'SUBSTR(' . $value . ', ' . $from . ')';
10388 return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
10393 * Returns the SQL string to return the current system date and time.
10397 public function getNowExpression()
10399 return 'LOCALTIMESTAMP(0)';
10405 * @return string the regular expression operator
10408 public function getRegexpExpression()
10410 return 'SIMILAR TO';
10414 * returns the position of the first occurrence of substring $substr in string $str
10416 * @param string $substr literal string to find
10417 * @param string $str literal string
10418 * @param int $pos position to start at, beginning of string by default
10421 public function getLocateExpression($str, $substr, $startPos = false)
10423 if ($startPos !== false) {
10424 $str = $this->getSubstringExpression($str, $startPos);
10425 return 'CASE WHEN (POSITION('.$substr.' IN '.$str.') = 0) THEN 0 ELSE (POSITION('.$substr.' IN '.$str.') + '.($startPos-1).') END';
10427 return 'POSITION('.$substr.' IN '.$str.')';
10432 * parses a literal boolean value and returns
10433 * proper sql equivalent
10435 * @param string $value boolean value to be parsed
10436 * @return string parsed boolean value
10438 /*public function parseBoolean($value)
10444 * Whether the platform supports sequences.
10445 * Postgres has native support for sequences.
10449 public function supportsSequences()
10455 * Whether the platform supports database schemas.
10459 public function supportsSchemas()
10465 * Whether the platform supports identity columns.
10466 * Postgres supports these through the SERIAL keyword.
10470 public function supportsIdentityColumns()
10476 * Whether the platform prefers sequences for ID generation.
10480 public function prefersSequences()
10485 public function getListDatabasesSQL()
10487 return 'SELECT datname FROM pg_database';
10490 public function getListSequencesSQL($database)
10496 WHERE relkind = 'S' AND relnamespace IN
10497 (SELECT oid FROM pg_namespace
10498 WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema')";
10501 public function getListTablesSQL()
10504 c.relname AS table_name
10505 FROM pg_class c, pg_user u
10506 WHERE c.relowner = u.usesysid
10507 AND c.relkind = 'r'
10508 AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname)
10509 AND c.relname !~ '^(pg_|sql_)'
10511 SELECT c.relname AS table_name
10513 WHERE c.relkind = 'r'
10514 AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname)
10515 AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner)
10516 AND c.relname !~ '^pg_'";
10519 public function getListViewsSQL($database)
10521 return 'SELECT viewname, definition FROM pg_views';
10524 public function getListTableForeignKeysSQL($table, $database = null)
10526 return "SELECT r.conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef
10527 FROM pg_catalog.pg_constraint r
10531 FROM pg_catalog.pg_class c
10532 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
10533 WHERE c.relname = '" . $table . "' AND pg_catalog.pg_table_is_visible(c.oid)
10535 AND r.contype = 'f'";
10538 public function getCreateViewSQL($name, $sql)
10540 return 'CREATE VIEW ' . $name . ' AS ' . $sql;
10543 public function getDropViewSQL($name)
10545 return 'DROP VIEW '. $name;
10548 public function getListTableConstraintsSQL($table)
10556 FROM pg_index, pg_class
10557 WHERE pg_class.relname = '$table'
10558 AND pg_class.oid = pg_index.indrelid
10559 AND (indisunique = 't' OR indisprimary = 't')
10564 * @license New BSD License
10565 * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
10566 * @param string $table
10569 public function getListTableIndexesSQL($table)
10571 return "SELECT relname, pg_index.indisunique, pg_index.indisprimary,
10572 pg_index.indkey, pg_index.indrelid
10573 FROM pg_class, pg_index
10576 FROM pg_index, pg_class
10577 WHERE pg_class.relname='$table' AND pg_class.oid=pg_index.indrelid
10578 ) AND pg_index.indexrelid = oid";
10581 public function getListTableColumnsSQL($table)
10585 a.attname AS field,
10587 format_type(a.atttypid, a.atttypmod) AS complete_type,
10588 (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type,
10589 (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM pg_catalog.pg_type t2
10590 WHERE t2.typtype = 'd' AND t2.typname = format_type(a.atttypid, a.atttypmod)) AS domain_complete_type,
10591 a.attnotnull AS isnotnull,
10594 WHERE c.oid = pg_index.indrelid
10595 AND pg_index.indkey[0] = a.attnum
10596 AND pg_index.indisprimary = 't'
10598 (SELECT pg_attrdef.adsrc
10600 WHERE c.oid = pg_attrdef.adrelid
10601 AND pg_attrdef.adnum=a.attnum
10603 FROM pg_attribute a, pg_class c, pg_type t
10604 WHERE c.relname = '$table'
10606 AND a.attrelid = c.oid
10607 AND a.atttypid = t.oid
10608 ORDER BY a.attnum";
10612 * create a new database
10614 * @param string $name name of the database that should be created
10615 * @throws PDOException
10619 public function getCreateDatabaseSQL($name)
10621 return 'CREATE DATABASE ' . $name;
10625 * drop an existing database
10627 * @param string $name name of the database that should be dropped
10628 * @throws PDOException
10631 public function getDropDatabaseSQL($name)
10633 return 'DROP DATABASE ' . $name;
10637 * Return the FOREIGN KEY query section dealing with non-standard options
10638 * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
10640 * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey foreign key definition
10644 public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey)
10647 if ($foreignKey->hasOption('match')) {
10648 $query .= ' MATCH ' . $foreignKey->getOption('match');
10650 $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
10651 if ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) {
10652 $query .= ' DEFERRABLE';
10654 $query .= ' NOT DEFERRABLE';
10656 if ($foreignKey->hasOption('feferred') && $foreignKey->getOption('feferred') !== false) {
10657 $query .= ' INITIALLY DEFERRED';
10659 $query .= ' INITIALLY IMMEDIATE';
10665 * generates the sql for altering an existing table on postgresql
10667 * @param string $name name of the table that is intended to be changed.
10668 * @param array $changes associative array that contains the details of each type *
10669 * @param boolean $check indicates whether the function should just check if the DBMS driver
10670 * can perform the requested table alterations if the value is true or
10671 * actually perform them otherwise.
10672 * @see Doctrine_Export::alterTable()
10676 public function getAlterTableSQL(TableDiff $diff)
10680 foreach ($diff->addedColumns as $column) {
10681 $query = 'ADD ' . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
10682 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
10685 foreach ($diff->removedColumns as $column) {
10686 $query = 'DROP ' . $column->getName();
10687 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
10690 foreach ($diff->changedColumns AS $columnDiff) {
10691 $oldColumnName = $columnDiff->oldColumnName;
10692 $column = $columnDiff->column;
10694 if ($columnDiff->hasChanged('type')) {
10695 $type = $column->getType();
10697 // here was a server version check before, but DBAL API does not support this anymore.
10698 $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $type->getSqlDeclaration($column->toArray(), $this);
10699 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
10701 if ($columnDiff->hasChanged('default')) {
10702 $query = 'ALTER ' . $oldColumnName . ' SET ' . $this->getDefaultValueDeclarationSQL($column->toArray());
10703 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
10705 if ($columnDiff->hasChanged('notnull')) {
10706 $query = 'ALTER ' . $oldColumnName . ' ' . ($column->getNotNull() ? 'SET' : 'DROP') . ' NOT NULL';
10707 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
10709 if ($columnDiff->hasChanged('autoincrement')) {
10710 if ($column->getAutoincrement()) {
10711 // add autoincrement
10712 $seqName = $diff->name . '_' . $oldColumnName . '_seq';
10714 $sql[] = "CREATE SEQUENCE " . $seqName;
10715 $sql[] = "SELECT setval('" . $seqName . "', (SELECT MAX(" . $oldColumnName . ") FROM " . $diff->name . "))";
10716 $query = "ALTER " . $oldColumnName . " SET DEFAULT nextval('" . $seqName . "')";
10717 $sql[] = "ALTER TABLE " . $diff->name . " " . $query;
10719 // Drop autoincrement, but do NOT drop the sequence. It might be re-used by other tables or have
10720 $query = "ALTER " . $oldColumnName . " " . "DROP DEFAULT";
10721 $sql[] = "ALTER TABLE " . $diff->name . " " . $query;
10726 foreach ($diff->renamedColumns as $oldColumnName => $column) {
10727 $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName . ' TO ' . $column->getName();
10730 if ($diff->newName !== false) {
10731 $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName;
10734 $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
10740 * Gets the SQL to create a sequence on this platform.
10742 * @param \Doctrine\DBAL\Schema\Sequence $sequence
10745 public function getCreateSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
10747 return 'CREATE SEQUENCE ' . $sequence->getName() .
10748 ' INCREMENT BY ' . $sequence->getAllocationSize() .
10749 ' MINVALUE ' . $sequence->getInitialValue() .
10750 ' START ' . $sequence->getInitialValue();
10754 * Drop existing sequence
10755 * @param \Doctrine\DBAL\Schema\Sequence $sequence
10758 public function getDropSequenceSQL($sequence)
10760 if ($sequence instanceof \Doctrine\DBAL\Schema\Sequence) {
10761 $sequence = $sequence->getName();
10763 return 'DROP SEQUENCE ' . $sequence;
10767 * @param ForeignKeyConstraint|string $foreignKey
10768 * @param Table|string $table
10771 public function getDropForeignKeySQL($foreignKey, $table)
10773 return $this->getDropConstraintSQL($foreignKey, $table);
10777 * Gets the SQL used to create a table.
10779 * @param unknown_type $tableName
10780 * @param array $columns
10781 * @param array $options
10784 protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
10786 $queryFields = $this->getColumnDeclarationListSQL($columns);
10788 if (isset($options['primary']) && ! empty($options['primary'])) {
10789 $keyColumns = array_unique(array_values($options['primary']));
10790 $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
10793 $query = 'CREATE TABLE ' . $tableName . ' (' . $queryFields . ')';
10797 if (isset($options['indexes']) && ! empty($options['indexes'])) {
10798 foreach ($options['indexes'] AS $index) {
10799 $sql[] = $this->getCreateIndexSQL($index, $tableName);
10803 if (isset($options['foreignKeys'])) {
10804 foreach ((array) $options['foreignKeys'] as $definition) {
10805 $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
10813 * Postgres wants boolean values converted to the strings 'true'/'false'.
10815 * @param array $item
10818 public function convertBooleans($item)
10820 if (is_array($item)) {
10821 foreach ($item as $key => $value) {
10822 if (is_bool($value) || is_numeric($item)) {
10823 $item[$key] = ($value) ? 'true' : 'false';
10827 if (is_bool($item) || is_numeric($item)) {
10828 $item = ($item) ? 'true' : 'false';
10834 public function getSequenceNextValSQL($sequenceName)
10836 return "SELECT NEXTVAL('" . $sequenceName . "')";
10839 public function getSetTransactionIsolationSQL($level)
10841 return 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL '
10842 . $this->_getTransactionIsolationLevelSQL($level);
10848 public function getBooleanTypeDeclarationSQL(array $field)
10856 public function getIntegerTypeDeclarationSQL(array $field)
10858 if ( ! empty($field['autoincrement'])) {
10868 public function getBigIntTypeDeclarationSQL(array $field)
10870 if ( ! empty($field['autoincrement'])) {
10871 return 'BIGSERIAL';
10879 public function getSmallIntTypeDeclarationSQL(array $field)
10887 public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
10889 return 'TIMESTAMP(0) WITHOUT TIME ZONE';
10895 public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
10897 return 'TIMESTAMP(0) WITH TIME ZONE';
10903 public function getDateTypeDeclarationSQL(array $fieldDeclaration)
10911 public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
10913 return 'TIME(0) WITHOUT TIME ZONE';
10919 protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
10925 * Gets the SQL snippet used to declare a VARCHAR column on the MySql platform.
10927 * @params array $field
10930 public function getVarcharTypeDeclarationSQL(array $field)
10932 if ( ! isset($field['length'])) {
10933 if (array_key_exists('default', $field)) {
10934 $field['length'] = $this->getVarcharMaxLength();
10936 $field['length'] = false;
10940 $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
10941 $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
10943 return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
10944 : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
10948 public function getClobTypeDeclarationSQL(array $field)
10954 * Get the platform name for this instance
10958 public function getName()
10960 return 'postgresql';
10964 * Gets the character casing of a column in an SQL result set.
10966 * PostgreSQL returns all column names in SQL result sets in lowercase.
10968 * @param string $column The column name for which to get the correct character casing.
10969 * @return string The column name in the character casing used in SQL result sets.
10971 public function getSQLResultCasing($column)
10973 return strtolower($column);
10976 public function getDateTimeTzFormatString()
10978 return 'Y-m-d H:i:sO';
10982 * Get the insert sql for an empty insert statement
10984 * @param string $tableName
10985 * @param string $identifierColumnName
10986 * @return string $sql
10988 public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName)
10990 return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)';
10996 public function getTruncateTableSQL($tableName, $cascade = false)
10998 return 'TRUNCATE '.$tableName.' '.($cascade)?'CASCADE':'';
11001 public function getReadLockSQL()
11003 return 'FOR SHARE';
11006 protected function initializeDoctrineTypeMappings()
11008 $this->doctrineTypeMapping = array(
11009 'smallint' => 'smallint',
11010 'int2' => 'smallint',
11011 'serial' => 'integer',
11012 'serial4' => 'integer',
11013 'int' => 'integer',
11014 'int4' => 'integer',
11015 'integer' => 'integer',
11016 'bigserial' => 'bigint',
11017 'serial8' => 'bigint',
11018 'bigint' => 'bigint',
11019 'int8' => 'bigint',
11020 'bool' => 'boolean',
11021 'boolean' => 'boolean',
11023 'varchar' => 'string',
11024 'interval' => 'string',
11025 '_varchar' => 'string',
11026 'char' => 'string',
11027 'bpchar' => 'string',
11029 'datetime' => 'datetime',
11030 'timestamp' => 'datetime',
11031 'timestamptz' => 'datetimetz',
11033 'timetz' => 'time',
11034 'float' => 'float',
11035 'float4' => 'float',
11036 'float8' => 'float',
11037 'double' => 'float',
11038 'double precision' => 'float',
11040 'decimal' => 'decimal',
11041 'money' => 'decimal',
11042 'numeric' => 'decimal',
11050 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
11051 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11052 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11053 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
11054 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11055 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11056 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11057 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11058 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
11059 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
11060 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11062 * This software consists of voluntary contributions made by many individuals
11063 * and is licensed under the LGPL. For more information, see
11064 * <http://www.doctrine-project.org>.
11067 namespace Doctrine\DBAL\Platforms;
11069 use Doctrine\DBAL\Schema\TableDiff;
11070 use Doctrine\DBAL\DBALException;
11071 use Doctrine\DBAL\Schema\Index, Doctrine\DBAL\Schema\Table;
11074 * The MsSqlPlatform provides the behavior, features and SQL dialect of the
11075 * MySQL database platform.
11078 * @author Roman Borschel <roman@code-factory.org>
11079 * @author Jonathan H. Wage <jonwage@gmail.com>
11080 * @author Benjamin Eberlei <kontakt@beberlei.de>
11081 * @todo Rename: MsSQLPlatform
11083 class MsSqlPlatform extends AbstractPlatform
11087 * Whether the platform prefers identity columns for ID generation.
11088 * MsSql prefers "autoincrement" identity columns since sequences can only
11089 * be emulated with a table.
11094 public function prefersIdentityColumns()
11100 * Whether the platform supports identity columns.
11101 * MsSql supports this through AUTO_INCREMENT columns.
11106 public function supportsIdentityColumns()
11112 * Whether the platform supports releasing savepoints.
11116 public function supportsReleaseSavepoints()
11122 * create a new database
11124 * @param string $name name of the database that should be created
11128 public function getCreateDatabaseSQL($name)
11130 return 'CREATE DATABASE ' . $name;
11134 * drop an existing database
11136 * @param string $name name of the database that should be dropped
11140 public function getDropDatabaseSQL($name)
11142 // @todo do we really need to force drop?
11143 return 'ALTER DATABASE [' . $name . ']
11145 WITH ROLLBACK IMMEDIATE;
11146 DROP DATABASE ' . $name . ';';
11152 public function quoteIdentifier($str)
11154 return '[' . $str . ']';
11160 public function getDropForeignKeySQL($foreignKey, $table)
11162 if ($foreignKey instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) {
11163 $foreignKey = $foreignKey->getName();
11166 if ($table instanceof \Doctrine\DBAL\Schema\Table) {
11167 $table = $table->getName();
11170 return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey;
11176 public function getDropIndexSQL($index, $table=null)
11178 if ($index instanceof \Doctrine\DBAL\Schema\Index) {
11180 $index = $index->getName();
11181 } else if (!is_string($index)) {
11182 throw new \InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
11185 if (!isset($table)) {
11186 return 'DROP INDEX ' . $index;
11188 if ($table instanceof \Doctrine\DBAL\Schema\Table) {
11189 $table = $table->getName();
11192 return "IF EXISTS (SELECT * FROM sysobjects WHERE name = '$index')
11193 ALTER TABLE " . $this->quoteIdentifier($table) . " DROP CONSTRAINT " . $this->quoteIdentifier($index) . "
11195 DROP INDEX " . $this->quoteIdentifier($index) . " ON " . $this->quoteIdentifier($table);
11202 public function getCreateTableSQL(Table $table, $createFlags=self::CREATE_INDEXES)
11204 $sql = parent::getCreateTableSQL($table, $createFlags);
11206 $primary = array();
11208 foreach ($table->getIndexes() AS $index) {
11209 /* @var $index Index */
11210 if ($index->isPrimary()) {
11211 $primary = $index->getColumns();
11215 if (count($primary) === 1) {
11216 foreach ($table->getForeignKeys() AS $definition) {
11217 $columns = $definition->getLocalColumns();
11218 if (count($columns) === 1 && in_array($columns[0], $primary)) {
11219 $sql[0] = str_replace(' IDENTITY', '', $sql[0]);
11230 protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
11232 $columnListSql = $this->getColumnDeclarationListSQL($columns);
11234 if (isset($options['uniqueConstraints']) && !empty($options['uniqueConstraints'])) {
11235 foreach ($options['uniqueConstraints'] as $name => $definition) {
11236 $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
11240 if (isset($options['primary']) && !empty($options['primary'])) {
11241 $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
11244 $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
11246 $check = $this->getCheckDeclarationSQL($columns);
11247 if (!empty($check)) {
11248 $query .= ', ' . $check;
11254 if (isset($options['indexes']) && !empty($options['indexes'])) {
11255 foreach ($options['indexes'] AS $index) {
11256 $sql[] = $this->getCreateIndexSQL($index, $tableName);
11260 if (isset($options['foreignKeys'])) {
11261 foreach ((array) $options['foreignKeys'] AS $definition) {
11262 $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
11272 public function getAlterTableSQL(TableDiff $diff)
11274 $queryParts = array();
11275 if ($diff->newName !== false) {
11276 $queryParts[] = 'RENAME TO ' . $diff->newName;
11279 foreach ($diff->addedColumns AS $fieldName => $column) {
11280 $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
11283 foreach ($diff->removedColumns AS $column) {
11284 $queryParts[] = 'DROP COLUMN ' . $column->getName();
11287 foreach ($diff->changedColumns AS $columnDiff) {
11288 /* @var $columnDiff Doctrine\DBAL\Schema\ColumnDiff */
11289 $column = $columnDiff->column;
11290 $queryParts[] = 'CHANGE ' . ($columnDiff->oldColumnName) . ' '
11291 . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
11294 foreach ($diff->renamedColumns AS $oldColumnName => $column) {
11295 $queryParts[] = 'CHANGE ' . $oldColumnName . ' '
11296 . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
11301 foreach ($queryParts as $query) {
11302 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
11305 $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
11313 public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName)
11315 return 'INSERT INTO ' . $quotedTableName . ' DEFAULT VALUES';
11321 public function getShowDatabasesSQL()
11323 return 'SHOW DATABASES';
11329 public function getListTablesSQL()
11331 return "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
11337 public function getListTableColumnsSQL($table)
11339 return 'exec sp_columns @table_name = ' . $table;
11345 public function getListTableForeignKeysSQL($table, $database = null)
11347 return "SELECT f.name AS ForeignKey,
11348 SCHEMA_NAME (f.SCHEMA_ID) AS SchemaName,
11349 OBJECT_NAME (f.parent_object_id) AS TableName,
11350 COL_NAME (fc.parent_object_id,fc.parent_column_id) AS ColumnName,
11351 SCHEMA_NAME (o.SCHEMA_ID) ReferenceSchemaName,
11352 OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
11353 COL_NAME(fc.referenced_object_id,fc.referenced_column_id) AS ReferenceColumnName,
11354 f.delete_referential_action_desc,
11355 f.update_referential_action_desc
11356 FROM sys.foreign_keys AS f
11357 INNER JOIN sys.foreign_key_columns AS fc
11358 INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id
11359 ON f.OBJECT_ID = fc.constraint_object_id
11360 WHERE OBJECT_NAME (f.parent_object_id) = '" . $table . "'";
11366 public function getListTableIndexesSQL($table)
11368 return "exec sp_helpindex '" . $table . "'";
11374 public function getCreateViewSQL($name, $sql)
11376 return 'CREATE VIEW ' . $name . ' AS ' . $sql;
11382 public function getListViewsSQL($database)
11384 return "SELECT name FROM sysobjects WHERE type = 'V' ORDER BY name";
11390 public function getDropViewSQL($name)
11392 return 'DROP VIEW ' . $name;
11396 * Returns the regular expression operator.
11401 public function getRegexpExpression()
11407 * Returns global unique identifier
11409 * @return string to get global unique identifier
11412 public function getGuidExpression()
11420 public function getLocateExpression($str, $substr, $startPos = false)
11422 if ($startPos == false) {
11423 return 'CHARINDEX(' . $substr . ', ' . $str . ')';
11425 return 'CHARINDEX(' . $substr . ', ' . $str . ', ' . $startPos . ')';
11432 public function getModExpression($expression1, $expression2)
11434 return $expression1 . ' % ' . $expression2;
11440 public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
11444 $trimChar = ($char != false) ? (', ' . $char) : '';
11446 if ($pos == self::TRIM_LEADING) {
11448 } else if ($pos == self::TRIM_TRAILING) {
11451 return 'LTRIM(RTRIM(' . $str . '))';
11454 return $trimFn . '(' . $str . ')';
11460 public function getConcatExpression()
11462 $args = func_get_args();
11463 return '(' . implode(' + ', $args) . ')';
11466 public function getListDatabasesSQL()
11468 return 'SELECT * FROM SYS.DATABASES';
11474 public function getSubstringExpression($value, $from, $len = null)
11476 if (!is_null($len)) {
11477 return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $len . ')';
11479 return 'SUBSTRING(' . $value . ', ' . $from . ', LEN(' . $value . ') - ' . $from . ' + 1)';
11485 public function getLengthExpression($column)
11487 return 'LEN(' . $column . ')';
11493 public function getSetTransactionIsolationSQL($level)
11495 return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level);
11501 public function getIntegerTypeDeclarationSQL(array $field)
11503 return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
11509 public function getBigIntTypeDeclarationSQL(array $field)
11511 return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
11517 public function getSmallIntTypeDeclarationSQL(array $field)
11519 return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
11523 public function getVarcharTypeDeclarationSQL(array $field)
11525 if (!isset($field['length'])) {
11526 if (array_key_exists('default', $field)) {
11527 $field['length'] = $this->getVarcharMaxLength();
11529 $field['length'] = false;
11533 $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
11534 $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
11536 return $fixed ? ($length ? 'NCHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'NVARCHAR(' . $length . ')' : 'NTEXT');
11540 public function getClobTypeDeclarationSQL(array $field)
11548 protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
11551 if (!empty($columnDef['autoincrement'])) {
11552 $autoinc = ' IDENTITY';
11554 $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : '';
11556 return $unsigned . $autoinc;
11562 public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
11564 // 6 - microseconds precision length
11565 return 'DATETIME2(6)';
11571 public function getDateTypeDeclarationSQL(array $fieldDeclaration)
11579 public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
11587 public function getBooleanTypeDeclarationSQL(array $field)
11593 * Adds an adapter-specific LIMIT clause to the SELECT statement.
11595 * @param string $query
11596 * @param mixed $limit
11597 * @param mixed $offset
11598 * @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
11601 public function modifyLimitQuery($query, $limit, $offset = null)
11604 $count = intval($limit);
11605 $offset = intval($offset);
11608 throw new Doctrine_Connection_Exception("LIMIT argument offset=$offset is not valid");
11611 if ($offset == 0) {
11612 $query = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . $count . ' ', $query);
11614 $orderby = stristr($query, 'ORDER BY');
11617 $over = 'ORDER BY (SELECT 0)';
11619 $over = preg_replace('/\"[^,]*\".\"([^,]*)\"/i', '"inner_tbl"."$1"', $orderby);
11622 // Remove ORDER BY clause from $query
11623 $query = preg_replace('/\s+ORDER BY(.*)/', '', $query);
11625 // Add ORDER BY clause as an argument for ROW_NUMBER()
11626 $query = "SELECT ROW_NUMBER() OVER ($over) AS \"doctrine_rownum\", * FROM ($query) AS inner_tbl";
11628 $start = $offset + 1;
11629 $end = $offset + $count;
11631 $query = "WITH outer_tbl AS ($query) SELECT * FROM outer_tbl WHERE \"doctrine_rownum\" BETWEEN $start AND $end";
11641 public function convertBooleans($item)
11643 if (is_array($item)) {
11644 foreach ($item as $key => $value) {
11645 if (is_bool($value) || is_numeric($item)) {
11646 $item[$key] = ($value) ? 'TRUE' : 'FALSE';
11650 if (is_bool($item) || is_numeric($item)) {
11651 $item = ($item) ? 'TRUE' : 'FALSE';
11660 public function getCreateTemporaryTableSnippetSQL()
11662 return "CREATE TABLE";
11668 public function getTemporaryTableName($tableName)
11670 return '#' . $tableName;
11676 public function getDateTimeFormatString()
11678 return 'Y-m-d H:i:s.u';
11684 public function getDateTimeTzFormatString()
11686 return $this->getDateTimeFormatString();
11690 * Get the platform name for this instance
11694 public function getName()
11699 protected function initializeDoctrineTypeMappings()
11701 $this->doctrineTypeMapping = array(
11702 'bigint' => 'bigint',
11703 'numeric' => 'decimal',
11704 'bit' => 'boolean',
11705 'smallint' => 'smallint',
11706 'decimal' => 'decimal',
11707 'smallmoney' => 'integer',
11708 'int' => 'integer',
11709 'tinyint' => 'smallint',
11710 'money' => 'integer',
11711 'float' => 'float',
11713 'double' => 'float',
11714 'double precision' => 'float',
11716 'datetimeoffset' => 'datetimetz',
11717 'datetime2' => 'datetime',
11718 'smalldatetime' => 'datetime',
11719 'datetime' => 'datetime',
11721 'char' => 'string',
11722 'varchar' => 'string',
11724 'nchar' => 'string',
11725 'nvarchar' => 'string',
11727 'binary' => 'text',
11728 'varbinary' => 'text',
11734 * Generate SQL to create a new savepoint
11736 * @param string $savepoint
11739 public function createSavePoint($savepoint)
11741 return 'SAVE TRANSACTION ' . $savepoint;
11745 * Generate SQL to release a savepoint
11747 * @param string $savepoint
11750 public function releaseSavePoint($savepoint)
11756 * Generate SQL to rollback a savepoint
11758 * @param string $savepoint
11761 public function rollbackSavePoint($savepoint)
11763 return 'ROLLBACK TRANSACTION ' . $savepoint;
11768 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
11769 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11770 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11771 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
11772 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11773 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11774 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11775 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11776 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
11777 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
11778 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11780 * This software consists of voluntary contributions made by many individuals
11781 * and is licensed under the LGPL. For more information, see
11782 * <http://www.doctrine-project.org>.
11785 namespace Doctrine\DBAL\Platforms;
11787 use Doctrine\DBAL\Schema\TableDiff;
11793 * @author Roman Borschel <roman@code-factory.org>
11794 * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
11795 * @author Benjamin Eberlei <kontakt@beberlei.de>
11797 class OraclePlatform extends AbstractPlatform
11800 * return string to call a function to get a substring inside an SQL statement
11802 * Note: Not SQL92, but common functionality.
11804 * @param string $value an sql string literal or column name/alias
11805 * @param integer $position where to start the substring portion
11806 * @param integer $length the substring portion length
11807 * @return string SQL substring function with given parameters
11810 public function getSubstringExpression($value, $position, $length = null)
11812 if ($length !== null) {
11813 return "SUBSTR($value, $position, $length)";
11816 return "SUBSTR($value, $position)";
11820 * Return string to call a variable with the current timestamp inside an SQL statement
11821 * There are three special variables for current date and time:
11822 * - CURRENT_TIMESTAMP (date and time, TIMESTAMP type)
11823 * - CURRENT_DATE (date, DATE type)
11824 * - CURRENT_TIME (time, TIME type)
11826 * @return string to call a variable with the current timestamp
11829 public function getNowExpression($type = 'timestamp')
11836 return 'TO_CHAR(CURRENT_TIMESTAMP, \'YYYY-MM-DD HH24:MI:SS\')';
11841 * returns the position of the first occurrence of substring $substr in string $str
11843 * @param string $substr literal string to find
11844 * @param string $str literal string
11845 * @param int $pos position to start at, beginning of string by default
11848 public function getLocateExpression($str, $substr, $startPos = false)
11850 if ($startPos == false) {
11851 return 'INSTR('.$str.', '.$substr.')';
11853 return 'INSTR('.$str.', '.$substr.', '.$startPos.')';
11858 * Returns global unique identifier
11860 * @return string to get global unique identifier
11863 public function getGuidExpression()
11865 return 'SYS_GUID()';
11869 * Gets the SQL used to create a sequence that starts with a given value
11870 * and increments by the given allocation size.
11872 * Need to specifiy minvalue, since start with is hidden in the system and MINVALUE <= START WITH.
11873 * Therefore we can use MINVALUE to be able to get a hint what START WITH was for later introspection
11874 * in {@see listSequences()}
11876 * @param \Doctrine\DBAL\Schema\Sequence $sequence
11879 public function getCreateSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
11881 return 'CREATE SEQUENCE ' . $sequence->getName() .
11882 ' START WITH ' . $sequence->getInitialValue() .
11883 ' MINVALUE ' . $sequence->getInitialValue() .
11884 ' INCREMENT BY ' . $sequence->getAllocationSize();
11890 * @param string $sequenceName
11893 public function getSequenceNextValSQL($sequenceName)
11895 return 'SELECT ' . $sequenceName . '.nextval FROM DUAL';
11901 * @param integer $level
11904 public function getSetTransactionIsolationSQL($level)
11906 return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level);
11909 protected function _getTransactionIsolationLevelSQL($level)
11912 case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED:
11913 return 'READ UNCOMMITTED';
11914 case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED:
11915 return 'READ COMMITTED';
11916 case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ:
11917 case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE:
11918 return 'SERIALIZABLE';
11920 return parent::_getTransactionIsolationLevelSQL($level);
11927 public function getBooleanTypeDeclarationSQL(array $field)
11929 return 'NUMBER(1)';
11935 public function getIntegerTypeDeclarationSQL(array $field)
11937 return 'NUMBER(10)';
11943 public function getBigIntTypeDeclarationSQL(array $field)
11945 return 'NUMBER(20)';
11951 public function getSmallIntTypeDeclarationSQL(array $field)
11953 return 'NUMBER(5)';
11959 public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
11961 return 'TIMESTAMP(0)';
11967 public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
11969 return 'TIMESTAMP(0) WITH TIME ZONE';
11975 public function getDateTypeDeclarationSQL(array $fieldDeclaration)
11983 public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
11991 protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
11997 * Gets the SQL snippet used to declare a VARCHAR column on the Oracle platform.
11999 * @params array $field
12002 public function getVarcharTypeDeclarationSQL(array $field)
12004 if ( ! isset($field['length'])) {
12005 if (array_key_exists('default', $field)) {
12006 $field['length'] = $this->getVarcharMaxLength();
12008 $field['length'] = false;
12012 $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
12013 $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
12015 return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(2000)')
12016 : ($length ? 'VARCHAR2(' . $length . ')' : 'VARCHAR2(4000)');
12020 public function getClobTypeDeclarationSQL(array $field)
12025 public function getListDatabasesSQL()
12027 return 'SELECT username FROM all_users';
12030 public function getListSequencesSQL($database)
12032 return "SELECT sequence_name, min_value, increment_by FROM sys.all_sequences ".
12033 "WHERE SEQUENCE_OWNER = '".strtoupper($database)."'";
12038 * @param string $table
12039 * @param array $columns
12040 * @param array $options
12043 protected function _getCreateTableSQL($table, array $columns, array $options = array())
12045 $indexes = isset($options['indexes']) ? $options['indexes'] : array();
12046 $options['indexes'] = array();
12047 $sql = parent::_getCreateTableSQL($table, $columns, $options);
12049 foreach ($columns as $name => $column) {
12050 if (isset($column['sequence'])) {
12051 $sql[] = $this->getCreateSequenceSQL($column['sequence'], 1);
12054 if (isset($column['autoincrement']) && $column['autoincrement'] ||
12055 (isset($column['autoinc']) && $column['autoinc'])) {
12056 $sql = array_merge($sql, $this->getCreateAutoincrementSql($name, $table));
12060 if (isset($indexes) && ! empty($indexes)) {
12061 foreach ($indexes as $indexName => $index) {
12062 $sql[] = $this->getCreateIndexSQL($index, $table);
12070 * @license New BSD License
12071 * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaOracleReader.html
12072 * @param string $table
12075 public function getListTableIndexesSQL($table)
12077 $table = strtoupper($table);
12079 return "SELECT uind.index_name AS name, " .
12080 " uind.index_type AS type, " .
12081 " decode( uind.uniqueness, 'NONUNIQUE', 0, 'UNIQUE', 1 ) AS is_unique, " .
12082 " uind_col.column_name AS column_name, " .
12083 " uind_col.column_position AS column_pos, " .
12084 " (SELECT ucon.constraint_type FROM user_constraints ucon WHERE ucon.constraint_name = uind.index_name) AS is_primary ".
12085 "FROM user_indexes uind, user_ind_columns uind_col " .
12086 "WHERE uind.index_name = uind_col.index_name AND uind_col.table_name = '$table' ORDER BY uind_col.column_position ASC";
12089 public function getListTablesSQL()
12091 return 'SELECT * FROM sys.user_tables';
12094 public function getListViewsSQL($database)
12096 return 'SELECT view_name, text FROM sys.user_views';
12099 public function getCreateViewSQL($name, $sql)
12101 return 'CREATE VIEW ' . $name . ' AS ' . $sql;
12104 public function getDropViewSQL($name)
12106 return 'DROP VIEW '. $name;
12109 public function getCreateAutoincrementSql($name, $table, $start = 1)
12111 $table = strtoupper($table);
12114 $indexName = $table . '_AI_PK';
12115 $definition = array(
12117 'columns' => array($name => true),
12120 $idx = new \Doctrine\DBAL\Schema\Index($indexName, array($name), true, true);
12123 constraints_Count NUMBER;
12125 SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = \''.$table.'\' AND CONSTRAINT_TYPE = \'P\';
12126 IF constraints_Count = 0 OR constraints_Count = \'\' THEN
12127 EXECUTE IMMEDIATE \''.$this->getCreateConstraintSQL($idx, $table).'\';
12131 $sequenceName = $table . '_SEQ';
12132 $sequence = new \Doctrine\DBAL\Schema\Sequence($sequenceName, $start);
12133 $sql[] = $this->getCreateSequenceSQL($sequence);
12135 $triggerName = $table . '_AI_PK';
12136 $sql[] = 'CREATE TRIGGER ' . $triggerName . '
12141 last_Sequence NUMBER;
12142 last_InsertID NUMBER;
12144 SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL;
12145 IF (:NEW.' . $name . ' IS NULL OR :NEW.'.$name.' = 0) THEN
12146 SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL;
12148 SELECT NVL(Last_Number, 0) INTO last_Sequence
12149 FROM User_Sequences
12150 WHERE Sequence_Name = \'' . $sequenceName . '\';
12151 SELECT :NEW.' . $name . ' INTO last_InsertID FROM DUAL;
12152 WHILE (last_InsertID > last_Sequence) LOOP
12153 SELECT ' . $sequenceName . '.NEXTVAL INTO last_Sequence FROM DUAL;
12160 public function getDropAutoincrementSql($table)
12162 $table = strtoupper($table);
12163 $trigger = $table . '_AI_PK';
12166 $sql[] = 'DROP TRIGGER ' . $trigger;
12167 $sql[] = $this->getDropSequenceSQL($table.'_SEQ');
12169 $indexName = $table . '_AI_PK';
12170 $sql[] = $this->getDropConstraintSQL($indexName, $table);
12176 public function getListTableForeignKeysSQL($table)
12178 $table = strtoupper($table);
12180 return "SELECT alc.constraint_name,
12182 alc.search_condition,
12183 cols.column_name \"local_column\",
12185 r_alc.table_name \"references_table\",
12186 r_cols.column_name \"foreign_column\"
12187 FROM all_cons_columns cols
12188 LEFT JOIN all_constraints alc
12189 ON alc.constraint_name = cols.constraint_name
12190 AND alc.owner = cols.owner
12191 LEFT JOIN all_constraints r_alc
12192 ON alc.r_constraint_name = r_alc.constraint_name
12193 AND alc.r_owner = r_alc.owner
12194 LEFT JOIN all_cons_columns r_cols
12195 ON r_alc.constraint_name = r_cols.constraint_name
12196 AND r_alc.owner = r_cols.owner
12197 AND cols.position = r_cols.position
12198 WHERE alc.constraint_name = cols.constraint_name
12199 AND alc.constraint_type = 'R'
12200 AND alc.table_name = '".$table."'";
12203 public function getListTableConstraintsSQL($table)
12205 $table = strtoupper($table);
12206 return 'SELECT * FROM user_constraints WHERE table_name = \'' . $table . '\'';
12209 public function getListTableColumnsSQL($table)
12211 $table = strtoupper($table);
12212 return "SELECT * FROM all_tab_columns WHERE table_name = '" . $table . "' ORDER BY column_name";
12217 * @param \Doctrine\DBAL\Schema\Sequence $sequence
12220 public function getDropSequenceSQL($sequence)
12222 if ($sequence instanceof \Doctrine\DBAL\Schema\Sequence) {
12223 $sequence = $sequence->getName();
12226 return 'DROP SEQUENCE ' . $sequence;
12230 * @param ForeignKeyConstraint|string $foreignKey
12231 * @param Table|string $table
12234 public function getDropForeignKeySQL($foreignKey, $table)
12236 if ($foreignKey instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) {
12237 $foreignKey = $foreignKey->getName();
12240 if ($table instanceof \Doctrine\DBAL\Schema\Table) {
12241 $table = $table->getName();
12244 return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey;
12247 public function getDropDatabaseSQL($database)
12249 return 'DROP USER ' . $database . ' CASCADE';
12253 * Gets the sql statements for altering an existing table.
12255 * The method returns an array of sql statements, since some platforms need several statements.
12257 * @param string $diff->name name of the table that is intended to be changed.
12258 * @param array $changes associative array that contains the details of each type *
12259 * @param boolean $check indicates whether the function should just check if the DBMS driver
12260 * can perform the requested table alterations if the value is true or
12261 * actually perform them otherwise.
12264 public function getAlterTableSQL(TableDiff $diff)
12269 foreach ($diff->addedColumns AS $column) {
12270 $fields[] = $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
12272 if (count($fields)) {
12273 $sql[] = 'ALTER TABLE ' . $diff->name . ' ADD (' . implode(', ', $fields) . ')';
12277 foreach ($diff->changedColumns AS $columnDiff) {
12278 $column = $columnDiff->column;
12279 $fields[] = $column->getName(). ' ' . $this->getColumnDeclarationSQL('', $column->toArray());
12281 if (count($fields)) {
12282 $sql[] = 'ALTER TABLE ' . $diff->name . ' MODIFY (' . implode(', ', $fields) . ')';
12285 foreach ($diff->renamedColumns AS $oldColumnName => $column) {
12286 $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName .' TO ' . $column->getName();
12290 foreach ($diff->removedColumns AS $column) {
12291 $fields[] = $column->getName();
12293 if (count($fields)) {
12294 $sql[] = 'ALTER TABLE ' . $diff->name . ' DROP COLUMN ' . implode(', ', $fields);
12297 if ($diff->newName !== false) {
12298 $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName;
12301 $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
12307 * Whether the platform prefers sequences for ID generation.
12311 public function prefersSequences()
12317 * Get the platform name for this instance
12321 public function getName()
12327 * Adds an driver-specific LIMIT clause to the query
12329 * @param string $query query to modify
12330 * @param integer $limit limit the number of rows
12331 * @param integer $offset start reading from given offset
12332 * @return string the modified query
12334 public function modifyLimitQuery($query, $limit, $offset = null)
12336 $limit = (int) $limit;
12337 $offset = (int) $offset;
12338 if (preg_match('/^\s*SELECT/i', $query)) {
12339 if ( ! preg_match('/\sFROM\s/i', $query)) {
12340 $query .= " FROM dual";
12343 $max = $offset + $limit;
12346 $min = $offset + 1;
12347 $query = 'SELECT b.'.$column.' FROM ('.
12348 'SELECT a.*, ROWNUM AS doctrine_rownum FROM ('
12351 'WHERE doctrine_rownum BETWEEN ' . $min . ' AND ' . $max;
12353 $query = 'SELECT a.'.$column.' FROM (' . $query .') a WHERE ROWNUM <= ' . $max;
12361 * Gets the character casing of a column in an SQL result set of this platform.
12363 * Oracle returns all column names in SQL result sets in uppercase.
12365 * @param string $column The column name for which to get the correct character casing.
12366 * @return string The column name in the character casing used in SQL result sets.
12368 public function getSQLResultCasing($column)
12370 return strtoupper($column);
12373 public function getCreateTemporaryTableSnippetSQL()
12375 return "CREATE GLOBAL TEMPORARY TABLE";
12378 public function getDateTimeTzFormatString()
12380 return 'Y-m-d H:i:sP';
12383 public function getDateFormatString()
12385 return 'Y-m-d 00:00:00';
12388 public function getTimeFormatString()
12390 return '1900-01-01 H:i:s';
12393 public function fixSchemaElementName($schemaElementName)
12395 if (strlen($schemaElementName) > 30) {
12397 return substr($schemaElementName, 0, 30);
12399 return $schemaElementName;
12403 * Maximum length of any given databse identifier, like tables or column names.
12407 public function getMaxIdentifierLength()
12413 * Whether the platform supports sequences.
12417 public function supportsSequences()
12422 public function supportsForeignKeyOnUpdate()
12428 * Whether the platform supports releasing savepoints.
12432 public function supportsReleaseSavepoints()
12440 public function getTruncateTableSQL($tableName, $cascade = false)
12442 return 'TRUNCATE TABLE '.$tableName;
12446 * This is for test reasons, many vendors have special requirements for dummy statements.
12450 public function getDummySelectSQL()
12452 return 'SELECT 1 FROM DUAL';
12455 protected function initializeDoctrineTypeMappings()
12457 $this->doctrineTypeMapping = array(
12458 'integer' => 'integer',
12459 'number' => 'integer',
12460 'pls_integer' => 'boolean',
12461 'binary_integer' => 'boolean',
12462 'varchar' => 'string',
12463 'varchar2' => 'string',
12464 'nvarchar2' => 'string',
12465 'char' => 'string',
12466 'nchar' => 'string',
12467 'date' => 'datetime',
12468 'timestamp' => 'datetime',
12469 'timestamptz' => 'datetimetz',
12470 'float' => 'float',
12471 'long' => 'string',
12474 'rowid' => 'string',
12475 'urowid' => 'string'
12480 * Generate SQL to release a savepoint
12482 * @param string $savepoint
12485 public function releaseSavePoint($savepoint)
12492 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
12493 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
12494 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
12495 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
12496 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
12497 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
12498 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12499 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12500 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12501 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
12502 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12504 * This software consists of voluntary contributions made by many individuals
12505 * and is licensed under the LGPL. For more information, see
12506 * <http://www.doctrine-project.org>.
12509 namespace Doctrine\DBAL\Platforms;
12511 use Doctrine\DBAL\DBALException;
12512 use Doctrine\DBAL\Schema\Index;
12513 use Doctrine\DBAL\Schema\TableDiff;
12515 class DB2Platform extends AbstractPlatform
12517 public function initializeDoctrineTypeMappings()
12519 $this->doctrineTypeMapping = array(
12520 'smallint' => 'smallint',
12521 'bigint' => 'bigint',
12522 'integer' => 'integer',
12525 'varchar' => 'string',
12526 'character' => 'string',
12528 'decimal' => 'decimal',
12529 'double' => 'decimal',
12530 'real' => 'decimal',
12531 'timestamp' => 'datetime',
12536 * Gets the SQL snippet used to declare a VARCHAR column type.
12538 * @param array $field
12540 public function getVarcharTypeDeclarationSQL(array $field)
12542 if ( ! isset($field['length'])) {
12543 if (array_key_exists('default', $field)) {
12544 $field['length'] = $this->getVarcharMaxLength();
12546 $field['length'] = false;
12550 $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
12551 $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
12553 return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
12554 : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)');
12558 * Gets the SQL snippet used to declare a CLOB column type.
12560 * @param array $field
12562 public function getClobTypeDeclarationSQL(array $field)
12564 // todo clob(n) with $field['length'];
12569 * Gets the name of the platform.
12573 public function getName()
12580 * Gets the SQL snippet that declares a boolean column.
12582 * @param array $columnDef
12585 public function getBooleanTypeDeclarationSQL(array $columnDef)
12591 * Gets the SQL snippet that declares a 4 byte integer column.
12593 * @param array $columnDef
12596 public function getIntegerTypeDeclarationSQL(array $columnDef)
12598 return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
12602 * Gets the SQL snippet that declares an 8 byte integer column.
12604 * @param array $columnDef
12607 public function getBigIntTypeDeclarationSQL(array $columnDef)
12609 return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
12613 * Gets the SQL snippet that declares a 2 byte integer column.
12615 * @param array $columnDef
12618 public function getSmallIntTypeDeclarationSQL(array $columnDef)
12620 return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
12624 * Gets the SQL snippet that declares common properties of an integer column.
12626 * @param array $columnDef
12629 protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
12632 if ( ! empty($columnDef['autoincrement'])) {
12633 $autoinc = ' GENERATED BY DEFAULT AS IDENTITY';
12639 * Obtain DBMS specific SQL to be used to create datetime fields in
12640 * statements like CREATE TABLE
12642 * @param array $fieldDeclaration
12645 public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
12647 if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) {
12648 return "TIMESTAMP(0) WITH DEFAULT";
12651 return 'TIMESTAMP(0)';
12655 * Obtain DBMS specific SQL to be used to create date fields in statements
12656 * like CREATE TABLE.
12658 * @param array $fieldDeclaration
12661 public function getDateTypeDeclarationSQL(array $fieldDeclaration)
12667 * Obtain DBMS specific SQL to be used to create time fields in statements
12668 * like CREATE TABLE.
12670 * @param array $fieldDeclaration
12673 public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
12678 public function getListDatabasesSQL()
12680 throw DBALException::notSupported(__METHOD__);
12683 public function getListSequencesSQL($database)
12685 throw DBALException::notSupported(__METHOD__);
12688 public function getListTableConstraintsSQL($table)
12690 throw DBALException::notSupported(__METHOD__);
12694 * This code fragment is originally from the Zend_Db_Adapter_Db2 class.
12696 * @license New BSD License
12697 * @param string $table
12700 public function getListTableColumnsSQL($table)
12702 return "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno,
12703 c.typename, c.default, c.nulls, c.length, c.scale,
12704 c.identity, tc.type AS tabconsttype, k.colseq
12705 FROM syscat.columns c
12706 LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc
12707 ON (k.tabschema = tc.tabschema
12708 AND k.tabname = tc.tabname
12709 AND tc.type = 'P'))
12710 ON (c.tabschema = k.tabschema
12711 AND c.tabname = k.tabname
12712 AND c.colname = k.colname)
12713 WHERE UPPER(c.tabname) = UPPER('" . $table . "') ORDER BY c.colno";
12716 public function getListTablesSQL()
12718 return "SELECT NAME FROM SYSIBM.SYSTABLES WHERE TYPE = 'T'";
12721 public function getListUsersSQL()
12723 throw DBALException::notSupported(__METHOD__);
12727 * Get the SQL to list all views of a database or user.
12729 * @param string $database
12732 public function getListViewsSQL($database)
12734 return "SELECT NAME, TEXT FROM SYSIBM.SYSVIEWS";
12737 public function getListTableIndexesSQL($table)
12739 return "SELECT NAME, COLNAMES, UNIQUERULE FROM SYSIBM.SYSINDEXES WHERE TBNAME = UPPER('" . $table . "')";
12742 public function getListTableForeignKeysSQL($table)
12744 return "SELECT TBNAME, RELNAME, REFTBNAME, DELETERULE, UPDATERULE, FKCOLNAMES, PKCOLNAMES ".
12745 "FROM SYSIBM.SYSRELS WHERE TBNAME = UPPER('".$table."')";
12748 public function getCreateViewSQL($name, $sql)
12750 return "CREATE VIEW ".$name." AS ".$sql;
12753 public function getDropViewSQL($name)
12755 return "DROP VIEW ".$name;
12758 public function getDropSequenceSQL($sequence)
12760 throw DBALException::notSupported(__METHOD__);
12763 public function getSequenceNextValSQL($sequenceName)
12765 throw DBALException::notSupported(__METHOD__);
12768 public function getCreateDatabaseSQL($database)
12770 return "CREATE DATABASE ".$database;
12773 public function getDropDatabaseSQL($database)
12775 return "DROP DATABASE ".$database.";";
12778 public function supportsCreateDropDatabase()
12784 * Whether the platform supports releasing savepoints.
12788 public function supportsReleaseSavepoints()
12794 * Gets the SQL specific for the platform to get the current date.
12798 public function getCurrentDateSQL()
12800 return 'VALUES CURRENT DATE';
12804 * Gets the SQL specific for the platform to get the current time.
12808 public function getCurrentTimeSQL()
12810 return 'VALUES CURRENT TIME';
12814 * Gets the SQL specific for the platform to get the current timestamp
12819 public function getCurrentTimestampSQL()
12821 return "VALUES CURRENT TIMESTAMP";
12825 * Obtain DBMS specific SQL code portion needed to set an index
12826 * declaration to be used in statements like CREATE TABLE.
12828 * @param string $name name of the index
12829 * @param Index $index index definition
12830 * @return string DBMS specific SQL code portion needed to set an index
12832 public function getIndexDeclarationSQL($name, Index $index)
12834 return $this->getUniqueConstraintDeclarationSQL($name, $index);
12838 * @param string $tableName
12839 * @param array $columns
12840 * @param array $options
12843 protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
12845 $indexes = array();
12846 if (isset($options['indexes'])) {
12847 $indexes = $options['indexes'];
12849 $options['indexes'] = array();
12851 $sqls = parent::_getCreateTableSQL($tableName, $columns, $options);
12853 foreach ($indexes as $index => $definition) {
12854 $sqls[] = $this->getCreateIndexSQL($definition, $tableName);
12860 * Gets the SQL to alter an existing table.
12862 * @param TableDiff $diff
12865 public function getAlterTableSQL(TableDiff $diff)
12869 $queryParts = array();
12870 foreach ($diff->addedColumns AS $fieldName => $column) {
12871 $queryParts[] = 'ADD COLUMN ' . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
12874 foreach ($diff->removedColumns AS $column) {
12875 $queryParts[] = 'DROP COLUMN ' . $column->getName();
12878 foreach ($diff->changedColumns AS $columnDiff) {
12879 /* @var $columnDiff Doctrine\DBAL\Schema\ColumnDiff */
12880 $column = $columnDiff->column;
12881 $queryParts[] = 'ALTER ' . ($columnDiff->oldColumnName) . ' '
12882 . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
12885 foreach ($diff->renamedColumns AS $oldColumnName => $column) {
12886 $queryParts[] = 'RENAME ' . $oldColumnName . ' TO ' . $column->getName();
12889 if (count($queryParts) > 0) {
12890 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(" ", $queryParts);
12893 $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
12895 if ($diff->newName !== false) {
12896 $sql[] = 'RENAME TABLE TO ' . $diff->newName;
12902 public function getDefaultValueDeclarationSQL($field)
12904 if (isset($field['notnull']) && $field['notnull'] && !isset($field['default'])) {
12905 if (in_array((string)$field['type'], array("Integer", "BigInteger", "SmallInteger"))) {
12906 $field['default'] = 0;
12907 } else if((string)$field['type'] == "DateTime") {
12908 $field['default'] = "00-00-00 00:00:00";
12909 } else if ((string)$field['type'] == "Date") {
12910 $field['default'] = "00-00-00";
12911 } else if((string)$field['type'] == "Time") {
12912 $field['default'] = "00:00:00";
12914 $field['default'] = '';
12918 unset($field['default']); // @todo this needs fixing
12919 if (isset($field['version']) && $field['version']) {
12920 if ((string)$field['type'] != "DateTime") {
12921 $field['default'] = "1";
12925 return parent::getDefaultValueDeclarationSQL($field);
12929 * Get the insert sql for an empty insert statement
12931 * @param string $tableName
12932 * @param string $identifierColumnName
12933 * @return string $sql
12935 public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName)
12937 return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (DEFAULT)';
12940 public function getCreateTemporaryTableSnippetSQL()
12942 return "DECLARE GLOBAL TEMPORARY TABLE";
12946 * DB2 automatically moves temporary tables into the SESSION. schema.
12948 * @param string $tableName
12951 public function getTemporaryTableName($tableName)
12953 return "SESSION." . $tableName;
12956 public function modifyLimitQuery($query, $limit, $offset = null)
12958 if ($limit === null && $offset === null) {
12962 $limit = (int)$limit;
12963 $offset = (int)(($offset)?:0);
12965 // Todo OVER() needs ORDER BY data!
12966 $sql = 'SELECT db22.* FROM (SELECT ROW_NUMBER() OVER() AS DC_ROWNUM, db21.* '.
12967 'FROM (' . $query . ') db21) db22 WHERE db22.DC_ROWNUM BETWEEN ' . ($offset+1) .' AND ' . ($offset+$limit);
12972 * returns the position of the first occurrence of substring $substr in string $str
12974 * @param string $substr literal string to find
12975 * @param string $str literal string
12976 * @param int $pos position to start at, beginning of string by default
12979 public function getLocateExpression($str, $substr, $startPos = false)
12981 if ($startPos == false) {
12982 return 'LOCATE(' . $substr . ', ' . $str . ')';
12984 return 'LOCATE(' . $substr . ', ' . $str . ', '.$startPos.')';
12989 * return string to call a function to get a substring inside an SQL statement
12991 * Note: Not SQL92, but common functionality.
12993 * SQLite only supports the 2 parameter variant of this function
12995 * @param string $value an sql string literal or column name/alias
12996 * @param integer $from where to start the substring portion
12997 * @param integer $len the substring portion length
13000 public function getSubstringExpression($value, $from, $len = null)
13003 return 'SUBSTR(' . $value . ', ' . $from . ')';
13005 return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
13009 public function supportsIdentityColumns()
13014 public function prefersIdentityColumns()
13020 * Gets the character casing of a column in an SQL result set of this platform.
13022 * DB2 returns all column names in SQL result sets in uppercase.
13024 * @param string $column The column name for which to get the correct character casing.
13025 * @return string The column name in the character casing used in SQL result sets.
13027 public function getSQLResultCasing($column)
13029 return strtoupper($column);
13032 public function getForUpdateSQL()
13034 return ' WITH RR USE AND KEEP UPDATE LOCKS';
13037 public function getDummySelectSQL()
13039 return 'SELECT 1 FROM sysibm.sysdummy1';
13043 * DB2 supports savepoints, but they work semantically different than on other vendor platforms.
13045 * TODO: We have to investigate how to get DB2 up and running with savepoints.
13049 public function supportsSavepoints()
13055 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
13056 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
13057 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
13058 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
13059 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
13060 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
13061 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
13062 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13063 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13064 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13065 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13067 * This software consists of voluntary contributions made by many individuals
13068 * and is licensed under the LGPL. For more information, see
13069 * <http://www.doctrine-project.org>.
13072 namespace Doctrine\DBAL\Platforms;
13074 use Doctrine\DBAL\DBALException,
13075 Doctrine\DBAL\Schema\TableDiff;
13078 * The MySqlPlatform provides the behavior, features and SQL dialect of the
13079 * MySQL database platform. This platform represents a MySQL 5.0 or greater platform that
13080 * uses the InnoDB storage engine.
13083 * @author Roman Borschel <roman@code-factory.org>
13084 * @author Benjamin Eberlei <kontakt@beberlei.de>
13085 * @todo Rename: MySQLPlatform
13087 class MySqlPlatform extends AbstractPlatform
13090 * Gets the character used for identifier quoting.
13095 public function getIdentifierQuoteCharacter()
13101 * Returns the regular expression operator.
13106 public function getRegexpExpression()
13112 * Returns global unique identifier
13114 * @return string to get global unique identifier
13117 public function getGuidExpression()
13123 * returns the position of the first occurrence of substring $substr in string $str
13125 * @param string $substr literal string to find
13126 * @param string $str literal string
13127 * @param int $pos position to start at, beginning of string by default
13130 public function getLocateExpression($str, $substr, $startPos = false)
13132 if ($startPos == false) {
13133 return 'LOCATE(' . $substr . ', ' . $str . ')';
13135 return 'LOCATE(' . $substr . ', ' . $str . ', '.$startPos.')';
13140 * Returns a series of strings concatinated
13142 * concat() accepts an arbitrary number of parameters. Each parameter
13143 * must contain an expression or an array with expressions.
13145 * @param string|array(string) strings that will be concatinated.
13148 public function getConcatExpression()
13150 $args = func_get_args();
13151 return 'CONCAT(' . join(', ', (array) $args) . ')';
13154 public function getListDatabasesSQL()
13156 return 'SHOW DATABASES';
13159 public function getListTableConstraintsSQL($table)
13161 return 'SHOW INDEX FROM ' . $table;
13164 public function getListTableIndexesSQL($table)
13166 return 'SHOW INDEX FROM ' . $table;
13169 public function getListViewsSQL($database)
13171 return "SELECT * FROM information_schema.VIEWS WHERE TABLE_SCHEMA = '".$database."'";
13174 public function getListTableForeignKeysSQL($table, $database = null)
13176 $sql = "SELECT DISTINCT k.`CONSTRAINT_NAME`, k.`COLUMN_NAME`, k.`REFERENCED_TABLE_NAME`, ".
13177 "k.`REFERENCED_COLUMN_NAME` /*!50116 , c.update_rule, c.delete_rule */ ".
13178 "FROM information_schema.key_column_usage k /*!50116 ".
13179 "INNER JOIN information_schema.referential_constraints c ON ".
13180 " c.constraint_name = k.constraint_name AND ".
13181 " c.table_name = '$table' */ WHERE k.table_name = '$table'";
13184 $sql .= " AND k.table_schema = '$database' /*!50116 AND c.constraint_schema = '$database' */";
13187 $sql .= " AND k.`REFERENCED_COLUMN_NAME` is not NULL";
13192 public function getCreateViewSQL($name, $sql)
13194 return 'CREATE VIEW ' . $name . ' AS ' . $sql;
13197 public function getDropViewSQL($name)
13199 return 'DROP VIEW '. $name;
13203 * Gets the SQL snippet used to declare a VARCHAR column on the MySql platform.
13205 * @params array $field
13207 public function getVarcharTypeDeclarationSQL(array $field)
13209 if ( ! isset($field['length'])) {
13210 if (array_key_exists('default', $field)) {
13211 $field['length'] = $this->getVarcharMaxLength();
13213 $field['length'] = false;
13217 $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
13218 $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
13220 return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
13221 : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)');
13225 public function getClobTypeDeclarationSQL(array $field)
13227 if ( ! empty($field['length']) && is_numeric($field['length'])) {
13228 $length = $field['length'];
13229 if ($length <= 255) {
13231 } else if ($length <= 65532) {
13233 } else if ($length <= 16777215) {
13234 return 'MEDIUMTEXT';
13243 public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
13245 if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) {
13246 return 'TIMESTAMP';
13255 public function getDateTypeDeclarationSQL(array $fieldDeclaration)
13263 public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
13271 public function getBooleanTypeDeclarationSQL(array $field)
13273 return 'TINYINT(1)';
13277 * Obtain DBMS specific SQL code portion needed to set the COLLATION
13278 * of a field declaration to be used in statements like CREATE TABLE.
13280 * @param string $collation name of the collation
13281 * @return string DBMS specific SQL code portion needed to set the COLLATION
13282 * of a field declaration.
13284 public function getCollationFieldDeclaration($collation)
13286 return 'COLLATE ' . $collation;
13290 * Whether the platform prefers identity columns for ID generation.
13291 * MySql prefers "autoincrement" identity columns since sequences can only
13292 * be emulated with a table.
13297 public function prefersIdentityColumns()
13303 * Whether the platform supports identity columns.
13304 * MySql supports this through AUTO_INCREMENT columns.
13309 public function supportsIdentityColumns()
13314 public function getShowDatabasesSQL()
13316 return 'SHOW DATABASES';
13319 public function getListTablesSQL()
13321 return 'SHOW FULL TABLES WHERE Table_type = "BASE TABLE"';
13324 public function getListTableColumnsSQL($table)
13326 return 'DESCRIBE ' . $table;
13330 * create a new database
13332 * @param string $name name of the database that should be created
13336 public function getCreateDatabaseSQL($name)
13338 return 'CREATE DATABASE ' . $name;
13342 * drop an existing database
13344 * @param string $name name of the database that should be dropped
13348 public function getDropDatabaseSQL($name)
13350 return 'DROP DATABASE ' . $name;
13354 * create a new table
13356 * @param string $tableName Name of the database that should be created
13357 * @param array $columns Associative array that contains the definition of each field of the new table
13358 * The indexes of the array entries are the names of the fields of the table an
13359 * the array entry values are associative arrays like those that are meant to be
13360 * passed with the field definitions to get[Type]Declaration() functions.
13363 * 'type' => 'integer',
13369 * 'type' => 'text',
13372 * 'password' => array(
13373 * 'type' => 'text',
13377 * @param array $options An associative array of table options:
13379 * 'comment' => 'Foo',
13380 * 'charset' => 'utf8',
13381 * 'collate' => 'utf8_unicode_ci',
13382 * 'type' => 'innodb',
13388 protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
13390 $queryFields = $this->getColumnDeclarationListSQL($columns);
13392 if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
13393 foreach ($options['uniqueConstraints'] as $index => $definition) {
13394 $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition);
13399 if (isset($options['indexes']) && ! empty($options['indexes'])) {
13400 foreach($options['indexes'] as $index => $definition) {
13401 $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
13405 // attach all primary keys
13406 if (isset($options['primary']) && ! empty($options['primary'])) {
13407 $keyColumns = array_unique(array_values($options['primary']));
13408 $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
13411 $query = 'CREATE ';
13412 if (!empty($options['temporary'])) {
13413 $query .= 'TEMPORARY ';
13415 $query.= 'TABLE ' . $tableName . ' (' . $queryFields . ')';
13417 $optionStrings = array();
13419 if (isset($options['comment'])) {
13420 $optionStrings['comment'] = 'COMMENT = ' . $this->quote($options['comment'], 'text');
13422 if (isset($options['charset'])) {
13423 $optionStrings['charset'] = 'DEFAULT CHARACTER SET ' . $options['charset'];
13424 if (isset($options['collate'])) {
13425 $optionStrings['charset'] .= ' COLLATE ' . $options['collate'];
13429 // get the type of the table
13430 if (isset($options['engine'])) {
13431 $optionStrings[] = 'ENGINE = ' . $options['engine'];
13433 // default to innodb
13434 $optionStrings[] = 'ENGINE = InnoDB';
13437 if ( ! empty($optionStrings)) {
13438 $query.= ' '.implode(' ', $optionStrings);
13442 if (isset($options['foreignKeys'])) {
13443 foreach ((array) $options['foreignKeys'] as $definition) {
13444 $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
13452 * Gets the SQL to alter an existing table.
13454 * @param TableDiff $diff
13457 public function getAlterTableSQL(TableDiff $diff)
13459 $queryParts = array();
13460 if ($diff->newName !== false) {
13461 $queryParts[] = 'RENAME TO ' . $diff->newName;
13464 foreach ($diff->addedColumns AS $fieldName => $column) {
13465 $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
13468 foreach ($diff->removedColumns AS $column) {
13469 $queryParts[] = 'DROP ' . $column->getName();
13472 foreach ($diff->changedColumns AS $columnDiff) {
13473 /* @var $columnDiff Doctrine\DBAL\Schema\ColumnDiff */
13474 $column = $columnDiff->column;
13475 $queryParts[] = 'CHANGE ' . ($columnDiff->oldColumnName) . ' '
13476 . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
13479 foreach ($diff->renamedColumns AS $oldColumnName => $column) {
13480 $queryParts[] = 'CHANGE ' . $oldColumnName . ' '
13481 . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
13485 if (count($queryParts) > 0) {
13486 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(", ", $queryParts);
13488 $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
13493 * Obtain DBMS specific SQL code portion needed to declare an integer type
13494 * field to be used in statements like CREATE TABLE.
13496 * @param string $name name the field to be declared.
13497 * @param string $field associative array with the name of the properties
13498 * of the field being declared as array indexes.
13499 * Currently, the types of supported field
13500 * properties are as follows:
13503 * Boolean flag that indicates whether the field
13504 * should be declared as unsigned integer if
13508 * Integer value to be used as default for this
13512 * Boolean flag that indicates whether this field is
13513 * constrained to not be set to null.
13514 * @return string DBMS specific SQL code portion that should be used to
13515 * declare the specified field.
13518 public function getIntegerTypeDeclarationSQL(array $field)
13520 return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
13524 public function getBigIntTypeDeclarationSQL(array $field)
13526 return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
13530 public function getSmallIntTypeDeclarationSQL(array $field)
13532 return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
13536 protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
13539 if ( ! empty($columnDef['autoincrement'])) {
13540 $autoinc = ' AUTO_INCREMENT';
13542 $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : '';
13544 return $unsigned . $autoinc;
13548 * Return the FOREIGN KEY query section dealing with non-standard options
13549 * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
13551 * @param ForeignKeyConstraint $foreignKey
13555 public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey)
13558 if ($foreignKey->hasOption('match')) {
13559 $query .= ' MATCH ' . $foreignKey->getOption('match');
13561 $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
13566 * Gets the SQL to drop an index of a table.
13568 * @param Index $index name of the index to be dropped
13569 * @param string|Table $table name of table that should be used in method
13572 public function getDropIndexSQL($index, $table=null)
13574 if($index instanceof \Doctrine\DBAL\Schema\Index) {
13575 $index = $index->getName();
13576 } else if(!is_string($index)) {
13577 throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
13580 if($table instanceof \Doctrine\DBAL\Schema\Table) {
13581 $table = $table->getName();
13582 } else if(!is_string($table)) {
13583 throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
13586 return 'DROP INDEX ' . $index . ' ON ' . $table;
13590 * Gets the SQL to drop a table.
13592 * @param string $table The name of table to drop.
13595 public function getDropTableSQL($table)
13597 if ($table instanceof \Doctrine\DBAL\Schema\Table) {
13598 $table = $table->getName();
13599 } else if(!is_string($table)) {
13600 throw new \InvalidArgumentException('MysqlPlatform::getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
13603 return 'DROP TABLE ' . $table;
13606 public function getSetTransactionIsolationSQL($level)
13608 return 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level);
13612 * Get the platform name for this instance.
13616 public function getName()
13621 public function getReadLockSQL()
13623 return 'LOCK IN SHARE MODE';
13626 protected function initializeDoctrineTypeMappings()
13628 $this->doctrineTypeMapping = array(
13629 'tinyint' => 'boolean',
13630 'smallint' => 'smallint',
13631 'mediumint' => 'integer',
13632 'int' => 'integer',
13633 'integer' => 'integer',
13634 'bigint' => 'bigint',
13635 'tinytext' => 'text',
13636 'mediumtext' => 'text',
13637 'longtext' => 'text',
13639 'varchar' => 'string',
13640 'string' => 'string',
13641 'char' => 'string',
13643 'datetime' => 'datetime',
13644 'timestamp' => 'datetime',
13646 'float' => 'decimal',
13647 'double' => 'decimal',
13648 'real' => 'decimal',
13649 'decimal' => 'decimal',
13650 'numeric' => 'decimal',
13657 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
13658 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
13659 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
13660 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
13661 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
13662 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
13663 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
13664 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13665 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13666 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13667 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13669 * This software consists of voluntary contributions made by many individuals
13670 * and is licensed under the LGPL. For more information, see
13671 * <http://www.doctrine-project.org>.
13674 namespace Doctrine\DBAL\Platforms;
13676 use Doctrine\DBAL\DBALException,
13677 Doctrine\DBAL\Connection,
13678 Doctrine\DBAL\Types,
13679 Doctrine\DBAL\Schema\Table,
13680 Doctrine\DBAL\Schema\Index,
13681 Doctrine\DBAL\Schema\ForeignKeyConstraint,
13682 Doctrine\DBAL\Schema\TableDiff;
13685 * Base class for all DatabasePlatforms. The DatabasePlatforms are the central
13686 * point of abstraction of platform-specific behaviors, features and SQL dialects.
13687 * They are a passive source of information.
13689 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
13690 * @link www.doctrine-project.org
13692 * @version $Revision: 3938 $
13693 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
13694 * @author Jonathan Wage <jonwage@gmail.com>
13695 * @author Roman Borschel <roman@code-factory.org>
13696 * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
13697 * @author Benjamin Eberlei <kontakt@beberlei.de>
13698 * @todo Remove any unnecessary methods.
13700 abstract class AbstractPlatform
13705 const CREATE_INDEXES = 1;
13710 const CREATE_FOREIGNKEYS = 2;
13715 const TRIM_UNSPECIFIED = 0;
13720 const TRIM_LEADING = 1;
13725 const TRIM_TRAILING = 2;
13730 const TRIM_BOTH = 3;
13735 protected $doctrineTypeMapping = null;
13740 public function __construct() {}
13743 * Gets the SQL snippet that declares a boolean column.
13745 * @param array $columnDef
13748 abstract public function getBooleanTypeDeclarationSQL(array $columnDef);
13751 * Gets the SQL snippet that declares a 4 byte integer column.
13753 * @param array $columnDef
13756 abstract public function getIntegerTypeDeclarationSQL(array $columnDef);
13759 * Gets the SQL snippet that declares an 8 byte integer column.
13761 * @param array $columnDef
13764 abstract public function getBigIntTypeDeclarationSQL(array $columnDef);
13767 * Gets the SQL snippet that declares a 2 byte integer column.
13769 * @param array $columnDef
13772 abstract public function getSmallIntTypeDeclarationSQL(array $columnDef);
13775 * Gets the SQL snippet that declares common properties of an integer column.
13777 * @param array $columnDef
13780 abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef);
13783 * Lazy load Doctrine Type Mappings
13787 abstract protected function initializeDoctrineTypeMappings();
13790 * Gets the SQL snippet used to declare a VARCHAR column type.
13792 * @param array $field
13794 abstract public function getVarcharTypeDeclarationSQL(array $field);
13797 * Gets the SQL snippet used to declare a CLOB column type.
13799 * @param array $field
13801 abstract public function getClobTypeDeclarationSQL(array $field);
13804 * Gets the name of the platform.
13808 abstract public function getName();
13811 * Register a doctrine type to be used in conjunction with a column type of this platform.
13813 * @param string $dbType
13814 * @param string $doctrineType
13816 public function registerDoctrineTypeMapping($dbType, $doctrineType)
13818 if ($this->doctrineTypeMapping === null) {
13819 $this->initializeDoctrineTypeMappings();
13822 if (!Types\Type::hasType($doctrineType)) {
13823 throw DBALException::typeNotFound($doctrineType);
13826 $dbType = strtolower($dbType);
13827 $this->doctrineTypeMapping[$dbType] = $doctrineType;
13831 * Get the Doctrine type that is mapped for the given database column type.
13833 * @param string $dbType
13836 public function getDoctrineTypeMapping($dbType)
13838 if ($this->doctrineTypeMapping === null) {
13839 $this->initializeDoctrineTypeMappings();
13842 $dbType = strtolower($dbType);
13843 if (isset($this->doctrineTypeMapping[$dbType])) {
13844 return $this->doctrineTypeMapping[$dbType];
13846 throw new \Doctrine\DBAL\DBALException("Unknown database type ".$dbType." requested, " . get_class($this) . " may not support it.");
13851 * Check if a database type is currently supported by this platform.
13853 * @param string $dbType
13856 public function hasDoctrineTypeMappingFor($dbType)
13858 if ($this->doctrineTypeMapping === null) {
13859 $this->initializeDoctrineTypeMappings();
13862 $dbType = strtolower($dbType);
13863 return isset($this->doctrineTypeMapping[$dbType]);
13867 * Gets the character used for identifier quoting.
13871 public function getIdentifierQuoteCharacter()
13877 * Gets the string portion that starts an SQL comment.
13881 public function getSqlCommentStartString()
13887 * Gets the string portion that ends an SQL comment.
13891 public function getSqlCommentEndString()
13897 * Gets the maximum length of a varchar field.
13901 public function getVarcharMaxLength()
13907 * Gets all SQL wildcard characters of the platform.
13911 public function getWildcards()
13913 return array('%', '_');
13917 * Returns the regular expression operator.
13921 public function getRegexpExpression()
13923 throw DBALException::notSupported(__METHOD__);
13927 * Returns the average value of a column
13929 * @param string $column the column to use
13930 * @return string generated sql including an AVG aggregate function
13932 public function getAvgExpression($column)
13934 return 'AVG(' . $column . ')';
13938 * Returns the number of rows (without a NULL value) of a column
13940 * If a '*' is used instead of a column the number of selected rows
13943 * @param string|integer $column the column to use
13944 * @return string generated sql including a COUNT aggregate function
13946 public function getCountExpression($column)
13948 return 'COUNT(' . $column . ')';
13952 * Returns the highest value of a column
13954 * @param string $column the column to use
13955 * @return string generated sql including a MAX aggregate function
13957 public function getMaxExpression($column)
13959 return 'MAX(' . $column . ')';
13963 * Returns the lowest value of a column
13965 * @param string $column the column to use
13968 public function getMinExpression($column)
13970 return 'MIN(' . $column . ')';
13974 * Returns the total sum of a column
13976 * @param string $column the column to use
13979 public function getSumExpression($column)
13981 return 'SUM(' . $column . ')';
13984 // scalar functions
13987 * Returns the md5 sum of a field.
13989 * Note: Not SQL92, but common functionality
13993 public function getMd5Expression($column)
13995 return 'MD5(' . $column . ')';
13999 * Returns the length of a text field.
14001 * @param string $expression1
14002 * @param string $expression2
14005 public function getLengthExpression($column)
14007 return 'LENGTH(' . $column . ')';
14011 * Rounds a numeric field to the number of decimals specified.
14013 * @param string $expression1
14014 * @param string $expression2
14017 public function getRoundExpression($column, $decimals = 0)
14019 return 'ROUND(' . $column . ', ' . $decimals . ')';
14023 * Returns the remainder of the division operation
14024 * $expression1 / $expression2.
14026 * @param string $expression1
14027 * @param string $expression2
14030 public function getModExpression($expression1, $expression2)
14032 return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
14036 * Trim a string, leading/trailing/both and with a given char which defaults to space.
14038 * @param string $str
14040 * @param string $char has to be quoted already
14043 public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
14046 $trimChar = ($char != false) ? $char . ' FROM ' : '';
14048 if ($pos == self::TRIM_LEADING) {
14049 $posStr = 'LEADING '.$trimChar;
14050 } else if($pos == self::TRIM_TRAILING) {
14051 $posStr = 'TRAILING '.$trimChar;
14052 } else if($pos == self::TRIM_BOTH) {
14053 $posStr = 'BOTH '.$trimChar;
14056 return 'TRIM(' . $posStr . $str . ')';
14061 * returns the string $str with proceeding space characters removed
14063 * @param string $str literal string or column name
14066 public function getRtrimExpression($str)
14068 return 'RTRIM(' . $str . ')';
14073 * returns the string $str with leading space characters removed
14075 * @param string $str literal string or column name
14078 public function getLtrimExpression($str)
14080 return 'LTRIM(' . $str . ')';
14085 * Returns the string $str with all characters changed to
14086 * uppercase according to the current character set mapping.
14088 * @param string $str literal string or column name
14091 public function getUpperExpression($str)
14093 return 'UPPER(' . $str . ')';
14098 * Returns the string $str with all characters changed to
14099 * lowercase according to the current character set mapping.
14101 * @param string $str literal string or column name
14104 public function getLowerExpression($str)
14106 return 'LOWER(' . $str . ')';
14110 * returns the position of the first occurrence of substring $substr in string $str
14112 * @param string $substr literal string to find
14113 * @param string $str literal string
14114 * @param int $pos position to start at, beginning of string by default
14117 public function getLocateExpression($str, $substr, $startPos = false)
14119 throw DBALException::notSupported(__METHOD__);
14123 * Returns the current system date.
14127 public function getNowExpression()
14133 * return string to call a function to get a substring inside an SQL statement
14135 * Note: Not SQL92, but common functionality.
14137 * SQLite only supports the 2 parameter variant of this function
14139 * @param string $value an sql string literal or column name/alias
14140 * @param integer $from where to start the substring portion
14141 * @param integer $len the substring portion length
14144 public function getSubstringExpression($value, $from, $len = null)
14147 return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
14149 return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $len . ')';
14154 * Returns a series of strings concatinated
14156 * concat() accepts an arbitrary number of parameters. Each parameter
14157 * must contain an expression
14159 * @param string $arg1, $arg2 ... $argN strings that will be concatinated.
14162 public function getConcatExpression()
14164 return join(' || ' , func_get_args());
14168 * Returns the SQL for a logical not.
14172 * $q = new Doctrine_Query();
14174 * $q->select('*')->from('table')
14175 * ->where($e->eq('id', $e->not('null'));
14178 * @return string a logical expression
14180 public function getNotExpression($expression)
14182 return 'NOT(' . $expression . ')';
14186 * Returns the SQL to check if a value is one in a set of
14189 * in() accepts an arbitrary number of parameters. The first parameter
14190 * must always specify the value that should be matched against. Successive
14191 * must contain a logical expression or an array with logical expressions.
14192 * These expressions will be matched against the first parameter.
14194 * @param string $column the value that should be matched against
14195 * @param string|array(string) values that will be matched against $column
14196 * @return string logical expression
14198 public function getInExpression($column, $values)
14200 if ( ! is_array($values)) {
14201 $values = array($values);
14203 $values = $this->getIdentifiers($values);
14205 if (count($values) == 0) {
14206 throw \InvalidArgumentException('Values must not be empty.');
14208 return $column . ' IN (' . implode(', ', $values) . ')';
14212 * Returns SQL that checks if a expression is null.
14214 * @param string $expression the expression that should be compared to null
14215 * @return string logical expression
14217 public function getIsNullExpression($expression)
14219 return $expression . ' IS NULL';
14223 * Returns SQL that checks if a expression is not null.
14225 * @param string $expression the expression that should be compared to null
14226 * @return string logical expression
14228 public function getIsNotNullExpression($expression)
14230 return $expression . ' IS NOT NULL';
14234 * Returns SQL that checks if an expression evaluates to a value between
14237 * The parameter $expression is checked if it is between $value1 and $value2.
14239 * Note: There is a slight difference in the way BETWEEN works on some databases.
14240 * http://www.w3schools.com/sql/sql_between.asp. If you want complete database
14241 * independence you should avoid using between().
14243 * @param string $expression the value to compare to
14244 * @param string $value1 the lower value to compare with
14245 * @param string $value2 the higher value to compare with
14246 * @return string logical expression
14248 public function getBetweenExpression($expression, $value1, $value2)
14250 return $expression . ' BETWEEN ' .$value1 . ' AND ' . $value2;
14253 public function getAcosExpression($value)
14255 return 'ACOS(' . $value . ')';
14258 public function getSinExpression($value)
14260 return 'SIN(' . $value . ')';
14263 public function getPiExpression()
14268 public function getCosExpression($value)
14270 return 'COS(' . $value . ')';
14273 public function getForUpdateSQL()
14275 return 'FOR UPDATE';
14279 * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
14281 * @param string $fromClause
14282 * @param int $lockMode
14285 public function appendLockHint($fromClause, $lockMode)
14287 return $fromClause;
14291 * Get the sql snippet to append to any SELECT statement which locks rows in shared read lock.
14293 * This defaults to the ASNI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database
14294 * vendors allow to lighten this constraint up to be a real read lock.
14298 public function getReadLockSQL()
14300 return $this->getForUpdateSQL();
14304 * Get the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
14306 * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ASNI SQL standard.
14310 public function getWriteLockSQL()
14312 return $this->getForUpdateSQL();
14315 public function getDropDatabaseSQL($database)
14317 return 'DROP DATABASE ' . $database;
14323 * @param Table|string $table
14326 public function getDropTableSQL($table)
14328 if ($table instanceof \Doctrine\DBAL\Schema\Table) {
14329 $table = $table->getName();
14332 return 'DROP TABLE ' . $table;
14336 * Drop index from a table
14338 * @param Index|string $name
14339 * @param string|Table $table
14342 public function getDropIndexSQL($index, $table=null)
14344 if($index instanceof \Doctrine\DBAL\Schema\Index) {
14345 $index = $index->getName();
14346 } else if(!is_string($index)) {
14347 throw new \InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
14350 return 'DROP INDEX ' . $index;
14354 * Get drop constraint sql
14356 * @param \Doctrine\DBAL\Schema\Constraint $constraint
14357 * @param string|Table $table
14360 public function getDropConstraintSQL($constraint, $table)
14362 if ($constraint instanceof \Doctrine\DBAL\Schema\Constraint) {
14363 $constraint = $constraint->getName();
14366 if ($table instanceof \Doctrine\DBAL\Schema\Table) {
14367 $table = $table->getName();
14370 return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint;
14374 * @param ForeignKeyConstraint|string $foreignKey
14375 * @param Table|string $table
14378 public function getDropForeignKeySQL($foreignKey, $table)
14380 if ($foreignKey instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) {
14381 $foreignKey = $foreignKey->getName();
14384 if ($table instanceof \Doctrine\DBAL\Schema\Table) {
14385 $table = $table->getName();
14388 return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey;
14392 * Gets the SQL statement(s) to create a table with the specified name, columns and constraints
14393 * on this platform.
14395 * @param string $table The name of the table.
14396 * @param int $createFlags
14397 * @return array The sequence of SQL statements.
14399 public function getCreateTableSQL(Table $table, $createFlags=self::CREATE_INDEXES)
14401 if ( ! is_int($createFlags)) {
14402 throw new \InvalidArgumentException("Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.");
14405 if (count($table->getColumns()) == 0) {
14406 throw DBALException::noColumnsSpecifiedForTable($table->getName());
14409 $tableName = $table->getName();
14410 $options = $table->getOptions();
14411 $options['uniqueConstraints'] = array();
14412 $options['indexes'] = array();
14413 $options['primary'] = array();
14415 if (($createFlags&self::CREATE_INDEXES) > 0) {
14416 foreach ($table->getIndexes() AS $index) {
14417 /* @var $index Index */
14418 if ($index->isPrimary()) {
14419 $options['primary'] = $index->getColumns();
14421 $options['indexes'][$index->getName()] = $index;
14426 $columns = array();
14427 foreach ($table->getColumns() AS $column) {
14428 /* @var \Doctrine\DBAL\Schema\Column $column */
14429 $columnData = array();
14430 $columnData['name'] = $column->getName();
14431 $columnData['type'] = $column->getType();
14432 $columnData['length'] = $column->getLength();
14433 $columnData['notnull'] = $column->getNotNull();
14434 $columnData['unique'] = false; // TODO: what do we do about this?
14435 $columnData['version'] = ($column->hasPlatformOption("version"))?$column->getPlatformOption('version'):false;
14436 if(strtolower($columnData['type']) == "string" && $columnData['length'] === null) {
14437 $columnData['length'] = 255;
14439 $columnData['precision'] = $column->getPrecision();
14440 $columnData['scale'] = $column->getScale();
14441 $columnData['default'] = $column->getDefault();
14442 $columnData['columnDefinition'] = $column->getColumnDefinition();
14443 $columnData['autoincrement'] = $column->getAutoincrement();
14445 if(in_array($column->getName(), $options['primary'])) {
14446 $columnData['primary'] = true;
14449 $columns[$columnData['name']] = $columnData;
14452 if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) {
14453 $options['foreignKeys'] = array();
14454 foreach ($table->getForeignKeys() AS $fkConstraint) {
14455 $options['foreignKeys'][] = $fkConstraint;
14459 return $this->_getCreateTableSQL($tableName, $columns, $options);
14463 * @param string $tableName
14464 * @param array $columns
14465 * @param array $options
14468 protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
14470 $columnListSql = $this->getColumnDeclarationListSQL($columns);
14472 if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
14473 foreach ($options['uniqueConstraints'] as $name => $definition) {
14474 $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
14478 if (isset($options['primary']) && ! empty($options['primary'])) {
14479 $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
14482 if (isset($options['indexes']) && ! empty($options['indexes'])) {
14483 foreach($options['indexes'] as $index => $definition) {
14484 $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
14488 $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
14490 $check = $this->getCheckDeclarationSQL($columns);
14491 if ( ! empty($check)) {
14492 $query .= ', ' . $check;
14498 if (isset($options['foreignKeys'])) {
14499 foreach ((array) $options['foreignKeys'] AS $definition) {
14500 $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
14507 public function getCreateTemporaryTableSnippetSQL()
14509 return "CREATE TEMPORARY TABLE";
14513 * Gets the SQL to create a sequence on this platform.
14515 * @param \Doctrine\DBAL\Schema\Sequence $sequence
14516 * @throws DBALException
14518 public function getCreateSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
14520 throw DBALException::notSupported(__METHOD__);
14524 * Gets the SQL to create a constraint on a table on this platform.
14526 * @param Constraint $constraint
14527 * @param string|Table $table
14530 public function getCreateConstraintSQL(\Doctrine\DBAL\Schema\Constraint $constraint, $table)
14532 if ($table instanceof \Doctrine\DBAL\Schema\Table) {
14533 $table = $table->getName();
14536 $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getName();
14538 $columns = array();
14539 foreach ($constraint->getColumns() as $column) {
14540 $columns[] = $column;
14542 $columnList = '('. implode(', ', $columns) . ')';
14544 $referencesClause = '';
14545 if ($constraint instanceof \Doctrine\DBAL\Schema\Index) {
14546 if($constraint->isPrimary()) {
14547 $query .= ' PRIMARY KEY';
14548 } elseif ($constraint->isUnique()) {
14549 $query .= ' UNIQUE';
14551 throw new \InvalidArgumentException(
14552 'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
14555 } else if ($constraint instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) {
14556 $query .= ' FOREIGN KEY';
14558 $foreignColumns = array();
14559 foreach ($constraint->getForeignColumns() AS $column) {
14560 $foreignColumns[] = $column;
14563 $referencesClause = ' REFERENCES '.$constraint->getForeignTableName(). ' ('.implode(', ', $foreignColumns).')';
14565 $query .= ' '.$columnList.$referencesClause;
14571 * Gets the SQL to create an index on a table on this platform.
14573 * @param Index $index
14574 * @param string|Table $table name of the table on which the index is to be created
14577 public function getCreateIndexSQL(Index $index, $table)
14579 if ($table instanceof Table) {
14580 $table = $table->getName();
14582 $name = $index->getName();
14583 $columns = $index->getColumns();
14585 if (count($columns) == 0) {
14586 throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
14590 if ($index->isUnique()) {
14594 $query = 'CREATE ' . $type . 'INDEX ' . $name . ' ON ' . $table;
14596 $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')';
14602 * Quotes a string so that it can be safely used as a table or column name,
14603 * even if it is a reserved word of the platform.
14605 * NOTE: Just because you CAN use quoted identifiers doesn't mean
14606 * you SHOULD use them. In general, they end up causing way more
14607 * problems than they solve.
14609 * @param string $str identifier name to be quoted
14610 * @return string quoted identifier string
14612 public function quoteIdentifier($str)
14614 $c = $this->getIdentifierQuoteCharacter();
14616 return $c . $str . $c;
14620 * Create a new foreign key
14622 * @param ForeignKeyConstraint $foreignKey ForeignKey instance
14623 * @param string|Table $table name of the table on which the foreign key is to be created
14626 public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
14628 if ($table instanceof \Doctrine\DBAL\Schema\Table) {
14629 $table = $table->getName();
14632 $query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
14638 * Gets the sql statements for altering an existing table.
14640 * The method returns an array of sql statements, since some platforms need several statements.
14642 * @param TableDiff $diff
14645 public function getAlterTableSQL(TableDiff $diff)
14647 throw DBALException::notSupported(__METHOD__);
14651 * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
14653 * @param TableDiff $diff
14656 protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff)
14658 if ($diff->newName !== false) {
14659 $tableName = $diff->newName;
14661 $tableName = $diff->name;
14665 if ($this->supportsForeignKeyConstraints()) {
14666 foreach ($diff->removedForeignKeys AS $foreignKey) {
14667 $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
14669 foreach ($diff->addedForeignKeys AS $foreignKey) {
14670 $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
14672 foreach ($diff->changedForeignKeys AS $foreignKey) {
14673 $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
14674 $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
14678 foreach ($diff->addedIndexes AS $index) {
14679 $sql[] = $this->getCreateIndexSQL($index, $tableName);
14681 foreach ($diff->removedIndexes AS $index) {
14682 $sql[] = $this->getDropIndexSQL($index, $tableName);
14684 foreach ($diff->changedIndexes AS $index) {
14685 $sql[] = $this->getDropIndexSQL($index, $tableName);
14686 $sql[] = $this->getCreateIndexSQL($index, $tableName);
14693 * Get declaration of a number of fields in bulk
14695 * @param array $fields a multidimensional associative array.
14696 * The first dimension determines the field name, while the second
14697 * dimension is keyed with the name of the properties
14698 * of the field being declared as array indexes. Currently, the types
14699 * of supported field properties are as follows:
14702 * Integer value that determines the maximum length of the text
14703 * field. If this argument is missing the field should be
14704 * declared to have the longest length allowed by the DBMS.
14707 * Text value to be used as default for this field.
14710 * Boolean flag that indicates whether this field is constrained
14711 * to not be set to null.
14713 * Text value with the default CHARACTER SET for this field.
14715 * Text value with the default COLLATION for this field.
14717 * unique constraint
14721 public function getColumnDeclarationListSQL(array $fields)
14723 $queryFields = array();
14724 foreach ($fields as $fieldName => $field) {
14725 $query = $this->getColumnDeclarationSQL($fieldName, $field);
14726 $queryFields[] = $query;
14728 return implode(', ', $queryFields);
14732 * Obtain DBMS specific SQL code portion needed to declare a generic type
14733 * field to be used in statements like CREATE TABLE.
14735 * @param string $name name the field to be declared.
14736 * @param array $field associative array with the name of the properties
14737 * of the field being declared as array indexes. Currently, the types
14738 * of supported field properties are as follows:
14741 * Integer value that determines the maximum length of the text
14742 * field. If this argument is missing the field should be
14743 * declared to have the longest length allowed by the DBMS.
14746 * Text value to be used as default for this field.
14749 * Boolean flag that indicates whether this field is constrained
14750 * to not be set to null.
14752 * Text value with the default CHARACTER SET for this field.
14754 * Text value with the default COLLATION for this field.
14756 * unique constraint
14758 * column check constraint
14760 * a string that defines the complete column
14762 * @return string DBMS specific SQL code portion that should be used to declare the column.
14764 public function getColumnDeclarationSQL($name, array $field)
14766 if (isset($field['columnDefinition'])) {
14767 $columnDef = $this->getCustomTypeDeclarationSQL($field);
14769 $default = $this->getDefaultValueDeclarationSQL($field);
14771 $charset = (isset($field['charset']) && $field['charset']) ?
14772 ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : '';
14774 $collation = (isset($field['collation']) && $field['collation']) ?
14775 ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
14777 $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : '';
14779 $unique = (isset($field['unique']) && $field['unique']) ?
14780 ' ' . $this->getUniqueFieldDeclarationSQL() : '';
14782 $check = (isset($field['check']) && $field['check']) ?
14783 ' ' . $field['check'] : '';
14785 $typeDecl = $field['type']->getSqlDeclaration($field, $this);
14786 $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
14789 return $name . ' ' . $columnDef;
14793 * Gets the SQL snippet that declares a floating point column of arbitrary precision.
14795 * @param array $columnDef
14798 public function getDecimalTypeDeclarationSQL(array $columnDef)
14800 $columnDef['precision'] = ( ! isset($columnDef['precision']) || empty($columnDef['precision']))
14801 ? 10 : $columnDef['precision'];
14802 $columnDef['scale'] = ( ! isset($columnDef['scale']) || empty($columnDef['scale']))
14803 ? 0 : $columnDef['scale'];
14805 return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')';
14809 * Obtain DBMS specific SQL code portion needed to set a default value
14810 * declaration to be used in statements like CREATE TABLE.
14812 * @param array $field field definition array
14813 * @return string DBMS specific SQL code portion needed to set a default value
14815 public function getDefaultValueDeclarationSQL($field)
14817 $default = empty($field['notnull']) ? ' DEFAULT NULL' : '';
14819 if (isset($field['default'])) {
14820 $default = " DEFAULT '".$field['default']."'";
14821 if (isset($field['type'])) {
14822 if (in_array((string)$field['type'], array("Integer", "BigInteger", "SmallInteger"))) {
14823 $default = " DEFAULT ".$field['default'];
14824 } else if ((string)$field['type'] == 'DateTime' && $field['default'] == $this->getCurrentTimestampSQL()) {
14825 $default = " DEFAULT ".$this->getCurrentTimestampSQL();
14833 * Obtain DBMS specific SQL code portion needed to set a CHECK constraint
14834 * declaration to be used in statements like CREATE TABLE.
14836 * @param array $definition check definition
14837 * @return string DBMS specific SQL code portion needed to set a CHECK constraint
14839 public function getCheckDeclarationSQL(array $definition)
14841 $constraints = array();
14842 foreach ($definition as $field => $def) {
14843 if (is_string($def)) {
14844 $constraints[] = 'CHECK (' . $def . ')';
14846 if (isset($def['min'])) {
14847 $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')';
14850 if (isset($def['max'])) {
14851 $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')';
14856 return implode(', ', $constraints);
14860 * Obtain DBMS specific SQL code portion needed to set a unique
14861 * constraint declaration to be used in statements like CREATE TABLE.
14863 * @param string $name name of the unique constraint
14864 * @param Index $index index definition
14865 * @return string DBMS specific SQL code portion needed
14866 * to set a constraint
14868 public function getUniqueConstraintDeclarationSQL($name, Index $index)
14870 if (count($index->getColumns()) == 0) {
14871 throw \InvalidArgumentException("Incomplete definition. 'columns' required.");
14874 return 'CONSTRAINT ' . $name . ' UNIQUE ('
14875 . $this->getIndexFieldDeclarationListSQL($index->getColumns())
14880 * Obtain DBMS specific SQL code portion needed to set an index
14881 * declaration to be used in statements like CREATE TABLE.
14883 * @param string $name name of the index
14884 * @param Index $index index definition
14885 * @return string DBMS specific SQL code portion needed to set an index
14887 public function getIndexDeclarationSQL($name, Index $index)
14891 if($index->isUnique()) {
14895 if (count($index->getColumns()) == 0) {
14896 throw \InvalidArgumentException("Incomplete definition. 'columns' required.");
14899 return $type . 'INDEX ' . $name . ' ('
14900 . $this->getIndexFieldDeclarationListSQL($index->getColumns())
14905 * getCustomTypeDeclarationSql
14906 * Obtail SQL code portion needed to create a custom column,
14907 * e.g. when a field has the "columnDefinition" keyword.
14908 * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate.
14912 public function getCustomTypeDeclarationSQL(array $columnDef)
14914 return $columnDef['columnDefinition'];
14918 * getIndexFieldDeclarationList
14919 * Obtain DBMS specific SQL code portion needed to set an index
14920 * declaration to be used in statements like CREATE TABLE.
14924 public function getIndexFieldDeclarationListSQL(array $fields)
14927 foreach ($fields as $field => $definition) {
14928 if (is_array($definition)) {
14931 $ret[] = $definition;
14934 return implode(', ', $ret);
14938 * A method to return the required SQL string that fits between CREATE ... TABLE
14939 * to create the table as a temporary table.
14941 * Should be overridden in driver classes to return the correct string for the
14942 * specific database type.
14944 * The default is to return the string "TEMPORARY" - this will result in a
14945 * SQL error for any database that does not support temporary tables, or that
14946 * requires a different SQL command from "CREATE TEMPORARY TABLE".
14948 * @return string The string required to be placed between "CREATE" and "TABLE"
14949 * to generate a temporary table, if possible.
14951 public function getTemporaryTableSQL()
14953 return 'TEMPORARY';
14957 * Some vendors require temporary table names to be qualified specially.
14959 * @param string $tableName
14962 public function getTemporaryTableName($tableName)
14968 * Get sql query to show a list of database.
14972 public function getShowDatabasesSQL()
14974 throw DBALException::notSupported(__METHOD__);
14978 * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
14979 * of a field declaration to be used in statements like CREATE TABLE.
14981 * @param array $definition an associative array with the following structure:
14982 * name optional constraint name
14984 * local the local field(s)
14986 * foreign the foreign reference field(s)
14988 * foreignTable the name of the foreign table
14990 * onDelete referential delete action
14992 * onUpdate referential update action
14994 * deferred deferred constraint checking
14996 * The onDelete and onUpdate keys accept the following values:
14998 * CASCADE: Delete or update the row from the parent table and automatically delete or
14999 * update the matching rows in the child table. Both ON DELETE CASCADE and ON UPDATE CASCADE are supported.
15000 * Between two tables, you should not define several ON UPDATE CASCADE clauses that act on the same column
15001 * in the parent table or in the child table.
15003 * SET NULL: Delete or update the row from the parent table and set the foreign key column or columns in the
15004 * child table to NULL. This is valid only if the foreign key columns do not have the NOT NULL qualifier
15005 * specified. Both ON DELETE SET NULL and ON UPDATE SET NULL clauses are supported.
15007 * NO ACTION: In standard SQL, NO ACTION means no action in the sense that an attempt to delete or update a primary
15008 * key value is not allowed to proceed if there is a related foreign key value in the referenced table.
15010 * RESTRICT: Rejects the delete or update operation for the parent table. NO ACTION and RESTRICT are the same as
15011 * omitting the ON DELETE or ON UPDATE clause.
15015 * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
15016 * of a field declaration.
15018 public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
15020 $sql = $this->getForeignKeyBaseDeclarationSQL($foreignKey);
15021 $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey);
15027 * Return the FOREIGN KEY query section dealing with non-standard options
15028 * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
15030 * @param ForeignKeyConstraint $foreignKey foreign key definition
15033 public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
15036 if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) {
15037 $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate'));
15039 if ($foreignKey->hasOption('onDelete')) {
15040 $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete'));
15046 * returns given referential action in uppercase if valid, otherwise throws
15049 * @throws Doctrine_Exception_Exception if unknown referential action given
15050 * @param string $action foreign key referential action
15051 * @param string foreign key referential action in uppercase
15053 public function getForeignKeyReferentialActionSQL($action)
15055 $upper = strtoupper($action);
15061 case 'SET DEFAULT':
15065 throw \InvalidArgumentException('Invalid foreign key action: ' . $upper);
15070 * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
15071 * of a field declaration to be used in statements like CREATE TABLE.
15073 * @param ForeignKeyConstraint $foreignKey
15076 public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
15079 if (strlen($foreignKey->getName())) {
15080 $sql .= 'CONSTRAINT ' . $foreignKey->getName() . ' ';
15082 $sql .= 'FOREIGN KEY (';
15084 if (count($foreignKey->getLocalColumns()) == 0) {
15085 throw new \InvalidArgumentException("Incomplete definition. 'local' required.");
15087 if (count($foreignKey->getForeignColumns()) == 0) {
15088 throw new \InvalidArgumentException("Incomplete definition. 'foreign' required.");
15090 if (strlen($foreignKey->getForeignTableName()) == 0) {
15091 throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
15094 $sql .= implode(', ', $foreignKey->getLocalColumns())
15096 . $foreignKey->getForeignTableName() . '('
15097 . implode(', ', $foreignKey->getForeignColumns()) . ')';
15103 * Obtain DBMS specific SQL code portion needed to set the UNIQUE constraint
15104 * of a field declaration to be used in statements like CREATE TABLE.
15106 * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint
15107 * of a field declaration.
15109 public function getUniqueFieldDeclarationSQL()
15115 * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
15116 * of a field declaration to be used in statements like CREATE TABLE.
15118 * @param string $charset name of the charset
15119 * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
15120 * of a field declaration.
15122 public function getColumnCharsetDeclarationSQL($charset)
15128 * Obtain DBMS specific SQL code portion needed to set the COLLATION
15129 * of a field declaration to be used in statements like CREATE TABLE.
15131 * @param string $collation name of the collation
15132 * @return string DBMS specific SQL code portion needed to set the COLLATION
15133 * of a field declaration.
15135 public function getColumnCollationDeclarationSQL($collation)
15141 * Whether the platform prefers sequences for ID generation.
15142 * Subclasses should override this method to return TRUE if they prefer sequences.
15146 public function prefersSequences()
15152 * Whether the platform prefers identity columns (eg. autoincrement) for ID generation.
15153 * Subclasses should override this method to return TRUE if they prefer identity columns.
15157 public function prefersIdentityColumns()
15163 * Some platforms need the boolean values to be converted.
15165 * The default conversion in this implementation converts to integers (false => 0, true => 1).
15167 * @param mixed $item
15169 public function convertBooleans($item)
15171 if (is_array($item)) {
15172 foreach ($item as $k => $value) {
15173 if (is_bool($value)) {
15174 $item[$k] = (int) $value;
15177 } else if (is_bool($item)) {
15178 $item = (int) $item;
15184 * Gets the SQL statement specific for the platform to set the charset.
15186 * This function is MySQL specific and required by
15187 * {@see \Doctrine\DBAL\Connection::setCharset($charset)}
15189 * @param string $charset
15192 public function getSetCharsetSQL($charset)
15194 return "SET NAMES '".$charset."'";
15198 * Gets the SQL specific for the platform to get the current date.
15202 public function getCurrentDateSQL()
15204 return 'CURRENT_DATE';
15208 * Gets the SQL specific for the platform to get the current time.
15212 public function getCurrentTimeSQL()
15214 return 'CURRENT_TIME';
15218 * Gets the SQL specific for the platform to get the current timestamp
15222 public function getCurrentTimestampSQL()
15224 return 'CURRENT_TIMESTAMP';
15228 * Get sql for transaction isolation level Connection constant
15230 * @param integer $level
15232 protected function _getTransactionIsolationLevelSQL($level)
15235 case Connection::TRANSACTION_READ_UNCOMMITTED:
15236 return 'READ UNCOMMITTED';
15237 case Connection::TRANSACTION_READ_COMMITTED:
15238 return 'READ COMMITTED';
15239 case Connection::TRANSACTION_REPEATABLE_READ:
15240 return 'REPEATABLE READ';
15241 case Connection::TRANSACTION_SERIALIZABLE:
15242 return 'SERIALIZABLE';
15244 throw new \InvalidArgumentException('Invalid isolation level:' . $level);
15248 public function getListDatabasesSQL()
15250 throw DBALException::notSupported(__METHOD__);
15253 public function getListSequencesSQL($database)
15255 throw DBALException::notSupported(__METHOD__);
15258 public function getListTableConstraintsSQL($table)
15260 throw DBALException::notSupported(__METHOD__);
15263 public function getListTableColumnsSQL($table)
15265 throw DBALException::notSupported(__METHOD__);
15268 public function getListTablesSQL()
15270 throw DBALException::notSupported(__METHOD__);
15273 public function getListUsersSQL()
15275 throw DBALException::notSupported(__METHOD__);
15279 * Get the SQL to list all views of a database or user.
15281 * @param string $database
15284 public function getListViewsSQL($database)
15286 throw DBALException::notSupported(__METHOD__);
15289 public function getListTableIndexesSQL($table)
15291 throw DBALException::notSupported(__METHOD__);
15294 public function getListTableForeignKeysSQL($table)
15296 throw DBALException::notSupported(__METHOD__);
15299 public function getCreateViewSQL($name, $sql)
15301 throw DBALException::notSupported(__METHOD__);
15304 public function getDropViewSQL($name)
15306 throw DBALException::notSupported(__METHOD__);
15309 public function getDropSequenceSQL($sequence)
15311 throw DBALException::notSupported(__METHOD__);
15314 public function getSequenceNextValSQL($sequenceName)
15316 throw DBALException::notSupported(__METHOD__);
15319 public function getCreateDatabaseSQL($database)
15321 throw DBALException::notSupported(__METHOD__);
15325 * Get sql to set the transaction isolation level
15327 * @param integer $level
15329 public function getSetTransactionIsolationSQL($level)
15331 throw DBALException::notSupported(__METHOD__);
15335 * Obtain DBMS specific SQL to be used to create datetime fields in
15336 * statements like CREATE TABLE
15338 * @param array $fieldDeclaration
15341 public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
15343 throw DBALException::notSupported(__METHOD__);
15347 * Obtain DBMS specific SQL to be used to create datetime with timezone offset fields.
15349 * @param array $fieldDeclaration
15351 public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
15353 return $this->getDateTimeTypeDeclarationSQL($fieldDeclaration);
15358 * Obtain DBMS specific SQL to be used to create date fields in statements
15359 * like CREATE TABLE.
15361 * @param array $fieldDeclaration
15364 public function getDateTypeDeclarationSQL(array $fieldDeclaration)
15366 throw DBALException::notSupported(__METHOD__);
15370 * Obtain DBMS specific SQL to be used to create time fields in statements
15371 * like CREATE TABLE.
15373 * @param array $fieldDeclaration
15376 public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
15378 throw DBALException::notSupported(__METHOD__);
15381 public function getFloatDeclarationSQL(array $fieldDeclaration)
15383 return 'DOUBLE PRECISION';
15387 * Gets the default transaction isolation level of the platform.
15389 * @return integer The default isolation level.
15390 * @see Doctrine\DBAL\Connection\TRANSACTION_* constants.
15392 public function getDefaultTransactionIsolationLevel()
15394 return Connection::TRANSACTION_READ_COMMITTED;
15397 /* supports*() metods */
15400 * Whether the platform supports sequences.
15404 public function supportsSequences()
15410 * Whether the platform supports identity columns.
15411 * Identity columns are columns that recieve an auto-generated value from the
15412 * database on insert of a row.
15416 public function supportsIdentityColumns()
15422 * Whether the platform supports indexes.
15426 public function supportsIndexes()
15431 public function supportsAlterTable()
15437 * Whether the platform supports transactions.
15441 public function supportsTransactions()
15447 * Whether the platform supports savepoints.
15451 public function supportsSavepoints()
15457 * Whether the platform supports releasing savepoints.
15461 public function supportsReleaseSavepoints()
15463 return $this->supportsSavepoints();
15467 * Whether the platform supports primary key constraints.
15471 public function supportsPrimaryConstraints()
15477 * Does the platform supports foreign key constraints?
15481 public function supportsForeignKeyConstraints()
15487 * Does this platform supports onUpdate in foreign key constraints?
15491 public function supportsForeignKeyOnUpdate()
15493 return ($this->supportsForeignKeyConstraints() && true);
15497 * Whether the platform supports database schemas.
15501 public function supportsSchemas()
15507 * Some databases don't allow to create and drop databases at all or only with certain tools.
15511 public function supportsCreateDropDatabase()
15517 * Whether the platform supports getting the affected rows of a recent
15518 * update/delete type query.
15522 public function supportsGettingAffectedRows()
15527 public function getIdentityColumnNullInsertSQL()
15533 * Gets the format string, as accepted by the date() function, that describes
15534 * the format of a stored datetime value of this platform.
15536 * @return string The format string.
15538 public function getDateTimeFormatString()
15540 return 'Y-m-d H:i:s';
15544 * Gets the format string, as accepted by the date() function, that describes
15545 * the format of a stored datetime with timezone value of this platform.
15547 * @return string The format string.
15549 public function getDateTimeTzFormatString()
15551 return 'Y-m-d H:i:s';
15555 * Gets the format string, as accepted by the date() function, that describes
15556 * the format of a stored date value of this platform.
15558 * @return string The format string.
15560 public function getDateFormatString()
15566 * Gets the format string, as accepted by the date() function, that describes
15567 * the format of a stored time value of this platform.
15569 * @return string The format string.
15571 public function getTimeFormatString()
15576 public function modifyLimitQuery($query, $limit, $offset = null)
15578 if ( ! is_null($limit)) {
15579 $query .= ' LIMIT ' . $limit;
15582 if ( ! is_null($offset)) {
15583 $query .= ' OFFSET ' . $offset;
15590 * Gets the character casing of a column in an SQL result set of this platform.
15592 * @param string $column The column name for which to get the correct character casing.
15593 * @return string The column name in the character casing used in SQL result sets.
15595 public function getSQLResultCasing($column)
15601 * Makes any fixes to a name of a schema element (table, sequence, ...) that are required
15602 * by restrictions of the platform, like a maximum length.
15604 * @param string $schemaName
15607 public function fixSchemaElementName($schemaElementName)
15609 return $schemaElementName;
15613 * Maximum length of any given databse identifier, like tables or column names.
15617 public function getMaxIdentifierLength()
15623 * Get the insert sql for an empty insert statement
15625 * @param string $tableName
15626 * @param string $identifierColumnName
15627 * @return string $sql
15629 public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName)
15631 return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (null)';
15635 * Generate a Truncate Table SQL statement for a given table.
15637 * Cascade is not supported on many platforms but would optionally cascade the truncate by
15638 * following the foreign keys.
15640 * @param string $tableName
15641 * @param bool $cascade
15644 public function getTruncateTableSQL($tableName, $cascade = false)
15646 return 'TRUNCATE '.$tableName;
15650 * This is for test reasons, many vendors have special requirements for dummy statements.
15654 public function getDummySelectSQL()
15660 * Generate SQL to create a new savepoint
15662 * @param string $savepoint
15665 public function createSavePoint($savepoint)
15667 return 'SAVEPOINT ' . $savepoint;
15671 * Generate SQL to release a savepoint
15673 * @param string $savepoint
15676 public function releaseSavePoint($savepoint)
15678 return 'RELEASE SAVEPOINT ' . $savepoint;
15682 * Generate SQL to rollback a savepoint
15684 * @param string $savepoint
15687 public function rollbackSavePoint($savepoint)
15689 return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
15693 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15694 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15695 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
15696 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
15697 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
15698 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
15699 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
15700 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
15701 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
15702 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15703 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15705 * This software consists of voluntary contributions made by many individuals
15706 * and is licensed under the LGPL. For more information, see
15707 * <http://www.doctrine-project.org>.
15710 namespace Doctrine\DBAL\Platforms;
15712 use Doctrine\DBAL\DBALException;
15715 * The SqlitePlatform class describes the specifics and dialects of the SQLite
15716 * database platform.
15719 * @author Roman Borschel <roman@code-factory.org>
15720 * @author Benjamin Eberlei <kontakt@beberlei.de>
15721 * @todo Rename: SQLitePlatform
15723 class SqlitePlatform extends AbstractPlatform
15726 * returns the regular expression operator
15731 public function getRegexpExpression()
15737 * Return string to call a variable with the current timestamp inside an SQL statement
15738 * There are three special variables for current date and time.
15740 * @return string sqlite function as string
15743 public function getNowExpression($type = 'timestamp')
15747 return 'time(\'now\')';
15749 return 'date(\'now\')';
15752 return 'datetime(\'now\')';
15757 * Trim a string, leading/trailing/both and with a given char which defaults to space.
15759 * @param string $str
15761 * @param string $char
15764 public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
15767 $trimChar = ($char != false) ? (', ' . $char) : '';
15769 if ($pos == self::TRIM_LEADING) {
15771 } else if($pos == self::TRIM_TRAILING) {
15777 return $trimFn . '(' . $str . $trimChar . ')';
15781 * return string to call a function to get a substring inside an SQL statement
15783 * Note: Not SQL92, but common functionality.
15785 * SQLite only supports the 2 parameter variant of this function
15787 * @param string $value an sql string literal or column name/alias
15788 * @param integer $position where to start the substring portion
15789 * @param integer $length the substring portion length
15790 * @return string SQL substring function with given parameters
15793 public function getSubstringExpression($value, $position, $length = null)
15795 if ($length !== null) {
15796 return 'SUBSTR(' . $value . ', ' . $position . ', ' . $length . ')';
15798 return 'SUBSTR(' . $value . ', ' . $position . ', LENGTH(' . $value . '))';
15802 * returns the position of the first occurrence of substring $substr in string $str
15804 * @param string $substr literal string to find
15805 * @param string $str literal string
15806 * @param int $pos position to start at, beginning of string by default
15809 public function getLocateExpression($str, $substr, $startPos = false)
15811 if ($startPos == false) {
15812 return 'LOCATE('.$str.', '.$substr.')';
15814 return 'LOCATE('.$str.', '.$substr.', '.$startPos.')';
15818 protected function _getTransactionIsolationLevelSQL($level)
15821 case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED:
15823 case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED:
15824 case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ:
15825 case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE:
15828 return parent::_getTransactionIsolationLevelSQL($level);
15832 public function getSetTransactionIsolationSQL($level)
15834 return 'PRAGMA read_uncommitted = ' . $this->_getTransactionIsolationLevelSQL($level);
15840 public function prefersIdentityColumns()
15848 public function getBooleanTypeDeclarationSQL(array $field)
15856 public function getIntegerTypeDeclarationSQL(array $field)
15858 return $this->_getCommonIntegerTypeDeclarationSQL($field);
15864 public function getBigIntTypeDeclarationSQL(array $field)
15866 return $this->_getCommonIntegerTypeDeclarationSQL($field);
15872 public function getTinyIntTypeDeclarationSql(array $field)
15874 return $this->_getCommonIntegerTypeDeclarationSQL($field);
15880 public function getSmallIntTypeDeclarationSQL(array $field)
15882 return $this->_getCommonIntegerTypeDeclarationSQL($field);
15888 public function getMediumIntTypeDeclarationSql(array $field)
15890 return $this->_getCommonIntegerTypeDeclarationSQL($field);
15896 public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
15904 public function getDateTypeDeclarationSQL(array $fieldDeclaration)
15912 public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
15920 protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
15922 $autoinc = ! empty($columnDef['autoincrement']) ? ' AUTOINCREMENT' : '';
15923 $pk = ! empty($columnDef['primary']) && ! empty($autoinc) ? ' PRIMARY KEY' : '';
15925 return 'INTEGER' . $pk . $autoinc;
15929 * create a new table
15931 * @param string $name Name of the database that should be created
15932 * @param array $fields Associative array that contains the definition of each field of the new table
15933 * The indexes of the array entries are the names of the fields of the table an
15934 * the array entry values are associative arrays like those that are meant to be
15935 * passed with the field definitions to get[Type]Declaration() functions.
15938 * 'type' => 'integer',
15944 * 'type' => 'text',
15947 * 'password' => array(
15948 * 'type' => 'text',
15952 * @param array $options An associative array of table options:
15957 protected function _getCreateTableSQL($name, array $columns, array $options = array())
15959 $queryFields = $this->getColumnDeclarationListSQL($columns);
15962 foreach($columns as $field) {
15963 if (isset($field['autoincrement']) && $field['autoincrement']) {
15969 if ( ! $autoinc && isset($options['primary']) && ! empty($options['primary'])) {
15970 $keyColumns = array_unique(array_values($options['primary']));
15971 $keyColumns = array_map(array($this, 'quoteIdentifier'), $keyColumns);
15972 $queryFields.= ', PRIMARY KEY('.implode(', ', $keyColumns).')';
15975 $query[] = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')';
15977 if (isset($options['indexes']) && ! empty($options['indexes'])) {
15978 foreach ($options['indexes'] as $index => $indexDef) {
15979 $query[] = $this->getCreateIndexSQL($indexDef, $name);
15982 if (isset($options['unique']) && ! empty($options['unique'])) {
15983 foreach ($options['unique'] as $index => $indexDef) {
15984 $query[] = $this->getCreateIndexSQL($indexDef, $name);
15993 public function getVarcharTypeDeclarationSQL(array $field)
15995 if ( ! isset($field['length'])) {
15996 if (array_key_exists('default', $field)) {
15997 $field['length'] = $this->getVarcharMaxLength();
15999 $field['length'] = false;
16002 $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
16003 $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
16005 return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
16006 : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
16009 public function getClobTypeDeclarationSQL(array $field)
16014 public function getListTableConstraintsSQL($table)
16016 return "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = '$table' AND sql NOT NULL ORDER BY name";
16019 public function getListTableColumnsSQL($table)
16021 return "PRAGMA table_info($table)";
16024 public function getListTableIndexesSQL($table)
16026 return "PRAGMA index_list($table)";
16029 public function getListTablesSQL()
16031 return "SELECT name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence' "
16032 . "UNION ALL SELECT name FROM sqlite_temp_master "
16033 . "WHERE type = 'table' ORDER BY name";
16036 public function getListViewsSQL($database)
16038 return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL";
16041 public function getCreateViewSQL($name, $sql)
16043 return 'CREATE VIEW ' . $name . ' AS ' . $sql;
16046 public function getDropViewSQL($name)
16048 return 'DROP VIEW '. $name;
16052 * SQLite does support foreign key constraints, but only in CREATE TABLE statements...
16053 * This really limits their usefulness and requires SQLite specific handling, so
16054 * we simply say that SQLite does NOT support foreign keys for now...
16056 * @return boolean FALSE
16059 public function supportsForeignKeyConstraints()
16064 public function supportsAlterTable()
16069 public function supportsIdentityColumns()
16075 * Get the platform name for this instance
16079 public function getName()
16087 public function getTruncateTableSQL($tableName, $cascade = false)
16089 return 'DELETE FROM '.$tableName;
16093 * User-defined function for Sqlite that is used with PDO::sqliteCreateFunction()
16095 * @param int|float $value
16098 static public function udfSqrt($value)
16100 return sqrt($value);
16104 * User-defined function for Sqlite that implements MOD(a, b)
16106 static public function udfMod($a, $b)
16112 * @param string $str
16113 * @param string $substr
16114 * @param int $offset
16116 static public function udfLocate($str, $substr, $offset = 0)
16118 $pos = strpos($str, $substr, $offset);
16119 if ($pos !== false) {
16125 public function getForUpdateSql()
16130 protected function initializeDoctrineTypeMappings()
16132 $this->doctrineTypeMapping = array(
16133 'boolean' => 'boolean',
16134 'tinyint' => 'boolean',
16135 'smallint' => 'smallint',
16136 'mediumint' => 'integer',
16137 'int' => 'integer',
16138 'integer' => 'integer',
16139 'serial' => 'integer',
16140 'bigint' => 'bigint',
16141 'bigserial' => 'bigint',
16143 'tinytext' => 'text',
16144 'mediumtext' => 'text',
16145 'longtext' => 'text',
16147 'varchar' => 'string',
16148 'varchar2' => 'string',
16149 'nvarchar' => 'string',
16150 'image' => 'string',
16151 'ntext' => 'string',
16152 'char' => 'string',
16154 'datetime' => 'datetime',
16155 'timestamp' => 'datetime',
16157 'float' => 'float',
16158 'double' => 'float',
16160 'decimal' => 'decimal',
16161 'numeric' => 'decimal',
16167 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16168 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16169 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16170 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
16171 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
16172 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
16173 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
16174 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
16175 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
16176 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
16177 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16179 * This software consists of voluntary contributions made by many individuals
16180 * and is licensed under the LGPL. For more information, see
16181 * <http://www.doctrine-project.org>.
16184 namespace Doctrine\DBAL;
16187 * Class to store and retrieve the version of Doctrine
16189 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
16190 * @link www.doctrine-project.org
16192 * @version $Revision$
16193 * @author Benjamin Eberlei <kontakt@beberlei.de>
16194 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
16195 * @author Jonathan Wage <jonwage@gmail.com>
16196 * @author Roman Borschel <roman@code-factory.org>
16201 * Current Doctrine Version
16203 const VERSION = '2.0.0RC1-DEV';
16206 * Compares a Doctrine version with the current one.
16208 * @param string $version Doctrine version to compare.
16209 * @return int Returns -1 if older, 0 if it is the same, 1 if version
16210 * passed as argument is newer.
16212 public static function compare($version)
16214 $currentVersion = str_replace(' ', '', strtolower(self::VERSION));
16215 $version = str_replace(' ', '', $version);
16217 return version_compare($version, $currentVersion);
16221 * $Id: Exception.php 4628 2008-07-04 16:32:19Z romanb $
16223 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16224 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16225 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16226 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
16227 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
16228 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
16229 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
16230 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
16231 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
16232 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
16233 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16235 * This software consists of voluntary contributions made by many individuals
16236 * and is licensed under the LGPL. For more information, see
16237 * <http://www.doctrine-project.org>.
16240 namespace Doctrine\DBAL;
16243 * Doctrine\DBAL\ConnectionException
16245 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
16246 * @link www.doctrine-project.org
16248 * @version $Revision: 4628 $
16249 * @author Jonathan H. Wage <jonwage@gmail.com
16251 class ConnectionException extends DBALException
16253 public static function commitFailedRollbackOnly()
16255 return new self("Transaction commit failed because the transaction has been marked for rollback only.");
16258 public static function noActiveTransaction()
16260 return new self("There is no active transaction.");
16263 public static function savepointsNotSupported()
16265 return new self("Savepoints are not supported by this driver.");
16268 public static function mayNotAlterNestedTransactionWithSavepointsInTransaction()
16270 return new self("May not alter the nested transaction with savepoints behavior while a transaction is open.");
16274 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16275 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16276 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16277 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
16278 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
16279 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
16280 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
16281 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
16282 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
16283 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
16284 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16286 * This software consists of voluntary contributions made by many individuals
16287 * and is licensed under the LGPL. For more information, see
16288 * <http://www.doctrine-project.org>.
16291 namespace Doctrine\DBAL;
16293 use PDO, Closure, Exception,
16294 Doctrine\DBAL\Types\Type,
16295 Doctrine\DBAL\Driver\Connection as DriverConnection,
16296 Doctrine\Common\EventManager,
16297 Doctrine\DBAL\DBALException;
16300 * A wrapper around a Doctrine\DBAL\Driver\Connection that adds features like
16301 * events, transaction isolation levels, configuration, emulated transaction nesting,
16302 * lazy connecting and more.
16304 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
16305 * @link www.doctrine-project.org
16307 * @version $Revision: 3938 $
16308 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
16309 * @author Jonathan Wage <jonwage@gmail.com>
16310 * @author Roman Borschel <roman@code-factory.org>
16311 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
16312 * @author Lukas Smith <smith@pooteeweet.org> (MDB2 library)
16313 * @author Benjamin Eberlei <kontakt@beberlei.de>
16315 class Connection implements DriverConnection
16318 * Constant for transaction isolation level READ UNCOMMITTED.
16320 const TRANSACTION_READ_UNCOMMITTED = 1;
16323 * Constant for transaction isolation level READ COMMITTED.
16325 const TRANSACTION_READ_COMMITTED = 2;
16328 * Constant for transaction isolation level REPEATABLE READ.
16330 const TRANSACTION_REPEATABLE_READ = 3;
16333 * Constant for transaction isolation level SERIALIZABLE.
16335 const TRANSACTION_SERIALIZABLE = 4;
16338 * The wrapped driver connection.
16340 * @var Doctrine\DBAL\Driver\Connection
16345 * @var Doctrine\DBAL\Configuration
16347 protected $_config;
16350 * @var Doctrine\Common\EventManager
16352 protected $_eventManager;
16355 * Whether or not a connection has been established.
16359 private $_isConnected = false;
16362 * The transaction nesting level.
16366 private $_transactionNestingLevel = 0;
16369 * The currently active transaction isolation level.
16373 private $_transactionIsolationLevel;
16376 * If nested transations should use savepoints
16380 private $_nestTransactionsWithSavepoints;
16383 * The parameters used during creation of the Connection instance.
16387 private $_params = array();
16390 * The DatabasePlatform object that provides information about the
16391 * database platform used by the connection.
16393 * @var Doctrine\DBAL\Platforms\AbstractPlatform
16395 protected $_platform;
16398 * The schema manager.
16400 * @var Doctrine\DBAL\Schema\SchemaManager
16402 protected $_schemaManager;
16405 * The used DBAL driver.
16407 * @var Doctrine\DBAL\Driver
16409 protected $_driver;
16412 * Flag that indicates whether the current transaction is marked for rollback only.
16416 private $_isRollbackOnly = false;
16419 * Initializes a new instance of the Connection class.
16421 * @param array $params The connection parameters.
16422 * @param Driver $driver
16423 * @param Configuration $config
16424 * @param EventManager $eventManager
16426 public function __construct(array $params, Driver $driver, Configuration $config = null,
16427 EventManager $eventManager = null)
16429 $this->_driver = $driver;
16430 $this->_params = $params;
16432 if (isset($params['pdo'])) {
16433 $this->_conn = $params['pdo'];
16434 $this->_isConnected = true;
16437 // Create default config and event manager if none given
16439 $config = new Configuration();
16442 if ( ! $eventManager) {
16443 $eventManager = new EventManager();
16446 $this->_config = $config;
16447 $this->_eventManager = $eventManager;
16448 if ( ! isset($params['platform'])) {
16449 $this->_platform = $driver->getDatabasePlatform();
16450 } else if ($params['platform'] instanceof Platforms\AbstractPlatform) {
16451 $this->_platform = $params['platform'];
16453 throw DBALException::invalidPlatformSpecified();
16455 $this->_transactionIsolationLevel = $this->_platform->getDefaultTransactionIsolationLevel();
16459 * Gets the parameters used during instantiation.
16461 * @return array $params
16463 public function getParams()
16465 return $this->_params;
16469 * Gets the name of the database this Connection is connected to.
16471 * @return string $database
16473 public function getDatabase()
16475 return $this->_driver->getDatabase($this);
16479 * Gets the hostname of the currently connected database.
16483 public function getHost()
16485 return isset($this->_params['host']) ? $this->_params['host'] : null;
16489 * Gets the port of the currently connected database.
16493 public function getPort()
16495 return isset($this->_params['port']) ? $this->_params['port'] : null;
16499 * Gets the username used by this connection.
16503 public function getUsername()
16505 return isset($this->_params['user']) ? $this->_params['user'] : null;
16509 * Gets the password used by this connection.
16513 public function getPassword()
16515 return isset($this->_params['password']) ? $this->_params['password'] : null;
16519 * Gets the DBAL driver instance.
16521 * @return Doctrine\DBAL\Driver
16523 public function getDriver()
16525 return $this->_driver;
16529 * Gets the Configuration used by the Connection.
16531 * @return Doctrine\DBAL\Configuration
16533 public function getConfiguration()
16535 return $this->_config;
16539 * Gets the EventManager used by the Connection.
16541 * @return Doctrine\Common\EventManager
16543 public function getEventManager()
16545 return $this->_eventManager;
16549 * Gets the DatabasePlatform for the connection.
16551 * @return Doctrine\DBAL\Platforms\AbstractPlatform
16553 public function getDatabasePlatform()
16555 return $this->_platform;
16559 * Establishes the connection with the database.
16561 * @return boolean TRUE if the connection was successfully established, FALSE if
16562 * the connection is already open.
16564 public function connect()
16566 if ($this->_isConnected) return false;
16568 $driverOptions = isset($this->_params['driverOptions']) ?
16569 $this->_params['driverOptions'] : array();
16570 $user = isset($this->_params['user']) ? $this->_params['user'] : null;
16571 $password = isset($this->_params['password']) ?
16572 $this->_params['password'] : null;
16574 $this->_conn = $this->_driver->connect($this->_params, $user, $password, $driverOptions);
16575 $this->_isConnected = true;
16577 if ($this->_eventManager->hasListeners(Events::postConnect)) {
16578 $eventArgs = new Event\ConnectionEventArgs($this);
16579 $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
16586 * Prepares and executes an SQL query and returns the first row of the result
16587 * as an associative array.
16589 * @param string $statement The SQL query.
16590 * @param array $params The query parameters.
16593 public function fetchAssoc($statement, array $params = array())
16595 return $this->executeQuery($statement, $params)->fetch(PDO::FETCH_ASSOC);
16599 * Prepares and executes an SQL query and returns the first row of the result
16600 * as a numerically indexed array.
16602 * @param string $statement sql query to be executed
16603 * @param array $params prepared statement params
16606 public function fetchArray($statement, array $params = array())
16608 return $this->executeQuery($statement, $params)->fetch(PDO::FETCH_NUM);
16612 * Prepares and executes an SQL query and returns the value of a single column
16613 * of the first row of the result.
16615 * @param string $statement sql query to be executed
16616 * @param array $params prepared statement params
16617 * @param int $colnum 0-indexed column number to retrieve
16620 public function fetchColumn($statement, array $params = array(), $colnum = 0)
16622 return $this->executeQuery($statement, $params)->fetchColumn($colnum);
16626 * Whether an actual connection to the database is established.
16630 public function isConnected()
16632 return $this->_isConnected;
16636 * Checks whether a transaction is currently active.
16638 * @return boolean TRUE if a transaction is currently active, FALSE otherwise.
16640 public function isTransactionActive()
16642 return $this->_transactionNestingLevel > 0;
16646 * Executes an SQL DELETE statement on a table.
16648 * @param string $table The name of the table on which to delete.
16649 * @param array $identifier The deletion criteria. An associateve array containing column-value pairs.
16650 * @return integer The number of affected rows.
16652 public function delete($tableName, array $identifier)
16656 $criteria = array();
16658 foreach (array_keys($identifier) as $columnName) {
16659 $criteria[] = $columnName . ' = ?';
16662 $query = 'DELETE FROM ' . $tableName . ' WHERE ' . implode(' AND ', $criteria);
16664 return $this->executeUpdate($query, array_values($identifier));
16668 * Closes the connection.
16672 public function close()
16674 unset($this->_conn);
16676 $this->_isConnected = false;
16680 * Sets the transaction isolation level.
16682 * @param integer $level The level to set.
16684 public function setTransactionIsolation($level)
16686 $this->_transactionIsolationLevel = $level;
16688 return $this->executeUpdate($this->_platform->getSetTransactionIsolationSQL($level));
16692 * Gets the currently active transaction isolation level.
16694 * @return integer The current transaction isolation level.
16696 public function getTransactionIsolation()
16698 return $this->_transactionIsolationLevel;
16702 * Executes an SQL UPDATE statement on a table.
16704 * @param string $table The name of the table to update.
16705 * @param array $identifier The update criteria. An associative array containing column-value pairs.
16706 * @return integer The number of affected rows.
16708 public function update($tableName, array $data, array $identifier)
16712 foreach ($data as $columnName => $value) {
16713 $set[] = $columnName . ' = ?';
16716 $params = array_merge(array_values($data), array_values($identifier));
16718 $sql = 'UPDATE ' . $tableName . ' SET ' . implode(', ', $set)
16719 . ' WHERE ' . implode(' = ? AND ', array_keys($identifier))
16722 return $this->executeUpdate($sql, $params);
16726 * Inserts a table row with specified data.
16728 * @param string $table The name of the table to insert data into.
16729 * @param array $data An associative array containing column-value pairs.
16730 * @return integer The number of affected rows.
16732 public function insert($tableName, array $data)
16736 // column names are specified as array keys
16738 $placeholders = array();
16740 foreach ($data as $columnName => $value) {
16741 $cols[] = $columnName;
16742 $placeholders[] = '?';
16745 $query = 'INSERT INTO ' . $tableName
16746 . ' (' . implode(', ', $cols) . ')'
16747 . ' VALUES (' . implode(', ', $placeholders) . ')';
16749 return $this->executeUpdate($query, array_values($data));
16753 * Sets the given charset on the current connection.
16755 * @param string $charset The charset to set.
16757 public function setCharset($charset)
16759 $this->executeUpdate($this->_platform->getSetCharsetSQL($charset));
16763 * Quote a string so it can be safely used as a table or column name, even if
16764 * it is a reserved name.
16766 * Delimiting style depends on the underlying database platform that is being used.
16768 * NOTE: Just because you CAN use quoted identifiers does not mean
16769 * you SHOULD use them. In general, they end up causing way more
16770 * problems than they solve.
16772 * @param string $str The name to be quoted.
16773 * @return string The quoted name.
16775 public function quoteIdentifier($str)
16777 return $this->_platform->quoteIdentifier($str);
16781 * Quotes a given input parameter.
16783 * @param mixed $input Parameter to be quoted.
16784 * @param string $type Type of the parameter.
16785 * @return string The quoted parameter.
16787 public function quote($input, $type = null)
16791 return $this->_conn->quote($input, $type);
16795 * Prepares and executes an SQL query and returns the result as an associative array.
16797 * @param string $sql The SQL query.
16798 * @param array $params The query parameters.
16801 public function fetchAll($sql, array $params = array())
16803 return $this->executeQuery($sql, $params)->fetchAll(PDO::FETCH_ASSOC);
16807 * Prepares an SQL statement.
16809 * @param string $statement The SQL statement to prepare.
16810 * @return Doctrine\DBAL\Driver\Statement The prepared statement.
16812 public function prepare($statement)
16816 return new Statement($statement, $this);
16820 * Executes an, optionally parameterized, SQL query.
16822 * If the query is parameterized, a prepared statement is used.
16823 * If an SQLLogger is configured, the execution is logged.
16825 * @param string $query The SQL query to execute.
16826 * @param array $params The parameters to bind to the query, if any.
16827 * @return Doctrine\DBAL\Driver\Statement The executed statement.
16828 * @internal PERF: Directly prepares a driver statement, not a wrapper.
16830 public function executeQuery($query, array $params = array(), $types = array())
16834 $hasLogger = $this->_config->getSQLLogger() !== null;
16836 $this->_config->getSQLLogger()->startQuery($query, $params, $types);
16840 $stmt = $this->_conn->prepare($query);
16842 $this->_bindTypedValues($stmt, $params, $types);
16845 $stmt->execute($params);
16848 $stmt = $this->_conn->query($query);
16852 $this->_config->getSQLLogger()->stopQuery();
16859 * Executes an, optionally parameterized, SQL query and returns the result,
16860 * applying a given projection/transformation function on each row of the result.
16862 * @param string $query The SQL query to execute.
16863 * @param array $params The parameters, if any.
16864 * @param Closure $mapper The transformation function that is applied on each row.
16865 * The function receives a single paramater, an array, that
16866 * represents a row of the result set.
16867 * @return mixed The projected result of the query.
16869 public function project($query, array $params, Closure $function)
16872 $stmt = $this->executeQuery($query, $params ?: array());
16874 while ($row = $stmt->fetch()) {
16875 $result[] = $function($row);
16878 $stmt->closeCursor();
16884 * Executes an SQL statement, returning a result set as a Statement object.
16886 * @param string $statement
16887 * @param integer $fetchType
16888 * @return Doctrine\DBAL\Driver\Statement
16890 public function query()
16894 return call_user_func_array(array($this->_conn, 'query'), func_get_args());
16898 * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
16899 * and returns the number of affected rows.
16901 * This method supports PDO binding types as well as DBAL mapping types.
16903 * @param string $query The SQL query.
16904 * @param array $params The query parameters.
16905 * @param array $types The parameter types.
16906 * @return integer The number of affected rows.
16907 * @internal PERF: Directly prepares a driver statement, not a wrapper.
16909 public function executeUpdate($query, array $params = array(), array $types = array())
16913 $hasLogger = $this->_config->getSQLLogger() !== null;
16915 $this->_config->getSQLLogger()->startQuery($query, $params, $types);
16919 $stmt = $this->_conn->prepare($query);
16921 $this->_bindTypedValues($stmt, $params, $types);
16924 $stmt->execute($params);
16926 $result = $stmt->rowCount();
16928 $result = $this->_conn->exec($query);
16932 $this->_config->getSQLLogger()->stopQuery();
16939 * Execute an SQL statement and return the number of affected rows.
16941 * @param string $statement
16942 * @return integer The number of affected rows.
16944 public function exec($statement)
16947 return $this->_conn->exec($statement);
16951 * Returns the current transaction nesting level.
16953 * @return integer The nesting level. A value of 0 means there's no active transaction.
16955 public function getTransactionNestingLevel()
16957 return $this->_transactionNestingLevel;
16961 * Fetch the SQLSTATE associated with the last database operation.
16963 * @return integer The last error code.
16965 public function errorCode()
16968 return $this->_conn->errorCode();
16972 * Fetch extended error information associated with the last database operation.
16974 * @return array The last error information.
16976 public function errorInfo()
16979 return $this->_conn->errorInfo();
16983 * Returns the ID of the last inserted row, or the last value from a sequence object,
16984 * depending on the underlying driver.
16986 * Note: This method may not return a meaningful or consistent result across different drivers,
16987 * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
16988 * columns or sequences.
16990 * @param string $seqName Name of the sequence object from which the ID should be returned.
16991 * @return string A string representation of the last inserted ID.
16993 public function lastInsertId($seqName = null)
16996 return $this->_conn->lastInsertId($seqName);
17000 * Executes a function in a transaction.
17002 * The function gets passed this Connection instance as an (optional) parameter.
17004 * If an exception occurs during execution of the function or transaction commit,
17005 * the transaction is rolled back and the exception re-thrown.
17007 * @param Closure $func The function to execute transactionally.
17009 public function transactional(Closure $func)
17011 $this->beginTransaction();
17015 } catch (Exception $e) {
17022 * Set if nested transactions should use savepoints
17027 public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints)
17029 if ($this->_transactionNestingLevel > 0) {
17030 throw ConnectionException::mayNotAlterNestedTransactionWithSavepointsInTransaction();
17033 if (!$this->_platform->supportsSavepoints()) {
17034 throw ConnectionException::savepointsNotSupported();
17037 $this->_nestTransactionsWithSavepoints = $nestTransactionsWithSavepoints;
17041 * Get if nested transactions should use savepoints
17045 public function getNestTransactionsWithSavepoints()
17047 return $this->_nestTransactionsWithSavepoints;
17051 * Returns the savepoint name to use for nested transactions are false if they are not supported
17052 * "savepointFormat" parameter is not set
17054 * @return mixed a string with the savepoint name or false
17056 protected function _getNestedTransactionSavePointName()
17058 return 'DOCTRINE2_SAVEPOINT_'.$this->_transactionNestingLevel;
17062 * Starts a transaction by suspending auto-commit mode.
17066 public function beginTransaction()
17070 ++$this->_transactionNestingLevel;
17072 if ($this->_transactionNestingLevel == 1) {
17073 $this->_conn->beginTransaction();
17074 } else if ($this->_nestTransactionsWithSavepoints) {
17075 $this->createSavepoint($this->_getNestedTransactionSavePointName());
17080 * Commits the current transaction.
17083 * @throws ConnectionException If the commit failed due to no active transaction or
17084 * because the transaction was marked for rollback only.
17086 public function commit()
17088 if ($this->_transactionNestingLevel == 0) {
17089 throw ConnectionException::noActiveTransaction();
17091 if ($this->_isRollbackOnly) {
17092 throw ConnectionException::commitFailedRollbackOnly();
17097 if ($this->_transactionNestingLevel == 1) {
17098 $this->_conn->commit();
17099 } else if ($this->_nestTransactionsWithSavepoints) {
17100 $this->releaseSavepoint($this->_getNestedTransactionSavePointName());
17103 --$this->_transactionNestingLevel;
17107 * Cancel any database changes done during the current transaction.
17109 * this method can be listened with onPreTransactionRollback and onTransactionRollback
17110 * eventlistener methods
17112 * @throws ConnectionException If the rollback operation failed.
17114 public function rollback()
17116 if ($this->_transactionNestingLevel == 0) {
17117 throw ConnectionException::noActiveTransaction();
17122 if ($this->_transactionNestingLevel == 1) {
17123 $this->_transactionNestingLevel = 0;
17124 $this->_conn->rollback();
17125 $this->_isRollbackOnly = false;
17126 } else if ($this->_nestTransactionsWithSavepoints) {
17127 $this->rollbackSavepoint($this->_getNestedTransactionSavePointName());
17128 --$this->_transactionNestingLevel;
17130 $this->_isRollbackOnly = true;
17131 --$this->_transactionNestingLevel;
17137 * creates a new savepoint
17139 * @param string $savepoint name of a savepoint to set
17142 public function createSavepoint($savepoint)
17144 if (!$this->_platform->supportsSavepoints()) {
17145 throw ConnectionException::savepointsNotSupported();
17148 $this->_conn->exec($this->_platform->createSavePoint($savepoint));
17153 * releases given savepoint
17155 * @param string $savepoint name of a savepoint to release
17158 public function releaseSavepoint($savepoint)
17160 if (!$this->_platform->supportsSavepoints()) {
17161 throw ConnectionException::savepointsNotSupported();
17164 if ($this->_platform->supportsReleaseSavepoints()) {
17165 $this->_conn->exec($this->_platform->releaseSavePoint($savepoint));
17170 * rollbackSavePoint
17171 * releases given savepoint
17173 * @param string $savepoint name of a savepoint to rollback to
17176 public function rollbackSavepoint($savepoint)
17178 if (!$this->_platform->supportsSavepoints()) {
17179 throw ConnectionException::savepointsNotSupported();
17182 $this->_conn->exec($this->_platform->rollbackSavePoint($savepoint));
17186 * Gets the wrapped driver connection.
17188 * @return Doctrine\DBAL\Driver\Connection
17190 public function getWrappedConnection()
17194 return $this->_conn;
17198 * Gets the SchemaManager that can be used to inspect or change the
17199 * database schema through the connection.
17201 * @return Doctrine\DBAL\Schema\SchemaManager
17203 public function getSchemaManager()
17205 if ( ! $this->_schemaManager) {
17206 $this->_schemaManager = $this->_driver->getSchemaManager($this);
17209 return $this->_schemaManager;
17213 * Marks the current transaction so that the only possible
17214 * outcome for the transaction to be rolled back.
17216 * @throws ConnectionException If no transaction is active.
17218 public function setRollbackOnly()
17220 if ($this->_transactionNestingLevel == 0) {
17221 throw ConnectionException::noActiveTransaction();
17223 $this->_isRollbackOnly = true;
17227 * Check whether the current transaction is marked for rollback only.
17230 * @throws ConnectionException If no transaction is active.
17232 public function isRollbackOnly()
17234 if ($this->_transactionNestingLevel == 0) {
17235 throw ConnectionException::noActiveTransaction();
17237 return $this->_isRollbackOnly;
17241 * Converts a given value to its database representation according to the conversion
17242 * rules of a specific DBAL mapping type.
17244 * @param mixed $value The value to convert.
17245 * @param string $type The name of the DBAL mapping type.
17246 * @return mixed The converted value.
17248 public function convertToDatabaseValue($value, $type)
17250 return Type::getType($type)->convertToDatabaseValue($value, $this->_platform);
17254 * Converts a given value to its PHP representation according to the conversion
17255 * rules of a specific DBAL mapping type.
17257 * @param mixed $value The value to convert.
17258 * @param string $type The name of the DBAL mapping type.
17259 * @return mixed The converted type.
17261 public function convertToPHPValue($value, $type)
17263 return Type::getType($type)->convertToPHPValue($value, $this->_platform);
17267 * Binds a set of parameters, some or all of which are typed with a PDO binding type
17268 * or DBAL mapping type, to a given statement.
17270 * @param $stmt The statement to bind the values to.
17271 * @param array $params The map/list of named/positional parameters.
17272 * @param array $types The parameter types (PDO binding types or DBAL mapping types).
17273 * @internal Duck-typing used on the $stmt parameter to support driver statements as well as
17274 * raw PDOStatement instances.
17276 private function _bindTypedValues($stmt, array $params, array $types)
17278 // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO.
17279 if (is_int(key($params))) {
17280 // Positional parameters
17281 $typeOffset = isset($types[0]) ? -1 : 0;
17283 foreach ($params as $position => $value) {
17284 $typeIndex = $bindIndex + $typeOffset;
17285 if (isset($types[$typeIndex])) {
17286 $type = $types[$typeIndex];
17287 if (is_string($type)) {
17288 $type = Type::getType($type);
17290 if ($type instanceof Type) {
17291 $value = $type->convertToDatabaseValue($value, $this->_platform);
17292 $bindingType = $type->getBindingType();
17294 $bindingType = $type; // PDO::PARAM_* constants
17296 $stmt->bindValue($bindIndex, $value, $bindingType);
17298 $stmt->bindValue($bindIndex, $value);
17303 // Named parameters
17304 foreach ($params as $name => $value) {
17305 if (isset($types[$name])) {
17306 $type = $types[$name];
17307 if (is_string($type)) {
17308 $type = Type::getType($type);
17310 if ($type instanceof Type) {
17311 $value = $type->convertToDatabaseValue($value, $this->_platform);
17312 $bindingType = $type->getBindingType();
17314 $bindingType = $type; // PDO::PARAM_* constants
17316 $stmt->bindValue($name, $value, $bindingType);
17318 $stmt->bindValue($name, $value);
17327 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17328 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17329 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17330 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17331 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17332 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17333 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17334 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17335 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17336 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17337 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17339 * This software consists of voluntary contributions made by many individuals
17340 * and is licensed under the LGPL. For more information, see
17341 * <http://www.doctrine-project.org>.
17344 namespace Doctrine\DBAL\Logging;
17347 * A SQL logger that logs to the standard output using echo/var_dump.
17349 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17350 * @link www.doctrine-project.org
17352 * @version $Revision$
17353 * @author Benjamin Eberlei <kontakt@beberlei.de>
17354 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
17355 * @author Jonathan Wage <jonwage@gmail.com>
17356 * @author Roman Borschel <roman@code-factory.org>
17358 class EchoSQLLogger implements SQLLogger
17363 public function startQuery($sql, array $params = null, array $types = null)
17365 echo $sql . PHP_EOL;
17379 public function stopQuery()
17387 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17388 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17389 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17390 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17391 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17392 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17393 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17394 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17395 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17396 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17397 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17399 * This software consists of voluntary contributions made by many individuals
17400 * and is licensed under the LGPL. For more information, see
17401 * <http://www.doctrine-project.org>.
17404 namespace Doctrine\DBAL\Logging;
17407 * Includes executed SQLs in a Debug Stack
17409 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17410 * @link www.doctrine-project.org
17412 * @version $Revision$
17413 * @author Benjamin Eberlei <kontakt@beberlei.de>
17414 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
17415 * @author Jonathan Wage <jonwage@gmail.com>
17416 * @author Roman Borschel <roman@code-factory.org>
17418 class DebugStack implements SQLLogger
17420 /** @var array $queries Executed SQL queries. */
17421 public $queries = array();
17423 /** @var boolean $enabled If Debug Stack is enabled (log queries) or not. */
17424 public $enabled = true;
17426 public $start = null;
17431 public function startQuery($sql, array $params = null, array $types = null)
17433 if ($this->enabled) {
17434 $this->start = microtime(true);
17435 $this->queries[] = array('sql' => $sql, 'params' => $params, 'types' => $types, 'executionMS' => 0);
17442 public function stopQuery()
17444 $this->queries[(count($this->queries)-1)]['executionMS'] = microtime(true) - $this->start;
17452 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17453 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17454 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17455 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17456 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17457 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17458 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17459 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17460 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17461 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17462 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17464 * This software consists of voluntary contributions made by many individuals
17465 * and is licensed under the LGPL. For more information, see
17466 * <http://www.doctrine-project.org>.
17469 namespace Doctrine\DBAL\Logging;
17472 * Interface for SQL loggers.
17474 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17475 * @link www.doctrine-project.org
17477 * @version $Revision$
17478 * @author Benjamin Eberlei <kontakt@beberlei.de>
17479 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
17480 * @author Jonathan Wage <jonwage@gmail.com>
17481 * @author Roman Borschel <roman@code-factory.org>
17483 interface SQLLogger
17486 * Logs a SQL statement somewhere.
17488 * @param string $sql The SQL to be executed.
17489 * @param array $params The SQL parameters.
17490 * @param float $executionMS The microtime difference it took to execute this query.
17493 public function startQuery($sql, array $params = null, array $types = null);
17496 * Mark the last started query as stopped. This can be used for timing of queries.
17500 public function stopQuery();
17505 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17506 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17507 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17508 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17509 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17510 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17511 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17512 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17513 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17514 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17515 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17517 * This software consists of voluntary contributions made by many individuals
17518 * and is licensed under the LGPL. For more information, see
17519 * <http://www.doctrine-project.org>.
17522 namespace Doctrine\DBAL\Tools\Console\Command;
17524 use Symfony\Component\Console\Input\InputArgument,
17525 Symfony\Component\Console;
17528 * Task for executing arbitrary SQL that can come from a file or directly from
17529 * the command line.
17531 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17532 * @link www.doctrine-project.org
17534 * @version $Revision$
17535 * @author Benjamin Eberlei <kontakt@beberlei.de>
17536 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
17537 * @author Jonathan Wage <jonwage@gmail.com>
17538 * @author Roman Borschel <roman@code-factory.org>
17540 class ImportCommand extends Console\Command\Command
17543 * @see Console\Command\Command
17545 protected function configure()
17548 ->setName('dbal:import')
17549 ->setDescription('Import SQL file(s) directly to Database.')
17550 ->setDefinition(array(
17552 'file', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'File path(s) of SQL to be executed.'
17556 Import SQL file(s) directly to Database.
17562 * @see Console\Command\Command
17564 protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
17566 $conn = $this->getHelper('db')->getConnection();
17568 if (($fileNames = $input->getArgument('file')) !== null) {
17569 foreach ((array) $fileNames as $fileName) {
17570 $fileName = realpath($fileName);
17572 if ( ! file_exists($fileName)) {
17573 throw new \InvalidArgumentException(
17574 sprintf("SQL file '<info>%s</info>' does not exist.", $fileName)
17576 } else if ( ! is_readable($fileName)) {
17577 throw new \InvalidArgumentException(
17578 sprintf("SQL file '<info>%s</info>' does not have read permissions.", $fileName)
17582 $output->write(sprintf("Processing file '<info>%s</info>'... ", $fileName));
17583 $sql = file_get_contents($fileName);
17585 if ($conn instanceof \Doctrine\DBAL\Driver\PDOConnection) {
17590 $stmt = $conn->prepare($sql);
17594 // Required due to "MySQL has gone away!" issue
17596 $stmt->closeCursor();
17599 } while ($stmt->nextRowset());
17601 $output->write(sprintf('%d statements executed!', $lines) . PHP_EOL);
17602 } catch (\PDOException $e) {
17603 $output->write('error!' . PHP_EOL);
17605 throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
17608 // Non-PDO Drivers (ie. OCI8 driver)
17609 $stmt = $conn->prepare($sql);
17610 $rs = $stmt->execute();
17613 $printer->writeln('OK!');
17615 $error = $stmt->errorInfo();
17617 $output->write('error!' . PHP_EOL);
17619 throw new \RuntimeException($error[2], $error[0]);
17622 $stmt->closeCursor();
17632 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17633 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17634 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17635 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17636 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17637 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17638 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17639 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17640 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17641 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17642 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17644 * This software consists of voluntary contributions made by many individuals
17645 * and is licensed under the LGPL. For more information, see
17646 * <http://www.doctrine-project.org>.
17649 namespace Doctrine\DBAL\Tools\Console\Command;
17651 use Symfony\Component\Console\Input\InputArgument,
17652 Symfony\Component\Console\Input\InputOption,
17653 Symfony\Component\Console;
17656 * Task for executing arbitrary SQL that can come from a file or directly from
17657 * the command line.
17659 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17660 * @link www.doctrine-project.org
17662 * @version $Revision$
17663 * @author Benjamin Eberlei <kontakt@beberlei.de>
17664 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
17665 * @author Jonathan Wage <jonwage@gmail.com>
17666 * @author Roman Borschel <roman@code-factory.org>
17668 class RunSqlCommand extends Console\Command\Command
17671 * @see Console\Command\Command
17673 protected function configure()
17676 ->setName('dbal:run-sql')
17677 ->setDescription('Executes arbitrary SQL directly from the command line.')
17678 ->setDefinition(array(
17679 new InputArgument('sql', InputArgument::REQUIRED, 'The SQL statement to execute.'),
17680 new InputOption('depth', null, InputOption::PARAMETER_REQUIRED, 'Dumping depth of result set.', 7)
17683 Executes arbitrary SQL directly from the command line.
17689 * @see Console\Command\Command
17691 protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
17693 $conn = $this->getHelper('db')->getConnection();
17695 if (($sql = $input->getArgument('sql')) === null) {
17696 throw new \RuntimeException("Argument 'SQL' is required in order to execute this command correctly.");
17699 $depth = $input->getOption('depth');
17701 if ( ! is_numeric($depth)) {
17702 throw new \LogicException("Option 'depth' must contains an integer value");
17705 if (preg_match('/^select/i', $sql)) {
17706 $resultSet = $conn->fetchAll($sql);
17708 $resultSet = $conn->executeUpdate($sql);
17711 \Doctrine\Common\Util\Debug::dump($resultSet, (int) $depth);
17718 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17719 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17720 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17721 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17722 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17723 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17724 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17725 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17726 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17727 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17728 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17730 * This software consists of voluntary contributions made by many individuals
17731 * and is licensed under the LGPL. For more information, see
17732 * <http://www.doctrine-project.org>.
17735 namespace Doctrine\DBAL\Tools\Console\Helper;
17737 use Symfony\Component\Console\Helper\Helper,
17738 Doctrine\DBAL\Connection;
17741 * Doctrine CLI Connection Helper.
17743 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17744 * @link www.doctrine-project.org
17746 * @version $Revision$
17747 * @author Benjamin Eberlei <kontakt@beberlei.de>
17748 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
17749 * @author Jonathan Wage <jonwage@gmail.com>
17750 * @author Roman Borschel <roman@code-factory.org>
17752 class ConnectionHelper extends Helper
17755 * Doctrine Database Connection
17758 protected $_connection;
17763 * @param Connection $connection Doctrine Database Connection
17765 public function __construct(Connection $connection)
17767 $this->_connection = $connection;
17771 * Retrieves Doctrine Database Connection
17773 * @return Connection
17775 public function getConnection()
17777 return $this->_connection;
17783 public function getName()
17785 return 'connection';
17790 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17791 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17792 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17793 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17794 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17795 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17796 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17797 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17798 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17799 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17800 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17802 * This software consists of voluntary contributions made by many individuals
17803 * and is licensed under the LGPL. For more information, see
17804 * <http://www.doctrine-project.org>.
17808 namespace Doctrine\DBAL\Types;
17810 use Doctrine\DBAL\Platforms\AbstractPlatform;
17813 * Variable DateTime Type using date_create() instead of DateTime::createFromFormat()
17815 * This type has performance implications as it runs twice as long as the regular
17816 * {@see DateTimeType}, however in certain PostgreSQL configurations with
17817 * TIMESTAMP(n) columns where n > 0 it is necessary to use this type.
17819 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17820 * @link www.doctrine-project.com
17822 * @author Benjamin Eberlei <kontakt@beberlei.de>
17823 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
17824 * @author Jonathan Wage <jonwage@gmail.com>
17825 * @author Roman Borschel <roman@code-factory.org>
17827 class VarDateTimeType extends DateTimeType
17830 * @throws ConversionException
17831 * @param string $value
17832 * @param AbstractPlatform $platform
17835 public function convertToPHPValue($value, AbstractPlatform $platform)
17837 if ($value === null) {
17841 $val = date_create($value);
17843 throw ConversionException::conversionFailed($value, $this->getName());
17851 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17852 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17853 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17854 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17855 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17856 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17857 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17858 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17859 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17860 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17861 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17863 * This software consists of voluntary contributions made by many individuals
17864 * and is licensed under the LGPL. For more information, see
17865 * <http://www.doctrine-project.org>.
17868 namespace Doctrine\DBAL\Types;
17870 use Doctrine\DBAL\Platforms\AbstractPlatform;
17873 * Type that maps an SQL INT to a PHP integer.
17875 * @author Roman Borschel <roman@code-factory.org>
17878 class IntegerType extends Type
17880 public function getName()
17882 return Type::INTEGER;
17885 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
17887 return $platform->getIntegerTypeDeclarationSQL($fieldDeclaration);
17890 public function convertToPHPValue($value, AbstractPlatform $platform)
17892 return (null === $value) ? null : (int) $value;
17895 public function getBindingType()
17897 return \PDO::PARAM_INT;
17901 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17902 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17903 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17904 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17905 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17906 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17907 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17908 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17909 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17910 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17911 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17913 * This software consists of voluntary contributions made by many individuals
17914 * and is licensed under the LGPL. For more information, see
17915 * <http://www.doctrine-project.org>.
17918 namespace Doctrine\DBAL\Types;
17920 use Doctrine\DBAL\Platforms\AbstractPlatform;
17923 * Type that maps an SQL DATE to a PHP Date object.
17927 class DateType extends Type
17929 public function getName()
17934 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
17936 return $platform->getDateTypeDeclarationSQL($fieldDeclaration);
17939 public function convertToDatabaseValue($value, AbstractPlatform $platform)
17941 return ($value !== null)
17942 ? $value->format($platform->getDateFormatString()) : null;
17945 public function convertToPHPValue($value, AbstractPlatform $platform)
17947 if ($value === null) {
17951 $val = \DateTime::createFromFormat('!'.$platform->getDateFormatString(), $value);
17953 throw ConversionException::conversionFailed($value, $this->getName());
17961 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17962 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17963 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17964 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17965 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17966 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17967 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17968 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17969 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17970 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
17971 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17973 * This software consists of voluntary contributions made by many individuals
17974 * and is licensed under the LGPL. For more information, see
17975 * <http://www.doctrine-project.org>.
17978 namespace Doctrine\DBAL\Types;
17980 use Doctrine\DBAL\Platforms\AbstractPlatform,
17981 Doctrine\DBAL\DBALException;
17984 * The base class for so-called Doctrine mapping types.
17986 * A Type object is obtained by calling the static {@link getType()} method.
17988 * @author Roman Borschel <roman@code-factory.org>
17991 abstract class Type
17993 const TARRAY = 'array';
17994 const BIGINT = 'bigint';
17995 const BOOLEAN = 'boolean';
17996 const DATETIME = 'datetime';
17997 const DATETIMETZ = 'datetimetz';
17998 const DATE = 'date';
17999 const TIME = 'time';
18000 const DECIMAL = 'decimal';
18001 const INTEGER = 'integer';
18002 const OBJECT = 'object';
18003 const SMALLINT = 'smallint';
18004 const STRING = 'string';
18005 const TEXT = 'text';
18006 const FLOAT = 'float';
18008 /** Map of already instantiated type objects. One instance per type (flyweight). */
18009 private static $_typeObjects = array();
18011 /** The map of supported doctrine mapping types. */
18012 private static $_typesMap = array(
18013 self::TARRAY => 'Doctrine\DBAL\Types\ArrayType',
18014 self::OBJECT => 'Doctrine\DBAL\Types\ObjectType',
18015 self::BOOLEAN => 'Doctrine\DBAL\Types\BooleanType',
18016 self::INTEGER => 'Doctrine\DBAL\Types\IntegerType',
18017 self::SMALLINT => 'Doctrine\DBAL\Types\SmallIntType',
18018 self::BIGINT => 'Doctrine\DBAL\Types\BigIntType',
18019 self::STRING => 'Doctrine\DBAL\Types\StringType',
18020 self::TEXT => 'Doctrine\DBAL\Types\TextType',
18021 self::DATETIME => 'Doctrine\DBAL\Types\DateTimeType',
18022 self::DATETIMETZ => 'Doctrine\DBAL\Types\DateTimeTzType',
18023 self::DATE => 'Doctrine\DBAL\Types\DateType',
18024 self::TIME => 'Doctrine\DBAL\Types\TimeType',
18025 self::DECIMAL => 'Doctrine\DBAL\Types\DecimalType',
18026 self::FLOAT => 'Doctrine\DBAL\Types\FloatType',
18029 /* Prevent instantiation and force use of the factory method. */
18030 final private function __construct() {}
18033 * Converts a value from its PHP representation to its database representation
18036 * @param mixed $value The value to convert.
18037 * @param AbstractPlatform $platform The currently used database platform.
18038 * @return mixed The database representation of the value.
18040 public function convertToDatabaseValue($value, AbstractPlatform $platform)
18046 * Converts a value from its database representation to its PHP representation
18049 * @param mixed $value The value to convert.
18050 * @param AbstractPlatform $platform The currently used database platform.
18051 * @return mixed The PHP representation of the value.
18053 public function convertToPHPValue($value, AbstractPlatform $platform)
18059 * Gets the default length of this type.
18063 public function getDefaultLength(AbstractPlatform $platform)
18069 * Gets the SQL declaration snippet for a field of this type.
18071 * @param array $fieldDeclaration The field declaration.
18072 * @param AbstractPlatform $platform The currently used database platform.
18074 abstract public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform);
18077 * Gets the name of this type.
18082 abstract public function getName();
18085 * Factory method to create type instances.
18086 * Type instances are implemented as flyweights.
18089 * @throws DBALException
18090 * @param string $name The name of the type (as returned by getName()).
18091 * @return Doctrine\DBAL\Types\Type
18093 public static function getType($name)
18095 if ( ! isset(self::$_typeObjects[$name])) {
18096 if ( ! isset(self::$_typesMap[$name])) {
18097 throw DBALException::unknownColumnType($name);
18099 self::$_typeObjects[$name] = new self::$_typesMap[$name]();
18102 return self::$_typeObjects[$name];
18106 * Adds a custom type to the type map.
18109 * @param string $name Name of the type. This should correspond to what getName() returns.
18110 * @param string $className The class name of the custom type.
18111 * @throws DBALException
18113 public static function addType($name, $className)
18115 if (isset(self::$_typesMap[$name])) {
18116 throw DBALException::typeExists($name);
18119 self::$_typesMap[$name] = $className;
18123 * Checks if exists support for a type.
18126 * @param string $name Name of the type
18127 * @return boolean TRUE if type is supported; FALSE otherwise
18129 public static function hasType($name)
18131 return isset(self::$_typesMap[$name]);
18135 * Overrides an already defined type to use a different implementation.
18138 * @param string $name
18139 * @param string $className
18140 * @throws DBALException
18142 public static function overrideType($name, $className)
18144 if ( ! isset(self::$_typesMap[$name])) {
18145 throw DBALException::typeNotFound($name);
18148 self::$_typesMap[$name] = $className;
18152 * Gets the (preferred) binding type for values of this type that
18153 * can be used when binding parameters to prepared statements.
18155 * This method should return one of the PDO::PARAM_* constants, that is, one of:
18165 public function getBindingType()
18167 return \PDO::PARAM_STR;
18171 * Get the types array map which holds all registered types and the corresponding
18174 * @return array $typesMap
18176 public static function getTypesMap()
18178 return self::$_typesMap;
18181 public function __toString()
18183 $e = explode('\\', get_class($this));
18184 return str_replace('Type', '', end($e));
18188 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18189 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18190 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18191 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18192 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18193 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18194 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18195 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18196 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18197 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18198 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18200 * This software consists of voluntary contributions made by many individuals
18201 * and is licensed under the LGPL. For more information, see
18202 * <http://www.doctrine-project.org>.
18206 namespace Doctrine\DBAL\Types;
18208 use Doctrine\DBAL\Platforms\AbstractPlatform;
18210 class FloatType extends Type
18212 public function getName()
18214 return Type::FLOAT;
18218 * @param array $fieldDeclaration
18219 * @param AbstractPlatform $platform
18222 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18224 return $platform->getFloatDeclarationSQL($fieldDeclaration);
18228 * Converts a value from its database representation to its PHP representation
18231 * @param mixed $value The value to convert.
18232 * @param AbstractPlatform $platform The currently used database platform.
18233 * @return mixed The PHP representation of the value.
18235 public function convertToPHPValue($value, AbstractPlatform $platform)
18237 return (null === $value) ? null : (double) $value;
18244 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18245 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18246 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18247 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18248 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18249 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18250 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18251 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18252 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18253 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18254 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18256 * This software consists of voluntary contributions made by many individuals
18257 * and is licensed under the LGPL. For more information, see
18258 * <http://www.doctrine-project.org>.
18261 namespace Doctrine\DBAL\Types;
18263 use Doctrine\DBAL\Platforms\AbstractPlatform;
18266 * Type that maps a database SMALLINT to a PHP integer.
18270 class SmallIntType extends Type
18272 public function getName()
18274 return Type::SMALLINT;
18277 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18279 return $platform->getSmallIntTypeDeclarationSQL($fieldDeclaration);
18282 public function convertToPHPValue($value, AbstractPlatform $platform)
18284 return (null === $value) ? null : (int) $value;
18287 public function getBindingType()
18289 return \PDO::PARAM_INT;
18295 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18296 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18297 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18298 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18299 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18300 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18301 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18302 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18303 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18304 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18305 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18307 * This software consists of voluntary contributions made by many individuals
18308 * and is licensed under the LGPL. For more information, see
18309 * <http://www.doctrine-project.org>.
18312 namespace Doctrine\DBAL\Types;
18314 use Doctrine\DBAL\Platforms\AbstractPlatform;
18317 * Type that maps a database BIGINT to a PHP string.
18322 class BigIntType extends Type
18324 public function getName()
18326 return Type::BIGINT;
18329 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18331 return $platform->getBigIntTypeDeclarationSQL($fieldDeclaration);
18334 public function getBindingType()
18336 return \PDO::PARAM_INT;
18342 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18343 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18344 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18345 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18346 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18347 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18348 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18349 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18350 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18351 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18352 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18354 * This software consists of voluntary contributions made by many individuals
18355 * and is licensed under the LGPL. For more information, see
18356 * <http://www.doctrine-project.org>.
18359 namespace Doctrine\DBAL\Types;
18361 use Doctrine\DBAL\Platforms\AbstractPlatform;
18364 * Type that maps an SQL VARCHAR to a PHP string.
18368 class StringType extends Type
18371 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18373 return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
18377 public function getDefaultLength(AbstractPlatform $platform)
18379 return $platform->getVarcharDefaultLength();
18383 public function getName()
18385 return Type::STRING;
18389 namespace Doctrine\DBAL\Types;
18392 * Type that maps a PHP object to a clob SQL type.
18396 class ObjectType extends Type
18398 public function getSQLDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18400 return $platform->getClobTypeDeclarationSQL($fieldDeclaration);
18403 public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18405 return serialize($value);
18408 public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18410 if ($value === null) {
18414 $value = (is_resource($value)) ? stream_get_contents($value) : $value;
18415 $val = unserialize($value);
18416 if ($val === false) {
18417 throw ConversionException::conversionFailed($value, $this->getName());
18422 public function getName()
18424 return Type::OBJECT;
18428 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18429 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18430 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18431 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18432 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18433 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18434 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18435 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18436 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18437 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18438 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18440 * This software consists of voluntary contributions made by many individuals
18441 * and is licensed under the LGPL. For more information, see
18442 * <http://www.doctrine-project.org>.
18446 namespace Doctrine\DBAL\Types;
18448 use Doctrine\DBAL\Platforms\AbstractPlatform;
18451 * DateTime type saving additional timezone information.
18453 * Caution: Databases are not necessarily experts at storing timezone related
18454 * data of dates. First, of all the supported vendors only PostgreSQL and Oracle
18455 * support storing Timezone data. But those two don't save the actual timezone
18456 * attached to a DateTime instance (for example "Europe/Berlin" or "America/Montreal")
18457 * but the current offset of them related to UTC. That means depending on daylight saving times
18458 * or not you may get different offsets.
18460 * This datatype makes only sense to use, if your application works with an offset, not
18461 * with an actual timezone that uses transitions. Otherwise your DateTime instance
18462 * attached with a timezone such as Europe/Berlin gets saved into the database with
18463 * the offset and re-created from persistence with only the offset, not the original timezone
18466 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
18467 * @link www.doctrine-project.com
18469 * @author Benjamin Eberlei <kontakt@beberlei.de>
18470 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
18471 * @author Jonathan Wage <jonwage@gmail.com>
18472 * @author Roman Borschel <roman@code-factory.org>
18474 class DateTimeTzType extends Type
18476 public function getName()
18478 return Type::DATETIMETZ;
18481 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18483 return $platform->getDateTimeTzTypeDeclarationSQL($fieldDeclaration);
18486 public function convertToDatabaseValue($value, AbstractPlatform $platform)
18488 return ($value !== null)
18489 ? $value->format($platform->getDateTimeTzFormatString()) : null;
18492 public function convertToPHPValue($value, AbstractPlatform $platform)
18494 if ($value === null) {
18498 $val = \DateTime::createFromFormat($platform->getDateTimeTzFormatString(), $value);
18500 throw ConversionException::conversionFailed($value, $this->getName());
18506 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18507 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18508 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18509 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18510 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18511 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18512 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18513 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18514 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18515 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18516 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18518 * This software consists of voluntary contributions made by many individuals
18519 * and is licensed under the LGPL. For more information, see
18520 * <http://www.doctrine-project.org>.
18525 * Conversion Exception is thrown when the database to PHP conversion fails
18527 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
18528 * @link www.doctrine-project.com
18530 * @author Benjamin Eberlei <kontakt@beberlei.de>
18531 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
18532 * @author Jonathan Wage <jonwage@gmail.com>
18533 * @author Roman Borschel <roman@code-factory.org>
18535 namespace Doctrine\DBAL\Types;
18537 class ConversionException extends \Doctrine\DBAL\DBALException
18540 * Thrown when a Database to Doctrine Type Conversion fails.
18542 * @param string $value
18543 * @param string $toType
18544 * @return ConversionException
18546 static public function conversionFailed($value, $toType)
18548 $value = (strlen($value) > 32) ? substr($value, 0, 20) . "..." : $value;
18549 return new self('Could not convert database value "' . $value . '" to Doctrine Type ' . $toType);
18553 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18554 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18555 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18556 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18557 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18558 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18559 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18560 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18561 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18562 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18563 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18565 * This software consists of voluntary contributions made by many individuals
18566 * and is licensed under the LGPL. For more information, see
18567 * <http://www.doctrine-project.org>.
18570 namespace Doctrine\DBAL\Types;
18572 use Doctrine\DBAL\Platforms\AbstractPlatform;
18575 * Type that maps an SQL DATETIME/TIMESTAMP to a PHP DateTime object.
18579 class DateTimeType extends Type
18581 public function getName()
18583 return Type::DATETIME;
18586 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18588 return $platform->getDateTimeTypeDeclarationSQL($fieldDeclaration);
18591 public function convertToDatabaseValue($value, AbstractPlatform $platform)
18593 return ($value !== null)
18594 ? $value->format($platform->getDateTimeFormatString()) : null;
18597 public function convertToPHPValue($value, AbstractPlatform $platform)
18599 if ($value === null) {
18603 $val = \DateTime::createFromFormat($platform->getDateTimeFormatString(), $value);
18605 throw ConversionException::conversionFailed($value, $this->getName());
18611 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18612 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18613 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18614 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18615 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18616 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18617 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18618 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18619 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18620 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18621 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18623 * This software consists of voluntary contributions made by many individuals
18624 * and is licensed under the LGPL. For more information, see
18625 * <http://www.doctrine-project.org>.
18628 namespace Doctrine\DBAL\Types;
18630 use Doctrine\DBAL\Platforms\AbstractPlatform;
18633 * Type that maps an SQL DECIMAL to a PHP double.
18637 class DecimalType extends Type
18639 public function getName()
18641 return Type::DECIMAL;
18644 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18646 return $platform->getDecimalTypeDeclarationSQL($fieldDeclaration);
18649 public function convertToPHPValue($value, AbstractPlatform $platform)
18651 return (null === $value) ? null : (double) $value;
18657 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18658 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18659 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18660 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18661 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18662 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18663 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18664 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18665 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18666 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18667 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18669 * This software consists of voluntary contributions made by many individuals
18670 * and is licensed under the LGPL. For more information, see
18671 * <http://www.doctrine-project.org>.
18674 namespace Doctrine\DBAL\Types;
18676 use Doctrine\DBAL\Platforms\AbstractPlatform;
18679 * Type that maps an SQL CLOB to a PHP string.
18683 class TextType extends Type
18686 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18688 return $platform->getClobTypeDeclarationSQL($fieldDeclaration);
18692 * Converts a value from its database representation to its PHP representation
18695 * @param mixed $value The value to convert.
18696 * @param AbstractPlatform $platform The currently used database platform.
18697 * @return mixed The PHP representation of the value.
18699 public function convertToPHPValue($value, AbstractPlatform $platform)
18701 return (is_resource($value)) ? stream_get_contents($value) : $value;
18704 public function getName()
18712 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18713 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18714 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18715 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18716 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18717 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18718 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18719 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18720 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18721 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18722 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18724 * This software consists of voluntary contributions made by many individuals
18725 * and is licensed under the LGPL. For more information, see
18726 * <http://www.doctrine-project.org>.
18729 namespace Doctrine\DBAL\Types;
18732 * Type that maps a PHP array to a clob SQL type.
18736 class ArrayType extends Type
18738 public function getSQLDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18740 return $platform->getClobTypeDeclarationSQL($fieldDeclaration);
18743 public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18745 return serialize($value);
18748 public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18750 if ($value === null) {
18754 $value = (is_resource($value)) ? stream_get_contents($value) : $value;
18755 $val = unserialize($value);
18756 if ($val === false) {
18757 throw ConversionException::conversionFailed($value, $this->getName());
18762 public function getName()
18764 return Type::TARRAY;
18770 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18771 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18772 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18773 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18774 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18775 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18776 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18777 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18778 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18779 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18780 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18782 * This software consists of voluntary contributions made by many individuals
18783 * and is licensed under the LGPL. For more information, see
18784 * <http://www.doctrine-project.org>.
18787 namespace Doctrine\DBAL\Types;
18789 use Doctrine\DBAL\Platforms\AbstractPlatform;
18792 * Type that maps an SQL boolean to a PHP boolean.
18796 class BooleanType extends Type
18798 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18800 return $platform->getBooleanTypeDeclarationSQL($fieldDeclaration);
18803 public function convertToDatabaseValue($value, AbstractPlatform $platform)
18805 return $platform->convertBooleans($value);
18808 public function convertToPHPValue($value, AbstractPlatform $platform)
18810 return (null === $value) ? null : (bool) $value;
18813 public function getName()
18815 return Type::BOOLEAN;
18818 public function getBindingType()
18820 return \PDO::PARAM_BOOL;
18824 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18825 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18826 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18827 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18828 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18829 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18830 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18831 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18832 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18833 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18834 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18836 * This software consists of voluntary contributions made by many individuals
18837 * and is licensed under the LGPL. For more information, see
18838 * <http://www.doctrine-project.org>.
18841 namespace Doctrine\DBAL\Types;
18843 use Doctrine\DBAL\Platforms\AbstractPlatform;
18846 * Type that maps an SQL TIME to a PHP DateTime object.
18850 class TimeType extends Type
18852 public function getName()
18860 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18862 return $platform->getTimeTypeDeclarationSQL($fieldDeclaration);
18868 public function convertToDatabaseValue($value, AbstractPlatform $platform)
18870 return ($value !== null)
18871 ? $value->format($platform->getTimeFormatString()) : null;
18877 public function convertToPHPValue($value, AbstractPlatform $platform)
18879 if ($value === null) {
18883 $val = \DateTime::createFromFormat($platform->getTimeFormatString(), $value);
18885 throw ConversionException::conversionFailed($value, $this->getName());
18893 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18894 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18895 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18896 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18897 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18898 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18899 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18900 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18901 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18902 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18903 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18905 * This software consists of voluntary contributions made by many individuals
18906 * and is licensed under the LGPL. For more information, see
18907 * <http://www.doctrine-project.org>.
18910 namespace Doctrine\DBAL\Event;
18912 use Doctrine\Common\EventArgs,
18913 Doctrine\DBAL\Connection;
18916 * Event Arguments used when a Driver connection is established inside Doctrine\DBAL\Connection.
18918 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
18919 * @link www.doctrine-project.com
18921 * @version $Revision$
18922 * @author Benjamin Eberlei <kontakt@beberlei.de>
18924 class ConnectionEventArgs extends EventArgs
18929 private $_connection = null;
18931 public function __construct(Connection $connection)
18933 $this->_connection = $connection;
18937 * @return Doctrine\DBAL\Connection
18939 public function getConnection()
18941 return $this->_connection;
18945 * @return Doctrine\DBAL\Driver
18947 public function getDriver()
18949 return $this->_connection->getDriver();
18953 * @return Doctrine\DBAL\Platforms\AbstractPlatform
18955 public function getDatabasePlatform()
18957 return $this->_connection->getDatabasePlatform();
18961 * @return Doctrine\DBAL\Schema\AbstractSchemaManager
18963 public function getSchemaManager()
18965 return $this->_connection->getSchemaManager();
18972 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18973 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18974 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18975 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18976 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18977 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18978 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18979 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18980 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18981 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18982 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18984 * This software consists of voluntary contributions made by many individuals
18985 * and is licensed under the LGPL. For more information, see
18986 * <http://www.doctrine-project.org>.
18989 namespace Doctrine\DBAL\Event\Listeners;
18991 use Doctrine\DBAL\Event\ConnectionEventArgs;
18992 use Doctrine\DBAL\Events;
18993 use Doctrine\Common\EventSubscriber;
18996 * MySQL Session Init Event Subscriber which allows to set the Client Encoding of the Connection
18998 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
18999 * @link www.doctrine-project.com
19001 * @version $Revision$
19002 * @author Benjamin Eberlei <kontakt@beberlei.de>
19004 class MysqlSessionInit implements EventSubscriber
19014 private $_collation;
19017 * Configure Charset and Collation options of MySQL Client for each Connection
19019 * @param string $charset
19020 * @param string $collation
19022 public function __construct($charset = 'utf8', $collation = false)
19024 $this->_charset = $charset;
19025 $this->_collation = $collation;
19029 * @param ConnectionEventArgs $args
19032 public function postConnect(ConnectionEventArgs $args)
19034 $collation = ($this->_collation) ? " COLLATE ".$this->_collation : "";
19035 $args->getConnection()->executeUpdate("SET NAMES ".$this->_charset . $collation);
19038 public function getSubscribedEvents()
19040 return array(Events::postConnect);
19046 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19047 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19048 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19049 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19050 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19051 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19052 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19053 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19054 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19055 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
19056 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19058 * This software consists of voluntary contributions made by many individuals
19059 * and is licensed under the LGPL. For more information, see
19060 * <http://www.doctrine-project.org>.
19063 namespace Doctrine\DBAL\Event\Listeners;
19065 use Doctrine\DBAL\Event\ConnectionEventArgs;
19066 use Doctrine\DBAL\Events;
19067 use Doctrine\Common\EventSubscriber;
19070 * Should be used when Oracle Server default enviroment does not match the Doctrine requirements.
19072 * The following enviroment variables are required for the Doctrine default date format:
19074 * NLS_TIME_FORMAT="HH24:MI:SS"
19075 * NLS_DATE_FORMAT="YYYY-MM-DD"
19076 * NLS_TIMESTAMP_FORMAT="YYYY-MM-DD HH24:MI:SS"
19077 * NLS_TIMESTAMP_TZ_FORMAT="YYYY-MM-DD HH24:MI:SS TZH:TZM"
19079 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
19080 * @link www.doctrine-project.com
19082 * @version $Revision$
19083 * @author Benjamin Eberlei <kontakt@beberlei.de>
19085 class OracleSessionInit implements EventSubscriber
19087 protected $_defaultSessionVars = array(
19088 'NLS_TIME_FORMAT' => "HH24:MI:SS",
19089 'NLS_DATE_FORMAT' => "YYYY-MM-DD HH24:MI:SS",
19090 'NLS_TIMESTAMP_FORMAT' => "YYYY-MM-DD HH24:MI:SS",
19091 'NLS_TIMESTAMP_TZ_FORMAT' => "YYYY-MM-DD HH24:MI:SS TZH:TZM",
19095 * @param array $oracleSessionVars
19097 public function __construct(array $oracleSessionVars = array())
19099 $this->_defaultSessionVars = array_merge($this->_defaultSessionVars, $oracleSessionVars);
19103 * @param ConnectionEventArgs $args
19106 public function postConnect(ConnectionEventArgs $args)
19108 if (count($this->_defaultSessionVars)) {
19109 array_change_key_case($this->_defaultSessionVars, \CASE_UPPER);
19111 foreach ($this->_defaultSessionVars AS $option => $value) {
19112 $vars[] = $option." = '".$value."'";
19114 $sql = "ALTER SESSION SET ".implode(" ", $vars);
19115 $args->getConnection()->executeUpdate($sql);
19119 public function getSubscribedEvents()
19121 return array(Events::postConnect);
19128 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19129 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19130 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19131 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19132 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19133 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19134 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19135 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19136 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19137 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
19138 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19140 * This software consists of voluntary contributions made by many individuals
19141 * and is licensed under the LGPL. For more information, see
19142 * <http://www.doctrine-project.org>.
19145 namespace Doctrine\Common;
19148 * EventArgs is the base class for classes containing event data.
19150 * This class contains no event data. It is used by events that do not pass state
19151 * information to an event handler when an event is raised. The single empty EventArgs
19152 * instance can be obtained through {@link getEmptyInstance}.
19154 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
19155 * @link www.doctrine-project.org
19157 * @version $Revision: 3938 $
19158 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
19159 * @author Jonathan Wage <jonwage@gmail.com>
19160 * @author Roman Borschel <roman@code-factory.org>
19165 * @var EventArgs Single instance of EventArgs
19168 private static $_emptyEventArgsInstance;
19171 * Gets the single, empty and immutable EventArgs instance.
19173 * This instance will be used when events are dispatched without any parameter,
19174 * like this: EventManager::dispatchEvent('eventname');
19176 * The benefit from this is that only one empty instance is instantiated and shared
19177 * (otherwise there would be instances for every dispatched in the abovementioned form)
19179 * @see EventManager::dispatchEvent
19180 * @link http://msdn.microsoft.com/en-us/library/system.eventargs.aspx
19182 * @return EventArgs
19184 public static function getEmptyInstance()
19186 if ( ! self::$_emptyEventArgsInstance) {
19187 self::$_emptyEventArgsInstance = new EventArgs;
19190 return self::$_emptyEventArgsInstance;
19195 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19196 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19197 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19198 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19199 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19200 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19201 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19202 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19203 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19204 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
19205 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19207 * This software consists of voluntary contributions made by many individuals
19208 * and is licensed under the LGPL. For more information, see
19209 * <http://www.doctrine-project.org>.
19212 namespace Doctrine\Common;
19215 * Base exception class for package Doctrine\Common
19219 class CommonException extends \Exception {
19222 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19223 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19224 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19225 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19226 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19227 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19228 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19229 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19230 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19231 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
19232 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19234 * This software consists of voluntary contributions made by many individuals
19235 * and is licensed under the LGPL. For more information, see
19236 * <http://www.doctrine-project.org>.
19239 namespace Doctrine\Common\Annotations;
19244 ReflectionProperty,
19245 Doctrine\Common\Cache\Cache;
19248 * A reader for docblock annotations.
19251 * @author Benjamin Eberlei <kontakt@beberlei.de>
19252 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
19253 * @author Jonathan Wage <jonwage@gmail.com>
19254 * @author Roman Borschel <roman@code-factory.org>
19256 class AnnotationReader
19264 private static $CACHE_SALT = '@<Annot>';
19267 * Annotations Parser
19269 * @var Doctrine\Common\Annotations\Parser
19274 * Cache mechanism to store processed Annotations
19276 * @var Doctrine\Common\Cache\Cache
19281 * Constructor. Initializes a new AnnotationReader that uses the given Cache provider.
19283 * @param Cache $cache The cache provider to use. If none is provided, ArrayCache is used.
19284 * @param Parser $parser The parser to use. If none is provided, the default parser is used.
19286 public function __construct(Cache $cache = null, Parser $parser = null)
19288 $this->parser = $parser ?: new Parser;
19289 $this->cache = $cache ?: new \Doctrine\Common\Cache\ArrayCache;
19293 * Sets the default namespace that the AnnotationReader should assume for annotations
19294 * with not fully qualified names.
19296 * @param string $defaultNamespace
19298 public function setDefaultAnnotationNamespace($defaultNamespace)
19300 $this->parser->setDefaultAnnotationNamespace($defaultNamespace);
19304 * Sets the custom function to use for creating new annotations on the
19305 * underlying parser.
19307 * The function is supplied two arguments. The first argument is the name
19308 * of the annotation and the second argument an array of values for this
19309 * annotation. The function is assumed to return an object or NULL.
19310 * Whenever the function returns NULL for an annotation, the implementation falls
19311 * back to the default annotation creation process of the underlying parser.
19313 * @param Closure $func
19315 public function setAnnotationCreationFunction(Closure $func)
19317 $this->parser->setAnnotationCreationFunction($func);
19321 * Sets an alias for an annotation namespace.
19323 * @param $namespace
19326 public function setAnnotationNamespaceAlias($namespace, $alias)
19328 $this->parser->setAnnotationNamespaceAlias($namespace, $alias);
19332 * Sets a flag whether to try to autoload annotation classes, as well as to distinguish
19333 * between what is an annotation and what not by triggering autoloading.
19335 * NOTE: Autoloading of annotation classes is inefficient and requires silently failing
19336 * autoloaders. In particular, setting this option to TRUE renders this AnnotationReader
19337 * incompatible with a {@link ClassLoader}.
19338 * @param boolean $bool Boolean flag.
19340 public function setAutoloadAnnotations($bool)
19342 $this->parser->setAutoloadAnnotations($bool);
19346 * Gets a flag whether to try to autoload annotation classes.
19348 * @see setAutoloadAnnotations
19351 public function getAutoloadAnnotations()
19353 return $this->parser->getAutoloadAnnotations();
19357 * Gets the annotations applied to a class.
19359 * @param string|ReflectionClass $class The name or ReflectionClass of the class from which
19360 * the class annotations should be read.
19361 * @return array An array of Annotations.
19363 public function getClassAnnotations(ReflectionClass $class)
19365 $cacheKey = $class->getName() . self::$CACHE_SALT;
19367 // Attempt to grab data from cache
19368 if (($data = $this->cache->fetch($cacheKey)) !== false) {
19372 $annotations = $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
19373 $this->cache->save($cacheKey, $annotations, null);
19375 return $annotations;
19379 * Gets a class annotation.
19382 * @param string $annotation The name of the annotation.
19383 * @return The Annotation or NULL, if the requested annotation does not exist.
19385 public function getClassAnnotation(ReflectionClass $class, $annotation)
19387 $annotations = $this->getClassAnnotations($class);
19389 return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
19393 * Gets the annotations applied to a property.
19395 * @param string|ReflectionClass $class The name or ReflectionClass of the class that owns the property.
19396 * @param string|ReflectionProperty $property The name or ReflectionProperty of the property
19397 * from which the annotations should be read.
19398 * @return array An array of Annotations.
19400 public function getPropertyAnnotations(ReflectionProperty $property)
19402 $cacheKey = $property->getDeclaringClass()->getName() . '$' . $property->getName() . self::$CACHE_SALT;
19404 // Attempt to grab data from cache
19405 if (($data = $this->cache->fetch($cacheKey)) !== false) {
19409 $context = 'property ' . $property->getDeclaringClass()->getName() . "::\$" . $property->getName();
19410 $annotations = $this->parser->parse($property->getDocComment(), $context);
19411 $this->cache->save($cacheKey, $annotations, null);
19413 return $annotations;
19417 * Gets a property annotation.
19419 * @param ReflectionProperty $property
19420 * @param string $annotation The name of the annotation.
19421 * @return The Annotation or NULL, if the requested annotation does not exist.
19423 public function getPropertyAnnotation(ReflectionProperty $property, $annotation)
19425 $annotations = $this->getPropertyAnnotations($property);
19427 return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
19431 * Gets the annotations applied to a method.
19433 * @param string|ReflectionClass $class The name or ReflectionClass of the class that owns the method.
19434 * @param string|ReflectionMethod $property The name or ReflectionMethod of the method from which
19435 * the annotations should be read.
19436 * @return array An array of Annotations.
19438 public function getMethodAnnotations(ReflectionMethod $method)
19440 $cacheKey = $method->getDeclaringClass()->getName() . '#' . $method->getName() . self::$CACHE_SALT;
19442 // Attempt to grab data from cache
19443 if (($data = $this->cache->fetch($cacheKey)) !== false) {
19447 $context = 'method ' . $method->getDeclaringClass()->getName() . '::' . $method->getName() . '()';
19448 $annotations = $this->parser->parse($method->getDocComment(), $context);
19449 $this->cache->save($cacheKey, $annotations, null);
19451 return $annotations;
19455 * Gets a method annotation.
19457 * @param ReflectionMethod $method
19458 * @param string $annotation The name of the annotation.
19459 * @return The Annotation or NULL, if the requested annotation does not exist.
19461 public function getMethodAnnotation(ReflectionMethod $method, $annotation)
19463 $annotations = $this->getMethodAnnotations($method);
19465 return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
19469 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19470 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19471 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19472 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19473 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19474 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19475 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19476 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19477 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19478 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
19479 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19481 * This software consists of voluntary contributions made by many individuals
19482 * and is licensed under the LGPL. For more information, see
19483 * <http://www.doctrine-project.org>.
19486 namespace Doctrine\Common\Annotations;
19489 * Description of AnnotationException
19492 * @author Benjamin Eberlei <kontakt@beberlei.de>
19493 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
19494 * @author Jonathan Wage <jonwage@gmail.com>
19495 * @author Roman Borschel <roman@code-factory.org>
19497 class AnnotationException extends \Exception
19500 * Creates a new AnnotationException describing a Syntax error.
19502 * @param string $message Exception message
19503 * @return AnnotationException
19505 public static function syntaxError($message)
19507 return new self('[Syntax Error] ' . $message);
19511 * Creates a new AnnotationException describing a Semantical error.
19513 * @param string $message Exception message
19514 * @return AnnotationException
19516 public static function semanticalError($message)
19518 return new self('[Semantical Error] ' . $message);
19522 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19523 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19524 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19525 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19526 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19527 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19528 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19529 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19530 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19531 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
19532 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19534 * This software consists of voluntary contributions made by many individuals
19535 * and is licensed under the LGPL. For more information, see
19536 * <http://www.doctrine-project.org>.
19539 namespace Doctrine\Common\Annotations;
19541 use Closure, Doctrine\Common\ClassLoader;
19544 * A simple parser for docblock annotations.
19546 * This Parser can be subclassed to customize certain aspects of the annotation
19547 * parsing and/or creation process. Note though that currently no special care
19548 * is taken to maintain full backwards compatibility for subclasses. Implementation
19549 * details of the default Parser can change without explicit notice.
19552 * @author Benjamin Eberlei <kontakt@beberlei.de>
19553 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
19554 * @author Jonathan Wage <jonwage@gmail.com>
19555 * @author Roman Borschel <roman@code-factory.org>
19560 * Some common tags that are stripped prior to parsing in order to reduce parsing overhead.
19564 private static $strippedTags = array(
19565 "{@internal", "{@inheritdoc", "{@link"
19571 * @var Doctrine\Common\Annotations\Lexer
19576 * Flag to control if the current annotation is nested or not.
19580 protected $isNestedAnnotation = false;
19583 * Default namespace for annotations.
19587 private $defaultAnnotationNamespace = '';
19590 * Hashmap to store namespace aliases.
19594 private $namespaceAliases = array();
19599 private $context = '';
19602 * @var boolean Whether to try to autoload annotations that are not yet defined.
19604 private $autoloadAnnotations = false;
19607 * @var Closure The custom function used to create new annotations, if any.
19609 private $annotationCreationFunction;
19612 * Constructs a new AnnotationParser.
19614 public function __construct(Lexer $lexer = null)
19616 $this->lexer = $lexer ?: new Lexer;
19620 * Gets the lexer used by this parser.
19622 * @return Lexer The lexer.
19624 public function getLexer()
19626 return $this->lexer;
19630 * Sets a flag whether to try to autoload annotation classes, as well as to distinguish
19631 * between what is an annotation and what not by triggering autoloading.
19633 * NOTE: Autoloading of annotation classes is inefficient and requires silently failing
19634 * autoloaders. In particular, setting this option to TRUE renders the Parser
19635 * incompatible with a {@link ClassLoader}.
19636 * @param boolean $bool Boolean flag.
19638 public function setAutoloadAnnotations($bool)
19640 $this->autoloadAnnotations = $bool;
19644 * Sets the custom function to use for creating new annotations.
19646 * The function is supplied two arguments. The first argument is the name
19647 * of the annotation and the second argument an array of values for this
19648 * annotation. The function is assumed to return an object or NULL.
19649 * Whenever the function returns NULL for an annotation, the parser falls
19650 * back to the default annotation creation process.
19652 * Whenever the function returns NULL for an annotation, the implementation falls
19653 * back to the default annotation creation process.
19655 * @param Closure $func
19657 public function setAnnotationCreationFunction(Closure $func)
19659 $this->annotationCreationFunction = $func;
19663 * Gets a flag whether to try to autoload annotation classes.
19665 * @see setAutoloadAnnotations
19668 public function getAutoloadAnnotations()
19670 return $this->autoloadAnnotations;
19674 * Sets the default namespace that is assumed for an annotation that does not
19675 * define a namespace prefix.
19677 * @param string $defaultNamespace
19679 public function setDefaultAnnotationNamespace($defaultNamespace)
19681 $this->defaultAnnotationNamespace = $defaultNamespace;
19685 * Sets an alias for an annotation namespace.
19687 * @param string $namespace
19688 * @param string $alias
19690 public function setAnnotationNamespaceAlias($namespace, $alias)
19692 $this->namespaceAliases[$alias] = $namespace;
19696 * Gets the namespace alias mappings used by this parser.
19698 * @return array The namespace alias mappings.
19700 public function getNamespaceAliases()
19702 return $this->namespaceAliases;
19706 * Parses the given docblock string for annotations.
19708 * @param string $docBlockString The docblock string to parse.
19709 * @param string $context The parsing context.
19710 * @return array Array of annotations. If no annotations are found, an empty array is returned.
19712 public function parse($docBlockString, $context='')
19714 $this->context = $context;
19716 // Strip out some known inline tags.
19717 $input = str_replace(self::$strippedTags, '', $docBlockString);
19719 // Cut of the beginning of the input until the first '@'.
19720 $input = substr($input, strpos($input, '@'));
19722 $this->lexer->reset();
19723 $this->lexer->setInput(trim($input, '* /'));
19724 $this->lexer->moveNext();
19726 if ($this->lexer->isNextToken(Lexer::T_AT)) {
19727 return $this->Annotations();
19734 * Attempts to match the given token with the current lookahead token.
19735 * If they match, updates the lookahead token; otherwise raises a syntax error.
19737 * @param int Token type.
19738 * @return bool True if tokens match; false otherwise.
19740 public function match($token)
19742 if ( ! ($this->lexer->lookahead['type'] === $token)) {
19743 $this->syntaxError($this->lexer->getLiteral($token));
19745 $this->lexer->moveNext();
19749 * Generates a new syntax error.
19751 * @param string $expected Expected string.
19752 * @param array $token Optional token.
19753 * @throws AnnotationException
19755 private function syntaxError($expected, $token = null)
19757 if ($token === null) {
19758 $token = $this->lexer->lookahead;
19761 $message = "Expected {$expected}, got ";
19763 if ($this->lexer->lookahead === null) {
19764 $message .= 'end of string';
19766 $message .= "'{$token['value']}' at position {$token['position']}";
19769 if (strlen($this->context)) {
19770 $message .= ' in ' . $this->context;
19775 throw AnnotationException::syntaxError($message);
19779 * Annotations ::= Annotation {[ "*" ]* [Annotation]}*
19783 public function Annotations()
19785 $this->isNestedAnnotation = false;
19787 $annotations = array();
19788 $annot = $this->Annotation();
19790 if ($annot !== false) {
19791 $annotations[get_class($annot)] = $annot;
19792 $this->lexer->skipUntil(Lexer::T_AT);
19795 while ($this->lexer->lookahead !== null && $this->lexer->isNextToken(Lexer::T_AT)) {
19796 $this->isNestedAnnotation = false;
19797 $annot = $this->Annotation();
19799 if ($annot !== false) {
19800 $annotations[get_class($annot)] = $annot;
19801 $this->lexer->skipUntil(Lexer::T_AT);
19805 return $annotations;
19809 * Annotation ::= "@" AnnotationName ["(" [Values] ")"]
19810 * AnnotationName ::= QualifiedName | SimpleName | AliasedName
19811 * QualifiedName ::= NameSpacePart "\" {NameSpacePart "\"}* SimpleName
19812 * AliasedName ::= Alias ":" SimpleName
19813 * NameSpacePart ::= identifier
19814 * SimpleName ::= identifier
19815 * Alias ::= identifier
19817 * @return mixed False if it is not a valid annotation.
19819 public function Annotation()
19822 $nameParts = array();
19824 $this->match(Lexer::T_AT);
19825 $this->match(Lexer::T_IDENTIFIER);
19826 $nameParts[] = $this->lexer->token['value'];
19828 while ($this->lexer->isNextToken(Lexer::T_NAMESPACE_SEPARATOR)) {
19829 $this->match(Lexer::T_NAMESPACE_SEPARATOR);
19830 $this->match(Lexer::T_IDENTIFIER);
19831 $nameParts[] = $this->lexer->token['value'];
19834 // Effectively pick the name of the class (append default NS if none, grab from NS alias, etc)
19835 if (strpos($nameParts[0], ':')) {
19836 list ($alias, $nameParts[0]) = explode(':', $nameParts[0]);
19838 // If the namespace alias doesnt exist, skip until next annotation
19839 if ( ! isset($this->namespaceAliases[$alias])) {
19840 $this->lexer->skipUntil(Lexer::T_AT);
19844 $name = $this->namespaceAliases[$alias] . implode('\\', $nameParts);
19845 } else if (count($nameParts) == 1) {
19846 $name = $this->defaultAnnotationNamespace . $nameParts[0];
19848 $name = implode('\\', $nameParts);
19851 // Does the annotation class exist?
19852 if ( ! class_exists($name, $this->autoloadAnnotations)) {
19853 $this->lexer->skipUntil(Lexer::T_AT);
19857 // Next will be nested
19858 $this->isNestedAnnotation = true;
19860 if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
19861 $this->match(Lexer::T_OPEN_PARENTHESIS);
19863 if ( ! $this->lexer->isNextToken(Lexer::T_CLOSE_PARENTHESIS)) {
19864 $values = $this->Values();
19867 $this->match(Lexer::T_CLOSE_PARENTHESIS);
19870 if ($this->annotationCreationFunction !== null) {
19871 $func = $this->annotationCreationFunction;
19872 $annot = $func($name, $values);
19875 return isset($annot) ? $annot : $this->newAnnotation($name, $values);
19879 * Values ::= Array | Value {"," Value}*
19883 public function Values()
19887 // Handle the case of a single array as value, i.e. @Foo({....})
19888 if ($this->lexer->isNextToken(Lexer::T_OPEN_CURLY_BRACES)) {
19889 $values['value'] = $this->Value();
19893 $values[] = $this->Value();
19895 while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
19896 $this->match(Lexer::T_COMMA);
19897 $value = $this->Value();
19899 if ( ! is_array($value)) {
19900 $this->syntaxError('Value', $value);
19903 $values[] = $value;
19906 foreach ($values as $k => $value) {
19907 if (is_array($value) && is_string(key($value))) {
19908 $key = key($value);
19909 $values[$key] = $value[$key];
19911 $values['value'] = $value;
19914 unset($values[$k]);
19921 * Value ::= PlainValue | FieldAssignment
19925 public function Value()
19927 $peek = $this->lexer->glimpse();
19929 if ($peek['value'] === '=') {
19930 return $this->FieldAssignment();
19933 return $this->PlainValue();
19937 * PlainValue ::= integer | string | float | boolean | Array | Annotation
19941 public function PlainValue()
19943 if ($this->lexer->isNextToken(Lexer::T_OPEN_CURLY_BRACES)) {
19944 return $this->Arrayx();
19947 if ($this->lexer->isNextToken(Lexer::T_AT)) {
19948 return $this->Annotation();
19951 switch ($this->lexer->lookahead['type']) {
19952 case Lexer::T_STRING:
19953 $this->match(Lexer::T_STRING);
19954 return $this->lexer->token['value'];
19956 case Lexer::T_INTEGER:
19957 $this->match(Lexer::T_INTEGER);
19958 return $this->lexer->token['value'];
19960 case Lexer::T_FLOAT:
19961 $this->match(Lexer::T_FLOAT);
19962 return $this->lexer->token['value'];
19964 case Lexer::T_TRUE:
19965 $this->match(Lexer::T_TRUE);
19968 case Lexer::T_FALSE:
19969 $this->match(Lexer::T_FALSE);
19973 $this->syntaxError('PlainValue');
19978 * FieldAssignment ::= FieldName "=" PlainValue
19979 * FieldName ::= identifier
19983 public function FieldAssignment()
19985 $this->match(Lexer::T_IDENTIFIER);
19986 $fieldName = $this->lexer->token['value'];
19987 $this->match(Lexer::T_EQUALS);
19989 return array($fieldName => $this->PlainValue());
19993 * Array ::= "{" ArrayEntry {"," ArrayEntry}* "}"
19997 public function Arrayx()
19999 $array = $values = array();
20001 $this->match(Lexer::T_OPEN_CURLY_BRACES);
20002 $values[] = $this->ArrayEntry();
20004 while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
20005 $this->match(Lexer::T_COMMA);
20006 $values[] = $this->ArrayEntry();
20009 $this->match(Lexer::T_CLOSE_CURLY_BRACES);
20011 foreach ($values as $value) {
20012 list ($key, $val) = $value;
20014 if ($key !== null) {
20015 $array[$key] = $val;
20025 * ArrayEntry ::= Value | KeyValuePair
20026 * KeyValuePair ::= Key "=" PlainValue
20027 * Key ::= string | integer
20031 public function ArrayEntry()
20033 $peek = $this->lexer->glimpse();
20035 if ($peek['value'] == '=') {
20037 $this->lexer->isNextToken(Lexer::T_INTEGER) ? Lexer::T_INTEGER : Lexer::T_STRING
20040 $key = $this->lexer->token['value'];
20041 $this->match(Lexer::T_EQUALS);
20043 return array($key, $this->PlainValue());
20046 return array(null, $this->Value());
20050 * Constructs a new annotation with a given map of values.
20052 * The default construction procedure is to instantiate a new object of a class
20053 * with the same name as the annotation. Subclasses can override this method to
20054 * change the construction process of new annotations.
20056 * @param string The name of the annotation.
20057 * @param array The map of annotation values.
20058 * @return mixed The new annotation with the given values.
20060 protected function newAnnotation($name, array $values)
20062 return new $name($values);
20066 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20067 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20068 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20069 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20070 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20071 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20072 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20073 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20074 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20075 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
20076 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20078 * This software consists of voluntary contributions made by many individuals
20079 * and is licensed under the LGPL. For more information, see
20080 * <http://www.doctrine-project.org>.
20083 namespace Doctrine\Common\Annotations;
20086 * Simple lexer for docblock annotations.
20088 * This Lexer can be subclassed to customize certain aspects of the annotation
20089 * lexing (token recognition) process. Note though that currently no special care
20090 * is taken to maintain full backwards compatibility for subclasses. Implementation
20091 * details of the default Lexer can change without explicit notice.
20094 * @author Benjamin Eberlei <kontakt@beberlei.de>
20095 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
20096 * @author Jonathan Wage <jonwage@gmail.com>
20097 * @author Roman Borschel <roman@code-factory.org>
20099 class Lexer extends \Doctrine\Common\Lexer
20102 const T_IDENTIFIER = 2;
20103 const T_INTEGER = 3;
20104 const T_STRING = 4;
20108 const T_CLOSE_CURLY_BRACES = 102;
20109 const T_CLOSE_PARENTHESIS = 103;
20110 const T_COMMA = 104;
20111 const T_EQUALS = 105;
20112 const T_FALSE = 106;
20113 const T_NAMESPACE_SEPARATOR = 107;
20114 const T_OPEN_CURLY_BRACES = 108;
20115 const T_OPEN_PARENTHESIS = 109;
20116 const T_TRUE = 110;
20121 protected function getCatchablePatterns()
20124 '[a-z_][a-z0-9_:]*',
20125 '(?:[0-9]+(?:[\.][0-9]+)*)(?:e[+-]?[0-9]+)?',
20133 protected function getNonCatchablePatterns()
20135 return array('\s+', '\*+', '(.)');
20141 protected function getType(&$value)
20143 $type = self::T_NONE;
20144 $newVal = $this->getNumeric($value);
20146 // Checking numeric value
20147 if ($newVal !== false) {
20150 return (strpos($value, '.') !== false || stripos($value, 'e') !== false)
20151 ? self::T_FLOAT : self::T_INTEGER;
20154 if ($value[0] === '"') {
20155 $value = str_replace('""', '"', substr($value, 1, strlen($value) - 2));
20157 return self::T_STRING;
20159 switch (strtolower($value)) {
20164 return self::T_COMMA;
20167 return self::T_OPEN_PARENTHESIS;
20170 return self::T_CLOSE_PARENTHESIS;
20173 return self::T_OPEN_CURLY_BRACES;
20175 case '}': return self::T_CLOSE_CURLY_BRACES;
20177 return self::T_EQUALS;
20180 return self::T_NAMESPACE_SEPARATOR;
20183 return self::T_TRUE;
20186 return self::T_FALSE;
20189 if (ctype_alpha($value[0]) || $value[0] === '_') {
20190 return self::T_IDENTIFIER;
20201 * Checks if a value is numeric or not
20203 * @param mixed $value Value to be inspected
20204 * @return boolean|integer|float Processed value
20207 private function getNumeric($value)
20209 if ( ! is_scalar($value)) {
20213 // Checking for valid numeric numbers: 1.234, -1.234e-2
20214 if (is_numeric($value)) {
20224 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20225 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20226 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20227 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20228 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20229 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20230 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20231 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20232 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20233 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
20234 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20236 * This software consists of voluntary contributions made by many individuals
20237 * and is licensed under the LGPL. For more information, see
20238 * <http://www.doctrine-project.org>.
20241 namespace Doctrine\Common\Annotations;
20244 * Annotations class
20246 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
20247 * @link www.doctrine-project.org
20249 * @version $Revision$
20250 * @author Benjamin Eberlei <kontakt@beberlei.de>
20251 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
20252 * @author Jonathan Wage <jonwage@gmail.com>
20253 * @author Roman Borschel <roman@code-factory.org>
20258 * Value property. Common among all derived classes.
20267 * @param array $data Key-value for properties to be defined in this class
20269 public final function __construct(array $data)
20271 foreach ($data as $key => $value) {
20272 $this->$key = $value;
20277 * Error handler for unknown property accessor in Annotation class.
20279 * @param string $name Unknown property name
20281 public function __get($name)
20283 throw new \BadMethodCallException(
20284 sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
20289 * Error handler for unknown property mutator in Annotation class.
20291 * @param string $name Unkown property name
20292 * @param mixed $value Property value
20294 public function __set($name, $value)
20296 throw new \BadMethodCallException(
20297 sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
20302 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20303 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20304 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20305 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20306 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20307 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20308 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20309 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20310 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20311 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
20312 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20314 * This software consists of voluntary contributions made by many individuals
20315 * and is licensed under the LGPL. For more information, see
20316 * <http://www.doctrine-project.org>.
20319 namespace Doctrine\Common;
20322 * A <tt>ClassLoader</tt> is an autoloader for class files that can be
20323 * installed on the SPL autoload stack. It is a class loader that either loads only classes
20324 * of a specific namespace or all namespaces and it is suitable for working together
20325 * with other autoloaders in the SPL autoload stack.
20327 * If no include path is configured through the constructor or {@link setIncludePath}, a ClassLoader
20328 * relies on the PHP <code>include_path</code>.
20330 * @author Roman Borschel <roman@code-factory.org>
20335 private $fileExtension = '.php';
20336 private $namespace;
20337 private $includePath;
20338 private $namespaceSeparator = '\\';
20341 * Creates a new <tt>ClassLoader</tt> that loads classes of the
20342 * specified namespace from the specified include path.
20344 * If no include path is given, the ClassLoader relies on the PHP include_path.
20345 * If neither a namespace nor an include path is given, the ClassLoader will
20346 * be responsible for loading all classes, thereby relying on the PHP include_path.
20348 * @param string $ns The namespace of the classes to load.
20349 * @param string $includePath The base include path to use.
20351 public function __construct($ns = null, $includePath = null)
20353 $this->namespace = $ns;
20354 $this->includePath = $includePath;
20358 * Sets the namespace separator used by classes in the namespace of this ClassLoader.
20360 * @param string $sep The separator to use.
20362 public function setNamespaceSeparator($sep)
20364 $this->namespaceSeparator = $sep;
20368 * Gets the namespace separator used by classes in the namespace of this ClassLoader.
20372 public function getNamespaceSeparator()
20374 return $this->namespaceSeparator;
20378 * Sets the base include path for all class files in the namespace of this ClassLoader.
20380 * @param string $includePath
20382 public function setIncludePath($includePath)
20384 $this->includePath = $includePath;
20388 * Gets the base include path for all class files in the namespace of this ClassLoader.
20392 public function getIncludePath()
20394 return $this->includePath;
20398 * Sets the file extension of class files in the namespace of this ClassLoader.
20400 * @param string $fileExtension
20402 public function setFileExtension($fileExtension)
20404 $this->fileExtension = $fileExtension;
20408 * Gets the file extension of class files in the namespace of this ClassLoader.
20412 public function getFileExtension()
20414 return $this->fileExtension;
20418 * Registers this ClassLoader on the SPL autoload stack.
20420 public function register()
20422 spl_autoload_register(array($this, 'loadClass'));
20426 * Removes this ClassLoader from the SPL autoload stack.
20428 public function unregister()
20430 spl_autoload_unregister(array($this, 'loadClass'));
20434 * Loads the given class or interface.
20436 * @param string $classname The name of the class to load.
20437 * @return boolean TRUE if the class has been successfully loaded, FALSE otherwise.
20439 public function loadClass($className)
20441 if ($this->namespace !== null && strpos($className, $this->namespace.$this->namespaceSeparator) !== 0) {
20445 require ($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '')
20446 . str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className)
20447 . $this->fileExtension;
20453 * Asks this ClassLoader whether it can potentially load the class (file) with
20456 * @param string $className The fully-qualified name of the class.
20457 * @return boolean TRUE if this ClassLoader can load the class, FALSE otherwise.
20459 public function canLoadClass($className)
20461 if ($this->namespace !== null && strpos($className, $this->namespace.$this->namespaceSeparator) !== 0) {
20464 return file_exists(($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '')
20465 . str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className)
20466 . $this->fileExtension);
20470 * Checks whether a class with a given name exists. A class "exists" if it is either
20471 * already defined in the current request or if there is an autoloader on the SPL
20472 * autoload stack that is a) responsible for the class in question and b) is able to
20473 * load a class file in which the class definition resides.
20475 * If the class is not already defined, each autoloader in the SPL autoload stack
20476 * is asked whether it is able to tell if the class exists. If the autoloader is
20477 * a <tt>ClassLoader</tt>, {@link canLoadClass} is used, otherwise the autoload
20478 * function of the autoloader is invoked and expected to return a value that
20479 * evaluates to TRUE if the class (file) exists. As soon as one autoloader reports
20480 * that the class exists, TRUE is returned.
20482 * Note that, depending on what kinds of autoloaders are installed on the SPL
20483 * autoload stack, the class (file) might already be loaded as a result of checking
20484 * for its existence. This is not the case with a <tt>ClassLoader</tt>, who separates
20485 * these responsibilities.
20487 * @param string $className The fully-qualified name of the class.
20488 * @return boolean TRUE if the class exists as per the definition given above, FALSE otherwise.
20490 public static function classExists($className)
20492 if (class_exists($className, false)) {
20496 foreach (spl_autoload_functions() as $loader) {
20497 if (is_array($loader)) { // array(???, ???)
20498 if (is_object($loader[0])) {
20499 if ($loader[0] instanceof ClassLoader) { // array($obj, 'methodName')
20500 if ($loader[0]->canLoadClass($className)) {
20503 } else if ($loader[0]->{$loader[1]}($className)) {
20506 } else if ($loader[0]::$loader[1]($className)) { // array('ClassName', 'methodName')
20509 } else if ($loader instanceof \Closure) { // function($className) {..}
20510 if ($loader($className)) {
20513 } else if (is_string($loader) && $loader($className)) { // "MyClass::loadClass"
20522 * Gets the <tt>ClassLoader</tt> from the SPL autoload stack that is responsible
20523 * for (and is able to load) the class with the given name.
20525 * @param string $className The name of the class.
20526 * @return The <tt>ClassLoader</tt> for the class or NULL if no such <tt>ClassLoader</tt> exists.
20528 public static function getClassLoader($className)
20530 foreach (spl_autoload_functions() as $loader) {
20531 if (is_array($loader) && $loader[0] instanceof ClassLoader &&
20532 $loader[0]->canLoadClass($className)) {
20541 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20542 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20543 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20544 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20545 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20546 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20547 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20548 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20549 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20550 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
20551 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20553 * This software consists of voluntary contributions made by many individuals
20554 * and is licensed under the LGPL. For more information, see
20555 * <http://www.doctrine-project.org>.
20558 namespace Doctrine\Common\Collections;
20560 use Closure, ArrayIterator;
20563 * An ArrayCollection is a Collection implementation that wraps a regular PHP array.
20566 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
20567 * @author Jonathan Wage <jonwage@gmail.com>
20568 * @author Roman Borschel <roman@code-factory.org>
20570 class ArrayCollection implements Collection
20573 * An array containing the entries of this collection.
20577 private $_elements;
20580 * Initializes a new ArrayCollection.
20582 * @param array $elements
20584 public function __construct(array $elements = array())
20586 $this->_elements = $elements;
20590 * Gets the PHP array representation of this collection.
20592 * @return array The PHP array representation of this collection.
20594 public function toArray()
20596 return $this->_elements;
20600 * Sets the internal iterator to the first element in the collection and
20601 * returns this element.
20605 public function first()
20607 return reset($this->_elements);
20611 * Sets the internal iterator to the last element in the collection and
20612 * returns this element.
20616 public function last()
20618 return end($this->_elements);
20622 * Gets the current key/index at the current internal iterator position.
20626 public function key()
20628 return key($this->_elements);
20632 * Moves the internal iterator position to the next element.
20636 public function next()
20638 return next($this->_elements);
20642 * Gets the element of the collection at the current internal iterator position.
20646 public function current()
20648 return current($this->_elements);
20652 * Removes an element with a specific key/index from the collection.
20654 * @param mixed $key
20655 * @return mixed The removed element or NULL, if no element exists for the given key.
20657 public function remove($key)
20659 if (isset($this->_elements[$key])) {
20660 $removed = $this->_elements[$key];
20661 unset($this->_elements[$key]);
20670 * Removes the specified element from the collection, if it is found.
20672 * @param mixed $element The element to remove.
20673 * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
20675 public function removeElement($element)
20677 $key = array_search($element, $this->_elements, true);
20679 if ($key !== false) {
20680 unset($this->_elements[$key]);
20689 * ArrayAccess implementation of offsetExists()
20691 * @see containsKey()
20693 public function offsetExists($offset)
20695 return $this->containsKey($offset);
20699 * ArrayAccess implementation of offsetGet()
20703 public function offsetGet($offset)
20705 return $this->get($offset);
20709 * ArrayAccess implementation of offsetGet()
20714 public function offsetSet($offset, $value)
20716 if ( ! isset($offset)) {
20717 return $this->add($value);
20719 return $this->set($offset, $value);
20723 * ArrayAccess implementation of offsetUnset()
20727 public function offsetUnset($offset)
20729 return $this->remove($offset);
20733 * Checks whether the collection contains a specific key/index.
20735 * @param mixed $key The key to check for.
20736 * @return boolean TRUE if the given key/index exists, FALSE otherwise.
20738 public function containsKey($key)
20740 return isset($this->_elements[$key]);
20744 * Checks whether the given element is contained in the collection.
20745 * Only element values are compared, not keys. The comparison of two elements
20746 * is strict, that means not only the value but also the type must match.
20747 * For objects this means reference equality.
20749 * @param mixed $element
20750 * @return boolean TRUE if the given element is contained in the collection,
20753 public function contains($element)
20755 return in_array($element, $this->_elements, true);
20759 * Tests for the existance of an element that satisfies the given predicate.
20761 * @param Closure $p The predicate.
20762 * @return boolean TRUE if the predicate is TRUE for at least one element, FALSE otherwise.
20764 public function exists(Closure $p)
20766 foreach ($this->_elements as $key => $element)
20767 if ($p($key, $element)) return true;
20772 * Searches for a given element and, if found, returns the corresponding key/index
20773 * of that element. The comparison of two elements is strict, that means not
20774 * only the value but also the type must match.
20775 * For objects this means reference equality.
20777 * @param mixed $element The element to search for.
20778 * @return mixed The key/index of the element or FALSE if the element was not found.
20780 public function indexOf($element)
20782 return array_search($element, $this->_elements, true);
20786 * Gets the element with the given key/index.
20788 * @param mixed $key The key.
20789 * @return mixed The element or NULL, if no element exists for the given key.
20791 public function get($key)
20793 if (isset($this->_elements[$key])) {
20794 return $this->_elements[$key];
20800 * Gets all keys/indexes of the collection elements.
20804 public function getKeys()
20806 return array_keys($this->_elements);
20810 * Gets all elements.
20814 public function getValues()
20816 return array_values($this->_elements);
20820 * Returns the number of elements in the collection.
20822 * Implementation of the Countable interface.
20824 * @return integer The number of elements in the collection.
20826 public function count()
20828 return count($this->_elements);
20832 * Adds/sets an element in the collection at the index / with the specified key.
20834 * When the collection is a Map this is like put(key,value)/add(key,value).
20835 * When the collection is a List this is like add(position,value).
20837 * @param mixed $key
20838 * @param mixed $value
20840 public function set($key, $value)
20842 $this->_elements[$key] = $value;
20846 * Adds an element to the collection.
20848 * @param mixed $value
20849 * @return boolean Always TRUE.
20851 public function add($value)
20853 $this->_elements[] = $value;
20858 * Checks whether the collection is empty.
20860 * Note: This is preferrable over count() == 0.
20862 * @return boolean TRUE if the collection is empty, FALSE otherwise.
20864 public function isEmpty()
20866 return ! $this->_elements;
20870 * Gets an iterator for iterating over the elements in the collection.
20872 * @return ArrayIterator
20874 public function getIterator()
20876 return new ArrayIterator($this->_elements);
20880 * Applies the given function to each element in the collection and returns
20881 * a new collection with the elements returned by the function.
20883 * @param Closure $func
20884 * @return Collection
20886 public function map(Closure $func)
20888 return new ArrayCollection(array_map($func, $this->_elements));
20892 * Returns all the elements of this collection that satisfy the predicate p.
20893 * The order of the elements is preserved.
20895 * @param Closure $p The predicate used for filtering.
20896 * @return Collection A collection with the results of the filter operation.
20898 public function filter(Closure $p)
20900 return new ArrayCollection(array_filter($this->_elements, $p));
20904 * Applies the given predicate p to all elements of this collection,
20905 * returning true, if the predicate yields true for all elements.
20907 * @param Closure $p The predicate.
20908 * @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.
20910 public function forAll(Closure $p)
20912 foreach ($this->_elements as $key => $element) {
20913 if ( ! $p($key, $element)) {
20922 * Partitions this collection in two collections according to a predicate.
20923 * Keys are preserved in the resulting collections.
20925 * @param Closure $p The predicate on which to partition.
20926 * @return array An array with two elements. The first element contains the collection
20927 * of elements where the predicate returned TRUE, the second element
20928 * contains the collection of elements where the predicate returned FALSE.
20930 public function partition(Closure $p)
20932 $coll1 = $coll2 = array();
20933 foreach ($this->_elements as $key => $element) {
20934 if ($p($key, $element)) {
20935 $coll1[$key] = $element;
20937 $coll2[$key] = $element;
20940 return array(new ArrayCollection($coll1), new ArrayCollection($coll2));
20944 * Returns a string representation of this object.
20948 public function __toString()
20950 return __CLASS__ . '@' . spl_object_hash($this);
20954 * Clears the collection.
20956 public function clear()
20958 $this->_elements = array();
20962 * Extract a slice of $length elements starting at position $offset from the Collection.
20964 * If $length is null it returns all elements from $offset to the end of the Collection.
20965 * Keys have to be preserved by this method. Calling this method will only return the
20966 * selected slice and NOT change the elements contained in the collection slice is called on.
20968 * @param int $offset
20969 * @param int $length
20972 public function slice($offset, $length = null)
20974 return array_slice($this->_elements, $offset, $length, true);
20979 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20980 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20981 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20982 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20983 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20984 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20985 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20986 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20987 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20988 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
20989 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20991 * This software consists of voluntary contributions made by many individuals
20992 * and is licensed under the LGPL. For more information, see
20993 * <http://www.doctrine-project.org>.
20996 namespace Doctrine\Common\Collections;
20998 use Closure, Countable, IteratorAggregate, ArrayAccess;
21001 * The missing (SPL) Collection/Array/OrderedMap interface.
21003 * A Collection resembles the nature of a regular PHP array. That is,
21004 * it is essentially an <b>ordered map</b> that can also be used
21007 * A Collection has an internal iterator just like a PHP array. In addition,
21008 * a Collection can be iterated with external iterators, which is preferrable.
21009 * To use an external iterator simply use the foreach language construct to
21010 * iterate over the collection (which calls {@link getIterator()} internally) or
21011 * explicitly retrieve an iterator though {@link getIterator()} which can then be
21012 * used to iterate over the collection.
21013 * You can not rely on the internal iterator of the collection being at a certain
21014 * position unless you explicitly positioned it before. Prefer iteration with
21015 * external iterators.
21018 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21019 * @author Jonathan Wage <jonwage@gmail.com>
21020 * @author Roman Borschel <roman@code-factory.org>
21022 interface Collection extends Countable, IteratorAggregate, ArrayAccess
21025 * Adds an element at the end of the collection.
21027 * @param mixed $element The element to add.
21028 * @return boolean Always TRUE.
21030 function add($element);
21033 * Clears the collection, removing all elements.
21038 * Checks whether an element is contained in the collection.
21039 * This is an O(n) operation, where n is the size of the collection.
21041 * @param mixed $element The element to search for.
21042 * @return boolean TRUE if the collection contains the element, FALSE otherwise.
21044 function contains($element);
21047 * Checks whether the collection is empty (contains no elements).
21049 * @return boolean TRUE if the collection is empty, FALSE otherwise.
21051 function isEmpty();
21054 * Removes the element at the specified index from the collection.
21056 * @param string|integer $key The kex/index of the element to remove.
21057 * @return mixed The removed element or NULL, if the collection did not contain the element.
21059 function remove($key);
21062 * Removes the specified element from the collection, if it is found.
21064 * @param mixed $element The element to remove.
21065 * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
21067 function removeElement($element);
21070 * Checks whether the collection contains an element with the specified key/index.
21072 * @param string|integer $key The key/index to check for.
21073 * @return boolean TRUE if the collection contains an element with the specified key/index,
21076 function containsKey($key);
21079 * Gets the element at the specified key/index.
21081 * @param string|integer $key The key/index of the element to retrieve.
21084 function get($key);
21087 * Gets all keys/indices of the collection.
21089 * @return array The keys/indices of the collection, in the order of the corresponding
21090 * elements in the collection.
21092 function getKeys();
21095 * Gets all values of the collection.
21097 * @return array The values of all elements in the collection, in the order they
21098 * appear in the collection.
21100 function getValues();
21103 * Sets an element in the collection at the specified key/index.
21105 * @param string|integer $key The key/index of the element to set.
21106 * @param mixed $value The element to set.
21108 function set($key, $value);
21111 * Gets a native PHP array representation of the collection.
21115 function toArray();
21118 * Sets the internal iterator to the first element in the collection and
21119 * returns this element.
21126 * Sets the internal iterator to the last element in the collection and
21127 * returns this element.
21134 * Gets the key/index of the element at the current iterator position.
21140 * Gets the element of the collection at the current iterator position.
21143 function current();
21146 * Moves the internal iterator position to the next element.
21152 * Tests for the existence of an element that satisfies the given predicate.
21154 * @param Closure $p The predicate.
21155 * @return boolean TRUE if the predicate is TRUE for at least one element, FALSE otherwise.
21157 function exists(Closure $p);
21160 * Returns all the elements of this collection that satisfy the predicate p.
21161 * The order of the elements is preserved.
21163 * @param Closure $p The predicate used for filtering.
21164 * @return Collection A collection with the results of the filter operation.
21166 function filter(Closure $p);
21169 * Applies the given predicate p to all elements of this collection,
21170 * returning true, if the predicate yields true for all elements.
21172 * @param Closure $p The predicate.
21173 * @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.
21175 function forAll(Closure $p);
21178 * Applies the given function to each element in the collection and returns
21179 * a new collection with the elements returned by the function.
21181 * @param Closure $func
21182 * @return Collection
21184 function map(Closure $func);
21187 * Partitions this collection in two collections according to a predicate.
21188 * Keys are preserved in the resulting collections.
21190 * @param Closure $p The predicate on which to partition.
21191 * @return array An array with two elements. The first element contains the collection
21192 * of elements where the predicate returned TRUE, the second element
21193 * contains the collection of elements where the predicate returned FALSE.
21195 function partition(Closure $p);
21198 * Gets the index/key of a given element. The comparison of two elements is strict,
21199 * that means not only the value but also the type must match.
21200 * For objects this means reference equality.
21202 * @param mixed $element The element to search for.
21203 * @return mixed The key/index of the element or FALSE if the element was not found.
21205 function indexOf($element);
21208 * Extract a slice of $length elements starting at position $offset from the Collection.
21210 * If $length is null it returns all elements from $offset to the end of the Collection.
21211 * Keys have to be preserved by this method. Calling this method will only return the
21212 * selected slice and NOT change the elements contained in the collection slice is called on.
21214 * @param int $offset
21215 * @param int $length
21218 public function slice($offset, $length = null);
21221 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21222 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21223 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21224 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21225 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21226 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21227 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21228 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21229 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21230 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21231 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21233 * This software consists of voluntary contributions made by many individuals
21234 * and is licensed under the LGPL. For more information, see
21235 * <http://www.doctrine-project.org>.
21238 namespace Doctrine\Common;
21241 * Class to store and retrieve the version of Doctrine
21243 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21244 * @link www.doctrine-project.org
21246 * @version $Revision$
21247 * @author Benjamin Eberlei <kontakt@beberlei.de>
21248 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21249 * @author Jonathan Wage <jonwage@gmail.com>
21250 * @author Roman Borschel <roman@code-factory.org>
21255 * Current Doctrine Version
21257 const VERSION = '2.0.0RC2-DEV';
21260 * Compares a Doctrine version with the current one.
21262 * @param string $version Doctrine version to compare.
21263 * @return int Returns -1 if older, 0 if it is the same, 1 if version
21264 * passed as argument is newer.
21266 public static function compare($version)
21268 $currentVersion = str_replace(' ', '', strtolower(self::VERSION));
21269 $version = str_replace(' ', '', $version);
21271 return version_compare($version, $currentVersion);
21277 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21278 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21279 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21280 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21281 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21282 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21283 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21284 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21285 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21286 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21287 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21289 * This software consists of voluntary contributions made by many individuals
21290 * and is licensed under the LGPL. For more information, see
21291 * <http://www.doctrine-project.org>.
21294 namespace Doctrine\Common\Cache;
21297 * Xcache cache driver.
21299 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21300 * @link www.doctrine-project.org
21302 * @version $Revision: 3938 $
21303 * @author Benjamin Eberlei <kontakt@beberlei.de>
21304 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21305 * @author Jonathan Wage <jonwage@gmail.com>
21306 * @author Roman Borschel <roman@code-factory.org>
21307 * @author David Abdemoulaie <dave@hobodave.com>
21309 class XcacheCache extends AbstractCache
21314 public function getIds()
21316 $this->_checkAuth();
21319 for ($i = 0, $count = xcache_count(XC_TYPE_VAR); $i < $count; $i++) {
21320 $entries = xcache_list(XC_TYPE_VAR, $i);
21322 if (is_array($entries['cache_list'])) {
21323 foreach ($entries['cache_list'] as $entry) {
21324 $keys[] = $entry['name'];
21335 protected function _doFetch($id)
21337 return $this->_doContains($id) ? unserialize(xcache_get($id)) : false;
21343 protected function _doContains($id)
21345 return xcache_isset($id);
21351 protected function _doSave($id, $data, $lifeTime = 0)
21353 return xcache_set($id, serialize($data), (int) $lifeTime);
21359 protected function _doDelete($id)
21361 return xcache_unset($id);
21366 * Checks that xcache.admin.enable_auth is Off
21368 * @throws \BadMethodCallException When xcache.admin.enable_auth is On
21371 protected function _checkAuth()
21373 if (ini_get('xcache.admin.enable_auth')) {
21374 throw new \BadMethodCallException('To use all features of \Doctrine\Common\Cache\XcacheCache, you must set "xcache.admin.enable_auth" to "Off" in your php.ini.');
21381 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21382 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21383 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21384 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21385 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21386 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21387 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21388 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21389 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21390 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21391 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21393 * This software consists of voluntary contributions made by many individuals
21394 * and is licensed under the LGPL. For more information, see
21395 * <http://www.doctrine-project.org>.
21398 namespace Doctrine\Common\Cache;
21401 * Array cache driver.
21403 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21404 * @link www.doctrine-project.org
21406 * @version $Revision: 3938 $
21407 * @author Benjamin Eberlei <kontakt@beberlei.de>
21408 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21409 * @author Jonathan Wage <jonwage@gmail.com>
21410 * @author Roman Borschel <roman@code-factory.org>
21411 * @author David Abdemoulaie <dave@hobodave.com>
21413 class ArrayCache extends AbstractCache
21418 private $data = array();
21423 public function getIds()
21425 return array_keys($this->data);
21431 protected function _doFetch($id)
21433 if (isset($this->data[$id])) {
21434 return $this->data[$id];
21443 protected function _doContains($id)
21445 return isset($this->data[$id]);
21451 protected function _doSave($id, $data, $lifeTime = 0)
21453 $this->data[$id] = $data;
21461 protected function _doDelete($id)
21463 unset($this->data[$id]);
21471 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21472 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21473 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21474 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21475 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21476 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21477 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21478 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21479 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21480 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21481 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21483 * This software consists of voluntary contributions made by many individuals
21484 * and is licensed under the LGPL. For more information, see
21485 * <http://www.doctrine-project.org>.
21488 namespace Doctrine\Common\Cache;
21493 * Memcache cache driver.
21495 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21496 * @link www.doctrine-project.org
21498 * @version $Revision: 3938 $
21499 * @author Benjamin Eberlei <kontakt@beberlei.de>
21500 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21501 * @author Jonathan Wage <jonwage@gmail.com>
21502 * @author Roman Borschel <roman@code-factory.org>
21503 * @author David Abdemoulaie <dave@hobodave.com>
21505 class MemcacheCache extends AbstractCache
21510 private $_memcache;
21513 * Sets the memcache instance to use.
21515 * @param Memcache $memcache
21517 public function setMemcache(Memcache $memcache)
21519 $this->_memcache = $memcache;
21523 * Gets the memcache instance used by the cache.
21527 public function getMemcache()
21529 return $this->_memcache;
21535 public function getIds()
21538 $allSlabs = $this->_memcache->getExtendedStats('slabs');
21540 foreach ($allSlabs as $server => $slabs) {
21541 if (is_array($slabs)) {
21542 foreach (array_keys($slabs) as $slabId) {
21543 $dump = $this->_memcache->getExtendedStats('cachedump', (int) $slabId);
21546 foreach ($dump as $entries) {
21548 $keys = array_merge($keys, array_keys($entries));
21561 protected function _doFetch($id)
21563 return $this->_memcache->get($id);
21569 protected function _doContains($id)
21571 return (bool) $this->_memcache->get($id);
21577 protected function _doSave($id, $data, $lifeTime = 0)
21579 return $this->_memcache->set($id, $data, 0, (int) $lifeTime);
21585 protected function _doDelete($id)
21587 return $this->_memcache->delete($id);
21593 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21594 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21595 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21596 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21597 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21598 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21599 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21600 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21601 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21602 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21603 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21605 * This software consists of voluntary contributions made by many individuals
21606 * and is licensed under the LGPL. For more information, see
21607 * <http://www.doctrine-project.org>.
21610 namespace Doctrine\Common\Cache;
21613 * Interface for cache drivers.
21615 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21616 * @link www.doctrine-project.org
21618 * @version $Revision: 3938 $
21619 * @author Benjamin Eberlei <kontakt@beberlei.de>
21620 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21621 * @author Jonathan Wage <jonwage@gmail.com>
21622 * @author Roman Borschel <roman@code-factory.org>
21627 * Fetches an entry from the cache.
21629 * @param string $id cache id The id of the cache entry to fetch.
21630 * @return string The cached data or FALSE, if no cache entry exists for the given id.
21632 function fetch($id);
21635 * Test if an entry exists in the cache.
21637 * @param string $id cache id The cache id of the entry to check for.
21638 * @return boolean TRUE if a cache entry exists for the given cache id, FALSE otherwise.
21640 function contains($id);
21643 * Puts data into the cache.
21645 * @param string $id The cache id.
21646 * @param string $data The cache entry/data.
21647 * @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this cache entry (0 => infinite lifeTime).
21648 * @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise.
21650 function save($id, $data, $lifeTime = 0);
21653 * Deletes a cache entry.
21655 * @param string $id cache id
21656 * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise.
21658 function delete($id);
21663 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21664 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21665 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21666 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21667 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21668 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21669 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21670 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21671 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21672 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21673 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21675 * This software consists of voluntary contributions made by many individuals
21676 * and is licensed under the LGPL. For more information, see
21677 * <http://www.doctrine-project.org>.
21680 namespace Doctrine\Common\Cache;
21683 * APC cache driver.
21685 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21686 * @link www.doctrine-project.org
21688 * @version $Revision$
21689 * @author Benjamin Eberlei <kontakt@beberlei.de>
21690 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21691 * @author Jonathan Wage <jonwage@gmail.com>
21692 * @author Roman Borschel <roman@code-factory.org>
21693 * @author David Abdemoulaie <dave@hobodave.com>
21694 * @todo Rename: APCCache
21696 class ApcCache extends AbstractCache
21701 public function getIds()
21703 $ci = apc_cache_info('user');
21706 foreach ($ci['cache_list'] as $entry) {
21707 $keys[] = $entry['info'];
21716 protected function _doFetch($id)
21718 return apc_fetch($id);
21724 protected function _doContains($id)
21728 apc_fetch($id, $found);
21736 protected function _doSave($id, $data, $lifeTime = 0)
21738 return (bool) apc_store($id, $data, (int) $lifeTime);
21744 protected function _doDelete($id)
21746 return apc_delete($id);
21750 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21751 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21752 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21753 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21754 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21755 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21756 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21757 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21758 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21759 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21760 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21762 * This software consists of voluntary contributions made by many individuals
21763 * and is licensed under the LGPL. For more information, see
21764 * <http://www.doctrine-project.org>.
21767 namespace Doctrine\Common\Cache;
21770 * Base class for cache driver implementations.
21773 * @author Benjamin Eberlei <kontakt@beberlei.de>
21774 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
21775 * @author Jonathan Wage <jonwage@gmail.com>
21776 * @author Roman Borschel <roman@code-factory.org>
21778 abstract class AbstractCache implements Cache
21780 /** @var string The cache id to store the index of cache ids under */
21781 private $_cacheIdsIndexId = 'doctrine_cache_ids';
21783 /** @var string The namespace to prefix all cache ids with */
21784 private $_namespace = null;
21787 * Set the namespace to prefix all cache ids with.
21789 * @param string $namespace
21792 public function setNamespace($namespace)
21794 $this->_namespace = $namespace;
21800 public function fetch($id)
21802 return $this->_doFetch($this->_getNamespacedId($id));
21808 public function contains($id)
21810 return $this->_doContains($this->_getNamespacedId($id));
21816 public function save($id, $data, $lifeTime = 0)
21818 return $this->_doSave($this->_getNamespacedId($id), $data, $lifeTime);
21824 public function delete($id)
21826 $id = $this->_getNamespacedId($id);
21828 if (strpos($id, '*') !== false) {
21829 return $this->deleteByRegex('/' . str_replace('*', '.*', $id) . '/');
21832 return $this->_doDelete($id);
21836 * Delete all cache entries.
21838 * @return array $deleted Array of the deleted cache ids
21840 public function deleteAll()
21842 $ids = $this->getIds();
21844 foreach ($ids as $id) {
21845 $this->delete($id);
21852 * Delete cache entries where the id matches a PHP regular expressions
21854 * @param string $regex
21855 * @return array $deleted Array of the deleted cache ids
21857 public function deleteByRegex($regex)
21859 $deleted = array();
21861 $ids = $this->getIds();
21863 foreach ($ids as $id) {
21864 if (preg_match($regex, $id)) {
21865 $this->delete($id);
21874 * Delete cache entries where the id has the passed prefix
21876 * @param string $prefix
21877 * @return array $deleted Array of the deleted cache ids
21879 public function deleteByPrefix($prefix)
21881 $deleted = array();
21883 $prefix = $this->_getNamespacedId($prefix);
21884 $ids = $this->getIds();
21886 foreach ($ids as $id) {
21887 if (strpos($id, $prefix) === 0) {
21888 $this->delete($id);
21897 * Delete cache entries where the id has the passed suffix
21899 * @param string $suffix
21900 * @return array $deleted Array of the deleted cache ids
21902 public function deleteBySuffix($suffix)
21904 $deleted = array();
21906 $ids = $this->getIds();
21908 foreach ($ids as $id) {
21909 if (substr($id, -1 * strlen($suffix)) === $suffix) {
21910 $this->delete($id);
21919 * Prefix the passed id with the configured namespace value
21921 * @param string $id The id to namespace
21922 * @return string $id The namespaced id
21924 private function _getNamespacedId($id)
21926 if ( ! $this->_namespace || strpos($id, $this->_namespace) === 0) {
21929 return $this->_namespace . $id;
21934 * Fetches an entry from the cache.
21936 * @param string $id cache id The id of the cache entry to fetch.
21937 * @return string The cached data or FALSE, if no cache entry exists for the given id.
21939 abstract protected function _doFetch($id);
21942 * Test if an entry exists in the cache.
21944 * @param string $id cache id The cache id of the entry to check for.
21945 * @return boolean TRUE if a cache entry exists for the given cache id, FALSE otherwise.
21947 abstract protected function _doContains($id);
21950 * Puts data into the cache.
21952 * @param string $id The cache id.
21953 * @param string $data The cache entry/data.
21954 * @param int $lifeTime The lifetime. If != false, sets a specific lifetime for this cache entry (null => infinite lifeTime).
21955 * @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise.
21957 abstract protected function _doSave($id, $data, $lifeTime = false);
21960 * Deletes a cache entry.
21962 * @param string $id cache id
21963 * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise.
21965 abstract protected function _doDelete($id);
21968 * Get an array of all the cache ids stored
21970 * @return array $ids
21972 abstract public function getIds();
21977 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21978 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21979 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21980 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21981 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21982 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21983 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21984 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21985 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21986 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21987 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21989 * This software consists of voluntary contributions made by many individuals
21990 * and is licensed under the LGPL. For more information, see
21991 * <http://www.doctrine-project.org>.
21994 namespace Doctrine\Common\Util;
21997 * Static class containing most used debug methods.
21999 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22000 * @link www.doctrine-project.org
22002 * @version $Revision: 3938 $
22003 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
22004 * @author Jonathan Wage <jonwage@gmail.com>
22005 * @author Roman Borschel <roman@code-factory.org>
22006 * @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
22011 * Private constructor (prevents from instantiation)
22014 private function __construct() {}
22017 * Prints a dump of the public, protected and private properties of $var.
22020 * @link http://xdebug.org/
22021 * @param mixed $var
22022 * @param integer $maxDepth Maximum nesting level for object properties
22024 public static function dump($var, $maxDepth = 2)
22026 ini_set('html_errors', 'On');
22028 if (extension_loaded('xdebug')) {
22029 ini_set('xdebug.var_display_max_depth', $maxDepth);
22032 $var = self::export($var, $maxDepth++);
22036 $dump = ob_get_contents();
22039 echo strip_tags(html_entity_decode($dump));
22041 ini_set('html_errors', 'Off');
22044 public static function export($var, $maxDepth)
22047 $isObj = is_object($var);
22049 if ($isObj && in_array('Doctrine\Common\Collections\Collection', class_implements($var))) {
22050 $var = $var->toArray();
22054 if (is_array($var)) {
22057 foreach ($var as $k => $v) {
22058 $return[$k] = self::export($v, $maxDepth - 1);
22060 } else if ($isObj) {
22061 if ($var instanceof \DateTime) {
22062 $return = $var->format('c');
22064 $reflClass = new \ReflectionClass(get_class($var));
22065 $return = new \stdclass();
22066 $return->{'__CLASS__'} = get_class($var);
22068 if ($var instanceof \Doctrine\ORM\Proxy\Proxy && ! $var->__isInitialized__) {
22069 $reflProperty = $reflClass->getProperty('_identifier');
22070 $reflProperty->setAccessible(true);
22072 foreach ($reflProperty->getValue($var) as $name => $value) {
22073 $return->$name = self::export($value, $maxDepth - 1);
22076 $excludeProperties = array();
22078 if ($var instanceof \Doctrine\ORM\Proxy\Proxy) {
22079 $excludeProperties = array('_entityPersister', '__isInitialized__', '_identifier');
22082 foreach ($reflClass->getProperties() as $reflProperty) {
22083 $name = $reflProperty->getName();
22085 if ( ! in_array($name, $excludeProperties)) {
22086 $reflProperty->setAccessible(true);
22088 $return->$name = self::export($reflProperty->getValue($var), $maxDepth - 1);
22097 $return = is_object($var) ? get_class($var)
22098 : (is_array($var) ? 'Array(' . count($var) . ')' : $var);
22104 public static function toString($obj)
22106 return method_exists('__toString', $obj) ? (string) $obj : get_class($obj) . '@' . spl_object_hash($obj);
22111 * $Id: Inflector.php 3189 2007-11-18 20:37:44Z meus $
22113 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22114 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22115 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22116 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22117 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22118 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22119 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22120 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22121 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22122 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22123 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22125 * This software consists of voluntary contributions made by many individuals
22126 * and is licensed under the LGPL. For more information, see
22127 * <http://www.doctrine-project.org>.
22130 namespace Doctrine\Common\Util;
22133 * Doctrine inflector has static methods for inflecting text
22135 * The methods in these classes are from several different sources collected
22136 * across several different php projects and several different authors. The
22137 * original author names and emails are not known
22139 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22140 * @link www.doctrine-project.org
22142 * @version $Revision: 3189 $
22143 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
22144 * @author Jonathan H. Wage <jonwage@gmail.com>
22149 * Convert word in to the format for a Doctrine table name. Converts 'ModelName' to 'model_name'
22151 * @param string $word Word to tableize
22152 * @return string $word Tableized word
22154 public static function tableize($word)
22156 return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $word));
22160 * Convert a word in to the format for a Doctrine class name. Converts 'table_name' to 'TableName'
22162 * @param string $word Word to classify
22163 * @return string $word Classified word
22165 public static function classify($word)
22167 return str_replace(" ", "", ucwords(strtr($word, "_-", " ")));
22171 * Camelize a word. This uses the classify() method and turns the first character to lowercase
22173 * @param string $word
22174 * @return string $word
22176 public static function camelize($word)
22178 return lcfirst(self::classify($word));
22184 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22185 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22186 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22187 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22188 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22189 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22190 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22191 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22192 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22193 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22194 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22196 * This software consists of voluntary contributions made by many individuals
22197 * and is licensed under the LGPL. For more information, see
22198 * <http://www.doctrine-project.org>.
22201 namespace Doctrine\Common;
22204 * Contract for classes that provide the service of notifying listeners of
22205 * changes to their properties.
22207 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22208 * @link www.doctrine-project.org
22210 * @version $Revision: 3938 $
22211 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
22212 * @author Jonathan Wage <jonwage@gmail.com>
22213 * @author Roman Borschel <roman@code-factory.org>
22215 interface NotifyPropertyChanged
22218 * Adds a listener that wants to be notified about property changes.
22220 * @param PropertyChangedListener $listener
22222 function addPropertyChangedListener(PropertyChangedListener $listener);
22229 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22230 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22231 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22232 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22233 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22234 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22235 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22236 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22237 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22238 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22239 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22241 * This software consists of voluntary contributions made by many individuals
22242 * and is licensed under the LGPL. For more information, see
22243 * <http://www.doctrine-project.org>.
22246 namespace Doctrine\Common;
22249 * Contract for classes that are potential listeners of a <tt>NotifyPropertyChanged</tt>
22252 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22253 * @link www.doctrine-project.org
22255 * @version $Revision: 3938 $
22256 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
22257 * @author Jonathan Wage <jonwage@gmail.com>
22258 * @author Roman Borschel <roman@code-factory.org>
22260 interface PropertyChangedListener
22263 * Notifies the listener of a property change.
22265 * @param object $sender The object on which the property changed.
22266 * @param string $propertyName The name of the property that changed.
22267 * @param mixed $oldValue The old value of the property that changed.
22268 * @param mixed $newValue The new value of the property that changed.
22270 function propertyChanged($sender, $propertyName, $oldValue, $newValue);
22277 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22278 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22279 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22280 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22281 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22282 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22283 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22284 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22285 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22286 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22287 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22289 * This software consists of voluntary contributions made by many individuals
22290 * and is licensed under the LGPL. For more information, see
22291 * <http://www.doctrine-project.org>.
22294 namespace Doctrine\Common;
22296 use Doctrine\Common\Events\Event;
22299 * The EventManager is the central point of Doctrine's event listener system.
22300 * Listeners are registered on the manager and events are dispatched through the
22303 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22304 * @link www.doctrine-project.org
22306 * @version $Revision: 3938 $
22307 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
22308 * @author Jonathan Wage <jonwage@gmail.com>
22309 * @author Roman Borschel <roman@code-factory.org>
22314 * Map of registered listeners.
22315 * <event> => <listeners>
22319 private $_listeners = array();
22322 * Dispatches an event to all registered listeners.
22324 * @param string $eventName The name of the event to dispatch. The name of the event is
22325 * the name of the method that is invoked on listeners.
22326 * @param EventArgs $eventArgs The event arguments to pass to the event handlers/listeners.
22327 * If not supplied, the single empty EventArgs instance is used.
22330 public function dispatchEvent($eventName, EventArgs $eventArgs = null)
22332 if (isset($this->_listeners[$eventName])) {
22333 $eventArgs = $eventArgs === null ? EventArgs::getEmptyInstance() : $eventArgs;
22335 foreach ($this->_listeners[$eventName] as $listener) {
22336 $listener->$eventName($eventArgs);
22342 * Gets the listeners of a specific event or all listeners.
22344 * @param string $event The name of the event.
22345 * @return array The event listeners for the specified event, or all event listeners.
22347 public function getListeners($event = null)
22349 return $event ? $this->_listeners[$event] : $this->_listeners;
22353 * Checks whether an event has any registered listeners.
22355 * @param string $event
22356 * @return boolean TRUE if the specified event has any listeners, FALSE otherwise.
22358 public function hasListeners($event)
22360 return isset($this->_listeners[$event]) && $this->_listeners[$event];
22364 * Adds an event listener that listens on the specified events.
22366 * @param string|array $events The event(s) to listen on.
22367 * @param object $listener The listener object.
22369 public function addEventListener($events, $listener)
22371 // Picks the hash code related to that listener
22372 $hash = spl_object_hash($listener);
22374 foreach ((array) $events as $event) {
22375 // Overrides listener if a previous one was associated already
22376 // Prevents duplicate listeners on same event (same instance only)
22377 $this->_listeners[$event][$hash] = $listener;
22382 * Removes an event listener from the specified events.
22384 * @param string|array $events
22385 * @param object $listener
22387 public function removeEventListener($events, $listener)
22389 // Picks the hash code related to that listener
22390 $hash = spl_object_hash($listener);
22392 foreach ((array) $events as $event) {
22393 // Check if actually have this listener associated
22394 if (isset($this->_listeners[$event][$hash])) {
22395 unset($this->_listeners[$event][$hash]);
22401 * Adds an EventSubscriber. The subscriber is asked for all the events he is
22402 * interested in and added as a listener for these events.
22404 * @param Doctrine\Common\EventSubscriber $subscriber The subscriber.
22406 public function addEventSubscriber(EventSubscriber $subscriber)
22408 $this->addEventListener($subscriber->getSubscribedEvents(), $subscriber);
22412 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22413 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22414 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22415 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22416 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22417 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22418 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22419 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22420 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22421 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22422 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22424 * This software consists of voluntary contributions made by many individuals
22425 * and is licensed under the LGPL. For more information, see
22426 * <http://www.doctrine-project.org>.
22429 namespace Doctrine\Common;
22432 * Base class for writing simple lexers, i.e. for creating small DSLs.
22435 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
22436 * @author Jonathan Wage <jonwage@gmail.com>
22437 * @author Roman Borschel <roman@code-factory.org>
22438 * @todo Rename: AbstractLexer
22440 abstract class Lexer
22443 * @var array Array of scanned tokens
22445 private $tokens = array();
22448 * @var integer Current lexer position in input string
22450 private $position = 0;
22453 * @var integer Current peek of current lexer position
22458 * @var array The next token in the input.
22463 * @var array The last matched/seen token.
22468 * Sets the input data to be tokenized.
22470 * The Lexer is immediately reset and the new input tokenized.
22471 * Any unprocessed tokens from any previous input are lost.
22473 * @param string $input The input to be tokenized.
22475 public function setInput($input)
22477 $this->tokens = array();
22479 $this->scan($input);
22483 * Resets the lexer.
22485 public function reset()
22487 $this->lookahead = null;
22488 $this->token = null;
22490 $this->position = 0;
22494 * Resets the peek pointer to 0.
22496 public function resetPeek()
22502 * Resets the lexer position on the input to the given position.
22504 * @param integer $position Position to place the lexical scanner
22506 public function resetPosition($position = 0)
22508 $this->position = $position;
22512 * Checks whether a given token matches the current lookahead.
22514 * @param integer|string $token
22517 public function isNextToken($token)
22519 return $this->lookahead['type'] === $token;
22523 * Moves to the next token in the input string.
22525 * A token is an associative array containing three items:
22526 * - 'value' : the string value of the token in the input string
22527 * - 'type' : the type of the token (identifier, numeric, string, input
22529 * - 'position' : the position of the token in the input string
22531 * @return array|null the next token; null if there is no more tokens left
22533 public function moveNext()
22536 $this->token = $this->lookahead;
22537 $this->lookahead = (isset($this->tokens[$this->position]))
22538 ? $this->tokens[$this->position++] : null;
22540 return $this->lookahead !== null;
22544 * Tells the lexer to skip input tokens until it sees a token with the given value.
22546 * @param $type The token type to skip until.
22548 public function skipUntil($type)
22550 while ($this->lookahead !== null && $this->lookahead['type'] !== $type) {
22556 * Checks if given value is identical to the given token
22558 * @param mixed $value
22559 * @param integer $token
22562 public function isA($value, $token)
22564 return $this->getType($value) === $token;
22568 * Moves the lookahead token forward.
22570 * @return array | null The next token or NULL if there are no more tokens ahead.
22572 public function peek()
22574 if (isset($this->tokens[$this->position + $this->peek])) {
22575 return $this->tokens[$this->position + $this->peek++];
22582 * Peeks at the next token, returns it and immediately resets the peek.
22584 * @return array|null The next token or NULL if there are no more tokens ahead.
22586 public function glimpse()
22588 $peek = $this->peek();
22594 * Scans the input string for tokens.
22596 * @param string $input a query string
22598 protected function scan($input)
22602 if ( ! isset($regex)) {
22603 $regex = '/(' . implode(')|(', $this->getCatchablePatterns()) . ')|'
22604 . implode('|', $this->getNonCatchablePatterns()) . '/i';
22607 $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
22608 $matches = preg_split($regex, $input, -1, $flags);
22610 foreach ($matches as $match) {
22611 // Must remain before 'value' assignment since it can change content
22612 $type = $this->getType($match[0]);
22614 $this->tokens[] = array(
22615 'value' => $match[0],
22617 'position' => $match[1],
22623 * Gets the literal for a given token.
22625 * @param integer $token
22628 public function getLiteral($token)
22630 $className = get_class($this);
22631 $reflClass = new \ReflectionClass($className);
22632 $constants = $reflClass->getConstants();
22634 foreach ($constants as $name => $value) {
22635 if ($value === $token) {
22636 return $className . '::' . $name;
22644 * Lexical catchable patterns.
22648 abstract protected function getCatchablePatterns();
22651 * Lexical non-catchable patterns.
22655 abstract protected function getNonCatchablePatterns();
22658 * Retrieve token type. Also processes the token value if necessary.
22660 * @param string $value
22663 abstract protected function getType(&$value);
22666 * $Id: EventListener.php 4653 2008-07-10 17:17:58Z romanb $
22668 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22669 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22670 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22671 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22672 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22673 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22674 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22675 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22676 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22677 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22678 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22680 * This software consists of voluntary contributions made by many individuals
22681 * and is licensed under the LGPL. For more information, see
22682 * <http://www.doctrine-project.org>.
22685 namespace Doctrine\Common;
22688 * An EventSubscriber knows himself what events he is interested in.
22689 * If an EventSubscriber is added to an EventManager, the manager invokes
22690 * {@link getSubscribedEvents} and registers the subscriber as a listener for all
22693 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22694 * @link www.doctrine-project.org
22696 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
22697 * @author Jonathan Wage <jonwage@gmail.com>
22698 * @author Roman Borschel <roman@code-factory.org>
22700 interface EventSubscriber
22703 * Returns an array of events this subscriber wants to listen to.
22707 public function getSubscribedEvents();
22711 namespace Symfony\Component\Yaml;
22714 * This file is part of the symfony package.
22715 * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
22717 * For the full copyright and license information, please view the LICENSE
22718 * file that was distributed with this source code.
22722 * Yaml offers convenience methods to load and dump YAML.
22726 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
22730 static protected $spec = '1.2';
22733 * Sets the YAML specification version to use.
22735 * @param string $version The YAML specification version
22737 static public function setSpecVersion($version)
22739 if (!in_array($version, array('1.1', '1.2')))
22741 throw new \InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version));
22744 self::$spec = $version;
22748 * Gets the YAML specification version to use.
22750 * @return string The YAML specification version
22752 static public function getSpecVersion()
22754 return self::$spec;
22758 * Loads YAML into a PHP array.
22760 * The load method, when supplied with a YAML stream (string or file),
22761 * will do its best to convert YAML in a file into a PHP array.
22765 * $array = Yaml::load('config.yml');
22769 * @param string $input Path of YAML file or string containing YAML
22771 * @return array The YAML converted to a PHP array
22773 * @throws \InvalidArgumentException If the YAML is not valid
22775 public static function load($input)
22779 // if input is a file, process it
22780 if (strpos($input, "\n") === false && is_file($input))
22785 $retval = include($input);
22786 $content = ob_get_clean();
22788 // if an array is returned by the config file assume it's in plain php form else in YAML
22789 $input = is_array($retval) ? $retval : $content;
22792 // if an array is returned by the config file assume it's in plain php form else in YAML
22793 if (is_array($input))
22798 $yaml = new Parser();
22802 $ret = $yaml->parse($input);
22804 catch (\Exception $e)
22806 throw new \InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage()));
22813 * Dumps a PHP array to a YAML string.
22815 * The dump method, when supplied with an array, will do its best
22816 * to convert the array into friendly YAML.
22818 * @param array $array PHP array
22819 * @param integer $inline The level where you switch to inline YAML
22821 * @return string A YAML string representing the original PHP array
22823 public static function dump($array, $inline = 2)
22825 $yaml = new Dumper();
22827 return $yaml->dump($array, $inline);
22832 namespace Symfony\Component\Yaml;
22835 * This file is part of the symfony package.
22836 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
22838 * For the full copyright and license information, please view the LICENSE
22839 * file that was distributed with this source code.
22843 * Dumper dumps PHP variables to YAML strings.
22847 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
22852 * Dumps a PHP value to YAML.
22854 * @param mixed $input The PHP value
22855 * @param integer $inline The level where you switch to inline YAML
22856 * @param integer $indent The level o indentation indentation (used internally)
22858 * @return string The YAML representation of the PHP value
22860 public function dump($input, $inline = 0, $indent = 0)
22863 $prefix = $indent ? str_repeat(' ', $indent) : '';
22865 if ($inline <= 0 || !is_array($input) || empty($input))
22867 $output .= $prefix.Inline::dump($input);
22871 $isAHash = array_keys($input) !== range(0, count($input) - 1);
22873 foreach ($input as $key => $value)
22875 $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
22877 $output .= sprintf('%s%s%s%s',
22879 $isAHash ? Inline::dump($key).':' : '-',
22880 $willBeInlined ? ' ' : "\n",
22881 $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2)
22882 ).($willBeInlined ? "\n" : '');
22891 namespace Symfony\Component\Yaml;
22894 * This file is part of the symfony package.
22896 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
22898 * For the full copyright and license information, please view the LICENSE
22899 * file that was distributed with this source code.
22903 * Exception class used by all exceptions thrown by the component.
22907 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
22909 class ParserException extends Exception
22914 namespace Symfony\Component\Yaml;
22917 * This file is part of the symfony package.
22919 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
22921 * For the full copyright and license information, please view the LICENSE
22922 * file that was distributed with this source code.
22926 * Exception class used by all exceptions thrown by the component.
22930 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
22932 class Exception extends \Exception
22937 namespace Symfony\Component\Yaml;
22940 * This file is part of the symfony package.
22941 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
22943 * For the full copyright and license information, please view the LICENSE
22944 * file that was distributed with this source code.
22948 * Inline implements a YAML parser/dumper for the YAML inline syntax.
22952 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
22956 const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
22959 * Convert a YAML string to a PHP array.
22961 * @param string $value A YAML string
22963 * @return array A PHP array representing the YAML string
22965 static public function load($value)
22967 $value = trim($value);
22969 if (0 == strlen($value))
22977 return self::parseSequence($value);
22979 return self::parseMapping($value);
22981 return self::parseScalar($value);
22986 * Dumps a given PHP variable to a YAML string.
22988 * @param mixed $value The PHP variable to convert
22990 * @return string The YAML string representing the PHP array
22992 static public function dump($value)
22994 $trueValues = '1.1' == Yaml::getSpecVersion() ? array('true', 'on', '+', 'yes', 'y') : array('true');
22995 $falseValues = '1.1' == Yaml::getSpecVersion() ? array('false', 'off', '-', 'no', 'n') : array('false');
22999 case is_resource($value):
23000 throw new Exception('Unable to dump PHP resources in a YAML file.');
23001 case is_object($value):
23002 return '!!php/object:'.serialize($value);
23003 case is_array($value):
23004 return self::dumpArray($value);
23005 case null === $value:
23007 case true === $value:
23009 case false === $value:
23011 case ctype_digit($value):
23012 return is_string($value) ? "'$value'" : (int) $value;
23013 case is_numeric($value):
23014 return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value);
23015 case false !== strpos($value, "\n") || false !== strpos($value, "\r"):
23016 return sprintf('"%s"', str_replace(array('"', "\n", "\r"), array('\\"', '\n', '\r'), $value));
23017 case preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ - ? | < > = ! % @ ` ]/x', $value):
23018 return sprintf("'%s'", str_replace('\'', '\'\'', $value));
23021 case preg_match(self::getTimestampRegex(), $value):
23023 case in_array(strtolower($value), $trueValues):
23025 case in_array(strtolower($value), $falseValues):
23027 case in_array(strtolower($value), array('null', '~')):
23035 * Dumps a PHP array to a YAML string.
23037 * @param array $value The PHP array to dump
23039 * @return string The YAML string representing the PHP array
23041 static protected function dumpArray($value)
23044 $keys = array_keys($value);
23046 (1 == count($keys) && '0' == $keys[0])
23048 (count($keys) > 1 && array_reduce($keys, function ($v, $w) { return (integer) $v + $w; }, 0) == count($keys) * (count($keys) - 1) / 2))
23051 foreach ($value as $val)
23053 $output[] = self::dump($val);
23056 return sprintf('[%s]', implode(', ', $output));
23061 foreach ($value as $key => $val)
23063 $output[] = sprintf('%s: %s', self::dump($key), self::dump($val));
23066 return sprintf('{ %s }', implode(', ', $output));
23070 * Parses a scalar to a YAML string.
23072 * @param scalar $scalar
23073 * @param string $delimiters
23074 * @param array $stringDelimiter
23075 * @param integer $i
23076 * @param boolean $evaluate
23078 * @return string A YAML string
23080 static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
23082 if (in_array($scalar[$i], $stringDelimiters))
23085 $output = self::parseQuotedScalar($scalar, $i);
23092 $output = substr($scalar, $i);
23093 $i += strlen($output);
23096 if (false !== $strpos = strpos($output, ' #'))
23098 $output = rtrim(substr($output, 0, $strpos));
23101 else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match))
23103 $output = $match[1];
23104 $i += strlen($output);
23108 throw new ParserException(sprintf('Malformed inline YAML string (%s).', $scalar));
23111 $output = $evaluate ? self::evaluateScalar($output) : $output;
23118 * Parses a quoted scalar to YAML.
23120 * @param string $scalar
23121 * @param integer $i
23123 * @return string A YAML string
23125 static protected function parseQuotedScalar($scalar, &$i)
23127 if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/A', substr($scalar, $i), $match))
23129 throw new ParserException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
23132 $output = substr($match[0], 1, strlen($match[0]) - 2);
23134 if ('"' == $scalar[$i])
23136 // evaluate the string
23137 $output = str_replace(array('\\"', '\\n', '\\r'), array('"', "\n", "\r"), $output);
23142 $output = str_replace('\'\'', '\'', $output);
23145 $i += strlen($match[0]);
23151 * Parses a sequence to a YAML string.
23153 * @param string $sequence
23154 * @param integer $i
23156 * @return string A YAML string
23158 static protected function parseSequence($sequence, &$i = 0)
23161 $len = strlen($sequence);
23167 switch ($sequence[$i])
23171 $output[] = self::parseSequence($sequence, $i);
23175 $output[] = self::parseMapping($sequence, $i);
23183 $isQuoted = in_array($sequence[$i], array('"', "'"));
23184 $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
23186 if (!$isQuoted && false !== strpos($value, ': '))
23188 // embedded mapping?
23191 $value = self::parseMapping('{'.$value.'}');
23193 catch (\InvalidArgumentException $e)
23199 $output[] = $value;
23207 throw new ParserException(sprintf('Malformed inline YAML string %s', $sequence));
23211 * Parses a mapping to a YAML string.
23213 * @param string $mapping
23214 * @param integer $i
23216 * @return string A YAML string
23218 static protected function parseMapping($mapping, &$i = 0)
23221 $len = strlen($mapping);
23224 // {foo: bar, bar:foo, ...}
23227 switch ($mapping[$i])
23238 $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
23244 switch ($mapping[$i])
23248 $output[$key] = self::parseSequence($mapping, $i);
23253 $output[$key] = self::parseMapping($mapping, $i);
23260 $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
23274 throw new ParserException(sprintf('Malformed inline YAML string %s', $mapping));
23278 * Evaluates scalars and replaces magic values.
23280 * @param string $scalar
23282 * @return string A YAML string
23284 static protected function evaluateScalar($scalar)
23286 $scalar = trim($scalar);
23288 $trueValues = '1.1' == Yaml::getSpecVersion() ? array('true', 'on', '+', 'yes', 'y') : array('true');
23289 $falseValues = '1.1' == Yaml::getSpecVersion() ? array('false', 'off', '-', 'no', 'n') : array('false');
23293 case 'null' == strtolower($scalar):
23294 case '' == $scalar:
23295 case '~' == $scalar:
23297 case 0 === strpos($scalar, '!str'):
23298 return (string) substr($scalar, 5);
23299 case 0 === strpos($scalar, '! '):
23300 return intval(self::parseScalar(substr($scalar, 2)));
23301 case 0 === strpos($scalar, '!!php/object:'):
23302 return unserialize(substr($scalar, 13));
23303 case ctype_digit($scalar):
23305 $cast = intval($scalar);
23306 return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
23307 case in_array(strtolower($scalar), $trueValues):
23309 case in_array(strtolower($scalar), $falseValues):
23311 case is_numeric($scalar):
23312 return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
23313 case 0 == strcasecmp($scalar, '.inf'):
23314 case 0 == strcasecmp($scalar, '.NaN'):
23316 case 0 == strcasecmp($scalar, '-.inf'):
23318 case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
23319 return floatval(str_replace(',', '', $scalar));
23320 case preg_match(self::getTimestampRegex(), $scalar):
23321 return strtotime($scalar);
23323 return (string) $scalar;
23327 static protected function getTimestampRegex()
23331 (?P<year>[0-9][0-9][0-9][0-9])
23332 -(?P<month>[0-9][0-9]?)
23333 -(?P<day>[0-9][0-9]?)
23335 (?P<hour>[0-9][0-9]?)
23336 :(?P<minute>[0-9][0-9])
23337 :(?P<second>[0-9][0-9])
23338 (?:\.(?P<fraction>[0-9]*))?
23339 (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
23340 (?::(?P<tz_minute>[0-9][0-9]))?))?)?
23347 namespace Symfony\Component\Yaml;
23350 * This file is part of the symfony package.
23351 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
23353 * For the full copyright and license information, please view the LICENSE
23354 * file that was distributed with this source code.
23358 * Parser parses YAML strings to convert them to PHP arrays.
23362 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
23366 protected $offset = 0;
23367 protected $lines = array();
23368 protected $currentLineNb = -1;
23369 protected $currentLine = '';
23370 protected $refs = array();
23375 * @param integer $offset The offset of YAML document (used for line numbers in error messages)
23377 public function __construct($offset = 0)
23379 $this->offset = $offset;
23383 * Parses a YAML string to a PHP value.
23385 * @param string $value A YAML string
23387 * @return mixed A PHP value
23389 * @throws \InvalidArgumentException If the YAML is not valid
23391 public function parse($value)
23393 $this->currentLineNb = -1;
23394 $this->currentLine = '';
23395 $this->lines = explode("\n", $this->cleanup($value));
23398 while ($this->moveToNextLine())
23400 if ($this->isCurrentLineEmpty())
23406 if (preg_match('#^\t+#', $this->currentLine))
23408 throw new ParserException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine));
23411 $isRef = $isInPlace = $isProcessed = false;
23412 if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#', $this->currentLine, $values))
23414 if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#', $values['value'], $matches))
23416 $isRef = $matches['ref'];
23417 $values['value'] = $matches['value'];
23421 if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
23423 $c = $this->getRealCurrentLineNb() + 1;
23424 $parser = new Parser($c);
23425 $parser->refs =& $this->refs;
23426 $data[] = $parser->parse($this->getNextEmbedBlock());
23430 if (isset($values['leadspaces'])
23431 && ' ' == $values['leadspaces']
23432 && preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{].*?) *\:(\s+(?P<value>.+?))?\s*$#', $values['value'], $matches))
23434 // this is a compact notation element, add to next block and parse
23435 $c = $this->getRealCurrentLineNb();
23436 $parser = new Parser($c);
23437 $parser->refs =& $this->refs;
23439 $block = $values['value'];
23440 if (!$this->isNextLineIndented())
23442 $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + 2);
23445 $data[] = $parser->parse($block);
23449 $data[] = $this->parseValue($values['value']);
23453 else if (preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"].*?) *\:(\s+(?P<value>.+?))?\s*$#', $this->currentLine, $values))
23455 $key = Inline::parseScalar($values['key']);
23459 if (isset($values['value']) && '*' === substr($values['value'], 0, 1))
23461 $isInPlace = substr($values['value'], 1);
23462 if (!array_key_exists($isInPlace, $this->refs))
23464 throw new ParserException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine));
23469 if (isset($values['value']) && $values['value'] !== '')
23471 $value = $values['value'];
23475 $value = $this->getNextEmbedBlock();
23477 $c = $this->getRealCurrentLineNb() + 1;
23478 $parser = new Parser($c);
23479 $parser->refs =& $this->refs;
23480 $parsed = $parser->parse($value);
23483 if (!is_array($parsed))
23485 throw new ParserException(sprintf("YAML merge keys used with a scalar value instead of an array at line %s (%s)", $this->getRealCurrentLineNb() + 1, $this->currentLine));
23487 else if (isset($parsed[0]))
23489 // Numeric array, merge individual elements
23490 foreach (array_reverse($parsed) as $parsedItem)
23492 if (!is_array($parsedItem))
23494 throw new ParserException(sprintf("Merge items must be arrays at line %s (%s).", $this->getRealCurrentLineNb() + 1, $parsedItem));
23496 $merged = array_merge($parsedItem, $merged);
23501 // Associative array, merge
23502 $merged = array_merge($merge, $parsed);
23505 $isProcessed = $merged;
23508 else if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#', $values['value'], $matches))
23510 $isRef = $matches['ref'];
23511 $values['value'] = $matches['value'];
23517 $data = $isProcessed;
23520 else if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
23522 // if next line is less indented or equal, then it means that the current value is null
23523 if ($this->isNextLineIndented())
23525 $data[$key] = null;
23529 $c = $this->getRealCurrentLineNb() + 1;
23530 $parser = new Parser($c);
23531 $parser->refs =& $this->refs;
23532 $data[$key] = $parser->parse($this->getNextEmbedBlock());
23539 $data = $this->refs[$isInPlace];
23543 $data[$key] = $this->parseValue($values['value']);
23549 // 1-liner followed by newline
23550 if (2 == count($this->lines) && empty($this->lines[1]))
23552 $value = Inline::load($this->lines[0]);
23553 if (is_array($value))
23555 $first = reset($value);
23556 if ('*' === substr($first, 0, 1))
23559 foreach ($value as $alias)
23561 $data[] = $this->refs[substr($alias, 1)];
23570 switch (preg_last_error())
23572 case PREG_INTERNAL_ERROR:
23573 $error = 'Internal PCRE error on line';
23575 case PREG_BACKTRACK_LIMIT_ERROR:
23576 $error = 'pcre.backtrack_limit reached on line';
23578 case PREG_RECURSION_LIMIT_ERROR:
23579 $error = 'pcre.recursion_limit reached on line';
23581 case PREG_BAD_UTF8_ERROR:
23582 $error = 'Malformed UTF-8 data on line';
23584 case PREG_BAD_UTF8_OFFSET_ERROR:
23585 $error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point on line';
23588 $error = 'Unable to parse line';
23591 throw new ParserException(sprintf('%s %d (%s).', $error, $this->getRealCurrentLineNb() + 1, $this->currentLine));
23596 $this->refs[$isRef] = end($data);
23600 return empty($data) ? null : $data;
23604 * Returns the current line number (takes the offset into account).
23606 * @return integer The current line number
23608 protected function getRealCurrentLineNb()
23610 return $this->currentLineNb + $this->offset;
23614 * Returns the current line indentation.
23616 * @return integer The current line indentation
23618 protected function getCurrentLineIndentation()
23620 return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' '));
23624 * Returns the next embed block of YAML.
23626 * @param integer $indentation The indent level at which the block is to be read, or null for default
23628 * @return string A YAML string
23630 protected function getNextEmbedBlock($indentation = null)
23632 $this->moveToNextLine();
23634 if (null === $indentation)
23636 $newIndent = $this->getCurrentLineIndentation();
23638 if (!$this->isCurrentLineEmpty() && 0 == $newIndent)
23640 throw new ParserException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
23645 $newIndent = $indentation;
23648 $data = array(substr($this->currentLine, $newIndent));
23650 while ($this->moveToNextLine())
23652 if ($this->isCurrentLineEmpty())
23654 if ($this->isCurrentLineBlank())
23656 $data[] = substr($this->currentLine, $newIndent);
23662 $indent = $this->getCurrentLineIndentation();
23664 if (preg_match('#^(?P<text> *)$#', $this->currentLine, $match))
23667 $data[] = $match['text'];
23669 else if ($indent >= $newIndent)
23671 $data[] = substr($this->currentLine, $newIndent);
23673 else if (0 == $indent)
23675 $this->moveToPreviousLine();
23681 throw new ParserException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
23685 return implode("\n", $data);
23689 * Moves the parser to the next line.
23691 protected function moveToNextLine()
23693 if ($this->currentLineNb >= count($this->lines) - 1)
23698 $this->currentLine = $this->lines[++$this->currentLineNb];
23704 * Moves the parser to the previous line.
23706 protected function moveToPreviousLine()
23708 $this->currentLine = $this->lines[--$this->currentLineNb];
23712 * Parses a YAML value.
23714 * @param string $value A YAML value
23716 * @return mixed A PHP value
23718 protected function parseValue($value)
23720 if ('*' === substr($value, 0, 1))
23722 if (false !== $pos = strpos($value, '#'))
23724 $value = substr($value, 1, $pos - 2);
23728 $value = substr($value, 1);
23731 if (!array_key_exists($value, $this->refs))
23733 throw new ParserException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine));
23735 return $this->refs[$value];
23738 if (preg_match('/^(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?$/', $value, $matches))
23740 $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
23742 return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers)));
23746 return Inline::load($value);
23751 * Parses a folded scalar.
23753 * @param string $separator The separator that was used to begin this folded scalar (| or >)
23754 * @param string $indicator The indicator that was used to begin this folded scalar (+ or -)
23755 * @param integer $indentation The indentation that was used to begin this folded scalar
23757 * @return string The text value
23759 protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0)
23761 $separator = '|' == $separator ? "\n" : ' ';
23764 $notEOF = $this->moveToNextLine();
23766 while ($notEOF && $this->isCurrentLineBlank())
23770 $notEOF = $this->moveToNextLine();
23778 if (!preg_match('#^(?P<indent>'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P<text>.*)$#', $this->currentLine, $matches))
23780 $this->moveToPreviousLine();
23785 $textIndent = $matches['indent'];
23786 $previousIndent = 0;
23788 $text .= $matches['text'].$separator;
23789 while ($this->currentLineNb + 1 < count($this->lines))
23791 $this->moveToNextLine();
23793 if (preg_match('#^(?P<indent> {'.strlen($textIndent).',})(?P<text>.+)$#', $this->currentLine, $matches))
23795 if (' ' == $separator && $previousIndent != $matches['indent'])
23797 $text = substr($text, 0, -1)."\n";
23799 $previousIndent = $matches['indent'];
23801 $text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator);
23803 else if (preg_match('#^(?P<text> *)$#', $this->currentLine, $matches))
23805 $text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n";
23809 $this->moveToPreviousLine();
23815 if (' ' == $separator)
23817 // replace last separator by a newline
23818 $text = preg_replace('/ (\n*)$/', "\n$1", $text);
23821 switch ($indicator)
23824 $text = preg_replace('#\n+$#s', "\n", $text);
23829 $text = preg_replace('#\n+$#s', '', $text);
23837 * Returns true if the next line is indented.
23839 * @return Boolean Returns true if the next line is indented, false otherwise
23841 protected function isNextLineIndented()
23843 $currentIndentation = $this->getCurrentLineIndentation();
23844 $notEOF = $this->moveToNextLine();
23846 while ($notEOF && $this->isCurrentLineEmpty())
23848 $notEOF = $this->moveToNextLine();
23851 if (false === $notEOF)
23857 if ($this->getCurrentLineIndentation() <= $currentIndentation)
23862 $this->moveToPreviousLine();
23868 * Returns true if the current line is blank or if it is a comment line.
23870 * @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise
23872 protected function isCurrentLineEmpty()
23874 return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
23878 * Returns true if the current line is blank.
23880 * @return Boolean Returns true if the current line is blank, false otherwise
23882 protected function isCurrentLineBlank()
23884 return '' == trim($this->currentLine, ' ');
23888 * Returns true if the current line is a comment line.
23890 * @return Boolean Returns true if the current line is a comment line, false otherwise
23892 protected function isCurrentLineComment()
23894 //checking explicitly the first char of the trim is faster than loops or strpos
23895 $ltrimmedLine = ltrim($this->currentLine, ' ');
23896 return $ltrimmedLine[0] === '#';
23900 * Cleanups a YAML string to be parsed.
23902 * @param string $value The input YAML string
23904 * @return string A cleaned up YAML string
23906 protected function cleanup($value)
23908 $value = str_replace(array("\r\n", "\r"), "\n", $value);
23910 if (!preg_match("#\n$#", $value))
23915 // strip YAML header
23917 $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#s', '', $value, -1, $count);
23918 $this->offset += $count;
23920 // remove leading comments and/or ---
23921 $trimmedValue = preg_replace('#^((\#.*?\n)|(\-\-\-.*?\n))*#s', '', $value, -1, $count);
23924 // items have been removed, update the offset
23925 $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
23926 $value = $trimmedValue;
23934 namespace Symfony\Component\Console\Command;
23936 use Symfony\Component\Console\Input\InputArgument;
23937 use Symfony\Component\Console\Input\InputOption;
23938 use Symfony\Component\Console\Input\InputInterface;
23939 use Symfony\Component\Console\Output\OutputInterface;
23940 use Symfony\Component\Console\Output\Output;
23941 use Symfony\Component\Console\Command\Command;
23944 * This file is part of the Symfony framework.
23946 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
23948 * This source file is subject to the MIT license that is bundled
23949 * with this source code in the file LICENSE.
23953 * ListCommand displays the list of all available commands for the application.
23955 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
23957 class ListCommand extends Command
23962 protected function configure()
23965 ->setDefinition(array(
23966 new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
23967 new InputOption('xml', null, InputOption::PARAMETER_NONE, 'To output help as XML'),
23970 ->setDescription('Lists commands')
23972 The <info>list</info> command lists all commands:
23974 <info>./symfony list</info>
23976 You can also display the commands for a specific namespace:
23978 <info>./symfony list test</info>
23980 You can also output the information as XML by using the <comment>--xml</comment> option:
23982 <info>./symfony list --xml</info>
23990 protected function execute(InputInterface $input, OutputInterface $output)
23992 if ($input->getOption('xml')) {
23993 $output->writeln($this->application->asXml($input->getArgument('namespace')), Output::OUTPUT_RAW);
23995 $output->writeln($this->application->asText($input->getArgument('namespace')));
24001 namespace Symfony\Component\Console\Command;
24003 use Symfony\Component\Console\Input\InputArgument;
24004 use Symfony\Component\Console\Input\InputOption;
24005 use Symfony\Component\Console\Input\InputInterface;
24006 use Symfony\Component\Console\Output\OutputInterface;
24007 use Symfony\Component\Console\Output\Output;
24008 use Symfony\Component\Console\Command\Command;
24011 * This file is part of the Symfony framework.
24013 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24015 * This source file is subject to the MIT license that is bundled
24016 * with this source code in the file LICENSE.
24020 * HelpCommand displays the help for a given command.
24022 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24024 class HelpCommand extends Command
24026 protected $command;
24031 protected function configure()
24033 $this->ignoreValidationErrors = true;
24036 ->setDefinition(array(
24037 new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
24038 new InputOption('xml', null, InputOption::PARAMETER_NONE, 'To output help as XML'),
24041 ->setAliases(array('?'))
24042 ->setDescription('Displays help for a command')
24044 The <info>help</info> command displays help for a given command:
24046 <info>./symfony help list</info>
24048 You can also output the help as XML by using the <comment>--xml</comment> option:
24050 <info>./symfony help --xml list</info>
24055 public function setCommand(Command $command)
24057 $this->command = $command;
24063 protected function execute(InputInterface $input, OutputInterface $output)
24065 if (null === $this->command) {
24066 $this->command = $this->application->getCommand($input->getArgument('command_name'));
24069 if ($input->getOption('xml')) {
24070 $output->writeln($this->command->asXml(), Output::OUTPUT_RAW);
24072 $output->writeln($this->command->asText());
24078 namespace Symfony\Component\Console\Command;
24080 use Symfony\Component\Console\Input\InputDefinition;
24081 use Symfony\Component\Console\Input\InputOption;
24082 use Symfony\Component\Console\Input\InputArgument;
24083 use Symfony\Component\Console\Input\InputInterface;
24084 use Symfony\Component\Console\Output\OutputInterface;
24085 use Symfony\Component\Console\Application;
24088 * This file is part of the Symfony framework.
24090 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24092 * This source file is subject to the MIT license that is bundled
24093 * with this source code in the file LICENSE.
24097 * Base class for all commands.
24099 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24104 protected $namespace;
24105 protected $aliases;
24106 protected $definition;
24108 protected $application;
24109 protected $description;
24110 protected $ignoreValidationErrors;
24111 protected $applicationDefinitionMerged;
24117 * @param string $name The name of the command
24119 * @throws \LogicException When the command name is empty
24121 public function __construct($name = null)
24123 $this->definition = new InputDefinition();
24124 $this->ignoreValidationErrors = false;
24125 $this->applicationDefinitionMerged = false;
24126 $this->aliases = array();
24128 if (null !== $name) {
24129 $this->setName($name);
24132 $this->configure();
24134 if (!$this->name) {
24135 throw new \LogicException('The command name cannot be empty.');
24140 * Sets the application instance for this command.
24142 * @param Application $application An Application instance
24144 public function setApplication(Application $application = null)
24146 $this->application = $application;
24150 * Configures the current command.
24152 protected function configure()
24157 * Executes the current command.
24159 * @param InputInterface $input An InputInterface instance
24160 * @param OutputInterface $output An OutputInterface instance
24162 * @return integer 0 if everything went fine, or an error code
24164 * @throws \LogicException When this abstract class is not implemented
24166 protected function execute(InputInterface $input, OutputInterface $output)
24168 throw new \LogicException('You must override the execute() method in the concrete command class.');
24172 * Interacts with the user.
24174 * @param InputInterface $input An InputInterface instance
24175 * @param OutputInterface $output An OutputInterface instance
24177 protected function interact(InputInterface $input, OutputInterface $output)
24182 * Initializes the command just after the input has been validated.
24184 * This is mainly useful when a lot of commands extends one main command
24185 * where some things need to be initialized based on the input arguments and options.
24187 * @param InputInterface $input An InputInterface instance
24188 * @param OutputInterface $output An OutputInterface instance
24190 protected function initialize(InputInterface $input, OutputInterface $output)
24195 * Runs the command.
24197 * @param InputInterface $input An InputInterface instance
24198 * @param OutputInterface $output An OutputInterface instance
24200 public function run(InputInterface $input, OutputInterface $output)
24202 // add the application arguments and options
24203 $this->mergeApplicationDefinition();
24205 // bind the input against the command specific arguments/options
24207 $input->bind($this->definition);
24208 } catch (\Exception $e) {
24209 if (!$this->ignoreValidationErrors) {
24214 $this->initialize($input, $output);
24216 if ($input->isInteractive()) {
24217 $this->interact($input, $output);
24220 $input->validate();
24223 return call_user_func($this->code, $input, $output);
24225 return $this->execute($input, $output);
24230 * Sets the code to execute when running this command.
24232 * @param \Closure $code A \Closure
24234 * @return Command The current instance
24236 public function setCode(\Closure $code)
24238 $this->code = $code;
24244 * Merges the application definition with the command definition.
24246 protected function mergeApplicationDefinition()
24248 if (null === $this->application || true === $this->applicationDefinitionMerged) {
24252 $this->definition->setArguments(array_merge(
24253 $this->application->getDefinition()->getArguments(),
24254 $this->definition->getArguments()
24257 $this->definition->addOptions($this->application->getDefinition()->getOptions());
24259 $this->applicationDefinitionMerged = true;
24263 * Sets an array of argument and option instances.
24265 * @param array|Definition $definition An array of argument and option instances or a definition instance
24267 * @return Command The current instance
24269 public function setDefinition($definition)
24271 if ($definition instanceof InputDefinition) {
24272 $this->definition = $definition;
24274 $this->definition->setDefinition($definition);
24277 $this->applicationDefinitionMerged = false;
24283 * Gets the InputDefinition attached to this Command.
24285 * @return InputDefinition An InputDefinition instance
24287 public function getDefinition()
24289 return $this->definition;
24293 * Adds an argument.
24295 * @param string $name The argument name
24296 * @param integer $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
24297 * @param string $description A description text
24298 * @param mixed $default The default value (for InputArgument::OPTIONAL mode only)
24300 * @return Command The current instance
24302 public function addArgument($name, $mode = null, $description = '', $default = null)
24304 $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
24312 * @param string $name The option name
24313 * @param string $shortcut The shortcut (can be null)
24314 * @param integer $mode The option mode: self::PARAMETER_REQUIRED, self::PARAMETER_NONE or self::PARAMETER_OPTIONAL
24315 * @param string $description A description text
24316 * @param mixed $default The default value (must be null for self::PARAMETER_REQUIRED or self::PARAMETER_NONE)
24318 * @return Command The current instance
24320 public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
24322 $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
24328 * Sets the name of the command.
24330 * This method can set both the namespace and the name if
24331 * you separate them by a colon (:)
24333 * $command->setName('foo:bar');
24335 * @param string $name The command name
24337 * @return Command The current instance
24339 * @throws \InvalidArgumentException When command name given is empty
24341 public function setName($name)
24343 if (false !== $pos = strrpos($name, ':')) {
24344 $namespace = substr($name, 0, $pos);
24345 $name = substr($name, $pos + 1);
24347 $namespace = $this->namespace;
24351 throw new \InvalidArgumentException('A command name cannot be empty.');
24354 $this->namespace = $namespace;
24355 $this->name = $name;
24361 * Returns the command namespace.
24363 * @return string The command namespace
24365 public function getNamespace()
24367 return $this->namespace;
24371 * Returns the command name
24373 * @return string The command name
24375 public function getName()
24377 return $this->name;
24381 * Returns the fully qualified command name.
24383 * @return string The fully qualified command name
24385 public function getFullName()
24387 return $this->getNamespace() ? $this->getNamespace().':'.$this->getName() : $this->getName();
24391 * Sets the description for the command.
24393 * @param string $description The description for the command
24395 * @return Command The current instance
24397 public function setDescription($description)
24399 $this->description = $description;
24405 * Returns the description for the command.
24407 * @return string The description for the command
24409 public function getDescription()
24411 return $this->description;
24415 * Sets the help for the command.
24417 * @param string $help The help for the command
24419 * @return Command The current instance
24421 public function setHelp($help)
24423 $this->help = $help;
24429 * Returns the help for the command.
24431 * @return string The help for the command
24433 public function getHelp()
24435 return $this->help;
24439 * Returns the processed help for the command replacing the %command.name% and
24440 * %command.full_name% patterns with the real values dynamically.
24442 * @return string The processed help for the command
24444 public function getProcessedHelp()
24446 $name = $this->namespace.':'.$this->name;
24448 $placeholders = array(
24450 '%command.full_name%'
24452 $replacements = array(
24454 $_SERVER['PHP_SELF'].' '.$name
24457 return str_replace($placeholders, $replacements, $this->getHelp());
24461 * Sets the aliases for the command.
24463 * @param array $aliases An array of aliases for the command
24465 * @return Command The current instance
24467 public function setAliases($aliases)
24469 $this->aliases = $aliases;
24475 * Returns the aliases for the command.
24477 * @return array An array of aliases for the command
24479 public function getAliases()
24481 return $this->aliases;
24485 * Returns the synopsis for the command.
24487 * @return string The synopsis
24489 public function getSynopsis()
24491 return sprintf('%s %s', $this->getFullName(), $this->definition->getSynopsis());
24495 * Gets a helper instance by name.
24497 * @param string $name The helper name
24499 * @return mixed The helper value
24501 * @throws \InvalidArgumentException if the helper is not defined
24503 protected function getHelper($name)
24505 return $this->application->getHelperSet()->get($name);
24509 * Gets a helper instance by name.
24511 * @param string $name The helper name
24513 * @return mixed The helper value
24515 * @throws \InvalidArgumentException if the helper is not defined
24517 public function __get($name)
24519 return $this->application->getHelperSet()->get($name);
24523 * Returns a text representation of the command.
24525 * @return string A string representing the command
24527 public function asText()
24530 '<comment>Usage:</comment>',
24531 ' '.$this->getSynopsis(),
24535 if ($this->getAliases()) {
24536 $messages[] = '<comment>Aliases:</comment> <info>'.implode(', ', $this->getAliases()).'</info>';
24539 $messages[] = $this->definition->asText();
24541 if ($help = $this->getProcessedHelp()) {
24542 $messages[] = '<comment>Help:</comment>';
24543 $messages[] = ' '.implode("\n ", explode("\n", $help))."\n";
24546 return implode("\n", $messages);
24550 * Returns an XML representation of the command.
24552 * @param Boolean $asDom Whether to return a DOM or an XML string
24554 * @return string|DOMDocument An XML string representing the command
24556 public function asXml($asDom = false)
24558 $dom = new \DOMDocument('1.0', 'UTF-8');
24559 $dom->formatOutput = true;
24560 $dom->appendChild($commandXML = $dom->createElement('command'));
24561 $commandXML->setAttribute('id', $this->getFullName());
24562 $commandXML->setAttribute('namespace', $this->getNamespace() ? $this->getNamespace() : '_global');
24563 $commandXML->setAttribute('name', $this->getName());
24565 $commandXML->appendChild($usageXML = $dom->createElement('usage'));
24566 $usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
24568 $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
24569 $descriptionXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $this->getDescription()))));
24571 $commandXML->appendChild($helpXML = $dom->createElement('help'));
24572 $help = $this->help;
24573 $helpXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $help))));
24575 $commandXML->appendChild($aliasesXML = $dom->createElement('aliases'));
24576 foreach ($this->getAliases() as $alias) {
24577 $aliasesXML->appendChild($aliasXML = $dom->createElement('alias'));
24578 $aliasXML->appendChild($dom->createTextNode($alias));
24581 $definition = $this->definition->asXml(true);
24582 $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('arguments')->item(0), true));
24583 $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('options')->item(0), true));
24585 return $asDom ? $dom : $dom->saveXml();
24590 namespace Symfony\Component\Console\Output;
24593 * This file is part of the Symfony framework.
24595 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24597 * This source file is subject to the MIT license that is bundled
24598 * with this source code in the file LICENSE.
24602 * ConsoleOutput is the default class for all CLI output. It uses STDOUT.
24604 * This class is a convenient wrapper around `StreamOutput`.
24606 * $output = new ConsoleOutput();
24608 * This is equivalent to:
24610 * $output = new StreamOutput(fopen('php://stdout', 'w'));
24612 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24614 class ConsoleOutput extends StreamOutput
24619 * @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
24620 * @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
24622 public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null)
24624 parent::__construct(fopen('php://stdout', 'w'), $verbosity, $decorated);
24629 namespace Symfony\Component\Console\Output;
24632 * This file is part of the Symfony framework.
24634 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24636 * This source file is subject to the MIT license that is bundled
24637 * with this source code in the file LICENSE.
24641 * OutputInterface is the interface implemented by all Output classes.
24643 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24645 interface OutputInterface
24648 * Writes a message to the output.
24650 * @param string|array $messages The message as an array of lines of a single string
24651 * @param Boolean $newline Whether to add a newline or not
24652 * @param integer $type The type of output
24654 * @throws \InvalidArgumentException When unknown output type is given
24656 function write($messages, $newline = false, $type = 0);
24659 * Sets the verbosity of the output.
24661 * @param integer $level The level of verbosity
24663 function setVerbosity($level);
24666 * Sets the decorated flag.
24668 * @param Boolean $decorated Whether to decorated the messages or not
24670 function setDecorated($decorated);
24674 namespace Symfony\Component\Console\Output;
24677 * This file is part of the Symfony framework.
24679 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24681 * This source file is subject to the MIT license that is bundled
24682 * with this source code in the file LICENSE.
24686 * StreamOutput writes the output to a given stream.
24690 * $output = new StreamOutput(fopen('php://stdout', 'w'));
24692 * As `StreamOutput` can use any stream, you can also use a file:
24694 * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false));
24696 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24698 class StreamOutput extends Output
24705 * @param mixed $stream A stream resource
24706 * @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
24707 * @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
24709 * @throws \InvalidArgumentException When first argument is not a real stream
24711 public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null)
24713 if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
24714 throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
24717 $this->stream = $stream;
24719 if (null === $decorated) {
24720 $decorated = $this->hasColorSupport($decorated);
24723 parent::__construct($verbosity, $decorated);
24727 * Gets the stream attached to this StreamOutput instance.
24729 * @return resource A stream resource
24731 public function getStream()
24733 return $this->stream;
24737 * Writes a message to the output.
24739 * @param string $message A message to write to the output
24740 * @param Boolean $newline Whether to add a newline or not
24742 * @throws \RuntimeException When unable to write output (should never happen)
24744 public function doWrite($message, $newline)
24746 if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) {
24747 // @codeCoverageIgnoreStart
24748 // should never happen
24749 throw new \RuntimeException('Unable to write output.');
24750 // @codeCoverageIgnoreEnd
24757 * Returns true if the stream supports colorization.
24759 * Colorization is disabled if not supported by the stream:
24761 * - windows without ansicon
24762 * - non tty consoles
24764 * @return Boolean true if the stream supports colorization, false otherwise
24766 protected function hasColorSupport()
24768 // @codeCoverageIgnoreStart
24769 if (DIRECTORY_SEPARATOR == '\\') {
24770 return false !== getenv('ANSICON');
24772 return function_exists('posix_isatty') && @posix_isatty($this->stream);
24774 // @codeCoverageIgnoreEnd
24779 namespace Symfony\Component\Console\Output;
24782 * This file is part of the Symfony framework.
24784 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24786 * This source file is subject to the MIT license that is bundled
24787 * with this source code in the file LICENSE.
24791 * Base class for output classes.
24793 * There is three level of verbosity:
24795 * * normal: no option passed (normal output - information)
24796 * * verbose: -v (more output - debug)
24797 * * quiet: -q (no output)
24799 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24801 abstract class Output implements OutputInterface
24803 const VERBOSITY_QUIET = 0;
24804 const VERBOSITY_NORMAL = 1;
24805 const VERBOSITY_VERBOSE = 2;
24807 const OUTPUT_NORMAL = 0;
24808 const OUTPUT_RAW = 1;
24809 const OUTPUT_PLAIN = 2;
24811 protected $verbosity;
24812 protected $decorated;
24814 static protected $styles = array(
24815 'error' => array('bg' => 'red', 'fg' => 'white'),
24816 'info' => array('fg' => 'green'),
24817 'comment' => array('fg' => 'yellow'),
24818 'question' => array('bg' => 'cyan', 'fg' => 'black'),
24820 static protected $options = array('bold' => 1, 'underscore' => 4, 'blink' => 5, 'reverse' => 7, 'conceal' => 8);
24821 static protected $foreground = array('black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'white' => 37);
24822 static protected $background = array('black' => 40, 'red' => 41, 'green' => 42, 'yellow' => 43, 'blue' => 44, 'magenta' => 45, 'cyan' => 46, 'white' => 47);
24827 * @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
24828 * @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
24830 public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null)
24832 $this->decorated = (Boolean) $decorated;
24833 $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
24837 * Sets a new style.
24839 * @param string $name The style name
24840 * @param array $options An array of options
24842 static public function setStyle($name, $options = array())
24844 static::$styles[strtolower($name)] = $options;
24848 * Sets the decorated flag.
24850 * @param Boolean $decorated Whether to decorated the messages or not
24852 public function setDecorated($decorated)
24854 $this->decorated = (Boolean) $decorated;
24858 * Gets the decorated flag.
24860 * @return Boolean true if the output will decorate messages, false otherwise
24862 public function isDecorated()
24864 return $this->decorated;
24868 * Sets the verbosity of the output.
24870 * @param integer $level The level of verbosity
24872 public function setVerbosity($level)
24874 $this->verbosity = (int) $level;
24878 * Gets the current verbosity of the output.
24880 * @return integer The current level of verbosity
24882 public function getVerbosity()
24884 return $this->verbosity;
24888 * Writes a message to the output and adds a newline at the end.
24890 * @param string|array $messages The message as an array of lines of a single string
24891 * @param integer $type The type of output
24893 public function writeln($messages, $type = 0)
24895 $this->write($messages, true, $type);
24899 * Writes a message to the output.
24901 * @param string|array $messages The message as an array of lines of a single string
24902 * @param Boolean $newline Whether to add a newline or not
24903 * @param integer $type The type of output
24905 * @throws \InvalidArgumentException When unknown output type is given
24907 public function write($messages, $newline = false, $type = 0)
24909 if (self::VERBOSITY_QUIET === $this->verbosity) {
24913 if (!is_array($messages)) {
24914 $messages = array($messages);
24917 foreach ($messages as $message) {
24919 case Output::OUTPUT_NORMAL:
24920 $message = $this->format($message);
24922 case Output::OUTPUT_RAW:
24924 case Output::OUTPUT_PLAIN:
24925 $message = strip_tags($this->format($message));
24928 throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type));
24931 $this->doWrite($message, $newline);
24936 * Writes a message to the output.
24938 * @param string $message A message to write to the output
24939 * @param Boolean $newline Whether to add a newline or not
24941 abstract public function doWrite($message, $newline);
24944 * Formats a message according to the given styles.
24946 * @param string $message The message to style
24948 * @return string The styled message
24950 protected function format($message)
24952 $message = preg_replace_callback('#<([a-z][a-z0-9\-_=;]+)>#i', array($this, 'replaceStartStyle'), $message);
24954 return preg_replace_callback('#</([a-z][a-z0-9\-_]*)?>#i', array($this, 'replaceEndStyle'), $message);
24958 * @throws \InvalidArgumentException When style is unknown
24960 protected function replaceStartStyle($match)
24962 if (!$this->decorated) {
24966 if (isset(static::$styles[strtolower($match[1])])) {
24967 $parameters = static::$styles[strtolower($match[1])];
24970 if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($match[1]), $matches, PREG_SET_ORDER)) {
24971 throw new \InvalidArgumentException(sprintf('Unknown style "%s".', $match[1]));
24974 $parameters = array();
24975 foreach ($matches as $match) {
24976 $parameters[$match[1]] = $match[2];
24982 if (isset($parameters['fg'])) {
24983 $codes[] = static::$foreground[$parameters['fg']];
24986 if (isset($parameters['bg'])) {
24987 $codes[] = static::$background[$parameters['bg']];
24990 foreach (static::$options as $option => $value) {
24991 if (isset($parameters[$option]) && $parameters[$option]) {
24996 return "\033[".implode(';', $codes).'m';
24999 protected function replaceEndStyle($match)
25001 if (!$this->decorated) {
25010 namespace Symfony\Component\Console\Output;
25013 * This file is part of the Symfony framework.
25015 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25017 * This source file is subject to the MIT license that is bundled
25018 * with this source code in the file LICENSE.
25022 * NullOutput suppresses all output.
25024 * $output = new NullOutput();
25026 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25028 class NullOutput extends Output
25031 * Writes a message to the output.
25033 * @param string $message A message to write to the output
25034 * @param Boolean $newline Whether to add a newline or not
25036 public function doWrite($message, $newline)
25042 namespace Symfony\Component\Console;
25044 use Symfony\Component\Console\Application;
25045 use Symfony\Component\Console\Input\StringInput;
25046 use Symfony\Component\Console\Output\ConsoleOutput;
25049 * This file is part of the Symfony framework.
25051 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25053 * This source file is subject to the MIT license that is bundled
25054 * with this source code in the file LICENSE.
25058 * A Shell wraps an Application to add shell capabilities to it.
25060 * This class only works with a PHP compiled with readline support
25061 * (either --with-readline or --with-libedit)
25063 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25067 protected $application;
25068 protected $history;
25074 * If there is no readline support for the current PHP executable
25075 * a \RuntimeException exception is thrown.
25077 * @param Application $application An application instance
25079 * @throws \RuntimeException When Readline extension is not enabled
25081 public function __construct(Application $application)
25083 if (!function_exists('readline')) {
25084 throw new \RuntimeException('Unable to start the shell as the Readline extension is not enabled.');
25087 $this->application = $application;
25088 $this->history = getenv('HOME').'/.history_'.$application->getName();
25089 $this->output = new ConsoleOutput();
25095 public function run()
25097 $this->application->setAutoExit(false);
25098 $this->application->setCatchExceptions(true);
25100 readline_read_history($this->history);
25101 readline_completion_function(array($this, 'autocompleter'));
25103 $this->output->writeln($this->getHeader());
25105 $command = readline($this->application->getName().' > ');
25107 if (false === $command) {
25108 $this->output->writeln("\n");
25113 readline_add_history($command);
25114 readline_write_history($this->history);
25116 if (0 !== $ret = $this->application->run(new StringInput($command), $this->output)) {
25117 $this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
25123 * Tries to return autocompletion for the current entered text.
25125 * @param string $text The last segment of the entered text
25126 * @param integer $position The current position
25128 protected function autocompleter($text, $position)
25130 $info = readline_info();
25131 $text = substr($info['line_buffer'], 0, $info['end']);
25133 if ($info['point'] !== $info['end']) {
25138 if (false === strpos($text, ' ') || !$text) {
25139 return array_keys($this->application->getCommands());
25142 // options and arguments?
25144 $command = $this->application->findCommand(substr($text, 0, strpos($text, ' ')));
25145 } catch (\Exception $e) {
25149 $list = array('--help');
25150 foreach ($command->getDefinition()->getOptions() as $option) {
25151 $list[] = '--'.$option->getName();
25158 * Returns the shell header.
25160 * @return string The header string
25162 protected function getHeader()
25166 Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).
25168 At the prompt, type <comment>help</comment> for some help,
25169 or <comment>list</comment> to get a list available commands.
25171 To exit the shell, type <comment>^D</comment>.
25178 namespace Symfony\Component\Console\Helper;
25181 * This file is part of the Symfony framework.
25183 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25185 * This source file is subject to the MIT license that is bundled
25186 * with this source code in the file LICENSE.
25190 * The Formatter class provides helpers to format messages.
25192 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25194 class FormatterHelper extends Helper
25197 * Formats a message within a section.
25199 * @param string $section The section name
25200 * @param string $message The message
25201 * @param string $style The style to apply to the section
25203 public function formatSection($section, $message, $style = 'info')
25205 return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
25209 * Formats a message as a block of text.
25211 * @param string|array $messages The message to write in the block
25212 * @param string $style The style to apply to the whole block
25213 * @param Boolean $large Whether to return a large block
25215 * @return string The formatter message
25217 public function formatBlock($messages, $style, $large = false)
25219 if (!is_array($messages)) {
25220 $messages = array($messages);
25225 foreach ($messages as $message) {
25226 $lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
25227 $len = max($this->strlen($message) + ($large ? 4 : 2), $len);
25230 $messages = $large ? array(str_repeat(' ', $len)) : array();
25231 foreach ($lines as $line) {
25232 $messages[] = $line.str_repeat(' ', $len - $this->strlen($line));
25235 $messages[] = str_repeat(' ', $len);
25238 foreach ($messages as &$message) {
25239 $message = sprintf('<%s>%s</%s>', $style, $message, $style);
25242 return implode("\n", $messages);
25245 protected function strlen($string)
25247 return function_exists('mb_strlen') ? mb_strlen($string) : strlen($string);
25251 * Returns the helper's canonical name
25253 public function getName()
25255 return 'formatter';
25260 namespace Symfony\Component\Console\Helper;
25262 use Symfony\Component\Console\Command\Command;
25265 * This file is part of the Symfony framework.
25267 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25269 * This source file is subject to the MIT license that is bundled
25270 * with this source code in the file LICENSE.
25274 * HelperSet represents a set of helpers to be used with a command.
25276 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25280 protected $helpers;
25281 protected $command;
25284 * @param Helper[] $helpers An array of helper.
25286 public function __construct(array $helpers = array())
25288 $this->helpers = array();
25289 foreach ($helpers as $alias => $helper) {
25290 $this->set($helper, is_int($alias) ? null : $alias);
25297 * @param HelperInterface $value The helper instance
25298 * @param string $alias An alias
25300 public function set(HelperInterface $helper, $alias = null)
25302 $this->helpers[$helper->getName()] = $helper;
25303 if (null !== $alias) {
25304 $this->helpers[$alias] = $helper;
25307 $helper->setHelperSet($this);
25311 * Returns true if the helper if defined.
25313 * @param string $name The helper name
25315 * @return Boolean true if the helper is defined, false otherwise
25317 public function has($name)
25319 return isset($this->helpers[$name]);
25323 * Gets a helper value.
25325 * @param string $name The helper name
25327 * @return HelperInterface The helper instance
25329 * @throws \InvalidArgumentException if the helper is not defined
25331 public function get($name)
25333 if (!$this->has($name)) {
25334 throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
25337 return $this->helpers[$name];
25341 * Sets the command associated with this helper set.
25343 * @param Command $command A Command instance
25345 public function setCommand(Command $command = null)
25347 $this->command = $command;
25351 * Gets the command associated with this helper set.
25353 * @return Command A Command instance
25355 public function getCommand()
25357 return $this->command;
25362 namespace Symfony\Component\Console\Helper;
25365 * This file is part of the Symfony framework.
25367 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25369 * This source file is subject to the MIT license that is bundled
25370 * with this source code in the file LICENSE.
25374 * Helper is the base class for all helper classes.
25376 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25378 abstract class Helper implements HelperInterface
25380 protected $helperSet = null;
25383 * Sets the helper set associated with this helper.
25385 * @param HelperSet $helperSet A HelperSet instance
25387 public function setHelperSet(HelperSet $helperSet = null)
25389 $this->helperSet = $helperSet;
25393 * Gets the helper set associated with this helper.
25395 * @return HelperSet A HelperSet instance
25397 public function getHelperSet()
25399 return $this->helperSet;
25404 namespace Symfony\Component\Console\Helper;
25407 * This file is part of the Symfony framework.
25409 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25411 * This source file is subject to the MIT license that is bundled
25412 * with this source code in the file LICENSE.
25416 * HelperInterface is the interface all helpers must implement.
25418 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25420 interface HelperInterface
25423 * Sets the helper set associated with this helper.
25425 * @param HelperSet $helperSet A HelperSet instance
25427 function setHelperSet(HelperSet $helperSet = null);
25430 * Gets the helper set associated with this helper.
25432 * @return HelperSet A HelperSet instance
25434 function getHelperSet();
25437 * Returns the canonical name of this helper.
25439 * @return string The canonical name
25441 function getName();
25445 namespace Symfony\Component\Console\Helper;
25447 use Symfony\Component\Console\Output\OutputInterface;
25450 * This file is part of the Symfony framework.
25452 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25454 * This source file is subject to the MIT license that is bundled
25455 * with this source code in the file LICENSE.
25459 * The Dialog class provides helpers to interact with the user.
25461 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25463 class DialogHelper extends Helper
25466 * Asks a question to the user.
25468 * @param OutputInterface $output
25469 * @param string|array $question The question to ask
25470 * @param string $default The default answer if none is given by the user
25472 * @return string The user answer
25474 public function ask(OutputInterface $output, $question, $default = null)
25476 // @codeCoverageIgnoreStart
25477 $output->writeln($question);
25479 $ret = trim(fgets(STDIN));
25481 return $ret ? $ret : $default;
25482 // @codeCoverageIgnoreEnd
25486 * Asks a confirmation to the user.
25488 * The question will be asked until the user answer by nothing, yes, or no.
25490 * @param OutputInterface $output
25491 * @param string|array $question The question to ask
25492 * @param Boolean $default The default answer if the user enters nothing
25494 * @return Boolean true if the user has confirmed, false otherwise
25496 public function askConfirmation(OutputInterface $output, $question, $default = true)
25498 // @codeCoverageIgnoreStart
25500 while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) {
25501 $answer = $this->ask($output, $question);
25504 if (false === $default) {
25505 return $answer && 'y' == strtolower($answer[0]);
25507 return !$answer || 'y' == strtolower($answer[0]);
25509 // @codeCoverageIgnoreEnd
25513 * Asks for a value and validates the response.
25515 * @param OutputInterface $output
25516 * @param string|array $question
25517 * @param Closure $validator
25518 * @param integer $attempts Max number of times to ask before giving up (false by default, which means infinite)
25522 * @throws \Exception When any of the validator returns an error
25524 public function askAndValidate(OutputInterface $output, $question, \Closure $validator, $attempts = false)
25526 // @codeCoverageIgnoreStart
25528 while (false === $attempts || $attempts--) {
25529 if (null !== $error) {
25530 $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'));
25533 $value = $this->ask($output, $question, null);
25536 return $validator($value);
25537 } catch (\Exception $error) {
25542 // @codeCoverageIgnoreEnd
25546 * Returns the helper's canonical name
25548 public function getName()
25555 namespace Symfony\Component\Console;
25557 use Symfony\Component\Console\Input\InputInterface;
25558 use Symfony\Component\Console\Input\ArgvInput;
25559 use Symfony\Component\Console\Input\ArrayInput;
25560 use Symfony\Component\Console\Input\InputDefinition;
25561 use Symfony\Component\Console\Input\InputOption;
25562 use Symfony\Component\Console\Input\InputArgument;
25563 use Symfony\Component\Console\Output\OutputInterface;
25564 use Symfony\Component\Console\Output\Output;
25565 use Symfony\Component\Console\Output\ConsoleOutput;
25566 use Symfony\Component\Console\Command\Command;
25567 use Symfony\Component\Console\Command\HelpCommand;
25568 use Symfony\Component\Console\Command\ListCommand;
25569 use Symfony\Component\Console\Helper\HelperSet;
25570 use Symfony\Component\Console\Helper\FormatterHelper;
25571 use Symfony\Component\Console\Helper\DialogHelper;
25574 * This file is part of the Symfony framework.
25576 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25578 * This source file is subject to the MIT license that is bundled
25579 * with this source code in the file LICENSE.
25583 * An Application is the container for a collection of commands.
25585 * It is the main entry point of a Console application.
25587 * This class is optimized for a standard CLI environment.
25591 * $app = new Application('myapp', '1.0 (stable)');
25592 * $app->addCommand(new SimpleCommand());
25595 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25599 protected $commands;
25600 protected $aliases;
25601 protected $wantHelps = false;
25602 protected $runningCommand;
25604 protected $version;
25605 protected $catchExceptions;
25606 protected $autoExit;
25607 protected $definition;
25608 protected $helperSet;
25613 * @param string $name The name of the application
25614 * @param string $version The version of the application
25616 public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
25618 $this->name = $name;
25619 $this->version = $version;
25620 $this->catchExceptions = true;
25621 $this->autoExit = true;
25622 $this->commands = array();
25623 $this->aliases = array();
25624 $this->helperSet = new HelperSet(array(
25625 new FormatterHelper(),
25626 new DialogHelper(),
25629 $this->addCommand(new HelpCommand());
25630 $this->addCommand(new ListCommand());
25632 $this->definition = new InputDefinition(array(
25633 new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
25635 new InputOption('--help', '-h', InputOption::PARAMETER_NONE, 'Display this help message.'),
25636 new InputOption('--quiet', '-q', InputOption::PARAMETER_NONE, 'Do not output any message.'),
25637 new InputOption('--verbose', '-v', InputOption::PARAMETER_NONE, 'Increase verbosity of messages.'),
25638 new InputOption('--version', '-V', InputOption::PARAMETER_NONE, 'Display this program version.'),
25639 new InputOption('--ansi', '-a', InputOption::PARAMETER_NONE, 'Force ANSI output.'),
25640 new InputOption('--no-interaction', '-n', InputOption::PARAMETER_NONE, 'Do not ask any interactive question.'),
25645 * Runs the current application.
25647 * @param InputInterface $input An Input instance
25648 * @param OutputInterface $output An Output instance
25650 * @return integer 0 if everything went fine, or an error code
25652 * @throws \Exception When doRun returns Exception
25654 public function run(InputInterface $input = null, OutputInterface $output = null)
25656 if (null === $input) {
25657 $input = new ArgvInput();
25660 if (null === $output) {
25661 $output = new ConsoleOutput();
25665 $statusCode = $this->doRun($input, $output);
25666 } catch (\Exception $e) {
25667 if (!$this->catchExceptions) {
25671 $this->renderException($e, $output);
25672 $statusCode = $e->getCode();
25674 $statusCode = is_numeric($statusCode) && $statusCode ? $statusCode : 1;
25677 if ($this->autoExit) {
25678 if ($statusCode > 255) {
25681 // @codeCoverageIgnoreStart
25683 // @codeCoverageIgnoreEnd
25685 return $statusCode;
25690 * Runs the current application.
25692 * @param InputInterface $input An Input instance
25693 * @param OutputInterface $output An Output instance
25695 * @return integer 0 if everything went fine, or an error code
25697 public function doRun(InputInterface $input, OutputInterface $output)
25699 $name = $this->getCommandName($input);
25701 if (true === $input->hasParameterOption(array('--ansi', '-a'))) {
25702 $output->setDecorated(true);
25705 if (true === $input->hasParameterOption(array('--help', '-h'))) {
25708 $input = new ArrayInput(array('command' => 'help'));
25710 $this->wantHelps = true;
25714 if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) {
25715 $input->setInteractive(false);
25718 if (true === $input->hasParameterOption(array('--quiet', '-q'))) {
25719 $output->setVerbosity(Output::VERBOSITY_QUIET);
25720 } elseif (true === $input->hasParameterOption(array('--verbose', '-v'))) {
25721 $output->setVerbosity(Output::VERBOSITY_VERBOSE);
25724 if (true === $input->hasParameterOption(array('--version', '-V'))) {
25725 $output->writeln($this->getLongVersion());
25732 $input = new ArrayInput(array('command' => 'list'));
25735 // the command name MUST be the first element of the input
25736 $command = $this->findCommand($name);
25738 $this->runningCommand = $command;
25739 $statusCode = $command->run($input, $output);
25740 $this->runningCommand = null;
25742 return is_numeric($statusCode) ? $statusCode : 0;
25746 * Set a helper set to be used with the command.
25748 * @param HelperSet $helperSet The helper set
25750 public function setHelperSet(HelperSet $helperSet)
25752 $this->helperSet = $helperSet;
25756 * Get the helper set associated with the command
25758 * @return HelperSet The HelperSet instance associated with this command
25760 public function getHelperSet()
25762 return $this->helperSet;
25766 * Gets the InputDefinition related to this Application.
25768 * @return InputDefinition The InputDefinition instance
25770 public function getDefinition()
25772 return $this->definition;
25776 * Gets the help message.
25778 * @return string A help message.
25780 public function getHelp()
25783 $this->getLongVersion(),
25785 '<comment>Usage:</comment>',
25786 sprintf(" [options] command [arguments]\n"),
25787 '<comment>Options:</comment>',
25790 foreach ($this->definition->getOptions() as $option) {
25791 $messages[] = sprintf(' %-29s %s %s',
25792 '<info>--'.$option->getName().'</info>',
25793 $option->getShortcut() ? '<info>-'.$option->getShortcut().'</info>' : ' ',
25794 $option->getDescription()
25798 return implode("\n", $messages);
25802 * Sets whether to catch exceptions or not during commands execution.
25804 * @param Boolean $boolean Whether to catch exceptions or not during commands execution
25806 public function setCatchExceptions($boolean)
25808 $this->catchExceptions = (Boolean) $boolean;
25812 * Sets whether to automatically exit after a command execution or not.
25814 * @param Boolean $boolean Whether to automatically exit after a command execution or not
25816 public function setAutoExit($boolean)
25818 $this->autoExit = (Boolean) $boolean;
25822 * Gets the name of the application.
25824 * @return string The application name
25826 public function getName()
25828 return $this->name;
25832 * Sets the application name.
25834 * @param string $name The application name
25836 public function setName($name)
25838 $this->name = $name;
25842 * Gets the application version.
25844 * @return string The application version
25846 public function getVersion()
25848 return $this->version;
25852 * Sets the application version.
25854 * @param string $version The application version
25856 public function setVersion($version)
25858 $this->version = $version;
25862 * Returns the long version of the application.
25864 * @return string The long application version
25866 public function getLongVersion()
25868 if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
25869 return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
25871 return '<info>Console Tool</info>';
25876 * Registers a new command.
25878 * @param string $name The command name
25880 * @return Command The newly created command
25882 public function register($name)
25884 return $this->addCommand(new Command($name));
25888 * Adds an array of command objects.
25890 * @param Command[] $commands An array of commands
25892 public function addCommands(array $commands)
25894 foreach ($commands as $command) {
25895 $this->addCommand($command);
25900 * Adds a command object.
25902 * If a command with the same name already exists, it will be overridden.
25904 * @param Command $command A Command object
25906 * @return Command The registered command
25908 public function addCommand(Command $command)
25910 $command->setApplication($this);
25912 $this->commands[$command->getFullName()] = $command;
25914 foreach ($command->getAliases() as $alias) {
25915 $this->aliases[$alias] = $command;
25922 * Returns a registered command by name or alias.
25924 * @param string $name The command name or alias
25926 * @return Command A Command object
25928 * @throws \InvalidArgumentException When command name given does not exist
25930 public function getCommand($name)
25932 if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
25933 throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
25936 $command = isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name];
25938 if ($this->wantHelps) {
25939 $this->wantHelps = false;
25941 $helpCommand = $this->getCommand('help');
25942 $helpCommand->setCommand($command);
25944 return $helpCommand;
25951 * Returns true if the command exists, false otherwise
25953 * @param string $name The command name or alias
25955 * @return Boolean true if the command exists, false otherwise
25957 public function hasCommand($name)
25959 return isset($this->commands[$name]) || isset($this->aliases[$name]);
25963 * Returns an array of all unique namespaces used by currently registered commands.
25965 * It does not returns the global namespace which always exists.
25967 * @return array An array of namespaces
25969 public function getNamespaces()
25971 $namespaces = array();
25972 foreach ($this->commands as $command) {
25973 if ($command->getNamespace()) {
25974 $namespaces[$command->getNamespace()] = true;
25978 return array_keys($namespaces);
25982 * Finds a registered namespace by a name or an abbreviation.
25984 * @return string A registered namespace
25986 * @throws \InvalidArgumentException When namespace is incorrect or ambiguous
25988 public function findNamespace($namespace)
25990 $abbrevs = static::getAbbreviations($this->getNamespaces());
25992 if (!isset($abbrevs[$namespace])) {
25993 throw new \InvalidArgumentException(sprintf('There are no commands defined in the "%s" namespace.', $namespace));
25996 if (count($abbrevs[$namespace]) > 1) {
25997 throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$namespace])));
26000 return $abbrevs[$namespace][0];
26004 * Finds a command by name or alias.
26006 * Contrary to getCommand, this command tries to find the best
26007 * match if you give it an abbreviation of a name or alias.
26009 * @param string $name A command name or a command alias
26011 * @return Command A Command instance
26013 * @throws \InvalidArgumentException When command name is incorrect or ambiguous
26015 public function findCommand($name)
26019 if (false !== $pos = strrpos($name, ':')) {
26020 $namespace = $this->findNamespace(substr($name, 0, $pos));
26021 $name = substr($name, $pos + 1);
26024 $fullName = $namespace ? $namespace.':'.$name : $name;
26027 $commands = array();
26028 foreach ($this->commands as $command) {
26029 if ($command->getNamespace() == $namespace) {
26030 $commands[] = $command->getName();
26034 $abbrevs = static::getAbbreviations($commands);
26035 if (isset($abbrevs[$name]) && 1 == count($abbrevs[$name])) {
26036 return $this->getCommand($namespace ? $namespace.':'.$abbrevs[$name][0] : $abbrevs[$name][0]);
26039 if (isset($abbrevs[$name]) && count($abbrevs[$name]) > 1) {
26040 $suggestions = $this->getAbbreviationSuggestions(array_map(function ($command) use ($namespace) { return $namespace.':'.$command; }, $abbrevs[$name]));
26042 throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $fullName, $suggestions));
26046 $abbrevs = static::getAbbreviations(array_keys($this->aliases));
26047 if (!isset($abbrevs[$fullName])) {
26048 throw new \InvalidArgumentException(sprintf('Command "%s" is not defined.', $fullName));
26051 if (count($abbrevs[$fullName]) > 1) {
26052 throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $fullName, $this->getAbbreviationSuggestions($abbrevs[$fullName])));
26055 return $this->getCommand($abbrevs[$fullName][0]);
26059 * Gets the commands (registered in the given namespace if provided).
26061 * The array keys are the full names and the values the command instances.
26063 * @param string $namespace A namespace name
26065 * @return array An array of Command instances
26067 public function getCommands($namespace = null)
26069 if (null === $namespace) {
26070 return $this->commands;
26073 $commands = array();
26074 foreach ($this->commands as $name => $command) {
26075 if ($namespace === $command->getNamespace()) {
26076 $commands[$name] = $command;
26084 * Returns an array of possible abbreviations given a set of names.
26086 * @param array $names An array of names
26088 * @return array An array of abbreviations
26090 static public function getAbbreviations($names)
26092 $abbrevs = array();
26093 foreach ($names as $name) {
26094 for ($len = strlen($name) - 1; $len > 0; --$len) {
26095 $abbrev = substr($name, 0, $len);
26096 if (!isset($abbrevs[$abbrev])) {
26097 $abbrevs[$abbrev] = array($name);
26099 $abbrevs[$abbrev][] = $name;
26104 // Non-abbreviations always get entered, even if they aren't unique
26105 foreach ($names as $name) {
26106 $abbrevs[$name] = array($name);
26113 * Returns a text representation of the Application.
26115 * @param string $namespace An optional namespace name
26117 * @return string A string representing the Application
26119 public function asText($namespace = null)
26121 $commands = $namespace ? $this->getCommands($this->findNamespace($namespace)) : $this->commands;
26123 $messages = array($this->getHelp(), '');
26125 $messages[] = sprintf("<comment>Available commands for the \"%s\" namespace:</comment>", $namespace);
26127 $messages[] = '<comment>Available commands:</comment>';
26131 foreach ($commands as $command) {
26132 $width = strlen($command->getName()) > $width ? strlen($command->getName()) : $width;
26136 // add commands by namespace
26137 foreach ($this->sortCommands($commands) as $space => $commands) {
26138 if (!$namespace && '_global' !== $space) {
26139 $messages[] = '<comment>'.$space.'</comment>';
26142 foreach ($commands as $command) {
26143 $aliases = $command->getAliases() ? '<comment> ('.implode(', ', $command->getAliases()).')</comment>' : '';
26145 $messages[] = sprintf(" <info>%-${width}s</info> %s%s", ($command->getNamespace() ? ':' : '').$command->getName(), $command->getDescription(), $aliases);
26149 return implode("\n", $messages);
26153 * Returns an XML representation of the Application.
26155 * @param string $namespace An optional namespace name
26156 * @param Boolean $asDom Whether to return a DOM or an XML string
26158 * @return string|DOMDocument An XML string representing the Application
26160 public function asXml($namespace = null, $asDom = false)
26162 $commands = $namespace ? $this->getCommands($this->findNamespace($namespace)) : $this->commands;
26164 $dom = new \DOMDocument('1.0', 'UTF-8');
26165 $dom->formatOutput = true;
26166 $dom->appendChild($xml = $dom->createElement('symfony'));
26168 $xml->appendChild($commandsXML = $dom->createElement('commands'));
26171 $commandsXML->setAttribute('namespace', $namespace);
26173 $xml->appendChild($namespacesXML = $dom->createElement('namespaces'));
26176 // add commands by namespace
26177 foreach ($this->sortCommands($commands) as $space => $commands) {
26179 $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
26180 $namespaceArrayXML->setAttribute('id', $space);
26183 foreach ($commands as $command) {
26185 $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
26186 $commandXML->appendChild($dom->createTextNode($command->getName()));
26189 $node = $command->asXml(true)->getElementsByTagName('command')->item(0);
26190 $node = $dom->importNode($node, true);
26192 $commandsXML->appendChild($node);
26196 return $asDom ? $dom : $dom->saveXml();
26200 * Renders a catched exception.
26202 * @param Exception $e An exception instance
26203 * @param OutputInterface $output An OutputInterface instance
26205 public function renderException($e, $output)
26207 $strlen = function ($string)
26209 return function_exists('mb_strlen') ? mb_strlen($string) : strlen($string);
26212 $title = sprintf(' [%s] ', get_class($e));
26213 $len = $strlen($title);
26215 foreach (explode("\n", $e->getMessage()) as $line) {
26216 $lines[] = sprintf(' %s ', $line);
26217 $len = max($strlen($line) + 4, $len);
26220 $messages = array(str_repeat(' ', $len), $title.str_repeat(' ', $len - $strlen($title)));
26222 foreach ($lines as $line) {
26223 $messages[] = $line.str_repeat(' ', $len - $strlen($line));
26226 $messages[] = str_repeat(' ', $len);
26228 $output->writeln("\n");
26229 foreach ($messages as $message) {
26230 $output->writeln('<error>'.$message.'</error>');
26232 $output->writeln("\n");
26234 if (null !== $this->runningCommand) {
26235 $output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())));
26236 $output->writeln("\n");
26239 if (Output::VERBOSITY_VERBOSE === $output->getVerbosity()) {
26240 $output->writeln('</comment>Exception trace:</comment>');
26242 // exception related properties
26243 $trace = $e->getTrace();
26244 array_unshift($trace, array(
26246 'file' => $e->getFile() != null ? $e->getFile() : 'n/a',
26247 'line' => $e->getLine() != null ? $e->getLine() : 'n/a',
26251 for ($i = 0, $count = count($trace); $i < $count; $i++) {
26252 $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
26253 $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
26254 $function = $trace[$i]['function'];
26255 $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';
26256 $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
26258 $output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line));
26261 $output->writeln("\n");
26265 protected function getCommandName(InputInterface $input)
26267 return $input->getFirstArgument('command');
26270 protected function sortCommands($commands)
26272 $namespacedCommands = array();
26273 foreach ($commands as $name => $command) {
26274 $key = $command->getNamespace() ? $command->getNamespace() : '_global';
26276 if (!isset($namespacedCommands[$key])) {
26277 $namespacedCommands[$key] = array();
26280 $namespacedCommands[$key][$name] = $command;
26282 ksort($namespacedCommands);
26284 foreach ($namespacedCommands as $name => &$commands) {
26288 return $namespacedCommands;
26291 protected function getAbbreviationSuggestions($abbrevs)
26293 return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
26298 namespace Symfony\Component\Console\Tester;
26300 use Symfony\Component\Console\Application;
26301 use Symfony\Component\Console\Input\ArrayInput;
26302 use Symfony\Component\Console\Output\StreamOutput;
26305 * This file is part of the Symfony framework.
26307 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
26309 * This source file is subject to the MIT license that is bundled
26310 * with this source code in the file LICENSE.
26314 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
26316 class ApplicationTester
26318 protected $application;
26319 protected $display;
26326 * @param Application $application A Application instance to test.
26328 public function __construct(Application $application)
26330 $this->application = $application;
26334 * Executes the application.
26336 * Available options:
26338 * * interactive: Sets the input interactive flag
26339 * * decorated: Sets the output decorated flag
26340 * * verbosity: Sets the output verbosity flag
26342 * @param array $input An array of arguments and options
26343 * @param array $options An array of options
26345 public function run(array $input, $options = array())
26347 $this->input = new ArrayInput($input);
26348 if (isset($options['interactive'])) {
26349 $this->input->setInteractive($options['interactive']);
26352 $this->output = new StreamOutput(fopen('php://memory', 'w', false));
26353 if (isset($options['decorated'])) {
26354 $this->output->setDecorated($options['decorated']);
26356 if (isset($options['verbosity'])) {
26357 $this->output->setVerbosity($options['verbosity']);
26360 $ret = $this->application->run($this->input, $this->output);
26362 rewind($this->output->getStream());
26364 return $this->display = stream_get_contents($this->output->getStream());
26368 * Gets the display returned by the last execution of the application.
26370 * @return string The display
26372 public function getDisplay()
26374 return $this->display;
26378 * Gets the input instance used by the last execution of the application.
26380 * @return InputInterface The current input instance
26382 public function getInput()
26384 return $this->input;
26388 * Gets the output instance used by the last execution of the application.
26390 * @return OutputInterface The current output instance
26392 public function getOutput()
26394 return $this->output;
26399 namespace Symfony\Component\Console\Tester;
26401 use Symfony\Component\Console\Command\Command;
26402 use Symfony\Component\Console\Input\ArrayInput;
26403 use Symfony\Component\Console\Output\StreamOutput;
26406 * This file is part of the Symfony framework.
26408 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
26410 * This source file is subject to the MIT license that is bundled
26411 * with this source code in the file LICENSE.
26415 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
26417 class CommandTester
26419 protected $command;
26420 protected $display;
26427 * @param Command $command A Command instance to test.
26429 public function __construct(Command $command)
26431 $this->command = $command;
26435 * Executes the command.
26437 * Available options:
26439 * * interactive: Sets the input interactive flag
26440 * * decorated: Sets the output decorated flag
26441 * * verbosity: Sets the output verbosity flag
26443 * @param array $input An array of arguments and options
26444 * @param array $options An array of options
26446 public function execute(array $input, array $options = array())
26448 $this->input = new ArrayInput($input);
26449 if (isset($options['interactive'])) {
26450 $this->input->setInteractive($options['interactive']);
26453 $this->output = new StreamOutput(fopen('php://memory', 'w', false));
26454 if (isset($options['decorated'])) {
26455 $this->output->setDecorated($options['decorated']);
26457 if (isset($options['verbosity'])) {
26458 $this->output->setVerbosity($options['verbosity']);
26461 $ret = $this->command->run($this->input, $this->output);
26463 rewind($this->output->getStream());
26465 return $this->display = stream_get_contents($this->output->getStream());
26469 * Gets the display returned by the last execution of the command.
26471 * @return string The display
26473 public function getDisplay()
26475 return $this->display;
26479 * Gets the input instance used by the last execution of the command.
26481 * @return InputInterface The current input instance
26483 public function getInput()
26485 return $this->input;
26489 * Gets the output instance used by the last execution of the command.
26491 * @return OutputInterface The current output instance
26493 public function getOutput()
26495 return $this->output;
26500 namespace Symfony\Component\Console\Input;
26503 * This file is part of the Symfony framework.
26505 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
26507 * This source file is subject to the MIT license that is bundled
26508 * with this source code in the file LICENSE.
26512 * Input is the base class for all concrete Input classes.
26514 * Three concrete classes are provided by default:
26516 * * `ArgvInput`: The input comes from the CLI arguments (argv)
26517 * * `StringInput`: The input is provided as a string
26518 * * `ArrayInput`: The input is provided as an array
26520 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
26522 abstract class Input implements InputInterface
26524 protected $definition;
26525 protected $options;
26526 protected $arguments;
26527 protected $interactive = true;
26532 * @param InputDefinition $definition A InputDefinition instance
26534 public function __construct(InputDefinition $definition = null)
26536 if (null === $definition) {
26537 $this->definition = new InputDefinition();
26539 $this->bind($definition);
26545 * Binds the current Input instance with the given arguments and options.
26547 * @param InputDefinition $definition A InputDefinition instance
26549 public function bind(InputDefinition $definition)
26551 $this->arguments = array();
26552 $this->options = array();
26553 $this->definition = $definition;
26559 * Processes command line arguments.
26561 abstract protected function parse();
26564 * @throws \RuntimeException When not enough arguments are given
26566 public function validate()
26568 if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) {
26569 throw new \RuntimeException('Not enough arguments.');
26573 public function isInteractive()
26575 return $this->interactive;
26578 public function setInteractive($interactive)
26580 $this->interactive = (Boolean) $interactive;
26584 * Returns the argument values.
26586 * @return array An array of argument values
26588 public function getArguments()
26590 return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
26594 * Returns the argument value for a given argument name.
26596 * @param string $name The argument name
26598 * @return mixed The argument value
26600 * @throws \InvalidArgumentException When argument given doesn't exist
26602 public function getArgument($name)
26604 if (!$this->definition->hasArgument($name)) {
26605 throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
26608 return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
26612 * Sets an argument value by name.
26614 * @param string $name The argument name
26615 * @param string $value The argument value
26617 * @throws \InvalidArgumentException When argument given doesn't exist
26619 public function setArgument($name, $value)
26621 if (!$this->definition->hasArgument($name)) {
26622 throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
26625 $this->arguments[$name] = $value;
26629 * Returns true if an InputArgument object exists by name or position.
26631 * @param string|integer $name The InputArgument name or position
26633 * @return Boolean true if the InputArgument object exists, false otherwise
26635 public function hasArgument($name)
26637 return $this->definition->hasArgument($name);
26641 * Returns the options values.
26643 * @return array An array of option values
26645 public function getOptions()
26647 return array_merge($this->definition->getOptionDefaults(), $this->options);
26651 * Returns the option value for a given option name.
26653 * @param string $name The option name
26655 * @return mixed The option value
26657 * @throws \InvalidArgumentException When option given doesn't exist
26659 public function getOption($name)
26661 if (!$this->definition->hasOption($name)) {
26662 throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
26665 return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
26669 * Sets an option value by name.
26671 * @param string $name The option name
26672 * @param string $value The option value
26674 * @throws \InvalidArgumentException When option given doesn't exist
26676 public function setOption($name, $value)
26678 if (!$this->definition->hasOption($name)) {
26679 throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
26682 $this->options[$name] = $value;
26686 * Returns true if an InputOption object exists by name.
26688 * @param string $name The InputOption name
26690 * @return Boolean true if the InputOption object exists, false otherwise
26692 public function hasOption($name)
26694 return $this->definition->hasOption($name);
26699 namespace Symfony\Component\Console\Input;
26702 * This file is part of the Symfony framework.
26704 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
26706 * This source file is subject to the MIT license that is bundled
26707 * with this source code in the file LICENSE.
26711 * ArrayInput represents an input provided as an array.
26715 * $input = new ArrayInput(array('name' => 'foo', '--bar' => 'foobar'));
26717 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
26719 class ArrayInput extends Input
26721 protected $parameters;
26726 * @param array $param An array of parameters
26727 * @param InputDefinition $definition A InputDefinition instance
26729 public function __construct(array $parameters, InputDefinition $definition = null)
26731 $this->parameters = $parameters;
26733 parent::__construct($definition);
26737 * Returns the first argument from the raw parameters (not parsed).
26739 * @return string The value of the first argument or null otherwise
26741 public function getFirstArgument()
26743 foreach ($this->parameters as $key => $value) {
26744 if ($key && '-' === $key[0]) {
26753 * Returns true if the raw parameters (not parsed) contains a value.
26755 * This method is to be used to introspect the input parameters
26756 * before it has been validated. It must be used carefully.
26758 * @param string|array $value The values to look for in the raw parameters (can be an array)
26760 * @return Boolean true if the value is contained in the raw parameters
26762 public function hasParameterOption($values)
26764 if (!is_array($values)) {
26765 $values = array($values);
26768 foreach ($this->parameters as $k => $v) {
26773 if (in_array($v, $values)) {
26782 * Processes command line arguments.
26784 protected function parse()
26786 foreach ($this->parameters as $key => $value) {
26787 if ('--' === substr($key, 0, 2)) {
26788 $this->addLongOption(substr($key, 2), $value);
26789 } elseif ('-' === $key[0]) {
26790 $this->addShortOption(substr($key, 1), $value);
26792 $this->addArgument($key, $value);
26798 * Adds a short option value.
26800 * @param string $shortcut The short option key
26801 * @param mixed $value The value for the option
26803 * @throws \RuntimeException When option given doesn't exist
26805 protected function addShortOption($shortcut, $value)
26807 if (!$this->definition->hasShortcut($shortcut)) {
26808 throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
26811 $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
26815 * Adds a long option value.
26817 * @param string $name The long option key
26818 * @param mixed $value The value for the option
26820 * @throws \InvalidArgumentException When option given doesn't exist
26821 * @throws \InvalidArgumentException When a required value is missing
26823 protected function addLongOption($name, $value)
26825 if (!$this->definition->hasOption($name)) {
26826 throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
26829 $option = $this->definition->getOption($name);
26831 if (null === $value) {
26832 if ($option->isParameterRequired()) {
26833 throw new \InvalidArgumentException(sprintf('The "--%s" option requires a value.', $name));
26836 $value = $option->isParameterOptional() ? $option->getDefault() : true;
26839 $this->options[$name] = $value;
26843 * Adds an argument value.
26845 * @param string $name The argument name
26846 * @param mixed $value The value for the argument
26848 * @throws \InvalidArgumentException When argument given doesn't exist
26850 protected function addArgument($name, $value)
26852 if (!$this->definition->hasArgument($name)) {
26853 throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
26856 $this->arguments[$name] = $value;
26861 namespace Symfony\Component\Console\Input;
26864 * This file is part of the Symfony framework.
26866 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
26868 * This source file is subject to the MIT license that is bundled
26869 * with this source code in the file LICENSE.
26873 * Represents a command line option.
26875 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
26879 const PARAMETER_NONE = 1;
26880 const PARAMETER_REQUIRED = 2;
26881 const PARAMETER_OPTIONAL = 4;
26882 const PARAMETER_IS_ARRAY = 8;
26885 protected $shortcut;
26887 protected $default;
26888 protected $description;
26893 * @param string $name The option name
26894 * @param string $shortcut The shortcut (can be null)
26895 * @param integer $mode The option mode: self::PARAMETER_REQUIRED, self::PARAMETER_NONE or self::PARAMETER_OPTIONAL
26896 * @param string $description A description text
26897 * @param mixed $default The default value (must be null for self::PARAMETER_REQUIRED or self::PARAMETER_NONE)
26899 * @throws \InvalidArgumentException If option mode is invalid or incompatible
26901 public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
26903 if ('--' === substr($name, 0, 2)) {
26904 $name = substr($name, 2);
26907 if (empty($shortcut)) {
26911 if (null !== $shortcut) {
26912 if ('-' === $shortcut[0]) {
26913 $shortcut = substr($shortcut, 1);
26917 if (null === $mode) {
26918 $mode = self::PARAMETER_NONE;
26919 } else if (!is_int($mode) || $mode > 15) {
26920 throw new \InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
26923 $this->name = $name;
26924 $this->shortcut = $shortcut;
26925 $this->mode = $mode;
26926 $this->description = $description;
26928 if ($this->isArray() && !$this->acceptParameter()) {
26929 throw new \InvalidArgumentException('Impossible to have an option mode PARAMETER_IS_ARRAY if the option does not accept a parameter.');
26932 $this->setDefault($default);
26936 * Returns the shortcut.
26938 * @return string The shortcut
26940 public function getShortcut()
26942 return $this->shortcut;
26946 * Returns the name.
26948 * @return string The name
26950 public function getName()
26952 return $this->name;
26956 * Returns true if the option accept a parameter.
26958 * @return Boolean true if parameter mode is not self::PARAMETER_NONE, false otherwise
26960 public function acceptParameter()
26962 return $this->isParameterRequired() || $this->isParameterOptional();
26966 * Returns true if the option requires a parameter.
26968 * @return Boolean true if parameter mode is self::PARAMETER_REQUIRED, false otherwise
26970 public function isParameterRequired()
26972 return self::PARAMETER_REQUIRED === (self::PARAMETER_REQUIRED & $this->mode);
26976 * Returns true if the option takes an optional parameter.
26978 * @return Boolean true if parameter mode is self::PARAMETER_OPTIONAL, false otherwise
26980 public function isParameterOptional()
26982 return self::PARAMETER_OPTIONAL === (self::PARAMETER_OPTIONAL & $this->mode);
26986 * Returns true if the option can take multiple values.
26988 * @return Boolean true if mode is self::PARAMETER_IS_ARRAY, false otherwise
26990 public function isArray()
26992 return self::PARAMETER_IS_ARRAY === (self::PARAMETER_IS_ARRAY & $this->mode);
26996 * Sets the default value.
26998 * @param mixed $default The default value
27000 public function setDefault($default = null)
27002 if (self::PARAMETER_NONE === (self::PARAMETER_NONE & $this->mode) && null !== $default) {
27003 throw new \LogicException('Cannot set a default value when using Option::PARAMETER_NONE mode.');
27006 if ($this->isArray()) {
27007 if (null === $default) {
27008 $default = array();
27009 } elseif (!is_array($default)) {
27010 throw new \LogicException('A default value for an array option must be an array.');
27014 $this->default = $this->acceptParameter() ? $default : false;
27018 * Returns the default value.
27020 * @return mixed The default value
27022 public function getDefault()
27024 return $this->default;
27028 * Returns the description text.
27030 * @return string The description text
27032 public function getDescription()
27034 return $this->description;
27039 namespace Symfony\Component\Console\Input;
27042 * This file is part of the Symfony framework.
27044 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
27046 * This source file is subject to the MIT license that is bundled
27047 * with this source code in the file LICENSE.
27051 * A InputDefinition represents a set of valid command line arguments and options.
27055 * $definition = new InputDefinition(array(
27056 * new InputArgument('name', InputArgument::REQUIRED),
27057 * new InputOption('foo', 'f', InputOption::PARAMETER_REQUIRED),
27060 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
27062 class InputDefinition
27064 protected $arguments;
27065 protected $requiredCount;
27066 protected $hasAnArrayArgument = false;
27067 protected $hasOptional;
27068 protected $options;
27069 protected $shortcuts;
27074 * @param array $definition An array of InputArgument and InputOption instance
27076 public function __construct(array $definition = array())
27078 $this->setDefinition($definition);
27081 public function setDefinition(array $definition)
27083 $arguments = array();
27084 $options = array();
27085 foreach ($definition as $item) {
27086 if ($item instanceof InputOption) {
27087 $options[] = $item;
27089 $arguments[] = $item;
27093 $this->setArguments($arguments);
27094 $this->setOptions($options);
27098 * Sets the InputArgument objects.
27100 * @param array $arguments An array of InputArgument objects
27102 public function setArguments($arguments = array())
27104 $this->arguments = array();
27105 $this->requiredCount = 0;
27106 $this->hasOptional = false;
27107 $this->hasAnArrayArgument = false;
27108 $this->addArguments($arguments);
27112 * Add an array of InputArgument objects.
27114 * @param InputArgument[] $arguments An array of InputArgument objects
27116 public function addArguments($arguments = array())
27118 if (null !== $arguments) {
27119 foreach ($arguments as $argument) {
27120 $this->addArgument($argument);
27126 * Add an InputArgument object.
27128 * @param InputArgument $argument An InputArgument object
27130 * @throws \LogicException When incorrect argument is given
27132 public function addArgument(InputArgument $argument)
27134 if (isset($this->arguments[$argument->getName()])) {
27135 throw new \LogicException(sprintf('An argument with name "%s" already exist.', $argument->getName()));
27138 if ($this->hasAnArrayArgument) {
27139 throw new \LogicException('Cannot add an argument after an array argument.');
27142 if ($argument->isRequired() && $this->hasOptional) {
27143 throw new \LogicException('Cannot add a required argument after an optional one.');
27146 if ($argument->isArray()) {
27147 $this->hasAnArrayArgument = true;
27150 if ($argument->isRequired()) {
27151 ++$this->requiredCount;
27153 $this->hasOptional = true;
27156 $this->arguments[$argument->getName()] = $argument;
27160 * Returns an InputArgument by name or by position.
27162 * @param string|integer $name The InputArgument name or position
27164 * @return InputArgument An InputArgument object
27166 * @throws \InvalidArgumentException When argument given doesn't exist
27168 public function getArgument($name)
27170 $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
27172 if (!$this->hasArgument($name)) {
27173 throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
27176 return $arguments[$name];
27180 * Returns true if an InputArgument object exists by name or position.
27182 * @param string|integer $name The InputArgument name or position
27184 * @return Boolean true if the InputArgument object exists, false otherwise
27186 public function hasArgument($name)
27188 $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
27190 return isset($arguments[$name]);
27194 * Gets the array of InputArgument objects.
27196 * @return array An array of InputArgument objects
27198 public function getArguments()
27200 return $this->arguments;
27204 * Returns the number of InputArguments.
27206 * @return integer The number of InputArguments
27208 public function getArgumentCount()
27210 return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);
27214 * Returns the number of required InputArguments.
27216 * @return integer The number of required InputArguments
27218 public function getArgumentRequiredCount()
27220 return $this->requiredCount;
27224 * Gets the default values.
27226 * @return array An array of default values
27228 public function getArgumentDefaults()
27231 foreach ($this->arguments as $argument) {
27232 $values[$argument->getName()] = $argument->getDefault();
27239 * Sets the InputOption objects.
27241 * @param array $options An array of InputOption objects
27243 public function setOptions($options = array())
27245 $this->options = array();
27246 $this->shortcuts = array();
27247 $this->addOptions($options);
27251 * Add an array of InputOption objects.
27253 * @param InputOption[] $options An array of InputOption objects
27255 public function addOptions($options = array())
27257 foreach ($options as $option) {
27258 $this->addOption($option);
27263 * Add an InputOption object.
27265 * @param InputOption $option An InputOption object
27267 * @throws \LogicException When option given already exist
27269 public function addOption(InputOption $option)
27271 if (isset($this->options[$option->getName()])) {
27272 throw new \LogicException(sprintf('An option named "%s" already exist.', $option->getName()));
27273 } else if (isset($this->shortcuts[$option->getShortcut()])) {
27274 throw new \LogicException(sprintf('An option with shortcut "%s" already exist.', $option->getShortcut()));
27277 $this->options[$option->getName()] = $option;
27278 if ($option->getShortcut()) {
27279 $this->shortcuts[$option->getShortcut()] = $option->getName();
27284 * Returns an InputOption by name.
27286 * @param string $name The InputOption name
27288 * @return InputOption A InputOption object
27290 public function getOption($name)
27292 if (!$this->hasOption($name)) {
27293 throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
27296 return $this->options[$name];
27300 * Returns true if an InputOption object exists by name.
27302 * @param string $name The InputOption name
27304 * @return Boolean true if the InputOption object exists, false otherwise
27306 public function hasOption($name)
27308 return isset($this->options[$name]);
27312 * Gets the array of InputOption objects.
27314 * @return array An array of InputOption objects
27316 public function getOptions()
27318 return $this->options;
27322 * Returns true if an InputOption object exists by shortcut.
27324 * @param string $name The InputOption shortcut
27326 * @return Boolean true if the InputOption object exists, false otherwise
27328 public function hasShortcut($name)
27330 return isset($this->shortcuts[$name]);
27334 * Gets an InputOption by shortcut.
27336 * @return InputOption An InputOption object
27338 public function getOptionForShortcut($shortcut)
27340 return $this->getOption($this->shortcutToName($shortcut));
27344 * Gets an array of default values.
27346 * @return array An array of all default values
27348 public function getOptionDefaults()
27351 foreach ($this->options as $option) {
27352 $values[$option->getName()] = $option->getDefault();
27359 * Returns the InputOption name given a shortcut.
27361 * @param string $shortcut The shortcut
27363 * @return string The InputOption name
27365 * @throws \InvalidArgumentException When option given does not exist
27367 protected function shortcutToName($shortcut)
27369 if (!isset($this->shortcuts[$shortcut])) {
27370 throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
27373 return $this->shortcuts[$shortcut];
27377 * Gets the synopsis.
27379 * @return string The synopsis
27381 public function getSynopsis()
27383 $elements = array();
27384 foreach ($this->getOptions() as $option) {
27385 $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
27386 $elements[] = sprintf('['.($option->isParameterRequired() ? '%s--%s="..."' : ($option->isParameterOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName());
27389 foreach ($this->getArguments() as $argument) {
27390 $elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : ''));
27392 if ($argument->isArray()) {
27393 $elements[] = sprintf('... [%sN]', $argument->getName());
27397 return implode(' ', $elements);
27401 * Returns a textual representation of the InputDefinition.
27403 * @return string A string representing the InputDefinition
27405 public function asText()
27407 // find the largest option or argument name
27409 foreach ($this->getOptions() as $option) {
27410 $max = strlen($option->getName()) + 2 > $max ? strlen($option->getName()) + 2 : $max;
27412 foreach ($this->getArguments() as $argument) {
27413 $max = strlen($argument->getName()) > $max ? strlen($argument->getName()) : $max;
27419 if ($this->getArguments()) {
27420 $text[] = '<comment>Arguments:</comment>';
27421 foreach ($this->getArguments() as $argument) {
27422 if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) {
27423 $default = sprintf('<comment> (default: %s)</comment>', is_array($argument->getDefault()) ? str_replace("\n", '', var_export($argument->getDefault(), true)): $argument->getDefault());
27428 $text[] = sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $argument->getDescription(), $default);
27434 if ($this->getOptions()) {
27435 $text[] = '<comment>Options:</comment>';
27437 foreach ($this->getOptions() as $option) {
27438 if ($option->acceptParameter() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) {
27439 $default = sprintf('<comment> (default: %s)</comment>', is_array($option->getDefault()) ? str_replace("\n", '', print_r($option->getDefault(), true)): $option->getDefault());
27444 $multiple = $option->isArray() ? '<comment> (multiple values allowed)</comment>' : '';
27445 $text[] = sprintf(' %-'.$max.'s %s%s%s%s', '<info>--'.$option->getName().'</info>', $option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '', $option->getDescription(), $default, $multiple);
27451 return implode("\n", $text);
27455 * Returns an XML representation of the InputDefinition.
27457 * @param Boolean $asDom Whether to return a DOM or an XML string
27459 * @return string|DOMDocument An XML string representing the InputDefinition
27461 public function asXml($asDom = false)
27463 $dom = new \DOMDocument('1.0', 'UTF-8');
27464 $dom->formatOutput = true;
27465 $dom->appendChild($definitionXML = $dom->createElement('definition'));
27467 $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
27468 foreach ($this->getArguments() as $argument) {
27469 $argumentsXML->appendChild($argumentXML = $dom->createElement('argument'));
27470 $argumentXML->setAttribute('name', $argument->getName());
27471 $argumentXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
27472 $argumentXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
27473 $argumentXML->appendChild($descriptionXML = $dom->createElement('description'));
27474 $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
27476 $argumentXML->appendChild($defaultsXML = $dom->createElement('defaults'));
27477 $defaults = is_array($argument->getDefault()) ? $argument->getDefault() : ($argument->getDefault() ? array($argument->getDefault()) : array());
27478 foreach ($defaults as $default) {
27479 $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
27480 $defaultXML->appendChild($dom->createTextNode($default));
27484 $definitionXML->appendChild($optionsXML = $dom->createElement('options'));
27485 foreach ($this->getOptions() as $option) {
27486 $optionsXML->appendChild($optionXML = $dom->createElement('option'));
27487 $optionXML->setAttribute('name', '--'.$option->getName());
27488 $optionXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
27489 $optionXML->setAttribute('accept_parameter', $option->acceptParameter() ? 1 : 0);
27490 $optionXML->setAttribute('is_parameter_required', $option->isParameterRequired() ? 1 : 0);
27491 $optionXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
27492 $optionXML->appendChild($descriptionXML = $dom->createElement('description'));
27493 $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
27495 if ($option->acceptParameter()) {
27496 $optionXML->appendChild($defaultsXML = $dom->createElement('defaults'));
27497 $defaults = is_array($option->getDefault()) ? $option->getDefault() : ($option->getDefault() ? array($option->getDefault()) : array());
27498 foreach ($defaults as $default) {
27499 $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
27500 $defaultXML->appendChild($dom->createTextNode($default));
27505 return $asDom ? $dom : $dom->saveXml();
27510 namespace Symfony\Component\Console\Input;
27513 * This file is part of the Symfony framework.
27515 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
27517 * This source file is subject to the MIT license that is bundled
27518 * with this source code in the file LICENSE.
27522 * InputInterface is the interface implemented by all input classes.
27524 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
27526 interface InputInterface
27529 * Returns the first argument from the raw parameters (not parsed).
27531 * @return string The value of the first argument or null otherwise
27533 function getFirstArgument();
27536 * Returns true if the raw parameters (not parsed) contains a value.
27538 * This method is to be used to introspect the input parameters
27539 * before it has been validated. It must be used carefully.
27541 * @param string $value The value to look for in the raw parameters
27543 * @return Boolean true if the value is contained in the raw parameters
27545 function hasParameterOption($value);
27548 * Binds the current Input instance with the given arguments and options.
27550 * @param InputDefinition $definition A InputDefinition instance
27552 function bind(InputDefinition $definition);
27554 function validate();
27556 function getArguments();
27558 function getArgument($name);
27560 function getOptions();
27562 function getOption($name);
27566 namespace Symfony\Component\Console\Input;
27569 * This file is part of the Symfony framework.
27571 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
27573 * This source file is subject to the MIT license that is bundled
27574 * with this source code in the file LICENSE.
27578 * ArgvInput represents an input coming from the CLI arguments.
27582 * $input = new ArgvInput();
27584 * By default, the `$_SERVER['argv']` array is used for the input values.
27586 * This can be overridden by explicitly passing the input values in the constructor:
27588 * $input = new ArgvInput($_SERVER['argv']);
27590 * If you pass it yourself, don't forget that the first element of the array
27591 * is the name of the running program.
27593 * When passing an argument to the constructor, be sure that it respects
27594 * the same rules as the argv one. It's almost always better to use the
27595 * `StringInput` when you want to provide your own input.
27597 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
27599 * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
27600 * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
27602 class ArgvInput extends Input
27610 * @param array $argv An array of parameters from the CLI (in the argv format)
27611 * @param InputDefinition $definition A InputDefinition instance
27613 public function __construct(array $argv = null, InputDefinition $definition = null)
27615 if (null === $argv) {
27616 $argv = $_SERVER['argv'];
27619 // strip the program name
27620 array_shift($argv);
27622 $this->tokens = $argv;
27624 parent::__construct($definition);
27628 * Processes command line arguments.
27630 protected function parse()
27632 $this->parsed = $this->tokens;
27633 while (null !== $token = array_shift($this->parsed)) {
27634 if ('--' === substr($token, 0, 2)) {
27635 $this->parseLongOption($token);
27636 } elseif ('-' === $token[0]) {
27637 $this->parseShortOption($token);
27639 $this->parseArgument($token);
27645 * Parses a short option.
27647 * @param string $token The current token.
27649 protected function parseShortOption($token)
27651 $name = substr($token, 1);
27653 if (strlen($name) > 1) {
27654 if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptParameter()) {
27655 // an option with a value (with no space)
27656 $this->addShortOption($name[0], substr($name, 1));
27658 $this->parseShortOptionSet($name);
27661 $this->addShortOption($name, null);
27666 * Parses a short option set.
27668 * @param string $token The current token
27670 * @throws \RuntimeException When option given doesn't exist
27672 protected function parseShortOptionSet($name)
27674 $len = strlen($name);
27675 for ($i = 0; $i < $len; $i++) {
27676 if (!$this->definition->hasShortcut($name[$i])) {
27677 throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
27680 $option = $this->definition->getOptionForShortcut($name[$i]);
27681 if ($option->acceptParameter()) {
27682 $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
27686 $this->addLongOption($option->getName(), true);
27692 * Parses a long option.
27694 * @param string $token The current token
27696 protected function parseLongOption($token)
27698 $name = substr($token, 2);
27700 if (false !== $pos = strpos($name, '=')) {
27701 $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
27703 $this->addLongOption($name, null);
27708 * Parses an argument.
27710 * @param string $token The current token
27712 * @throws \RuntimeException When too many arguments are given
27714 protected function parseArgument($token)
27716 if (!$this->definition->hasArgument(count($this->arguments))) {
27717 throw new \RuntimeException('Too many arguments.');
27720 $this->arguments[$this->definition->getArgument(count($this->arguments))->getName()] = $token;
27724 * Adds a short option value.
27726 * @param string $shortcut The short option key
27727 * @param mixed $value The value for the option
27729 * @throws \RuntimeException When option given doesn't exist
27731 protected function addShortOption($shortcut, $value)
27733 if (!$this->definition->hasShortcut($shortcut)) {
27734 throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
27737 $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
27741 * Adds a long option value.
27743 * @param string $name The long option key
27744 * @param mixed $value The value for the option
27746 * @throws \RuntimeException When option given doesn't exist
27748 protected function addLongOption($name, $value)
27750 if (!$this->definition->hasOption($name)) {
27751 throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
27754 $option = $this->definition->getOption($name);
27756 if (null === $value && $option->acceptParameter()) {
27757 // if option accepts an optional or mandatory argument
27758 // let's see if there is one provided
27759 $next = array_shift($this->parsed);
27760 if ('-' !== $next[0]) {
27763 array_unshift($this->parsed, $next);
27767 if (null === $value) {
27768 if ($option->isParameterRequired()) {
27769 throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
27772 $value = $option->isParameterOptional() ? $option->getDefault() : true;
27775 $this->options[$name] = $value;
27779 * Returns the first argument from the raw parameters (not parsed).
27781 * @return string The value of the first argument or null otherwise
27783 public function getFirstArgument()
27785 foreach ($this->tokens as $token) {
27786 if ($token && '-' === $token[0]) {
27795 * Returns true if the raw parameters (not parsed) contains a value.
27797 * This method is to be used to introspect the input parameters
27798 * before it has been validated. It must be used carefully.
27800 * @param string|array $values The value(s) to look for in the raw parameters (can be an array)
27802 * @return Boolean true if the value is contained in the raw parameters
27804 public function hasParameterOption($values)
27806 if (!is_array($values)) {
27807 $values = array($values);
27810 foreach ($this->tokens as $v) {
27811 if (in_array($v, $values)) {
27821 namespace Symfony\Component\Console\Input;
27824 * This file is part of the Symfony framework.
27826 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
27828 * This source file is subject to the MIT license that is bundled
27829 * with this source code in the file LICENSE.
27833 * StringInput represents an input provided as a string.
27837 * $input = new StringInput('foo --bar="foobar"');
27839 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
27841 class StringInput extends ArgvInput
27843 const REGEX_STRING = '([^ ]+?)(?: |(?<!\\\\)"|(?<!\\\\)\'|$)';
27844 const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
27849 * @param string $input An array of parameters from the CLI (in the argv format)
27850 * @param InputDefinition $definition A InputDefinition instance
27852 public function __construct($input, InputDefinition $definition = null)
27854 parent::__construct(array(), $definition);
27856 $this->tokens = $this->tokenize($input);
27860 * @throws \InvalidArgumentException When unable to parse input (should never happen)
27862 protected function tokenize($input)
27864 $input = preg_replace('/(\r\n|\r|\n|\t)/', ' ', $input);
27867 $length = strlen($input);
27869 while ($cursor < $length) {
27870 if (preg_match('/\s+/A', $input, $match, null, $cursor)) {
27871 } elseif (preg_match('/([^="\' ]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) {
27872 $tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2)));
27873 } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) {
27874 $tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
27875 } elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) {
27876 $tokens[] = stripcslashes($match[1]);
27878 // should never happen
27879 // @codeCoverageIgnoreStart
27880 throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
27881 // @codeCoverageIgnoreEnd
27884 $cursor += strlen($match[0]);
27892 namespace Symfony\Component\Console\Input;
27895 * This file is part of the Symfony framework.
27897 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
27899 * This source file is subject to the MIT license that is bundled
27900 * with this source code in the file LICENSE.
27904 * Represents a command line argument.
27906 * @author Fabien Potencier <fabien.potencier@symfony-project.com>
27908 class InputArgument
27910 const REQUIRED = 1;
27911 const OPTIONAL = 2;
27912 const IS_ARRAY = 4;
27916 protected $default;
27917 protected $description;
27922 * @param string $name The argument name
27923 * @param integer $mode The argument mode: self::REQUIRED or self::OPTIONAL
27924 * @param string $description A description text
27925 * @param mixed $default The default value (for self::OPTIONAL mode only)
27927 * @throws \InvalidArgumentException When argument mode is not valid
27929 public function __construct($name, $mode = null, $description = '', $default = null)
27931 if (null === $mode) {
27932 $mode = self::OPTIONAL;
27933 } else if (is_string($mode) || $mode > 7) {
27934 throw new \InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
27937 $this->name = $name;
27938 $this->mode = $mode;
27939 $this->description = $description;
27941 $this->setDefault($default);
27945 * Returns the argument name.
27947 * @return string The argument name
27949 public function getName()
27951 return $this->name;
27955 * Returns true if the argument is required.
27957 * @return Boolean true if parameter mode is self::REQUIRED, false otherwise
27959 public function isRequired()
27961 return self::REQUIRED === (self::REQUIRED & $this->mode);
27965 * Returns true if the argument can take multiple values.
27967 * @return Boolean true if mode is self::IS_ARRAY, false otherwise
27969 public function isArray()
27971 return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
27975 * Sets the default value.
27977 * @param mixed $default The default value
27979 * @throws \LogicException When incorrect default value is given
27981 public function setDefault($default = null)
27983 if (self::REQUIRED === $this->mode && null !== $default) {
27984 throw new \LogicException('Cannot set a default value except for Parameter::OPTIONAL mode.');
27987 if ($this->isArray()) {
27988 if (null === $default) {
27989 $default = array();
27990 } else if (!is_array($default)) {
27991 throw new \LogicException('A default value for an array argument must be an array.');
27995 $this->default = $default;
27999 * Returns the default value.
28001 * @return mixed The default value
28003 public function getDefault()
28005 return $this->default;
28009 * Returns the description text.
28011 * @return string The description text
28013 public function getDescription()
28015 return $this->description;
28018 Ûes
\85yepâC
\f÷p͸Õ
\ e<
\1e)¸
\ 2\0\0\0GBMB