error sms sending on live testing
[namibia] / doctrine-migrations.phar
1 <?php
2 /*
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.
14  *
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>.
18  */
19
20
21 Phar::mapPhar();
22
23 require_once 'phar://'.__FILE__.'/Doctrine/Common/ClassLoader.php';
24
25 $classLoader = new \Doctrine\Common\ClassLoader('Doctrine\Common', 'phar://'.__FILE__);
26 $classLoader->register();
27
28 $classLoader = new \Doctrine\Common\ClassLoader('Doctrine\DBAL', 'phar://'.__FILE__);
29 $classLoader->register();
30
31 $classLoader = new \Doctrine\Common\ClassLoader('Symfony', 'phar://'.__FILE__);
32 $classLoader->register();
33
34 $helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
35     'dialog' => new \Symfony\Component\Console\Helper\DialogHelper(),
36 ));
37
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()
49 ));
50
51 $input = file_exists('migrations-input.php')
52        ? include('migrations-input.php')
53        : null;
54
55 $output = file_exists('migrations-output.php')
56         ? include('migrations-output.php')
57         : null;
58
59 $cli->run($input, $output);
60
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\15\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
63 \0\0\99ÈÏL\f
64 \0\0\8c^Ñ<¶\ 1\0\0\0\0\0\0)\0\0\0Doctrine/DBAL/Driver/PDOOracle/Driver.php¤
65 \0\0\99ÈÏL¤
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\9c\ 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\1e\ 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\0\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äÍ\1c\ 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=
68 \0\0\99ÈÏL=
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¥        \93\ 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\r\ 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\0\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#
70 \0\0\99ÈÏL#
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(|\1c\ 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\0\9a\ 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
73 \0\0\99ÈÏL\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\0\8d\ 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;
75 \0\0\99ÈÏL;
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
77 \ 2\0\0\99ÈÏL
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
79 \0\0\99ÈÏLb
80 \0\0ôé*\19\ 1\0\0\0\0\0\02\0\0\0Symfony/Component/Console/Tester/CommandTester.php8
81 \0\0\99ÈÏL8
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
83 /*
84  *  $Id$
85  *
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.
97  *
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>.
101 */
102
103 namespace Doctrine\DBAL\Migrations;
104
105 /**
106  * Exception to be thrown in the down() methods of migrations that signifies it 
107  * is an irreversible migration and stops execution.
108  *
109  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
110  * @link        www.doctrine-project.org
111  * @since       2.0
112  * @version     $Revision$
113  * @author      Jonathan H. Wage <jonwage@gmail.com>
114  */
115 class IrreversibleMigrationException extends \Exception
116 {
117 }<?php
118
119 namespace Doctrine\DBAL\Migrations;
120
121 class AbortMigrationException extends MigrationException
122 {
123     
124 }<?php
125
126 namespace Doctrine\DBAL\Migrations;
127
128 class SkipMigrationException extends MigrationException
129 {
130     
131 }<?php
132 /*
133  *  $Id$
134  *
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.
146  *
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>.
150 */
151
152 namespace Doctrine\DBAL\Migrations;
153
154 use Doctrine\DBAL\Schema\Schema,
155     Doctrine\DBAL\Migrations\Configuration\Configuration,
156     Doctrine\DBAL\Migrations\Version;
157
158 /**
159  * Abstract class for individual migrations to extend from.
160  *
161  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
162  * @link        www.doctrine-project.org
163  * @since       2.0
164  * @version     $Revision$
165  * @author      Jonathan H. Wage <jonwage@gmail.com>
166  */
167 abstract class AbstractMigration
168 {
169     /** The Migrations Configuration instance for this migration */
170     protected $_configuration;
171
172     /** The OutputWriter object instance used for outputting information */
173     protected $_outputWriter;
174
175     /** The Doctrine\DBAL\Connection instance we are migrating */
176     protected $_connection;
177
178     /** Reference to the SchemaManager instance referened by $_connection */
179     protected $_sm;
180
181     /** Reference to the DatabasePlatform instance referenced by $_conection */
182     protected $_platform;
183
184     /** Reference to the Version instance representing this migration */
185     protected $_version;
186
187     public function __construct(Version $version)
188     {
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;
195     }
196
197     abstract public function up(Schema $schema);
198     abstract public function down(Schema $schema);
199
200     protected function _addSql($sql)
201     {
202         return $this->_version->addSql($sql);
203     }
204
205     protected function _write($message)
206     {
207         $this->_outputWriter->write($message);
208     }
209
210     protected function _throwIrreversibleMigrationException($message = null)
211     {
212         if ($message === null) {
213             $message = 'This migration is irreversible and cannot be reverted.';
214         }
215         throw new IrreversibleMigrationException($message);
216     }
217
218     /**
219      * Print a warning message if the condition evalutes to TRUE.
220      *
221      * @param bool $condition
222      * @param string $message
223      */
224     public function warnIf($condition, $message = '')
225     {
226         $message = (strlen($message)) ? $message : 'Unknown Reason';
227
228         if ($condition === true) {
229             $this->_outputWriter->write('    <warning>Warning during ' . $this->_version->getExecutionState() . ': ' . $message . '</warning>');
230         }
231     }
232
233     /**
234      * Abort the migration if the condition evalutes to TRUE.
235      *
236      * @param bool $condition
237      * @param string $message
238      */
239     public function abortIf($condition, $message = '')
240     {
241         $message = (strlen($message)) ? $message : 'Unknown Reason';
242
243         if ($condition === true) {
244             throw new AbortMigrationException($message);
245         }
246     }
247
248     /**
249      * Skip this migration (but not the next ones) if condition evalutes to TRUE.
250      *
251      * @param bool $condition
252      * @param string $message
253      */
254     public function skipIf($condition, $message = '')
255     {
256         $message = (strlen($message)) ? $message : 'Unknown Reason';
257
258         if ($condition === true) {
259             throw new SkipMigrationException($message);
260         }
261     }
262
263     public function preUp(Schema $schema)
264     {
265     }
266
267     public function postUp(Schema $schema)
268     {
269     }
270
271     public function preDown(Schema $schema)
272     {
273     }
274
275     public function postDown(Schema $schema)
276     {
277     }
278 }<?php
279 /*
280  *  $Id$
281  *
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.
293  *
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>.
297 */
298
299 namespace Doctrine\DBAL\Migrations;
300
301 /**
302  * Class for Migrations specific exceptions
303  *
304  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
305  * @link        www.doctrine-project.org
306  * @since       2.0
307  * @version     $Revision$
308  * @author      Jonathan H. Wage <jonwage@gmail.com>
309  */
310 class MigrationException extends \Exception
311 {
312     public static function migrationsNamespaceRequired()
313     {
314         return new self('Migrations namespace must be configured in order to use Doctrine migrations.', 2);
315     }
316
317     public static function migrationsDirectoryRequired()
318     {
319         return new self('Migrations directory must be configured in order to use Doctrine migrations.', 3);
320     }
321
322     public static function noMigrationsToExecute()
323     {
324         return new self('Could not find any migrations to execute.', 4);
325     }
326
327     public static function unknownMigrationVersion($version)
328     {
329         return new self(sprintf('Could not find migration version %s', $version), 5);
330     }
331
332     public static function alreadyAtVersion($version)
333     {
334         return new self(sprintf('Database is already at version %s', $version), 6);
335     }
336
337     public static function duplicateMigrationVersion($version, $class)
338     {
339         return new self(sprintf('Migration version %s already registered with class %s', $version, $class), 7);
340     }
341
342     public static function configurationFileAlreadyLoaded()
343     {
344         return new self(sprintf('Migrations configuration file already loaded'), 8);
345     }
346 }
347 <?php
348 /*
349  *  $Id$
350  *
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.
362  *
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>.
366 */
367
368 namespace Doctrine\DBAL\Migrations;
369
370 use Doctrine\DBAL\Migrations\Configuration\Configuration,
371     Doctrine\DBAL\Schema\Schema;
372
373 /**
374  * Class for running migrations to the current version or a manually specified version.
375  *
376  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
377  * @link        www.doctrine-project.org
378  * @since       2.0
379  * @version     $Revision$
380  * @author      Jonathan H. Wage <jonwage@gmail.com>
381  */
382 class Migration
383 {
384     /** The Doctrine\DBAL\Connection instance we are migrating */
385     private $_connection;
386
387     /** The OutputWriter object instance used for outputting information */
388     private $_outputWriter;
389
390     /**
391      * Construct a Migration instance
392      *
393      * @param Configuration $configuration  A migration Configuration instance
394      */
395     public function __construct(Configuration $configuration)
396     {
397         $this->_configuration = $configuration;
398         $this->_outputWriter = $configuration->getOutputWriter();
399     }
400
401     /**
402      * Get the array of versions and SQL queries that would be executed for 
403      * each version but do not execute anything.
404      *
405      * @param string $to   The version to migrate to.
406      * @return array $sql  The array of SQL queries.
407      */
408     public function getSql($to = null)
409     {
410         return $this->migrate($to, true);
411     }
412
413     /**
414      * Write a migration SQL file to the given path
415      *
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
419      */
420     public function writeSqlFile($path, $to = null)
421     {
422         $sql = $this->getSql($to);
423
424         $from = $this->_configuration->getCurrentVersion();
425         if ($to === null) {
426             $to = $this->_configuration->getLatestVersion();
427         }
428
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);
431
432         foreach ($sql as $version => $queries) {
433             $string .= "\n# Version " . $version . "\n";
434             foreach ($queries as $query) {
435                 $string .= $query . ";\n";
436             }
437         }
438         if (is_dir($path)) {
439             $path = realpath($path);
440             $path = $path . '/doctrine_migration_' . date('YmdHis') . '.sql';
441         }
442
443         $this->_outputWriter->write("\n".sprintf('Writing migration file to "<info>%s</info>"', $path));
444
445         return file_put_contents($path, $string);
446     }
447
448     /**
449      * Run a migration to the current version or the given target version.
450      *
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
455      */
456     public function migrate($to = null, $dryRun = false)
457     {
458         if ($to === null) {
459             $to = $this->_configuration->getLatestVersion();
460         }
461
462         $from = $this->_configuration->getCurrentVersion();
463         $from = (string) $from;
464         $to = (string) $to;
465
466         $migrations = $this->_configuration->getMigrations();
467         if ( ! isset($migrations[$to]) && $to > 0) {
468             throw MigrationException::unknownMigrationVersion($to);
469         }
470
471         if ($from === $to) {
472             throw MigrationException::alreadyAtVersion($to);
473         }
474
475         $direction = $from > $to ? 'down' : 'up';
476         $migrations = $this->_configuration->getMigrationsToExecute($direction, $to);
477
478         if ($dryRun === false) {
479             $this->_outputWriter->write(sprintf('Migrating <info>%s</info> to <comment>%s</comment> from <comment>%s</comment>', $direction, $to, $from));
480         } else {
481             $this->_outputWriter->write(sprintf('Executing dry run of migration <info>%s</info> to <comment>%s</comment> from <comment>%s</comment>', $direction, $to, $from));            
482         }
483
484         if (empty($migrations)) {
485             throw MigrationException::noMigrationsToExecute();
486         }
487
488         $sql = array();
489         $time = 0;
490         foreach ($migrations as $version) {
491             $versionSql = $version->execute($direction, $dryRun);
492             $sql[$version->getVersion()] = $versionSql;
493             $time += $version->getTime();
494         }
495
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)));
500
501         return $sql;
502     }
503 }
504 <?php
505 /*
506  *  $Id$
507  *
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.
519  *
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>.
523 */
524
525 namespace Doctrine\DBAL\Migrations\Configuration;
526
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;
534
535 /**
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.
539  *
540  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
541  * @link        www.doctrine-project.org
542  * @since       2.0
543  * @version     $Revision$
544  * @author      Jonathan H. Wage <jonwage@gmail.com>
545  */
546 class Configuration
547 {
548     /** Name of this set of migrations */
549     private $_name;
550
551     /** Flag for whether or not the migration table has been created */
552     private $_migrationTableCreated = false;
553
554     /** Connection instance to use for migrations */
555     private $_connection;
556
557     /** OutputWriter instance for writing output during migrations */
558     private $_outputWriter;
559
560     /** The migration table name to track versions in */
561     private $_migrationsTableName = 'doctrine_migration_versions';
562
563     /** The path to a directory where new migration classes will be written */
564     private $_migrationsDirectory;
565
566     /** Namespace the migration classes live in */
567     private $_migrationsNamespace;
568
569     /** Array of the registered migrations */
570     private $_migrations = array();
571
572     /**
573      * Construct a migration configuration object.
574      *
575      * @param Connection $connection      A Connection instance
576      * @param OutputWriter $outputWriter  A OutputWriter instance
577      */
578     public function __construct(Connection $connection, OutputWriter $outputWriter = null)
579     {
580         $this->_connection = $connection;
581         if ($outputWriter === null) {
582             $outputWriter = new OutputWriter();
583         }
584         $this->_outputWriter = $outputWriter;
585     }
586
587     /**
588      * Validation that this instance has all the required properties configured
589      *
590      * @return void
591      * @throws MigrationException
592      */
593     public function validate()
594     {
595         if ( ! $this->_migrationsNamespace) {
596             throw MigrationException::migrationsNamespaceRequired();
597         }
598         if ( ! $this->_migrationsDirectory) {
599             throw MigrationException::migrationsDirectoryRequired();
600         }
601     }
602
603     /**
604      * Set the name of this set of migrations
605      *
606      * @param string $name The name of this set of migrations
607      */
608     public function setName($name)
609     {
610         $this->_name = $name;
611     }
612
613     /**
614      * Returns the name of this set of migrations
615      *
616      * @return string $name The name of this set of migrations
617      */
618     public function getName()
619     {
620         return $this->_name;
621     }
622
623     /**
624      * Returns the OutputWriter instance
625      *
626      * @return OutputWriter $outputWriter  The OutputWriter instance
627      */
628     public function getOutputWriter()
629     {
630         return $this->_outputWriter;
631     }
632
633     /**
634      * Returns a timestamp version as a formatted date
635      *
636      * @param string $version 
637      * @return string $formattedVersion The formatted version
638      */
639     public function formatVersion($version)
640     {
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)
648         );
649     }
650
651     /**
652      * Returns the Connection instance
653      *
654      * @return Connection $connection  The Connection instance
655      */
656     public function getConnection()
657     {
658         return $this->_connection;
659     }
660
661     /**
662      * Set the migration table name
663      *
664      * @param string $tableName The migration table name
665      */
666     public function setMigrationsTableName($tableName)
667     {
668         $this->_migrationsTableName = $tableName;
669     }
670
671     /**
672      * Returns the migration table name
673      *
674      * @return string $migrationsTableName The migration table name
675      */
676     public function getMigrationsTableName()
677     {
678         return $this->_migrationsTableName;
679     }
680
681     /**
682      * Set the new migrations directory where new migration classes are generated
683      *
684      * @param string $migrationsDirectory The new migrations directory 
685      */
686     public function setMigrationsDirectory($migrationsDirectory)
687     {
688         $this->_migrationsDirectory = $migrationsDirectory;
689     }
690
691     /**
692      * Returns the new migrations directory where new migration classes are generated
693      *
694      * @return string $migrationsDirectory The new migrations directory
695      */
696     public function getMigrationsDirectory()
697     {
698         return $this->_migrationsDirectory;
699     }
700
701     /**
702      * Set the migrations namespace
703      *
704      * @param string $migrationsNamespace The migrations namespace
705      */
706     public function setMigrationsNamespace($migrationsNamespace)
707     {
708         $this->_migrationsNamespace = $migrationsNamespace;
709     }
710
711     /**
712      * Returns the migrations namespace
713      *
714      * @return string $migrationsNamespace The migrations namespace
715      */
716     public function getMigrationsNamespace()
717     {
718         return $this->_migrationsNamespace;
719     }
720
721     /**
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.
725      *
726      * @param string $path  The root directory to where some migration classes live.
727      * @return $migrations  The array of migrations registered.
728      */
729     public function registerMigrationsFromDirectory($path)
730     {
731         $path = realpath($path);
732         $path = rtrim($path, '/');
733         $files = glob($path . '/Version*.php');
734         $versions = array();
735         foreach ($files as $file) {
736             require_once($file);
737             $info = pathinfo($file);
738             $version = substr($info['filename'], 7);
739             $class = $this->_migrationsNamespace . '\\' . $info['filename'];
740             $versions[] = $this->registerMigration($version, $class);
741         }
742         return $versions;
743     }
744
745     /**
746      * Register a single migration version to be executed by a AbstractMigration
747      * class.
748      *
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.
751      */
752     public function registerMigration($version, $class)
753     {
754         $version = (string) $version;
755         $class = (string) $class;
756         if (isset($this->_migrations[$version])) {
757             throw MigrationException::duplicateMigrationVersion($version, get_class($this->_migrations[$version]));
758         }
759         $version = new Version($this, $version, $class);
760         $this->_migrations[$version->getVersion()] = $version;
761         ksort($this->_migrations);
762         return $version;
763     }
764
765     /**
766      * Register an array of migrations. Each key of the array is the version and
767      * the value is the migration class name.
768      *
769      *
770      * @param array $migrations
771      * @return void
772      */
773     public function registerMigrations(array $migrations)
774     {
775         $versions = array();
776         foreach ($migrations as $version => $class) {
777             $versions[] = $this->registerMigration($version, $class);
778         }
779         return $versions;
780     }
781
782     /**
783      * Get the array of registered migration versions.
784      *
785      * @return array $migrations
786      */
787     public function getMigrations()
788     {
789         return $this->_migrations;
790     }
791
792     /**
793      * Returns the Version instance for a given version in the format YYYYMMDDHHMMSS.
794      *
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.
798      */
799     public function getVersion($version)
800     {
801         if ( ! isset($this->_migrations[$version])) {
802             MigrationException::unknownMigrationVersion($version);
803         }
804         return $this->_migrations[$version];
805     }
806
807     /**
808      * Check if a version exists.
809      *
810      * @param string $version
811      * @return bool $exists
812      */
813     public function hasVersion($version)
814     {
815         return isset($this->_migrations[$version]) ? true : false;
816     }
817
818     /**
819      * Check if a version has been migrated or not yet
820      *
821      * @param Version $version
822      * @return bool $migrated
823      */
824     public function hasVersionMigrated(Version $version)
825     {
826         $this->createMigrationTable();
827
828         $version = $this->_connection->fetchColumn("SELECT version FROM " . $this->_migrationsTableName . " WHERE version = '" . $version->getVersion() . "'");
829         return $version !== false ? true : false;
830     }
831
832     /**
833      * Returns the current migrated version from the versions table.
834      *
835      * @return bool $currentVersion
836      */
837     public function getCurrentVersion()
838     {
839         $this->createMigrationTable();
840
841         $result = $this->_connection->fetchColumn("SELECT version FROM " . $this->_migrationsTableName . " ORDER BY version DESC LIMIT 1");
842         return $result !== false ? (string) $result : '0';
843     }
844
845     /**
846      * Returns the total number of executed migration versions
847      *
848      * @return integer $count
849      */
850     public function getNumberOfExecutedMigrations()
851     {
852         $this->createMigrationTable();
853
854         $result = $this->_connection->fetchColumn("SELECT COUNT(version) FROM " . $this->_migrationsTableName);
855         return $result !== false ? $result : 0;
856     }
857
858     /**
859      * Returns the total number of available migration versions
860      *
861      * @return integer $count
862      */
863     public function getNumberOfAvailableMigrations()
864     {
865         return count($this->_migrations);
866     }
867
868     /**
869      * Returns the latest available migration version.
870      *
871      * @return string $version  The version string in the format YYYYMMDDHHMMSS.
872      */
873     public function getLatestVersion()
874     {
875         $versions = array_keys($this->_migrations);
876         $latest = end($versions);
877         return $latest !== false ? (string) $latest : '0';
878     }
879
880     /**
881      * Create the migration table to track migrations with.
882      *
883      * @return bool $created  Whether or not the table was created.
884      */
885     public function createMigrationTable()
886     {
887         $this->validate();
888
889         if ($this->_migrationTableCreated) {
890             return false;
891         }
892
893         $schema = $this->_connection->getSchemaManager()->createSchema();
894         if ( ! $schema->hasTable($this->_migrationsTableName)) {
895             $columns = array(
896                 'version' => new Column('version', Type::getType('string'), array('length' => 14)),
897             );
898             $table = new Table($this->_migrationsTableName, $columns);
899             $table->setPrimaryKey(array('version'));
900             $this->_connection->getSchemaManager()->createTable($table);
901
902             $this->_migrationTableCreated = true;
903
904             return true;
905         }
906         return false;
907     }
908
909     /**
910      * Returns the array of migrations to executed based on the given direction
911      * and target version number.
912      *
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.
916      */
917     public function getMigrationsToExecute($direction, $to)
918     {
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);
923         } else {
924             $allVersions = $this->_migrations;
925         }
926         $versions = array();
927         foreach ($allVersions as $version) {
928             if ($this->_shouldExecuteMigration($direction, $version, $to)) {
929                 $versions[$version->getVersion()] = $version;
930             }
931         }
932         return $versions;
933     }
934
935     /**
936      * Check if we should execute a migration for a given direction and target
937      * migration version.
938      *
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.
942      * @return void
943      */
944     private function _shouldExecuteMigration($direction, Version $version, $to)
945     {
946         if ($direction === 'down') {
947             if ( ! $this->hasVersionMigrated($version)) {
948                 return false;
949             }
950             return $version->getVersion() > $to ? true : false;
951         } else if ($direction === 'up') {
952             if ($this->hasVersionMigrated($version)) {
953                 return false;
954             }
955             return $version->getVersion() <= $to ? true : false;
956         }
957     }
958 }<?php
959 /*
960  *  $Id$
961  *
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.
973  *
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>.
977 */
978
979 namespace Doctrine\DBAL\Migrations\Configuration;
980
981 /**
982  * Load migration configuration information from a XML configuration file.
983  *
984  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
985  * @link        www.doctrine-project.org
986  * @since       2.0
987  * @version     $Revision$
988  * @author      Jonathan H. Wage <jonwage@gmail.com>
989  */
990 class XmlConfiguration extends AbstractFileConfiguration
991 {
992     /**
993      * @inheritdoc
994      */
995     protected function _load($file)
996     {
997         $xml = simplexml_load_file($file);
998         if (isset($xml->name)) {
999             $this->setName((string) $xml->name);
1000         }
1001         if (isset($xml->table['name'])) {
1002             $this->setMigrationsTableName((string) $xml->table['name']);
1003         }
1004         if (isset($xml->{'migrations-namespace'})) {
1005             $this->setMigrationsNamespace((string) $xml->{'migrations-namespace'});
1006         }
1007         if (isset($xml->{'migrations-directory'})) {
1008             $migrationsDirectory = $this->_getDirectoryRelativeToFile($file, (string) $xml->{'migrations-directory'});
1009             $this->setMigrationsDirectory($migrationsDirectory);
1010             $this->registerMigrationsFromDirectory($migrationsDirectory);
1011         }
1012         if (isset($xml->migrations->migration)) {
1013             foreach ($xml->migrations->migration as $migration) {
1014                 $this->registerMigration((string) $migration['version'], (string) $migration['class']);
1015             }
1016         }
1017     }
1018 }<?php
1019 /*
1020  *  $Id$
1021  *
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.
1033  *
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>.
1037 */
1038
1039 namespace Doctrine\DBAL\Migrations\Configuration;
1040
1041 use Symfony\Component\Yaml\Yaml;
1042
1043 /**
1044  * Load migration configuration information from a YAML configuration file.
1045  *
1046  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
1047  * @link        www.doctrine-project.org
1048  * @since       2.0
1049  * @version     $Revision$
1050  * @author      Jonathan H. Wage <jonwage@gmail.com>
1051  */
1052 class YamlConfiguration extends AbstractFileConfiguration
1053 {
1054     /**
1055      * @inheritdoc
1056      */
1057     protected function _load($file)
1058     {
1059         $array = Yaml::load($file);
1060
1061         if (isset($array['name'])) {
1062             $this->setName($array['name']);
1063         }
1064         if (isset($array['table_name'])) {
1065             $this->setMigrationsTableName($array['table_name']);
1066         }
1067         if (isset($array['migrations_namespace'])) {
1068             $this->setMigrationsNamespace($array['migrations_namespace']);
1069         }
1070         if (isset($array['migrations_directory'])) {
1071             $migrationsDirectory = $this->_getDirectoryRelativeToFile($file, $array['migrations_directory']);
1072             $this->setMigrationsDirectory($migrationsDirectory);
1073             $this->registerMigrationsFromDirectory($migrationsDirectory);
1074         }
1075         if (isset($array['migrations']) && is_array($array['migrations'])) {
1076             foreach ($array['migrations'] as $migration) {
1077                 $this->registerMigration($migration['version'], $migration['class']);
1078             }
1079         }
1080     }
1081 }
1082 <?php
1083 /*
1084  *  $Id$
1085  *
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.
1097  *
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>.
1101 */
1102
1103 namespace Doctrine\DBAL\Migrations\Configuration;
1104
1105 use Doctrine\DBAL\Migrations\MigrationsException;
1106
1107 /**
1108  * Abstract Migration Configuration class for loading configuration information
1109  * from a configuration file (xml or yml).
1110  *
1111  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
1112  * @link        www.doctrine-project.org
1113  * @since       2.0
1114  * @version     $Revision$
1115  * @author      Jonathan H. Wage <jonwage@gmail.com>
1116  */
1117 abstract class AbstractFileConfiguration extends Configuration
1118 {
1119     /** The configuration file used to load configuration information */
1120     private $_file;
1121
1122     /** Whether or not the configuration file has been loaded yet or not */
1123     private $_loaded = false;
1124
1125     /**
1126      * Load the information from the passed configuration file
1127      *
1128      * @param string $file  The path to the configuration file
1129      * @return void
1130      * @throws MigrationException $exception Throws exception if configuration file was already loaded
1131      */
1132     public function load($file)
1133     {
1134         if ($this->_loaded) {
1135             throw MigrationsException::configurationFileAlreadyLoaded();
1136         }
1137         if (file_exists($path = getcwd() . '/' . $file)) {
1138             $file = $path;
1139         }
1140         $this->_file = $file;
1141         $this->_load($file);
1142         $this->_loaded = true;
1143     }
1144
1145     protected function _getDirectoryRelativeToFile($file, $input)
1146     {
1147         $path = realpath(dirname($file) . '/' . $input);
1148         if ($path !== false) {
1149             $directory = $path;
1150         } else {
1151             $directory = $input;
1152         }
1153         return $directory;
1154     }
1155
1156     public function getFile()
1157     {
1158         return $this->_file;
1159     }
1160
1161     /**
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
1164      * else.
1165      *
1166      * @param string $file  The path to a configuration file.
1167      */
1168     abstract protected function _load($file);
1169 }<?php
1170 /*
1171  *  $Id$
1172  *
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.
1184  *
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>.
1188 */
1189
1190 namespace Doctrine\DBAL\Migrations;
1191
1192 /**
1193  * Simple class for outputting information from migrations.
1194  *
1195  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
1196  * @link        www.doctrine-project.org
1197  * @since       2.0
1198  * @version     $Revision$
1199  * @author      Jonathan H. Wage <jonwage@gmail.com>
1200  */
1201 class OutputWriter
1202 {
1203     private $_closure;
1204
1205     public function __construct(\Closure $closure = null)
1206     {
1207         if ($closure === null) {
1208             $closure = function($message) {};
1209         }
1210         $this->_closure = $closure;
1211     }
1212
1213     /**
1214      * Write output using the configured closure.
1215      *
1216      * @param string $message  The message to write.
1217      */
1218     public function write($message)
1219     {
1220         $closure = $this->_closure;
1221         $closure($message);
1222     }
1223 }<?php
1224 /*
1225  *  $Id$
1226  *
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.
1238  *
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>.
1242 */
1243
1244 namespace Doctrine\DBAL\Migrations;
1245
1246 use Doctrine\DBAL\Migrations\Configuration\Configuration,
1247     Doctrine\DBAL\Schema\Schema;
1248
1249 /**
1250  * Class which wraps a migration version and allows execution of the
1251  * individual migration version up or down method.
1252  *
1253  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
1254  * @link        www.doctrine-project.org
1255  * @since       2.0
1256  * @version     $Revision$
1257  * @author      Jonathan H. Wage <jonwage@gmail.com>
1258  */
1259 class Version
1260 {
1261     const STATE_NONE = 0;
1262     const STATE_PRE  = 1;
1263     const STATE_EXEC = 2;
1264     const STATE_POST = 3;
1265
1266     /**
1267      * The Migrations Configuration instance for this migration
1268      *
1269      * @var Configuration
1270      */
1271     private $_configuration;
1272
1273     /**
1274      * The OutputWriter object instance used for outputting information
1275      *
1276      * @var OutputWriter
1277      */
1278     private $_outputWriter;
1279
1280     /**
1281      * The version in timestamp format (YYYYMMDDHHMMSS)
1282      *
1283      * @param int
1284      */
1285     private $_version;
1286
1287     /**
1288      * @var AbstractSchemaManager
1289      */
1290     private $_sm;
1291
1292     /**
1293      * @var AbstractPlatform
1294      */
1295     private $_platform;
1296
1297     /**
1298      * The migration instance for this version
1299      *
1300      * @var AbstractMigration
1301      */
1302     private $_migration;
1303
1304     /**
1305      * @var Connection
1306      */
1307     private $_connection;
1308
1309     /**
1310      * @var string
1311      */
1312     private $_class;
1313
1314     /** The array of collected SQL statements for this version */
1315     private $_sql = array();
1316
1317     /** The time in seconds that this migration version took to execute */
1318     private $_time;
1319
1320     /**
1321      * @var int
1322      */
1323     private $_state = self::STATE_NONE;
1324
1325     public function __construct(Configuration $configuration, $version, $class)
1326     {
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);
1335     }
1336
1337     /**
1338      * Returns the string version in the format YYYYMMDDHHMMSS
1339      *
1340      * @return string $version
1341      */
1342     public function getVersion()
1343     {
1344         return $this->_version;
1345     }
1346
1347     /**
1348      * Returns the Migrations Configuration object instance
1349      *
1350      * @return Configuration $configuration
1351      */
1352     public function getConfiguration()
1353     {
1354         return $this->_configuration;
1355     }
1356
1357     /**
1358      * Check if this version has been migrated or not.
1359      *
1360      * @param bool $bool
1361      * @return mixed
1362      */
1363     public function isMigrated()
1364     {
1365         return $this->_configuration->hasVersionMigrated($this);
1366     }
1367
1368     public function markMigrated()
1369     {
1370         $this->_configuration->createMigrationTable();
1371         $this->_connection->executeQuery("INSERT INTO " . $this->_configuration->getMigrationsTableName() . " (version) VALUES (?)", array($this->_version));
1372     }
1373
1374     public function markNotMigrated()
1375     {
1376         $this->_configuration->createMigrationTable();
1377         $this->_connection->executeQuery("DELETE FROM " . $this->_configuration->getMigrationsTableName() . " WHERE version = '$this->_version'");
1378     }
1379
1380     /**
1381      * Add some SQL queries to this versions migration
1382      *
1383      * @param mixed $sql
1384      * @return void
1385      */
1386     public function addSql($sql)
1387     {
1388         if (is_array($sql)) {
1389             foreach ($sql as $query) {
1390                 $this->_sql[] = $query;
1391             }
1392         } else {
1393             $this->_sql[] = $sql;
1394         }
1395     }
1396
1397     /**
1398      * Write a migration SQL file to the given path
1399      *
1400      * @param string $path          The path to write the migration SQL file.
1401      * @param string $direction     The direction to execute.
1402      * @return bool $written
1403      */
1404     public function writeSqlFile($path, $direction = 'up')
1405     {
1406         $queries = $this->execute($direction, true);
1407
1408         $string  = sprintf("# Doctrine Migration File Generated on %s\n", date('Y-m-d H:m:s'));
1409
1410         $string .= "\n# Version " . $this->_version . "\n";
1411         foreach ($queries as $query) {
1412             $string .= $query . ";\n";
1413         }
1414         if (is_dir($path)) {
1415             $path = realpath($path);
1416             $path = $path . '/doctrine_migration_' . date('YmdHis') . '.sql';
1417         }
1418
1419         $this->_outputWriter->write("\n".sprintf('Writing migration file to "<info>%s</info>"', $path));
1420
1421         return file_put_contents($path, $string);
1422     }
1423
1424     /**
1425      * Execute this migration version up or down and and return the SQL.
1426      *
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
1431      */
1432     public function execute($direction, $dryRun = false)
1433     {
1434         $this->_sql = array();
1435
1436         $this->_connection->beginTransaction();
1437
1438         try {
1439             $start = microtime(true);
1440
1441             $this->_state = self::STATE_PRE;
1442             $fromSchema = $this->_sm->createSchema();
1443             $this->_migration->{'pre' . ucfirst($direction)}($fromSchema);
1444
1445             if ($direction === 'up') {
1446                 $this->_outputWriter->write("\n" . sprintf('  <info>++</info> migrating <comment>%s</comment>', $this->_version) . "\n");
1447             } else {
1448                 $this->_outputWriter->write("\n" . sprintf('  <info>--</info> reverting <comment>%s</comment>', $this->_version) . "\n");
1449             }
1450
1451             $this->_state = self::STATE_EXEC;
1452
1453             $toSchema = clone $fromSchema;
1454             $this->_migration->$direction($toSchema);
1455             $this->addSql($fromSchema->getMigrateToSql($toSchema, $this->_platform));
1456
1457             if ($dryRun === false) {
1458                 if ($this->_sql) {
1459                     $count = count($this->_sql);
1460                     foreach ($this->_sql as $query) {
1461                         $this->_outputWriter->write('     <comment>-></comment> ' . $query);
1462                         $this->_connection->executeQuery($query);
1463                     }
1464
1465                     if ($direction === 'up') {
1466                         $this->markMigrated();
1467                     } else {
1468                         $this->markNotMigrated();
1469                     }
1470                 } else {
1471                     $this->_outputWriter->write(sprintf('<error>Migration %s was executed but did not result in any SQL statements.</error>', $this->_version));
1472                 }
1473             } else {
1474                 foreach ($this->_sql as $query) {
1475                     $this->_outputWriter->write('     <comment>-></comment> ' . $query);
1476                 }
1477             }
1478
1479             $this->_state = self::STATE_POST;
1480             $this->_migration->{'post' . ucfirst($direction)}($toSchema);
1481
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));
1486             } else {
1487                 $this->_outputWriter->write(sprintf("\n  <info>--</info> reverted (%ss)", $this->_time));
1488             }
1489
1490             $this->_connection->commit();
1491
1492             return $this->_sql;
1493         } catch(SkipMigrationException $e) {
1494             $this->_connection->rollback();
1495
1496             // now mark it as migrated
1497             if ($direction === 'up') {
1498                 $this->markMigrated();
1499             } else {
1500                 $this->markNotMigrated();
1501             }
1502
1503             $this->_outputWriter->write(sprintf("\n  <info>SS</info> skipped (Reason: %s)",  $e->getMessage()));
1504         } catch (\Exception $e) {
1505
1506             $this->_outputWriter->write(sprintf(
1507                 '<error>Migration %s failed during %s. Error %s</error>',
1508                 $this->_version, $this->getExecutionState(), $e->getMessage()
1509             ));
1510
1511             $this->_connection->rollback();
1512
1513             $this->_state = self::STATE_NONE;
1514             throw $e;
1515         }
1516         $this->_state = self::STATE_NONE;
1517     }
1518
1519     public function getExecutionState()
1520     {
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:
1527                 return 'Execution';
1528             default:
1529                 return 'No State';
1530         }
1531     }
1532
1533     /**
1534      * Returns the time this migration version took to execute
1535      *
1536      * @return integer $time The time this migration version took to execute
1537      */
1538     public function getTime()
1539     {
1540         return $this->_time;
1541     }
1542
1543     public function __toString()
1544     {
1545         return $this->_version;
1546     }
1547 }
1548 <?php
1549 /*
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.
1561  *
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>.
1565  */
1566
1567
1568 namespace Doctrine\DBAL\Migrations;
1569
1570 class MigrationsVersion
1571 {
1572     const VERSION = '2.0.0-DEV';
1573 }<?php
1574 /*
1575  *  $Id$
1576  *
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.
1588  *
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>.
1592  */
1593
1594 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
1595
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;
1602
1603 /**
1604  * Command for generate migration classes by comparing your current database schema
1605  * to your mapping information.
1606  *
1607  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1608  * @link    www.doctrine-project.org
1609  * @since   2.0
1610  * @version $Revision$
1611  * @author  Jonathan Wage <jonwage@gmail.com>
1612  */
1613 class DiffCommand extends GenerateCommand
1614 {
1615     protected function configure()
1616     {
1617         parent::configure();
1618
1619         $this
1620             ->setName('migrations:diff')
1621             ->setDescription('Generate a migration by comparing your current database to your mapping information.')
1622             ->setHelp(<<<EOT
1623 The <info>%command.name%</info> command generates a migration by comparing your current database to your mapping information:
1624
1625     <info>%command.full_name%</info>
1626
1627 You can optionally specify a <comment>--editor-cmd</comment> option to open the generated file in your favorite editor:
1628
1629     <info>%command.full_name% --editor-cmd=mate</info>
1630 EOT
1631         );
1632
1633     }
1634
1635     public function execute(InputInterface $input, OutputInterface $output)
1636     {
1637         $configuration = $this->_getMigrationConfiguration($input, $output);
1638
1639         $em = $this->getHelper('em')->getEntityManager();
1640         $conn = $em->getConnection();
1641         $platform = $conn->getDatabasePlatform();
1642         $metadata = $em->getMetadataFactory()->getAllMetadata();
1643
1644         if (empty($metadata)) {
1645             $output->writeln('No mapping information to process.', 'ERROR');
1646             return;
1647         }
1648
1649         $tool = new SchemaTool($em);
1650
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));
1655
1656         if ( ! $up && ! $down) {
1657             $output->writeln('No changes detected in your mapping information.', 'ERROR');
1658             return;
1659         }
1660
1661         $version = date('YmdHis');
1662         $path = $this->_generateMigration($configuration, $input, $version, $up, $down);
1663
1664         $output->writeln(sprintf('Generated new migration class to "<info>%s</info>" from schema differences.', $path));
1665     }
1666
1667     private function _buildCodeFromSql(Configuration $configuration, array $sql)
1668     {
1669         $code = array();
1670         foreach ($sql as $query) {
1671             if (strpos($query, $configuration->getMigrationsTableName()) !== false) {
1672                 continue;
1673             }
1674             $code[] = "\$this->_addSql('" . $query . "');";
1675         }
1676         return implode("\n", $code);
1677     }
1678 }
1679 <?php
1680 /*
1681  *  $Id$
1682  *
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.
1694  *
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>.
1698  */
1699  
1700 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
1701
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;
1712
1713 /**
1714  * CLI Command for adding and deleting migration versions from the version table.
1715  *
1716  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1717  * @link    www.doctrine-project.org
1718  * @since   2.0
1719  * @version $Revision$
1720  * @author  Jonathan Wage <jonwage@gmail.com>
1721  */
1722 abstract class AbstractCommand extends Command
1723 {
1724     protected $_configuration;
1725
1726     protected function configure()
1727     {
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.');
1730     }
1731
1732     protected function _outputHeader(Configuration $configuration, OutputInterface $output)
1733     {
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('');
1741     }
1742
1743     /**
1744      * @param InputInterface $input
1745      * @param OutputInterface $output
1746      * @return Configuration
1747      */
1748     protected function _getMigrationConfiguration(InputInterface $input, OutputInterface $output)
1749     {
1750         if ( ! $this->_configuration) {
1751             $outputWriter = new OutputWriter(function($message) use ($output) {
1752                 return $output->writeln($message);
1753             });
1754
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.");
1760                 }
1761
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.');
1765                 }
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.');
1771                 }
1772                 $conn = \Doctrine\DBAL\DriverManager::getConnection($params);
1773             } else {
1774                 throw new \InvalidArgumentException('You have to specify a --db-configuration file or pass a Database Connection as a dependency to the Migrations.');
1775             }
1776
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');
1788             } else {
1789                 $configuration = new Configuration($conn, $outputWriter);
1790             }
1791             $this->_configuration = $configuration;
1792         }
1793         return $this->_configuration;
1794     }
1795 }
1796 <?php
1797 /*
1798  *  $Id$
1799  *
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.
1811  *
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>.
1815  */
1816  
1817 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
1818
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;
1825
1826 /**
1827  * Command for generating new blank migration classes
1828  *
1829  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1830  * @link    www.doctrine-project.org
1831  * @since   2.0
1832  * @version $Revision$
1833  * @author  Jonathan Wage <jonwage@gmail.com>
1834  */
1835 class GenerateCommand extends AbstractCommand
1836 {
1837     private static $_template =
1838 '<?php
1839
1840 namespace <namespace>;
1841
1842 use Doctrine\DBAL\Migrations\AbstractMigration,
1843     Doctrine\DBAL\Schema\Schema;
1844
1845 class Version<version> extends AbstractMigration
1846 {
1847     public function up(Schema $schema)
1848     {
1849 <up>
1850     }
1851
1852     public function down(Schema $schema)
1853     {
1854 <down>
1855     }
1856 }';
1857
1858     protected function configure()
1859     {
1860         $this
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.')
1864             ->setHelp(<<<EOT
1865 The <info>%command.name%</info> command generates a blank migration class:
1866
1867     <info>%command.full_name%</info>
1868
1869 You can optionally specify a <comment>--editor-cmd</comment> option to open the generated file in your favorite editor:
1870
1871     <info>%command.full_name% --editor-cmd=mate</info>
1872 EOT
1873         );
1874
1875         parent::configure();
1876     }
1877
1878     public function execute(InputInterface $input, OutputInterface $output)
1879     {
1880         $configuration = $this->_getMigrationConfiguration($input, $output);
1881
1882         $version = date('YmdHis');
1883         $path = $this->_generateMigration($configuration, $input, $version);
1884         
1885         $output->writeln(sprintf('Generated new migration class to "<info>%s</info>"', $path));
1886     }
1887
1888     protected function _generateMigration(Configuration $configuration, InputInterface $input, $version, $up = null, $down = null)
1889     {
1890         $placeHolders = array(
1891             '<namespace>',
1892             '<version>',
1893             '<up>',
1894             '<down>'
1895         );
1896         $replacements = array(
1897             $configuration->getMigrationsNamespace(),
1898             $version,
1899             $up ? "        " . implode("\n        ", explode("\n", $up)) : null,
1900             $down ? "        " . implode("\n        ", explode("\n", $down)) : null
1901         );
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';
1907
1908         file_put_contents($path, $code);
1909
1910         if ($editorCmd = $input->getOption('editor-cmd'))
1911         {
1912           shell_exec($editorCmd . ' ' . escapeshellarg($path));
1913         }
1914
1915         return $path;
1916     }
1917 }
1918 <?php
1919 /*
1920  *  $Id$
1921  *
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.
1933  *
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>.
1937  */
1938
1939 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
1940
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;
1950
1951 /**
1952  * Command for manually adding and deleting migration versions from the version table.
1953  *
1954  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
1955  * @link    www.doctrine-project.org
1956  * @since   2.0
1957  * @version $Revision$
1958  * @author  Jonathan Wage <jonwage@gmail.com>
1959  */
1960 class VersionCommand extends AbstractCommand
1961 {
1962     protected function configure()
1963     {
1964         $this
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.')
1970             ->setHelp(<<<EOT
1971 The <info>%command.name%</info> command allows you to manually add and delete migration versions from the version table:
1972
1973     <info>%command.full_name% YYYYMMDDHHMMSS --add</info>
1974
1975 If you want to delete a version you can use the <comment>--delete</comment> option:
1976
1977     <info>%command.full_name% YYYYMMDDHHMMSS --delete</info>
1978 EOT
1979         );
1980
1981         parent::configure();
1982     }
1983
1984     public function execute(InputInterface $input, OutputInterface $output)
1985     {
1986         $configuration = $this->_getMigrationConfiguration($input, $output);
1987         $migration = new Migration($configuration);
1988
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.');
1991         }
1992
1993         $version = $input->getArgument('version');
1994         $markMigrated = $input->getOption('add') ? true : false;
1995
1996         if ( ! $configuration->hasVersion($version)) {
1997             throw MigrationException::unknownMigrationVersion($version);
1998         }
1999
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));
2003         }
2004
2005         if ( ! $markMigrated && ! $configuration->hasVersionMigrated($version)) {
2006             throw new \InvalidArgumentException(sprintf('The version "%s" does not exists in the version table.', $version));
2007         }
2008
2009         if ($markMigrated) {
2010             $version->markMigrated();
2011         } else {
2012             $version->markNotMigrated();
2013         }
2014     }
2015 }
2016 <?php
2017 /*
2018  *  $Id$
2019  *
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.
2031  *
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>.
2035  */
2036  
2037 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
2038
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;
2047
2048 /**
2049  * Command for executing single migrations up or down manually.
2050  *
2051  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
2052  * @link    www.doctrine-project.org
2053  * @since   2.0
2054  * @version $Revision$
2055  * @author  Jonathan Wage <jonwage@gmail.com>
2056  */
2057 class ExecuteCommand extends AbstractCommand
2058 {
2059     protected function configure()
2060     {
2061         $this
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.')
2069             ->setHelp(<<<EOT
2070 The <info>%command.name%</info> command executes a single migration version up or down manually:
2071
2072     <info>%command.full_name% YYYYMMDDHHMMSS</info>
2073
2074 If no <comment>--up</comment> or <comment>--down</comment> option is specified it defaults to up:
2075
2076     <info>%command.full_name% YYYYMMDDHHMMSS --down</info>
2077
2078 You can also execute the migration as a <comment>--dry-run</comment>:
2079
2080     <info>%command.full_name% YYYYMMDDHHMMSS --dry-run</info>
2081
2082 Or you can output the would be executed SQL statements to a file with <comment>--write-sql</comment>:
2083
2084     <info>%command.full_name% YYYYMMDDHHMMSS --write-sql</info>
2085 EOT
2086         );
2087
2088         parent::configure();
2089     }
2090
2091     public function execute(InputInterface $input, OutputInterface $output)
2092     {
2093         $version = $input->getArgument('version');
2094         $direction = $input->getOption('down') ? 'down' : 'up';
2095
2096         $configuration = $this->_getMigrationConfiguration($input, $output);
2097         $version = $configuration->getVersion($version);
2098
2099         if ($path = $input->getOption('write-sql')) {
2100             $path = is_bool($path) ? getcwd() : $path;
2101             $version->writeSqlFile($path, $direction);
2102         } else {
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);
2106             } else {
2107                 $output->writeln('<error>Migration cancelled!</error>');
2108             }
2109         }
2110     }
2111 }
2112 <?php
2113 /*
2114  *  $Id$
2115  *
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.
2127  *
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>.
2131  */
2132
2133 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
2134
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;
2144
2145 /**
2146  * Command to view the status of a set of migrations.
2147  *
2148  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
2149  * @link    www.doctrine-project.org
2150  * @since   2.0
2151  * @version $Revision$
2152  * @author  Jonathan Wage <jonwage@gmail.com>
2153  */
2154 class StatusCommand extends AbstractCommand
2155 {
2156     protected function configure()
2157     {
2158         $this
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')
2162             ->setHelp(<<<EOT
2163 The <info>%command.name%</info> command outputs the status of a set of migrations:
2164
2165     <info>%command.full_name%</info>
2166
2167 You can output a list of all available migrations and their status with <comment>--show-versions</comment>:
2168
2169     <info>%command.full_name% --show-versions</info>
2170 EOT
2171         );
2172
2173         parent::configure();
2174     }
2175
2176     public function execute(InputInterface $input, OutputInterface $output)
2177     {
2178         $configuration = $this->_getMigrationConfiguration($input, $output);
2179
2180         $currentVersion = $configuration->getCurrentVersion();
2181         if ($currentVersion) {
2182             $currentVersionFormatted = $configuration->formatVersion($currentVersion) . ' (<comment>'.$currentVersion.'</comment>)';
2183         } else {
2184             $currentVersionFormatted = 0;
2185         }
2186         $latestVersion = $configuration->getLatestVersion();
2187         if ($latestVersion) {
2188             $latestVersionFormatted = $configuration->formatVersion($latestVersion) . ' (<comment>'.$latestVersion.'</comment>)';
2189         } else {
2190             $latestVersionFormatted = 0;
2191         }
2192         $executedMigrations = $configuration->getNumberOfExecutedMigrations();
2193         $availableMigrations = $configuration->getNumberOfAvailableMigrations();
2194         $newMigrations = $availableMigrations - $executedMigrations;
2195
2196         $output->writeln("\n <info>==</info> Configuration\n");
2197
2198         $info = array(
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
2211         );
2212         foreach ($info as $name => $value) {
2213             $output->writeln('    <comment>>></comment> ' . $name . ': ' . str_repeat(' ', 50 - strlen($name)) . $value);
2214         }
2215
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);
2224                 }
2225             }
2226         }
2227     }
2228 }
2229 <?php
2230 /*
2231  *  $Id$
2232  *
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.
2244  *
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>.
2248  */
2249  
2250 namespace Doctrine\DBAL\Migrations\Tools\Console\Command;
2251
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;
2260
2261 /**
2262  * Command for executing a migration to a specified version or the latest available version.
2263  *
2264  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
2265  * @link    www.doctrine-project.org
2266  * @since   2.0
2267  * @version $Revision$
2268  * @author  Jonathan Wage <jonwage@gmail.com>
2269  */
2270 class MigrateCommand extends AbstractCommand
2271 {
2272     protected function configure()
2273     {
2274         $this
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.')
2280             ->setHelp(<<<EOT
2281 The <info>%command.name%</info> command executes a migration to a specified version or the latest available version:
2282
2283     <info>%command.full_name%</info>
2284
2285 You can optionally manually specify the version you wish to migrate to:
2286
2287     <info>%command.full_name% YYYYMMDDHHMMSS</info>
2288
2289 You can also execute the migration as a <comment>--dry-run</comment>:
2290
2291     <info>%command.full_name% YYYYMMDDHHMMSS --dry-run</info>
2292
2293 Or you can output the would be executed SQL statements to a file with <comment>--write-sql</comment>:
2294
2295     <info>%command.full_name% YYYYMMDDHHMMSS --write-sql</info>
2296     
2297 You can also execute the migration without a warning message wich you need to interact with:
2298     
2299     <info>%command.full_name% --no-interaction</info>
2300     
2301 EOT
2302         );
2303
2304         parent::configure();
2305     }
2306
2307     public function execute(InputInterface $input, OutputInterface $output)
2308     {
2309         $version = $input->getArgument('version');
2310
2311         $configuration = $this->_getMigrationConfiguration($input, $output);
2312         $migration = new Migration($configuration);
2313
2314         $this->_outputHeader($configuration, $output);
2315
2316         if ($path = $input->getOption('write-sql')) {
2317             $path = is_bool($path) ? getcwd() : $path;
2318             $migration->writeSqlFile($path, $version);
2319         } else {
2320             $dryRun = $input->getOption('dry-run') ? true : false;
2321             if ($dryRun === true) {
2322                 $migration->migrate($version, true);
2323             } else {
2324                 $noInteraction = $input->getOption('no-interaction') ? true : false;
2325                 if ($noInteraction === true) {
2326                     $migration->migrate($version, $dryRun);
2327                 } else {
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);
2331                     } else {
2332                         $output->writeln('<error>Migration cancelled!</error>');
2333                     }
2334                 }
2335             }
2336         }
2337     }
2338 }
2339 <?php
2340
2341 namespace Doctrine\DBAL;
2342
2343 class DBALException extends \Exception
2344 {
2345     public static function notSupported($method)
2346     {
2347         return new self("Operation '$method' is not supported by platform.");
2348     }
2349
2350     public static function invalidPlatformSpecified()
2351     {
2352         return new self(
2353             "Invalid 'platform' option specified, need to give an instance of ".
2354             "\Doctrine\DBAL\Platforms\AbstractPlatform.");
2355     }
2356
2357     public static function invalidPdoInstance()
2358     {
2359         return new self(
2360             "The 'pdo' option was used in DriverManager::getConnection() but no ".
2361             "instance of PDO was given."
2362         );
2363     }
2364
2365     public static function driverRequired()
2366     {
2367         return new self("The options 'driver' or 'driverClass' are mandatory if no PDO ".
2368             "instance is given to DriverManager::getConnection().");
2369     }
2370
2371     public static function unknownDriver($unknownDriverName, array $knownDrivers)
2372     {
2373         return new self("The given 'driver' ".$unknownDriverName." is unknown, ".
2374             "Doctrine currently supports only the following drivers: ".implode(", ", $knownDrivers));
2375     }
2376
2377     public static function invalidWrapperClass($wrapperClass)
2378     {
2379         return new self("The given 'wrapperClass' ".$wrapperClass." has to be a ".
2380             "subtype of \Doctrine\DBAL\Connection.");
2381     }
2382
2383     public static function invalidDriverClass($driverClass)
2384     {
2385         return new self("The given 'driverClass' ".$driverClass." has to implement the ".
2386             "\Doctrine\DBAL\Driver interface.");
2387     }
2388
2389     /**
2390      * @param string $tableName
2391      * @return DBALException
2392      */
2393     public static function invalidTableName($tableName)
2394     {
2395         return new self("Invalid table name specified: ".$tableName);
2396     }
2397
2398     /**
2399      * @param string $tableName
2400      * @return DBALException
2401      */
2402     public static function noColumnsSpecifiedForTable($tableName)
2403     {
2404         return new self("No columns specified for table ".$tableName);
2405     }
2406
2407     public static function limitOffsetInvalid()
2408     {
2409         return new self("Invalid Offset in Limit Query, it has to be larger or equal to 0.");
2410     }
2411
2412     public static function typeExists($name)
2413     {
2414         return new self('Type '.$name.' already exists.');
2415     }
2416
2417     public static function unknownColumnType($name)
2418     {
2419         return new self('Unknown column type '.$name.' requested.');
2420     }
2421
2422     public static function typeNotFound($name)
2423     {
2424         return new self('Type to be overwritten '.$name.' does not exist.');
2425     }
2426 }<?php
2427 /*
2428  *  $Id$
2429  *
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.
2441  *
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>.
2445  */
2446
2447 namespace Doctrine\DBAL\Driver\PDOOracle;
2448
2449 use Doctrine\DBAL\Platforms;
2450
2451 class Driver implements \Doctrine\DBAL\Driver
2452 {
2453     public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
2454     {
2455         return new \Doctrine\DBAL\Driver\PDOConnection(
2456             $this->_constructPdoDsn($params),
2457             $username,
2458             $password,
2459             $driverOptions
2460         );
2461     }
2462
2463     /**
2464      * Constructs the Oracle PDO DSN.
2465      *
2466      * @return string  The DSN.
2467      */
2468     private function _constructPdoDsn(array $params)
2469     {
2470         $dsn = 'oci:';
2471         if (isset($params['host'])) {
2472             $dsn .= 'dbname=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)' .
2473                    '(HOST=' . $params['host'] . ')';
2474
2475             if (isset($params['port'])) {
2476                 $dsn .= '(PORT=' . $params['port'] . ')';
2477             } else {
2478                 $dsn .= '(PORT=1521)';
2479             }
2480
2481             $dsn .= '))(CONNECT_DATA=(SID=' . $params['dbname'] . ')))';
2482         } else {
2483             $dsn .= 'dbname=' . $params['dbname'];
2484         }
2485
2486         if (isset($params['charset'])) {
2487             $dsn .= ';charset=' . $params['charset'];
2488         }
2489
2490         return $dsn;
2491     }
2492
2493     public function getDatabasePlatform()
2494     {
2495         return new \Doctrine\DBAL\Platforms\OraclePlatform();
2496     }
2497
2498     public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
2499     {
2500         return new \Doctrine\DBAL\Schema\OracleSchemaManager($conn);
2501     }
2502
2503     public function getName()
2504     {
2505         return 'pdo_oracle';
2506     }
2507
2508     public function getDatabase(\Doctrine\DBAL\Connection $conn)
2509     {
2510         $params = $conn->getParams();
2511         return $params['user'];
2512     }
2513 }<?php
2514 /*
2515  *  $Id$
2516  *
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.
2528  *
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>.
2532 */
2533
2534 namespace Doctrine\DBAL\Driver\IBMDB2;
2535
2536 class DB2Connection implements \Doctrine\DBAL\Driver\Connection
2537 {
2538     private $_conn = null;
2539
2540     public function __construct(array $params, $username, $password, $driverOptions = array())
2541     {
2542         $isPersistant = (isset($params['persistent']) && $params['persistent'] == true);
2543
2544         if ($isPersistant) {
2545             $this->_conn = db2_pconnect($params['dbname'], $username, $password, $driverOptions);
2546         } else {
2547             $this->_conn = db2_connect($params['dbname'], $username, $password, $driverOptions);
2548         }
2549         if (!$this->_conn) {
2550             throw new DB2Exception(db2_conn_errormsg());
2551         }
2552     }
2553
2554     function prepare($sql)
2555     {
2556         $stmt = @db2_prepare($this->_conn, $sql);
2557         if (!$stmt) {
2558             throw new DB2Exception(db2_stmt_errormsg());
2559         }
2560         return new DB2Statement($stmt);
2561     }
2562     
2563     function query()
2564     {
2565         $args = func_get_args();
2566         $sql = $args[0];
2567         $stmt = $this->prepare($sql);
2568         $stmt->execute();
2569         return $stmt;
2570     }
2571
2572     function quote($input, $type=\PDO::PARAM_STR)
2573     {
2574         $input = db2_escape_string($input);
2575         if ($type == \PDO::PARAM_INT ) {
2576             return $input;
2577         } else {
2578             return "'".$input."'";
2579         }
2580     }
2581
2582     function exec($statement)
2583     {
2584         $stmt = $this->prepare($statement);
2585         $stmt->execute();
2586         return $stmt->rowCount();
2587     }
2588
2589     function lastInsertId($name = null)
2590     {
2591         return db2_last_insert_id($this->_conn);
2592     }
2593
2594     function beginTransaction()
2595     {
2596         db2_autocommit($this->_conn, DB2_AUTOCOMMIT_OFF);
2597     }
2598
2599     function commit()
2600     {
2601         if (!db2_commit($this->_conn)) {
2602             throw new DB2Exception(db2_conn_errormsg($this->_conn));
2603         }
2604         db2_autocommit($this->_conn, DB2_AUTOCOMMIT_ON);
2605     }
2606
2607     function rollBack()
2608     {
2609         if (!db2_rollback($this->_conn)) {
2610             throw new DB2Exception(db2_conn_errormsg($this->_conn));
2611         }
2612         db2_autocommit($this->_conn, DB2_AUTOCOMMIT_ON);
2613     }
2614
2615     function errorCode()
2616     {
2617         return db2_conn_error($this->_conn);
2618     }
2619
2620     function errorInfo()
2621     {
2622         return array(
2623             0 => db2_conn_errormsg($this->_conn),
2624             1 => $this->errorCode(),
2625         );
2626     }
2627 }<?php
2628 /*
2629  *  $Id$
2630  *
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.
2642  *
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>.
2646 */
2647
2648 namespace Doctrine\DBAL\Driver\IBMDB2;
2649
2650 class DB2Statement implements \Doctrine\DBAL\Driver\Statement
2651 {
2652     private $_stmt = null;
2653
2654     private $_bindParam = array();
2655
2656     /**
2657      * DB2_BINARY, DB2_CHAR, DB2_DOUBLE, or DB2_LONG 
2658      * @var <type>
2659      */
2660     static private $_typeMap = array(
2661         \PDO::PARAM_INT => DB2_LONG,
2662         \PDO::PARAM_STR => DB2_CHAR,
2663     );
2664
2665     public function __construct($stmt)
2666     {
2667         $this->_stmt = $stmt;
2668     }
2669
2670     /**
2671      * Binds a value to a corresponding named or positional
2672      * placeholder in the SQL statement that was used to prepare the statement.
2673      *
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
2677      *
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.
2680      *
2681      * @return boolean              Returns TRUE on success or FALSE on failure.
2682      */
2683     function bindValue($param, $value, $type = null)
2684     {
2685         return $this->bindParam($param, $value, $type);
2686     }
2687
2688     /**
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.
2693      *
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.
2698      *
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
2702      *
2703      * @param mixed $variable       Name of the PHP variable to bind to the SQL statement parameter.
2704      *
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.
2709      */
2710     function bindParam($column, &$variable, $type = null)
2711     {
2712         $this->_bindParam[$column] =& $variable;
2713
2714         if ($type && isset(self::$_typeMap[$type])) {
2715             $type = self::$_typeMap[$type];
2716         } else {
2717             $type = DB2_CHAR;
2718         }
2719
2720         if (!db2_bind_param($this->_stmt, $column, "variable", DB2_PARAM_IN, $type)) {
2721             throw new DB2Exception(db2_stmt_errormsg());
2722         }
2723         return true;
2724     }
2725
2726     /**
2727      * Closes the cursor, enabling the statement to be executed again.
2728      *
2729      * @return boolean              Returns TRUE on success or FALSE on failure.
2730      */
2731     function closeCursor()
2732     {
2733         if (!$this->_stmt) {
2734             return false;
2735         }
2736
2737         $this->_bindParam = array();
2738         db2_free_result($this->_stmt);
2739         $ret = db2_free_stmt($this->_stmt);
2740         $this->_stmt = false;
2741         return $ret;
2742     }
2743
2744     /**
2745      * columnCount
2746      * Returns the number of columns in the result set
2747      *
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.
2751      */
2752     function columnCount()
2753     {
2754         if (!$this->_stmt) {
2755             return false;
2756         }
2757         return db2_num_fields($this->_stmt);
2758     }
2759
2760     /**
2761      * errorCode
2762      * Fetch the SQLSTATE associated with the last operation on the statement handle
2763      *
2764      * @see Doctrine_Adapter_Interface::errorCode()
2765      * @return string       error code string
2766      */
2767     function errorCode()
2768     {
2769         return db2_stmt_error();
2770     }
2771
2772     /**
2773      * errorInfo
2774      * Fetch extended error information associated with the last operation on the statement handle
2775      *
2776      * @see Doctrine_Adapter_Interface::errorInfo()
2777      * @return array        error info array
2778      */
2779     function errorInfo()
2780     {
2781         return array(
2782             0 => db2_stmt_errormsg(),
2783             1 => db2_stmt_error(),
2784         );
2785     }
2786
2787     /**
2788      * Executes a prepared statement
2789      *
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
2794      * parameter values
2795      *
2796      *
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.
2800      */
2801     function execute($params = null)
2802     {
2803         if (!$this->_stmt) {
2804             return false;
2805         }
2806
2807         /*$retval = true;
2808         if ($params !== null) {
2809             $retval = @db2_execute($this->_stmt, $params);
2810         } else {
2811             $retval = @db2_execute($this->_stmt);
2812         }*/
2813         if ($params === null) {
2814             ksort($this->_bindParam);
2815             $params = array_values($this->_bindParam);
2816         }
2817         $retval = @db2_execute($this->_stmt, $params);
2818
2819         if ($retval === false) {
2820             throw new DB2Exception(db2_stmt_errormsg());
2821         }
2822         return $retval;
2823     }
2824
2825     /**
2826      * fetch
2827      *
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
2832      *
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().
2840      *
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.
2844      *
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.
2849      *
2850      * @return mixed
2851      */
2852     function fetch($fetchStyle = \PDO::FETCH_BOTH)
2853     {
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);
2861             default:
2862                 throw new DB2Exception("Given Fetch-Style " . $fetchStyle . " is not supported.");
2863         }
2864     }
2865
2866     /**
2867      * Returns an array containing all of the result set rows
2868      *
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
2872      *
2873      * @param integer $columnIndex          Returns the indicated 0-indexed column when the value of $fetchStyle is
2874      *                                      Query::HYDRATE_COLUMN. Defaults to 0.
2875      *
2876      * @return array
2877      */
2878     function fetchAll($fetchStyle = \PDO::FETCH_BOTH)
2879     {
2880         $rows = array();
2881         while ($row = $this->fetch($fetchStyle)) {
2882             $rows[] = $row;
2883         }
2884         return $rows;
2885     }
2886
2887     /**
2888      * fetchColumn
2889      * Returns a single column from the next row of a
2890      * result set or FALSE if there are no more rows.
2891      *
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.
2895      *
2896      * @return string                       returns a single column in the next row of a result set.
2897      */
2898     function fetchColumn($columnIndex = 0)
2899     {
2900         $row = $this->fetch(\PDO::FETCH_NUM);
2901         if ($row && isset($row[$columnIndex])) {
2902             return $row[$columnIndex];
2903         }
2904         return false;
2905     }
2906
2907     /**
2908      * rowCount
2909      * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement
2910      * executed by the corresponding object.
2911      *
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.
2916      *
2917      * @return integer                      Returns the number of rows.
2918      */
2919     function rowCount()
2920     {
2921         return (@db2_num_rows($this->_stmt))?:0;
2922     }
2923 }
2924 <?php
2925 /*
2926  *  $Id$
2927  *
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.
2939  *
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>.
2943 */
2944
2945 namespace Doctrine\DBAL\Driver\IBMDB2;
2946
2947 class DB2Exception extends \Exception
2948 {
2949     
2950 }<?php
2951 /*
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.
2963  *
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>.
2967 */
2968
2969 namespace Doctrine\DBAL\Driver\IBMDB2;
2970
2971 use Doctrine\DBAL\Driver,
2972     Doctrine\DBAL\Connection;
2973
2974 /**
2975  * IBM DB2 Driver
2976  *
2977  * @since 2.0
2978  * @author Benjamin Eberlei <kontakt@beberlei.de>
2979  */
2980 class DB2Driver implements Driver
2981 {
2982     /**
2983      * Attempts to create a connection with the database.
2984      *
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.
2990      */
2991     public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
2992     {
2993         if ( !isset($params['schema']) ) {
2994             
2995         }
2996
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 .';';
3006             $username = null;
3007             $password = null;
3008         }
3009
3010         return new DB2Connection($params, $username, $password, $driverOptions);
3011     }
3012
3013     /**
3014      * Gets the DatabasePlatform instance that provides all the metadata about
3015      * the platform this driver connects to.
3016      *
3017      * @return Doctrine\DBAL\Platforms\AbstractPlatform The database platform.
3018      */
3019     public function getDatabasePlatform()
3020     {
3021         return new \Doctrine\DBAL\Platforms\DB2Platform;
3022     }
3023
3024     /**
3025      * Gets the SchemaManager that can be used to inspect and change the underlying
3026      * database schema of the platform this driver connects to.
3027      *
3028      * @param  Doctrine\DBAL\Connection $conn
3029      * @return Doctrine\DBAL\SchemaManager
3030      */
3031     public function getSchemaManager(Connection $conn)
3032     {
3033         return new \Doctrine\DBAL\Schema\DB2SchemaManager($conn);
3034     }
3035
3036     /**
3037      * Gets the name of the driver.
3038      *
3039      * @return string The name of the driver.
3040      */
3041     public function getName()
3042     {
3043         return 'ibm_db2';
3044     }
3045
3046     /**
3047      * Get the name of the database connected to for this driver.
3048      *
3049      * @param  Doctrine\DBAL\Connection $conn
3050      * @return string $database
3051      */
3052     public function getDatabase(\Doctrine\DBAL\Connection $conn)
3053     {
3054         $params = $conn->getParams();
3055         return $params['dbname'];
3056     }
3057 }
3058 <?php
3059 /*
3060  *  $Id: Interface.php 3882 2008-02-22 18:11:35Z jwage $
3061  *
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.
3073  *
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>.
3077  */
3078
3079 namespace Doctrine\DBAL\Driver;
3080
3081 /**
3082  * The PDO implementation of the Statement interface.
3083  * Used by all PDO-based drivers.
3084  *
3085  * @since 2.0
3086  */
3087 class PDOStatement extends \PDOStatement implements Statement
3088 {
3089     private function __construct() {}
3090 }<?php
3091 /*
3092  *  $Id$
3093  *
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.
3105  *
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>.
3109  */
3110
3111 namespace Doctrine\DBAL\Driver\PDOMsSql;
3112
3113 /**
3114  * The PDO-based MsSql driver.
3115  *
3116  * @since 2.0
3117  */
3118 class Driver implements \Doctrine\DBAL\Driver
3119 {
3120     public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3121     {
3122         return new Connection(
3123             $this->_constructPdoDsn($params),
3124             $username,
3125             $password,
3126             $driverOptions
3127         );
3128     }
3129
3130     /**
3131      * Constructs the MsSql PDO DSN.
3132      *
3133      * @return string  The DSN.
3134      */
3135     private function _constructPdoDsn(array $params)
3136     {
3137         // TODO: This might need to be revisted once we have access to a mssql server
3138         $dsn = 'mssql:';
3139         if (isset($params['host'])) {
3140             $dsn .= 'host=' . $params['host'] . ';';
3141         }
3142         if (isset($params['port'])) {
3143             $dsn .= 'port=' . $params['port'] . ';';
3144         }
3145         if (isset($params['dbname'])) {
3146             $dsn .= 'dbname=' . $params['dbname'] . ';';
3147         }
3148
3149         return $dsn;
3150     }
3151
3152
3153     public function getDatabasePlatform()
3154     {
3155         return new \Doctrine\DBAL\Platforms\MsSqlPlatform();
3156     }
3157
3158     public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
3159     {
3160         return new \Doctrine\DBAL\Schema\MsSqlSchemaManager($conn);
3161     }
3162
3163     public function getName()
3164     {
3165         return 'pdo_mssql';
3166     }
3167
3168     public function getDatabase(\Doctrine\DBAL\Connection $conn)
3169     {
3170         $params = $conn->getParams();
3171         return $params['dbname'];
3172     }
3173 }<?php
3174 /*
3175  *  $Id$
3176  *
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.
3188  *
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>.
3192  */
3193
3194 namespace Doctrine\DBAL\Driver\PDOMsSql;
3195
3196 /**
3197  * MsSql Connection implementation.
3198  *
3199  * @since 2.0
3200  */
3201 class Connection extends \PDO implements \Doctrine\DBAL\Driver\Connection
3202 {
3203     /**
3204      * Performs the rollback.
3205      * 
3206      * @override
3207      */
3208     public function rollback()
3209     {
3210         $this->exec('ROLLBACK TRANSACTION');
3211     }
3212
3213     /**
3214      * Performs the commit.
3215      * 
3216      * @override
3217      */
3218     public function commit()
3219     {
3220         $this->exec('COMMIT TRANSACTION');
3221     }
3222
3223     /**
3224      * Begins a database transaction.
3225      * 
3226      * @override
3227      */
3228     public function beginTransaction()
3229     {
3230         $this->exec('BEGIN TRANSACTION');
3231     }
3232 }<?php
3233 /*
3234  *  $Id$
3235  *
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.
3247  *
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>.
3251  */
3252
3253 namespace Doctrine\DBAL\Driver;
3254
3255 use \PDO;
3256
3257 /**
3258  * Statement interface.
3259  * Drivers must implement this interface.
3260  * 
3261  * This resembles (a subset of) the PDOStatement interface.
3262  * 
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
3267  * @since       2.0
3268  * @version     $Revision$
3269  */
3270 interface Statement
3271 {
3272     /**
3273      * Binds a value to a corresponding named or positional
3274      * placeholder in the SQL statement that was used to prepare the statement.
3275      *
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
3279      *
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.
3282      *
3283      * @return boolean              Returns TRUE on success or FALSE on failure.
3284      */
3285     function bindValue($param, $value, $type = null);
3286
3287     /**
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.
3292      *
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.
3297      *
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
3301      *
3302      * @param mixed $variable       Name of the PHP variable to bind to the SQL statement parameter.
3303      *
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.
3308      */
3309     function bindParam($column, &$variable, $type = null);
3310
3311     /**
3312      * Closes the cursor, enabling the statement to be executed again.
3313      *
3314      * @return boolean              Returns TRUE on success or FALSE on failure.
3315      */
3316     function closeCursor();
3317
3318     /** 
3319      * columnCount
3320      * Returns the number of columns in the result set 
3321      *
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.
3325      */
3326     function columnCount();
3327
3328     /**
3329      * errorCode
3330      * Fetch the SQLSTATE associated with the last operation on the statement handle 
3331      *
3332      * @see Doctrine_Adapter_Interface::errorCode()
3333      * @return string       error code string
3334      */
3335     function errorCode();
3336
3337     /**
3338      * errorInfo
3339      * Fetch extended error information associated with the last operation on the statement handle
3340      *
3341      * @see Doctrine_Adapter_Interface::errorInfo()
3342      * @return array        error info array
3343      */
3344     function errorInfo();
3345
3346     /**
3347      * Executes a prepared statement
3348      *
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
3353      * parameter values
3354      *
3355      *
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.
3359      */
3360     function execute($params = null);
3361
3362     /**
3363      * fetch
3364      *
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
3369      *
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().
3377      *
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.
3381      *                                      
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.
3386      *
3387      * @return mixed
3388      */
3389     function fetch($fetchStyle = PDO::FETCH_BOTH);
3390
3391     /**
3392      * Returns an array containing all of the result set rows
3393      *
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
3397      *
3398      * @param integer $columnIndex          Returns the indicated 0-indexed column when the value of $fetchStyle is
3399      *                                      Query::HYDRATE_COLUMN. Defaults to 0.
3400      *
3401      * @return array
3402      */
3403     function fetchAll($fetchStyle = PDO::FETCH_BOTH);
3404
3405     /**
3406      * fetchColumn
3407      * Returns a single column from the next row of a
3408      * result set or FALSE if there are no more rows.
3409      *
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.
3413      *
3414      * @return string                       returns a single column in the next row of a result set.
3415      */
3416     function fetchColumn($columnIndex = 0);
3417
3418     /**
3419      * rowCount
3420      * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement 
3421      * executed by the corresponding object.
3422      *
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.
3427      *
3428      * @return integer                      Returns the number of rows.
3429      */
3430     function rowCount();
3431 }<?php
3432
3433 namespace Doctrine\DBAL\Driver\PDOPgSql;
3434
3435 use Doctrine\DBAL\Platforms;
3436
3437 /**
3438  * Driver that connects through pdo_pgsql.
3439  *
3440  * @since 2.0
3441  */
3442 class Driver implements \Doctrine\DBAL\Driver
3443 {
3444     /**
3445      * Attempts to connect to the database and returns a driver connection on success.
3446      *
3447      * @return Doctrine\DBAL\Driver\Connection
3448      */
3449     public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3450     {
3451         return new \Doctrine\DBAL\Driver\PDOConnection(
3452             $this->_constructPdoDsn($params),
3453             $username,
3454             $password,
3455             $driverOptions
3456         );
3457     }
3458
3459     /**
3460      * Constructs the Postgres PDO DSN.
3461      *
3462      * @return string The DSN.
3463      */
3464     private function _constructPdoDsn(array $params)
3465     {
3466         $dsn = 'pgsql:';
3467         if (isset($params['host'])) {
3468             $dsn .= 'host=' . $params['host'] . ' ';
3469         }
3470         if (isset($params['port'])) {
3471             $dsn .= 'port=' . $params['port'] . ' ';
3472         }
3473         if (isset($params['dbname'])) {
3474             $dsn .= 'dbname=' . $params['dbname'] . ' ';
3475         }
3476
3477         return $dsn;
3478     }
3479
3480     public function getDatabasePlatform()
3481     {
3482         return new \Doctrine\DBAL\Platforms\PostgreSqlPlatform();
3483     }
3484
3485     public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
3486     {
3487         return new \Doctrine\DBAL\Schema\PostgreSqlSchemaManager($conn);
3488     }
3489
3490     public function getName()
3491     {
3492         return 'pdo_pgsql';
3493     }
3494
3495     public function getDatabase(\Doctrine\DBAL\Connection $conn)
3496     {
3497         $params = $conn->getParams();
3498         return $params['dbname'];
3499     }
3500 }<?php
3501 /*
3502  *  $Id$
3503  *
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.
3515  *
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>.
3519  */
3520
3521 namespace Doctrine\DBAL\Driver;
3522
3523 use \PDO;
3524
3525 /**
3526  * PDO implementation of the Connection interface.
3527  * Used by all PDO-based drivers.
3528  *
3529  * @since 2.0
3530  */
3531 class PDOConnection extends PDO implements Connection
3532 {
3533     public function __construct($dsn, $user = null, $password = null, array $options = null)
3534     {
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);
3538     }
3539 }<?php
3540 /*
3541  *  $Id$
3542  *
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.
3554  *
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>.
3558 */
3559
3560 namespace Doctrine\DBAL\Driver\PDOIbm;
3561
3562 use Doctrine\DBAL\Connection;
3563
3564 /**
3565  * Driver for the PDO IBM extension
3566  *
3567  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
3568  * @link        www.doctrine-project.com
3569  * @since       1.0
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>
3575  */
3576 class Driver implements \Doctrine\DBAL\Driver
3577 {
3578     /**
3579      * Attempts to establish a connection with the underlying driver.
3580      *
3581      * @param array $params
3582      * @param string $username
3583      * @param string $password
3584      * @param array $driverOptions
3585      * @return Doctrine\DBAL\Driver\Connection
3586      */
3587     public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3588     {
3589         $conn = new \Doctrine\DBAL\Driver\PDOConnection(
3590             $this->_constructPdoDsn($params),
3591             $username,
3592             $password,
3593             $driverOptions
3594         );
3595         return $conn;
3596     }
3597
3598     /**
3599      * Constructs the MySql PDO DSN.
3600      *
3601      * @return string  The DSN.
3602      */
3603     private function _constructPdoDsn(array $params)
3604     {
3605         $dsn = 'ibm:';
3606         if (isset($params['host'])) {
3607             $dsn .= 'HOSTNAME=' . $params['host'] . ';';
3608         }
3609         if (isset($params['port'])) {
3610             $dsn .= 'PORT=' . $params['port'] . ';';
3611         }
3612         $dsn .= 'PROTOCOL=TCPIP;';
3613         if (isset($params['dbname'])) {
3614             $dsn .= 'DATABASE=' . $params['dbname'] . ';';
3615         }
3616
3617         return $dsn;
3618     }
3619
3620     /**
3621      * Gets the DatabasePlatform instance that provides all the metadata about
3622      * the platform this driver connects to.
3623      *
3624      * @return Doctrine\DBAL\Platforms\AbstractPlatform The database platform.
3625      */
3626     public function getDatabasePlatform()
3627     {
3628         return new \Doctrine\DBAL\Platforms\DB2Platform;
3629     }
3630
3631     /**
3632      * Gets the SchemaManager that can be used to inspect and change the underlying
3633      * database schema of the platform this driver connects to.
3634      *
3635      * @param  Doctrine\DBAL\Connection $conn
3636      * @return Doctrine\DBAL\SchemaManager
3637      */
3638     public function getSchemaManager(Connection $conn)
3639     {
3640         return new \Doctrine\DBAL\Schema\DB2SchemaManager($conn);
3641     }
3642
3643     /**
3644      * Gets the name of the driver.
3645      *
3646      * @return string The name of the driver.
3647      */
3648     public function getName()
3649     {
3650         return 'pdo_ibm';
3651     }
3652
3653     /**
3654      * Get the name of the database connected to for this driver.
3655      *
3656      * @param  Doctrine\DBAL\Connection $conn
3657      * @return string $database
3658      */
3659     public function getDatabase(\Doctrine\DBAL\Connection $conn)
3660     {
3661         $params = $conn->getParams();
3662         return $params['dbname'];
3663     }
3664 }<?php
3665 /*
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.
3677  *
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>.
3681  */
3682
3683 namespace Doctrine\DBAL\Driver\PDOMySql;
3684
3685 use Doctrine\DBAL\Connection;
3686
3687 /**
3688  * PDO MySql driver.
3689  *
3690  * @since 2.0
3691  */
3692 class Driver implements \Doctrine\DBAL\Driver
3693 {
3694     /**
3695      * Attempts to establish a connection with the underlying driver.
3696      *
3697      * @param array $params
3698      * @param string $username
3699      * @param string $password
3700      * @param array $driverOptions
3701      * @return Doctrine\DBAL\Driver\Connection
3702      */
3703     public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3704     {
3705         $conn = new \Doctrine\DBAL\Driver\PDOConnection(
3706             $this->_constructPdoDsn($params),
3707             $username,
3708             $password,
3709             $driverOptions
3710         );
3711         return $conn;
3712     }
3713
3714     /**
3715      * Constructs the MySql PDO DSN.
3716      *
3717      * @return string  The DSN.
3718      */
3719     private function _constructPdoDsn(array $params)
3720     {
3721         $dsn = 'mysql:';
3722         if (isset($params['host'])) {
3723             $dsn .= 'host=' . $params['host'] . ';';
3724         }
3725         if (isset($params['port'])) {
3726             $dsn .= 'port=' . $params['port'] . ';';
3727         }
3728         if (isset($params['dbname'])) {
3729             $dsn .= 'dbname=' . $params['dbname'] . ';';
3730         }
3731         if (isset($params['unix_socket'])) {
3732             $dsn .= 'unix_socket=' . $params['unix_socket'] . ';';
3733         }
3734         
3735         return $dsn;
3736     }
3737
3738     public function getDatabasePlatform()
3739     {
3740         return new \Doctrine\DBAL\Platforms\MySqlPlatform();
3741     }
3742
3743     public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
3744     {
3745         return new \Doctrine\DBAL\Schema\MySqlSchemaManager($conn);
3746     }
3747
3748     public function getName()
3749     {
3750         return 'pdo_mysql';
3751     }
3752
3753     public function getDatabase(\Doctrine\DBAL\Connection $conn)
3754     {
3755         $params = $conn->getParams();
3756         return $params['dbname'];
3757     }
3758 }<?php
3759 /*
3760  *  $Id$
3761  *
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.
3773  *
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>.
3777  */
3778
3779 namespace Doctrine\DBAL\Driver\PDOSqlsrv;
3780
3781 /**
3782  * The PDO-based Sqlsrv driver.
3783  *
3784  * @since 2.0
3785  */
3786 class Driver implements \Doctrine\DBAL\Driver
3787 {
3788     public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3789     {        
3790         return new \Doctrine\DBAL\Driver\PDOConnection(
3791             $this->_constructPdoDsn($params),
3792             $username,
3793             $password,
3794             $driverOptions
3795         );
3796     }
3797
3798     /**
3799      * Constructs the Sqlsrv PDO DSN.
3800      *
3801      * @return string  The DSN.
3802      */
3803     private function _constructPdoDsn(array $params)
3804     {
3805         $dsn = 'sqlsrv:server=';
3806                 
3807         if (isset($params['host'])) {
3808             $dsn .= $params['host'];
3809         }
3810                 
3811         if (isset($params['port']) && !empty($params['port'])) {
3812             $dsn .= ',' . $params['port'];
3813         }
3814                 
3815                 if (isset($params['dbname'])) {
3816                         $dsn .= ';Database=' .  $params['dbname'];
3817                 }
3818                 
3819         return $dsn;
3820     }
3821
3822
3823     public function getDatabasePlatform()
3824     {
3825         return new \Doctrine\DBAL\Platforms\MsSqlPlatform();
3826     }
3827
3828     public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
3829     {
3830         return new \Doctrine\DBAL\Schema\MsSqlSchemaManager($conn);
3831     }
3832
3833     public function getName()
3834     {
3835         return 'pdo_sqlsrv';
3836     }
3837
3838     public function getDatabase(\Doctrine\DBAL\Connection $conn)
3839     {
3840         $params = $conn->getParams();
3841         return $params['dbname'];
3842     }
3843 }<?php
3844 /*
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.
3856  *
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>.
3860  */
3861
3862 namespace Doctrine\DBAL\Driver\PDOSqlite;
3863
3864 /**
3865  * The PDO Sqlite driver.
3866  *
3867  * @since 2.0
3868  */
3869 class Driver implements \Doctrine\DBAL\Driver
3870 {
3871     /**
3872      * @var array
3873      */
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),
3878     );
3879
3880     /**
3881      * Tries to establish a database connection to SQLite.
3882      *
3883      * @param array $params
3884      * @param string $username
3885      * @param string $password
3886      * @param array $driverOptions
3887      * @return Connection
3888      */
3889     public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
3890     {
3891         if (isset($driverOptions['userDefinedFunctions'])) {
3892             $this->_userDefinedFunctions = array_merge(
3893                 $this->_userDefinedFunctions, $driverOptions['userDefinedFunctions']);
3894             unset($driverOptions['userDefinedFunctions']);
3895         }
3896
3897         $pdo = new \Doctrine\DBAL\Driver\PDOConnection(
3898             $this->_constructPdoDsn($params),
3899             $username,
3900             $password,
3901             $driverOptions
3902         );
3903
3904         foreach ($this->_userDefinedFunctions AS $fn => $data) {
3905             $pdo->sqliteCreateFunction($fn, $data['callback'], $data['numArgs']);
3906         }
3907
3908         return $pdo;
3909     }
3910
3911     /**
3912      * Constructs the Sqlite PDO DSN.
3913      *
3914      * @return string  The DSN.
3915      * @override
3916      */
3917     protected function _constructPdoDsn(array $params)
3918     {
3919         $dsn = 'sqlite:';
3920         if (isset($params['path'])) {
3921             $dsn .= $params['path'];
3922         } else if (isset($params['memory'])) {
3923             $dsn .= ':memory:';
3924         }
3925         
3926         return $dsn;
3927     }
3928
3929     /**
3930      * Gets the database platform that is relevant for this driver.
3931      */
3932     public function getDatabasePlatform()
3933     {
3934         return new \Doctrine\DBAL\Platforms\SqlitePlatform();
3935     }
3936
3937     /**
3938      * Gets the schema manager that is relevant for this driver.
3939      *
3940      * @param Doctrine\DBAL\Connection $conn
3941      * @return Doctrine\DBAL\Schema\SqliteSchemaManager
3942      */
3943     public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
3944     {
3945         return new \Doctrine\DBAL\Schema\SqliteSchemaManager($conn);
3946     }
3947
3948     public function getName()
3949     {
3950         return 'pdo_sqlite';
3951     }
3952
3953     public function getDatabase(\Doctrine\DBAL\Connection $conn)
3954     {
3955         $params = $conn->getParams();
3956         return isset($params['path']) ? $params['path'] : null;
3957     }
3958 }<?php
3959 /*
3960  *  $Id$
3961  *
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.
3973  *
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>.
3977 */
3978
3979 namespace Doctrine\DBAL\Driver\OCI8;
3980
3981 class OCI8Exception extends \Exception
3982 {
3983     static public function fromErrorInfo($error)
3984     {
3985         return new self($error['message'], $error['code']);
3986     }
3987 }
3988 <?php
3989 /*
3990  *  $Id$
3991  *
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.
4003  *
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>.
4007  */
4008
4009 namespace Doctrine\DBAL\Driver\OCI8;
4010
4011 use Doctrine\DBAL\Platforms;
4012
4013 /**
4014  * A Doctrine DBAL driver for the Oracle OCI8 PHP extensions.
4015  * 
4016  * @author Roman Borschel <roman@code-factory.org>
4017  * @since 2.0
4018  */
4019 class Driver implements \Doctrine\DBAL\Driver
4020 {
4021     public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
4022     {
4023         return new OCI8Connection(
4024             $username,
4025             $password,
4026             $this->_constructDsn($params)
4027         );
4028     }
4029
4030     /**
4031      * Constructs the Oracle DSN.
4032      *
4033      * @return string The DSN.
4034      */
4035     private function _constructDsn(array $params)
4036     {
4037         $dsn = '';
4038         if (isset($params['host'])) {
4039             $dsn .= '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)' .
4040                    '(HOST=' . $params['host'] . ')';
4041
4042             if (isset($params['port'])) {
4043                 $dsn .= '(PORT=' . $params['port'] . ')';
4044             } else {
4045                 $dsn .= '(PORT=1521)';
4046             }
4047
4048             $dsn .= '))';
4049             if (isset($params['dbname'])) {
4050                 $dsn .= '(CONNECT_DATA=(SID=' . $params['dbname'] . ')';
4051             }
4052             $dsn .= '))';
4053         } else {
4054             $dsn .= $params['dbname'];
4055         }
4056
4057         if (isset($params['charset'])) {
4058             $dsn .= ';charset=' . $params['charset'];
4059         }
4060
4061         return $dsn;
4062     }
4063
4064     public function getDatabasePlatform()
4065     {
4066         return new \Doctrine\DBAL\Platforms\OraclePlatform();
4067     }
4068
4069     public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
4070     {
4071         return new \Doctrine\DBAL\Schema\OracleSchemaManager($conn);
4072     }
4073
4074     public function getName()
4075     {
4076         return 'oci8';
4077     }
4078
4079     public function getDatabase(\Doctrine\DBAL\Connection $conn)
4080     {
4081         $params = $conn->getParams();
4082         return $params['user'];
4083     }
4084 }<?php
4085 /*
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.
4097  *
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>.
4101  */
4102
4103 namespace Doctrine\DBAL\Driver\OCI8;
4104
4105 use \PDO;
4106
4107 /**
4108  * The OCI8 implementation of the Statement interface.
4109  *
4110  * @since 2.0
4111  * @author Roman Borschel <roman@code-factory.org>
4112  */
4113 class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
4114 {
4115     /** Statement handle. */
4116     private $_sth;
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
4122     );
4123     private $_paramMap = array();
4124
4125     /**
4126      * Creates a new OCI8Statement that uses the given connection handle and SQL statement.
4127      *
4128      * @param resource $dbh The connection handle.
4129      * @param string $statement The SQL statement.
4130      */
4131     public function __construct($dbh, $statement)
4132     {
4133         list($statement, $paramMap) = self::convertPositionalToNamedPlaceholders($statement);
4134         $this->_sth = oci_parse($dbh, $statement);
4135         $this->_paramMap = $paramMap;
4136     }
4137
4138     /**
4139      * Convert positional (?) into named placeholders (:param<num>)
4140      *
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.
4145      *
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.
4149      *
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.
4153      * @return string
4154      */
4155     static public function convertPositionalToNamedPlaceholders($statement)
4156     {   
4157         $count = 1;
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
4169                 ++$count;
4170             } else if ($statement[$i] == "'" || $statement[$i] == '"') {
4171                 $inLiteral = ! $inLiteral; // switch state!
4172             }
4173         }
4174
4175         return array($statement, $paramMap);
4176     }
4177
4178     /**
4179      * {@inheritdoc}
4180      */
4181     public function bindValue($param, $value, $type = null)
4182     {
4183         return $this->bindParam($param, $value, $type);
4184     }
4185
4186     /**
4187      * {@inheritdoc}
4188      */
4189     public function bindParam($column, &$variable, $type = null)
4190     {
4191         $column = isset($this->_paramMap[$column]) ? $this->_paramMap[$column] : $column;
4192         
4193         return oci_bind_by_name($this->_sth, $column, $variable);
4194     }
4195
4196     /**
4197      * Closes the cursor, enabling the statement to be executed again.
4198      *
4199      * @return boolean              Returns TRUE on success or FALSE on failure.
4200      */
4201     public function closeCursor()
4202     {
4203         return oci_free_statement($this->_sth);
4204     }
4205
4206     /** 
4207      * {@inheritdoc}
4208      */
4209     public function columnCount()
4210     {
4211         return oci_num_fields($this->_sth);
4212     }
4213
4214     /**
4215      * {@inheritdoc}
4216      */
4217     public function errorCode()
4218     {
4219         $error = oci_error($this->_sth);
4220         if ($error !== false) {
4221             $error = $error['code'];
4222         }
4223         return $error;
4224     }
4225     
4226     /**
4227      * {@inheritdoc}
4228      */
4229     public function errorInfo()
4230     {
4231         return oci_error($this->_sth);
4232     }
4233
4234     /**
4235      * {@inheritdoc}
4236      */
4237     public function execute($params = null)
4238     {
4239         if ($params) {
4240             $hasZeroIndex = isset($params[0]);
4241             foreach ($params as $key => $val) {
4242                 if ($hasZeroIndex && is_numeric($key)) {
4243                     $this->bindValue($key + 1, $val);
4244                 } else {
4245                     $this->bindValue($key, $val);
4246                 }
4247             }
4248         }
4249
4250         $ret = @oci_execute($this->_sth, OCI_DEFAULT);
4251         if ( ! $ret) {
4252             throw OCI8Exception::fromErrorInfo($this->errorInfo());
4253         }
4254         return $ret;
4255     }
4256
4257     /**
4258      * {@inheritdoc}
4259      */
4260     public function fetch($fetchStyle = PDO::FETCH_BOTH)
4261     {
4262         if ( ! isset(self::$fetchStyleMap[$fetchStyle])) {
4263             throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle);
4264         }
4265         
4266         return oci_fetch_array($this->_sth, self::$fetchStyleMap[$fetchStyle] | OCI_RETURN_NULLS | OCI_RETURN_LOBS);
4267     }
4268
4269     /**
4270      * {@inheritdoc}
4271      */
4272     public function fetchAll($fetchStyle = PDO::FETCH_BOTH)
4273     {
4274         if ( ! isset(self::$fetchStyleMap[$fetchStyle])) {
4275             throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle);
4276         }
4277         
4278         $result = array();
4279         oci_fetch_all($this->_sth, $result, 0, -1,
4280             self::$fetchStyleMap[$fetchStyle] | OCI_RETURN_NULLS | OCI_FETCHSTATEMENT_BY_ROW | OCI_RETURN_LOBS);
4281         
4282         return $result;
4283     }
4284
4285     /**
4286      * {@inheritdoc}
4287      */
4288     public function fetchColumn($columnIndex = 0)
4289     {
4290         $row = oci_fetch_array($this->_sth, OCI_NUM | OCI_RETURN_NULLS | OCI_RETURN_LOBS);
4291         return $row[$columnIndex];
4292     }
4293
4294     /**
4295      * {@inheritdoc}
4296      */
4297     public function rowCount()
4298     {
4299         return oci_num_rows($this->_sth);
4300     }    
4301 }<?php
4302 /*
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.
4314  *
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>.
4318  */
4319
4320 namespace Doctrine\DBAL\Driver\OCI8;
4321
4322 /**
4323  * OCI8 implementation of the Connection interface.
4324  *
4325  * @since 2.0
4326  */
4327 class OCI8Connection implements \Doctrine\DBAL\Driver\Connection
4328 {
4329     private $_dbh;
4330
4331     /**
4332      * Create a Connection to an Oracle Database using oci8 extension.
4333      * 
4334      * @param string $username
4335      * @param string $password
4336      * @param string $db
4337      */
4338     public function __construct($username, $password, $db)
4339     {
4340         $this->_dbh = @oci_connect($username, $password, $db);
4341         if (!$this->_dbh) {
4342             throw new OCI8Exception($this->errorInfo());
4343         }
4344     }
4345
4346     /**
4347      * Create a non-executed prepared statement.
4348      * 
4349      * @param  string $prepareString
4350      * @return OCI8Statement
4351      */
4352     public function prepare($prepareString)
4353     {
4354         return new OCI8Statement($this->_dbh, $prepareString);
4355     }
4356
4357     /**
4358      * @param string $sql
4359      * @return OCI8Statement
4360      */
4361     public function query()
4362     {
4363         $args = func_get_args();
4364         $sql = $args[0];
4365         //$fetchMode = $args[1];
4366         $stmt = $this->prepare($sql);
4367         $stmt->execute();
4368         return $stmt;
4369     }
4370
4371     /**
4372      * Quote input value.
4373      *
4374      * @param mixed $input
4375      * @param int $type PDO::PARAM* 
4376      * @return mixed
4377      */
4378     public function quote($input, $type=\PDO::PARAM_STR)
4379     {
4380         return is_numeric($input) ? $input : "'$input'";
4381     }
4382
4383     /**
4384      *
4385      * @param  string $statement
4386      * @return int
4387      */
4388     public function exec($statement)
4389     {
4390         $stmt = $this->prepare($statement);
4391         $stmt->execute();
4392         return $stmt->rowCount();
4393     }
4394     
4395     public function lastInsertId($name = null)
4396     {
4397         //TODO: throw exception or support sequences?
4398     }
4399
4400     /**
4401      * Start a transactiom
4402      *
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.
4406      *
4407      * @return bool
4408      */
4409     public function beginTransaction()
4410     {
4411         return true;
4412     }
4413
4414     /**
4415      * @throws OCI8Exception
4416      * @return bool
4417      */
4418     public function commit()
4419     {
4420         if (!oci_commit($this->_dbh)) {
4421             throw OCI8Exception::fromErrorInfo($this->errorInfo());
4422         }
4423         return true;
4424     }
4425
4426     /**
4427      * @throws OCI8Exception
4428      * @return bool
4429      */
4430     public function rollBack()
4431     {
4432         if (!oci_rollback($this->_dbh)) {
4433             throw OCI8Exception::fromErrorInfo($this->errorInfo());
4434         }
4435         return true;
4436     }
4437     
4438     public function errorCode()
4439     {
4440         $error = oci_error($this->_dbh);
4441         if ($error !== false) {
4442             $error = $error['code'];
4443         }
4444         return $error;
4445     }
4446     
4447     public function errorInfo()
4448     {
4449         return oci_error($this->_dbh);
4450     }
4451 }<?php
4452 /*
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.
4464  *
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>.
4468  */
4469
4470 namespace Doctrine\DBAL\Driver;
4471
4472 /**
4473  * Connection interface.
4474  * Driver connections must implement this interface.
4475  *
4476  * This resembles (a subset of) the PDO interface.
4477  * 
4478  * @since 2.0
4479  */
4480 interface Connection
4481 {
4482     function prepare($prepareString);
4483     function query();
4484     function quote($input, $type=\PDO::PARAM_STR);
4485     function exec($statement);
4486     function lastInsertId($name = null);
4487     function beginTransaction();
4488     function commit();
4489     function rollBack();
4490     function errorCode();
4491     function errorInfo();
4492 }<?php
4493 /*
4494  *  $Id$
4495  *
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.
4507  *
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>.
4511  */
4512
4513 namespace Doctrine\DBAL;
4514
4515 /**
4516  * Container for all DBAL events.
4517  *
4518  * This class cannot be instantiated.
4519  *
4520  * @author Roman Borschel <roman@code-factory.org>
4521  * @since 2.0
4522  */
4523 final class Events
4524 {
4525     private function __construct() {}
4526
4527     const postConnect = 'postConnect';
4528 }
4529
4530 <?php
4531 /*
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.
4543  *
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>.
4547  */
4548
4549 namespace Doctrine\DBAL;
4550
4551 use Doctrine\Common\EventManager;
4552
4553 /**
4554  * Factory for creating Doctrine\DBAL\Connection instances.
4555  *
4556  * @author Roman Borschel <roman@code-factory.org>
4557  * @since 2.0
4558  */
4559 final class DriverManager
4560 {
4561     /**
4562      * List of supported drivers and their mappings to the driver classes.
4563      *
4564      * @var array
4565      * @todo REMOVE. Users should directly supply class names instead.
4566      */
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',
4577             );
4578
4579     /** Private constructor. This class cannot be instantiated. */
4580     private function __construct() { }
4581
4582     /**
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.
4586      *
4587      * $params must contain at least one of the following.
4588      * 
4589      * Either 'driver' with one of the following values:
4590      *     pdo_mysql
4591      *     pdo_sqlite
4592      *     pdo_pgsql
4593      *     pdo_oracle
4594      *     pdo_mssql
4595      * 
4596      * OR 'driverClass' that contains the full class name (with namespace) of the
4597      * driver class to instantiate.
4598      * 
4599      * Other (optional) parameters:
4600      * 
4601      * <b>user (string)</b>:
4602      * The username to use when connecting. 
4603      * 
4604      * <b>password (string)</b>:
4605      * The password to use when connecting.
4606      * 
4607      * <b>driverOptions (array)</b>:
4608      * Any additional driver-specific options for the driver. These are just passed
4609      * through to the driver.
4610      * 
4611      * <b>pdo</b>:
4612      * You can pass an existing PDO instance through this parameter. The PDO
4613      * instance will be wrapped in a Doctrine\DBAL\Connection.
4614      * 
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.
4618      * 
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
4623      */
4624     public static function getConnection(
4625             array $params,
4626             Configuration $config = null,
4627             EventManager $eventManager = null)
4628     {
4629         // create default config and event manager, if not set
4630         if ( ! $config) {
4631             $config = new Configuration();
4632         }
4633         if ( ! $eventManager) {
4634             $eventManager = new EventManager();
4635         }
4636         
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);
4643         } else {
4644             self::_checkParams($params);
4645         }
4646         if (isset($params['driverClass'])) {
4647             $className = $params['driverClass'];
4648         } else {
4649             $className = self::$_driverMap[$params['driver']];
4650         }
4651         
4652         $driver = new $className();
4653         
4654         $wrapperClass = 'Doctrine\DBAL\Connection';
4655         if (isset($params['wrapperClass'])) {
4656             if (is_subclass_of($params['wrapperClass'], $wrapperClass)) {
4657                $wrapperClass = $params['wrapperClass'];
4658             } else {
4659                 throw DBALException::invalidWrapperClass($params['wrapperClass']);
4660             }
4661         }
4662         
4663         return new $wrapperClass($params, $driver, $config, $eventManager);
4664     }
4665
4666     /**
4667      * Checks the list of parameters.
4668      *
4669      * @param array $params
4670      */
4671     private static function _checkParams(array $params)
4672     {        
4673         // check existance of mandatory parameters
4674         
4675         // driver
4676         if ( ! isset($params['driver']) && ! isset($params['driverClass'])) {
4677             throw DBALException::driverRequired();
4678         }
4679         
4680         // check validity of parameters
4681         
4682         // driver
4683         if ( isset($params['driver']) && ! isset(self::$_driverMap[$params['driver']])) {
4684             throw DBALException::unknownDriver($params['driver'], array_keys(self::$_driverMap));
4685         }
4686
4687         if (isset($params['driverClass']) && ! in_array('Doctrine\DBAL\Driver', class_implements($params['driverClass'], true))) {
4688             throw DBALException::invalidDriverClass($params['driverClass']);
4689         }
4690     }
4691 }<?php 
4692 /*
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.
4704  *
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>.
4708  */
4709
4710 namespace Doctrine\DBAL;
4711
4712 use Doctrine\DBAL\Logging\SQLLogger;
4713
4714 /**
4715  * Configuration container for the Doctrine DBAL.
4716  *
4717  * @since   2.0
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.
4723  */
4724 class Configuration
4725 {
4726     /**
4727      * The attributes that are contained in the configuration.
4728      * Values are default values.
4729      *
4730      * @var array
4731      */
4732     protected $_attributes = array();
4733
4734     /**
4735      * Sets the SQL logger to use. Defaults to NULL which means SQL logging is disabled.
4736      *
4737      * @param SQLLogger $logger
4738      */
4739     public function setSQLLogger(SQLLogger $logger)
4740     {
4741         $this->_attributes['sqlLogger'] = $logger;
4742     }
4743
4744     /**
4745      * Gets the SQL logger that is used.
4746      * 
4747      * @return SQLLogger
4748      */
4749     public function getSQLLogger()
4750     {
4751         return isset($this->_attributes['sqlLogger']) ?
4752                 $this->_attributes['sqlLogger'] : null;
4753     }
4754 }<?php
4755 /*
4756  *  $Id$
4757  *
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.
4769  *
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>.
4773  */
4774
4775 namespace Doctrine\DBAL;
4776
4777 use PDO,
4778     Doctrine\DBAL\Types\Type,
4779     Doctrine\DBAL\Driver\Statement as DriverStatement;
4780
4781 /**
4782  * A thin wrapper around a Doctrine\DBAL\Driver\Statement that adds support
4783  * for logging, DBAL mapping types, etc.
4784  * 
4785  * @author Roman Borschel <roman@code-factory.org>
4786  * @since 2.0
4787  */
4788 class Statement implements DriverStatement
4789 {
4790     /**
4791      * @var string The SQL statement.
4792      */
4793     private $_sql;
4794     /**
4795      * @var array The bound parameters.
4796      */
4797     private $_params = array();
4798     /**
4799      * @var Doctrine\DBAL\Driver\Statement The underlying driver statement.
4800      */
4801     private $_stmt;
4802     /**
4803      * @var Doctrine\DBAL\Platforms\AbstractPlatform The underlying database platform.
4804      */
4805     private $_platform;
4806     /**
4807      * @var Doctrine\DBAL\Connection The connection this statement is bound to and executed on.
4808      */
4809     private $_conn;
4810
4811     /**
4812      * Creates a new <tt>Statement</tt> for the given SQL and <tt>Connection</tt>.
4813      *
4814      * @param string $sql The SQL of the statement.
4815      * @param Doctrine\DBAL\Connection The connection on which the statement should be executed.
4816      */
4817     public function __construct($sql, Connection $conn)
4818     {
4819         $this->_sql = $sql;
4820         $this->_stmt = $conn->getWrappedConnection()->prepare($sql);
4821         $this->_conn = $conn;
4822         $this->_platform = $conn->getDatabasePlatform();
4823     }
4824
4825     /**
4826      * Binds a parameter value to the statement.
4827      * 
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
4831      * being bound.
4832      * 
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.
4837      */
4838     public function bindValue($name, $value, $type = null)
4839     {
4840         $this->_params[$name] = $value;
4841         if ($type !== null) {
4842             if (is_string($type)) {
4843                 $type = Type::getType($type);
4844             }
4845             if ($type instanceof Type) {
4846                 $value = $type->convertToDatabaseValue($value, $this->_platform);
4847                 $bindingType = $type->getBindingType();
4848             } else {
4849                 $bindingType = $type; // PDO::PARAM_* constants
4850             }
4851             return $this->_stmt->bindValue($name, $value, $bindingType);
4852         } else {
4853             return $this->_stmt->bindValue($name, $value);
4854         }
4855     }
4856
4857     /**
4858      * Binds a parameter to a value by reference.
4859      * 
4860      * Binding a parameter by reference does not support DBAL mapping types.
4861      * 
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.
4866      */
4867     public function bindParam($name, &$var, $type = PDO::PARAM_STR)
4868     {
4869         return $this->_stmt->bindParam($name, $var, $type);
4870     }
4871
4872     /**
4873      * Executes the statement with the currently bound parameters.
4874      * 
4875      * @return boolean TRUE on success, FALSE on failure.
4876      */
4877     public function execute($params = null)
4878     {
4879         $hasLogger = $this->_conn->getConfiguration()->getSQLLogger();
4880         if ($hasLogger) {
4881             $this->_conn->getConfiguration()->getSQLLogger()->startQuery($this->_sql, $this->_params);
4882         }
4883
4884         $stmt = $this->_stmt->execute($params);
4885
4886         if ($hasLogger) {
4887             $this->_conn->getConfiguration()->getSQLLogger()->stopQuery();
4888         }
4889         $this->_params = array();
4890         return $stmt;
4891     }
4892
4893     /**
4894      * Closes the cursor, freeing the database resources used by this statement. 
4895      * 
4896      * @return boolean TRUE on success, FALSE on failure.
4897      */
4898     public function closeCursor()
4899     {
4900         return $this->_stmt->closeCursor();
4901     }
4902
4903     /**
4904      * Returns the number of columns in the result set.
4905      * 
4906      * @return integer
4907      */
4908     public function columnCount()
4909     {
4910         return $this->_stmt->columnCount();
4911     }
4912
4913     /**
4914      * Fetches the SQLSTATE associated with the last operation on the statement.
4915      * 
4916      * @return string
4917      */
4918     public function errorCode()
4919     {
4920         return $this->_stmt->errorCode();
4921     }
4922
4923     /**
4924      * Fetches extended error information associated with the last operation on the statement.
4925      * 
4926      * @return array
4927      */
4928     public function errorInfo()
4929     {
4930         return $this->_stmt->errorInfo();
4931     }
4932
4933     /**
4934      * Fetches the next row from a result set.
4935      * 
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.
4939      */
4940     public function fetch($fetchStyle = PDO::FETCH_BOTH)
4941     {
4942         return $this->_stmt->fetch($fetchStyle);
4943     }
4944
4945     /**
4946      * Returns an array containing all of the result set rows.
4947      * 
4948      * @param integer $fetchStyle
4949      * @param integer $columnIndex
4950      * @return array An array containing all of the remaining rows in the result set.
4951      */
4952     public function fetchAll($fetchStyle = PDO::FETCH_BOTH, $columnIndex = 0)
4953     {
4954         if ($columnIndex != 0) {
4955             return $this->_stmt->fetchAll($fetchStyle, $columnIndex);
4956         }
4957         return $this->_stmt->fetchAll($fetchStyle);
4958     }
4959
4960     /**
4961      * Returns a single column from the next row of a result set.
4962      * 
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. 
4965      */
4966     public function fetchColumn($columnIndex = 0)
4967     {
4968         return $this->_stmt->fetchColumn($columnIndex);
4969     }
4970
4971     /**
4972      * Returns the number of rows affected by the last execution of this statement.
4973      * 
4974      * @return integer The number of affected rows.
4975      */
4976     public function rowCount()
4977     {
4978         return $this->_stmt->rowCount();
4979     }
4980
4981     /**
4982      * Gets the wrapped driver statement.
4983      * 
4984      * @return Doctrine\DBAL\Driver\Statement
4985      */
4986     public function getWrappedStatement()
4987     {
4988         return $this->_stmt;
4989     }
4990 }<?php
4991 /*
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.
5003  *
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>.
5007  */
5008
5009 namespace Doctrine\DBAL\Schema;
5010
5011 /**
5012  * Schema manager for the MySql RDBMS.
5013  *
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$
5020  * @since       2.0
5021  */
5022 class MySqlSchemaManager extends AbstractSchemaManager
5023 {
5024     protected function _getPortableViewDefinition($view)
5025     {
5026         return new View($view['TABLE_NAME'], $view['VIEW_DEFINITION']);
5027     }
5028
5029     protected function _getPortableTableDefinition($table)
5030     {
5031         return array_shift($table);
5032     }
5033
5034     protected function _getPortableUserDefinition($user)
5035     {
5036         return array(
5037             'user' => $user['User'],
5038             'password' => $user['Password'],
5039         );
5040     }
5041
5042     protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
5043     {
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;
5048             } else {
5049                 $v['primary'] = false;
5050             }
5051             $tableIndexes[$k] = $v;
5052         }
5053         
5054         return parent::_getPortableTableIndexesList($tableIndexes, $tableName);
5055     }
5056
5057     protected function _getPortableSequenceDefinition($sequence)
5058     {
5059         return end($sequence);
5060     }
5061
5062     protected function _getPortableDatabaseDefinition($database)
5063     {
5064         return $database['Database'];
5065     }
5066     
5067     /**
5068      * Gets a portable column definition.
5069      * 
5070      * The database type is mapped to a corresponding Doctrine mapping type.
5071      * 
5072      * @param $tableColumn
5073      * @return array
5074      */
5075     protected function _getPortableTableColumnDefinition($tableColumn)
5076     {
5077         $tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
5078
5079         $dbType = strtolower($tableColumn['type']);
5080         $dbType = strtok($dbType, '(), ');
5081         if (isset($tableColumn['length'])) {
5082             $length = $tableColumn['length'];
5083             $decimal = '';
5084         } else {
5085             $length = strtok('(), ');
5086             $decimal = strtok('(), ') ? strtok('(), '):null;
5087         }
5088         $type = array();
5089         $unsigned = $fixed = null;
5090
5091         if ( ! isset($tableColumn['name'])) {
5092             $tableColumn['name'] = '';
5093         }
5094         
5095         $scale = null;
5096         $precision = null;
5097         
5098         $type = $this->_platform->getDoctrineTypeMapping($dbType);
5099         switch ($dbType) {
5100             case 'char':
5101                 $fixed = true;
5102                 break;
5103             case 'float':
5104             case 'double':
5105             case 'real':
5106             case 'numeric':
5107             case 'decimal':
5108                 if(preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['type'], $match)) {
5109                     $precision = $match[1];
5110                     $scale = $match[2];
5111                     $length = null;
5112                 }
5113                 break;
5114             case 'tinyint':
5115             case 'smallint':
5116             case 'mediumint':
5117             case 'int':
5118             case 'integer':
5119             case 'bigint':
5120             case 'tinyblob':
5121             case 'mediumblob':
5122             case 'longblob':
5123             case 'blob':
5124             case 'binary':
5125             case 'varbinary':
5126             case 'year':
5127                 $length = null;
5128                 break;
5129         }
5130
5131         $length = ((int) $length == 0) ? null : (int) $length;
5132         $def =  array(
5133             'type' => $type,
5134             'length' => $length,
5135             'unsigned' => (bool) $unsigned,
5136             'fixed' => (bool) $fixed
5137         );
5138
5139         $options = array(
5140             'length'        => $length,
5141             'unsigned'      => (bool)$unsigned,
5142             'fixed'         => (bool)$fixed,
5143             'default'       => $tableColumn['default'],
5144             'notnull'       => (bool) ($tableColumn['null'] != 'YES'),
5145             'scale'         => null,
5146             'precision'     => null,
5147             'autoincrement' => (bool) (strpos($tableColumn['extra'], 'auto_increment') !== false),
5148         );
5149
5150         if ($scale !== null && $precision !== null) {
5151             $options['scale'] = $scale;
5152             $options['precision'] = $precision;
5153         }
5154
5155         return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options);
5156     }
5157
5158     public function _getPortableTableForeignKeyDefinition($tableForeignKey)
5159     {
5160         $tableForeignKey = array_change_key_case($tableForeignKey, CASE_LOWER);
5161
5162         if (!isset($tableForeignKey['delete_rule']) || $tableForeignKey['delete_rule'] == "RESTRICT") {
5163             $tableForeignKey['delete_rule'] = null;
5164         }
5165         if (!isset($tableForeignKey['update_rule']) || $tableForeignKey['update_rule'] == "RESTRICT") {
5166             $tableForeignKey['update_rule'] = null;
5167         }
5168         
5169         return new ForeignKeyConstraint(
5170             (array)$tableForeignKey['column_name'],
5171             $tableForeignKey['referenced_table_name'],
5172             (array)$tableForeignKey['referenced_column_name'],
5173             $tableForeignKey['constraint_name'],
5174             array(
5175                 'onUpdate' => $tableForeignKey['update_rule'],
5176                 'onDelete' => $tableForeignKey['delete_rule'],
5177             )
5178         );
5179     }
5180 }<?php
5181
5182 /*
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.
5194  *
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>.
5198  */
5199
5200 namespace Doctrine\DBAL\Schema;
5201
5202 /**
5203  * xxx
5204  *
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$
5210  * @since       2.0
5211  */
5212 class PostgreSqlSchemaManager extends AbstractSchemaManager
5213 {
5214
5215     protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
5216     {
5217         $onUpdate = null;
5218         $onDelete = null;
5219
5220         if (preg_match('(ON UPDATE ([a-zA-Z0-9]+))', $tableForeignKey['condef'], $match)) {
5221             $onUpdate = $match[1];
5222         }
5223         if (preg_match('(ON DELETE ([a-zA-Z0-9]+))', $tableForeignKey['condef'], $match)) {
5224             $onDelete = $match[1];
5225         }
5226
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];
5231         }
5232
5233         return new ForeignKeyConstraint(
5234                 $localColumns, $foreignTable, $foreignColumns, $tableForeignKey['conname'],
5235                 array('onUpdate' => $onUpdate, 'onDelete' => $onDelete)
5236         );
5237     }
5238
5239     public function dropDatabase($database)
5240     {
5241         $params = $this->_conn->getParams();
5242         $params["dbname"] = "postgres";
5243         $tmpPlatform = $this->_platform;
5244         $tmpConn = $this->_conn;
5245
5246         $this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params);
5247         $this->_platform = $this->_conn->getDatabasePlatform();
5248
5249         parent::dropDatabase($database);
5250
5251         $this->_platform = $tmpPlatform;
5252         $this->_conn = $tmpConn;
5253     }
5254
5255     public function createDatabase($database)
5256     {
5257         $params = $this->_conn->getParams();
5258         $params["dbname"] = "postgres";
5259         $tmpPlatform = $this->_platform;
5260         $tmpConn = $this->_conn;
5261
5262         $this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params);
5263         $this->_platform = $this->_conn->getDatabasePlatform();
5264
5265         parent::createDatabase($database);
5266
5267         $this->_platform = $tmpPlatform;
5268         $this->_conn = $tmpConn;
5269     }
5270
5271     protected function _getPortableTriggerDefinition($trigger)
5272     {
5273         return $trigger['trigger_name'];
5274     }
5275
5276     protected function _getPortableViewDefinition($view)
5277     {
5278         return new View($view['viewname'], $view['definition']);
5279     }
5280
5281     protected function _getPortableUserDefinition($user)
5282     {
5283         return array(
5284             'user' => $user['usename'],
5285             'password' => $user['passwd']
5286         );
5287     }
5288
5289     protected function _getPortableTableDefinition($table)
5290     {
5291         return $table['table_name'];
5292     }
5293
5294     /**
5295      * @license New BSD License
5296      * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
5297      * @param  array $tableIndexes
5298      * @param  string $tableName
5299      * @return array
5300      */
5301     protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
5302     {
5303         $buffer = array();
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;";
5309
5310             $stmt = $this->_conn->executeQuery($columnNameSql);
5311             $indexColumns = $stmt->fetchAll();
5312
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']) {
5317                         $buffer[] = array(
5318                             'key_name' => $row['relname'],
5319                             'column_name' => trim($colRow['attname']),
5320                             'non_unique' => !$row['indisunique'],
5321                             'primary' => $row['indisprimary']
5322                         );
5323                     }
5324                 }
5325             }
5326         }
5327         return parent::_getPortableTableIndexesList($buffer);
5328     }
5329
5330     protected function _getPortableDatabaseDefinition($database)
5331     {
5332         return $database['datname'];
5333     }
5334
5335     protected function _getPortableSequenceDefinition($sequence)
5336     {
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']);
5339     }
5340
5341     protected function _getPortableTableColumnDefinition($tableColumn)
5342     {
5343         $tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
5344
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;
5349         }
5350
5351         $matches = array();
5352
5353         $autoincrement = false;
5354         if (preg_match("/^nextval\('(.*)'(::.*)?\)$/", $tableColumn['default'], $matches)) {
5355             $tableColumn['sequence'] = $matches[1];
5356             $tableColumn['default'] = null;
5357             $autoincrement = true;
5358         }
5359
5360         if (stripos($tableColumn['default'], 'NULL') === 0) {
5361             $tableColumn['default'] = null;
5362         }
5363
5364         $length = (isset($tableColumn['length'])) ? $tableColumn['length'] : null;
5365         if ($length == '-1' && isset($tableColumn['atttypmod'])) {
5366             $length = $tableColumn['atttypmod'] - 4;
5367         }
5368         if ((int) $length <= 0) {
5369             $length = null;
5370         }
5371         $type = array();
5372         $fixed = null;
5373
5374         if (!isset($tableColumn['name'])) {
5375             $tableColumn['name'] = '';
5376         }
5377
5378         $precision = null;
5379         $scale = null;
5380
5381         if ($this->_platform->hasDoctrineTypeMappingFor($tableColumn['type'])) {
5382             $dbType = strtolower($tableColumn['type']);
5383         } else {
5384             $dbType = strtolower($tableColumn['domain_type']);
5385             $tableColumn['complete_type'] = $tableColumn['domain_complete_type'];
5386         }
5387
5388         $type = $this->_platform->getDoctrineTypeMapping($dbType);
5389         switch ($dbType) {
5390             case 'smallint':
5391             case 'int2':
5392                 $length = null;
5393                 break;
5394             case 'int':
5395             case 'int4':
5396             case 'integer':
5397                 $length = null;
5398                 break;
5399             case 'bigint':
5400             case 'int8':
5401                 $length = null;
5402                 break;
5403             case 'bool':
5404             case 'boolean':
5405                 $length = null;
5406                 break;
5407             case 'text':
5408                 $fixed = false;
5409                 break;
5410             case 'varchar':
5411             case 'interval':
5412             case '_varchar':
5413                 $fixed = false;
5414                 break;
5415             case 'char':
5416             case 'bpchar':
5417                 $fixed = true;
5418                 break;
5419             case 'float':
5420             case 'float4':
5421             case 'float8':
5422             case 'double':
5423             case 'double precision':
5424             case 'real':
5425             case 'decimal':
5426             case 'money':
5427             case 'numeric':
5428                 if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['complete_type'], $match)) {
5429                     $precision = $match[1];
5430                     $scale = $match[2];
5431                     $length = null;
5432                 }
5433                 break;
5434             case 'year':
5435                 $length = null;
5436                 break;
5437         }
5438
5439         $options = array(
5440             'length' => $length,
5441             'notnull' => (bool) $tableColumn['isnotnull'],
5442             'default' => $tableColumn['default'],
5443             'primary' => (bool) ($tableColumn['pri'] == 't'),
5444             'precision' => $precision,
5445             'scale' => $scale,
5446             'fixed' => $fixed,
5447             'unsigned' => false,
5448             'autoincrement' => $autoincrement,
5449         );
5450
5451         return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options);
5452     }
5453
5454 }<?php
5455 /*
5456  *  $Id$
5457  *
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.
5469  *
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>.
5473 */
5474
5475 namespace Doctrine\DBAL\Schema;
5476
5477 /**
5478  * Representation of a Database View
5479  *
5480  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
5481  * @link        www.doctrine-project.com
5482  * @since       1.0
5483  * @version     $Revision$
5484  * @author      Benjamin Eberlei <kontakt@beberlei.de>
5485  */
5486 class View extends AbstractAsset
5487 {
5488     /**
5489      * @var string
5490      */
5491     private $_sql;
5492
5493     public function __construct($name, $sql)
5494     {
5495         $this->_setName($name);
5496         $this->_sql = $sql;
5497     }
5498
5499     /**
5500      * @return string
5501      */
5502     public function getSql()
5503     {
5504         return $this->_sql;
5505     }
5506 }<?php
5507 /*
5508  *  $Id$
5509  *
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.
5521  *
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>.
5525 */
5526
5527 namespace Doctrine\DBAL\Schema;
5528
5529 /**
5530  * IBM Db2 Schema Manager
5531  *
5532  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
5533  * @link        www.doctrine-project.com
5534  * @since       1.0
5535  * @version     $Revision$
5536  * @author      Benjamin Eberlei <kontakt@beberlei.de>
5537  */
5538 class DB2SchemaManager extends AbstractSchemaManager
5539 {
5540     /**
5541      * Return a list of all tables in the current database
5542      *
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}
5545      *
5546      * @return array
5547      */
5548     public function listTableNames()
5549     {
5550         $sql = $this->_platform->getListTablesSQL();
5551         $sql .= " AND CREATOR = UPPER('".$this->_conn->getUsername()."')";
5552
5553         $tables = $this->_conn->fetchAll($sql);
5554         
5555         return $this->_getPortableTablesList($tables);
5556     }
5557
5558
5559     /**
5560      * Get Table Column Definition
5561      *
5562      * @param array $tableColumn
5563      * @return Column
5564      */
5565     protected function _getPortableTableColumnDefinition($tableColumn)
5566     {
5567         $tableColumn = array_change_key_case($tableColumn, \CASE_LOWER);
5568
5569         $length = null;
5570         $fixed = null;
5571         $unsigned = false;
5572         $scale = false;
5573         $precision = false;
5574
5575         $type = $this->_platform->getDoctrineTypeMapping($tableColumn['typename']);
5576         
5577         switch (strtolower($tableColumn['typename'])) {
5578             case 'varchar':
5579                 $length = $tableColumn['length'];
5580                 $fixed = false;
5581                 break;
5582             case 'character':
5583                 $length = $tableColumn['length'];
5584                 $fixed = true;
5585                 break;
5586             case 'clob':
5587                 $length = $tableColumn['length'];
5588                 break;
5589             case 'decimal':
5590             case 'double':
5591             case 'real':
5592                 $scale = $tableColumn['scale'];
5593                 $precision = $tableColumn['length'];
5594                 break;
5595         }
5596
5597         $options = array(
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'),
5603             'scale'         => null,
5604             'precision'     => null,
5605             'platformOptions' => array(),
5606         );
5607
5608         if ($scale !== null && $precision !== null) {
5609             $options['scale'] = $scale;
5610             $options['precision'] = $precision;
5611         }
5612
5613         return new Column($tableColumn['colname'], \Doctrine\DBAL\Types\Type::getType($type), $options);
5614     }
5615
5616     protected function _getPortableTablesList($tables)
5617     {
5618         $tableNames = array();
5619         foreach ($tables AS $tableRow) {
5620             $tableRow = array_change_key_case($tableRow, \CASE_LOWER);
5621             $tableNames[] = $tableRow['name'];
5622         }
5623         return $tableNames;
5624     }
5625
5626     protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
5627     {
5628         $tableIndexRows = array();
5629         $indexes = 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");
5634
5635             $indexName = strtolower($data['name']);
5636             if ($primary) {
5637                 $keyName = 'primary';
5638             } else {
5639                 $keyName = $indexName;
5640             }
5641
5642             $indexes[$keyName] = new Index($indexName, explode("+", ltrim($data['colnames'], '+')), $unique, $primary);
5643         }
5644
5645         return $indexes;
5646     }
5647
5648     protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
5649     {
5650         $tableForeignKey = array_change_key_case($tableForeignKey, CASE_LOWER);
5651
5652         $tableForeignKey['deleterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['deleterule']);
5653         $tableForeignKey['updaterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['updaterule']);
5654
5655         return new ForeignKeyConstraint(
5656             array_map('trim', (array)$tableForeignKey['fkcolnames']),
5657             $tableForeignKey['reftbname'],
5658             array_map('trim', (array)$tableForeignKey['pkcolnames']),
5659             $tableForeignKey['relname'],
5660             array(
5661                 'onUpdate' => $tableForeignKey['updaterule'],
5662                 'onDelete' => $tableForeignKey['deleterule'],
5663             )
5664         );
5665     }
5666
5667     protected function _getPortableForeignKeyRuleDef($def)
5668     {
5669         if ($def == "C") {
5670             return "CASCADE";
5671         } else if ($def == "N") {
5672             return "SET NULL";
5673         }
5674         return null;
5675     }
5676
5677     protected function _getPortableViewDefinition($view)
5678     {
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);
5685         } else {
5686             $sql = '';
5687         }
5688
5689         return new View($view['name'], $sql);
5690     }
5691 }<?php
5692 /*
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.
5704  *
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>.
5708  */
5709
5710 namespace Doctrine\DBAL\Schema;
5711
5712 /**
5713  * SqliteSchemaManager
5714  *
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$
5720  * @since       2.0
5721  */
5722 class SqliteSchemaManager extends AbstractSchemaManager
5723 {
5724     /**
5725      * {@inheritdoc}
5726      * 
5727      * @override
5728      */
5729     public function dropDatabase($database)
5730     {
5731         if (file_exists($database)) {
5732             unlink($database);
5733         }
5734     }
5735
5736     /**
5737      * {@inheritdoc}
5738      * 
5739      * @override
5740      */
5741     public function createDatabase($database)
5742     {
5743         $params = $this->_conn->getParams();
5744         $driver = $params['driver'];
5745         $options = array(
5746             'driver' => $driver,
5747             'path' => $database
5748         );
5749         $conn = \Doctrine\DBAL\DriverManager::getConnection($options);
5750         $conn->connect();
5751         $conn->close();
5752     }
5753
5754     protected function _getPortableTableDefinition($table)
5755     {
5756         return $table['name'];
5757     }
5758
5759     /**
5760      * @license New BSD License
5761      * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
5762      * @param  array $tableIndexes
5763      * @param  string $tableName
5764      * @return array
5765      */
5766     protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
5767     {
5768         $indexBuffer = array();
5769
5770         // fetch primary
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',
5777                     'primary' => true,
5778                     'non_unique' => false,
5779                     'column_name' => $indexColumnRow['name']
5780                 );
5781             }
5782         }
5783
5784         // fetch regular indexes
5785         foreach($tableIndexes AS $tableIndex) {
5786             $keyName = $tableIndex['name'];
5787             $idx = array();
5788             $idx['key_name'] = $keyName;
5789             $idx['primary'] = false;
5790             $idx['non_unique'] = $tableIndex['unique']?false:true;
5791
5792             $stmt = $this->_conn->executeQuery( "PRAGMA INDEX_INFO ( '{$keyName}' )" );
5793             $indexArray = $stmt->fetchAll(\PDO::FETCH_ASSOC);
5794
5795             foreach ( $indexArray as $indexColumnRow ) {
5796                 $idx['column_name'] = $indexColumnRow['name'];
5797                 $indexBuffer[] = $idx;
5798             }
5799         }
5800
5801         return parent::_getPortableTableIndexesList($indexBuffer, $tableName);
5802     }
5803
5804     protected function _getPortableTableIndexDefinition($tableIndex)
5805     {
5806         return array(
5807             'name' => $tableIndex['name'],
5808             'unique' => (bool) $tableIndex['unique']
5809         );
5810     }
5811
5812     protected function _getPortableTableColumnDefinition($tableColumn)
5813     {
5814         $e = explode('(', $tableColumn['type']);
5815         $tableColumn['type'] = $e[0];
5816         if (isset($e[1])) {
5817             $length = trim($e[1], ')');
5818             $tableColumn['length'] = $length;
5819         }
5820
5821         $dbType = strtolower($tableColumn['type']);
5822         $length = isset($tableColumn['length']) ? $tableColumn['length'] : null;
5823         $unsigned = (boolean) isset($tableColumn['unsigned']) ? $tableColumn['unsigned'] : false;
5824         $fixed = false;
5825         $type = $this->_platform->getDoctrineTypeMapping($dbType);
5826         $default = $tableColumn['dflt_value'];
5827         if  ($default == 'NULL') {
5828             $default = null;
5829         }
5830         $notnull = (bool) $tableColumn['notnull'];
5831
5832         if ( ! isset($tableColumn['name'])) {
5833             $tableColumn['name'] = '';
5834         }
5835
5836         $precision = null;
5837         $scale = null;
5838
5839         switch ($dbType) {
5840             case 'char':
5841                 $fixed = true;
5842                 break;
5843             case 'float':
5844             case 'double':
5845             case 'real':
5846             case 'decimal':
5847             case 'numeric':
5848                 list($precision, $scale) = array_map('trim', explode(', ', $tableColumn['length']));
5849                 $length = null;
5850                 break;
5851         }
5852
5853         $options = array(
5854             'length'   => $length,
5855             'unsigned' => (bool) $unsigned,
5856             'fixed'    => $fixed,
5857             'notnull'  => $notnull,
5858             'default'  => $default,
5859             'precision' => $precision,
5860             'scale'     => $scale,
5861             'autoincrement' => (bool) $tableColumn['pk'],
5862         );
5863
5864         return new Column($tableColumn['name'], \Doctrine\DBAL\Types\Type::getType($type), $options);
5865     }
5866
5867     protected function _getPortableViewDefinition($view)
5868     {
5869         return new View($view['name'], $view['sql']);
5870     }
5871 }<?php
5872 /*
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.
5884  *
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>.
5888  */
5889
5890 namespace Doctrine\DBAL\Schema;
5891
5892 /**
5893  * Compare to Schemas and return an instance of SchemaDiff
5894  *
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
5899  * @since   2.0
5900  * @version $Revision$
5901  * @author  Benjamin Eberlei <kontakt@beberlei.de>
5902  */
5903 class Comparator
5904 {
5905     /**
5906      * @param Schema $fromSchema
5907      * @param Schema $toSchema
5908      * @return SchemaDiff
5909      */
5910     static public function compareSchemas( Schema $fromSchema, Schema $toSchema )
5911     {
5912         $c = new self();
5913         return $c->compare($fromSchema, $toSchema);
5914     }
5915
5916     /**
5917      * Returns a SchemaDiff object containing the differences between the schemas $fromSchema and $toSchema.
5918      *
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.
5922      *
5923      * @param Schema $fromSchema
5924      * @param Schema $toSchema
5925      *
5926      * @return SchemaDiff
5927      */
5928     public function compare(Schema $fromSchema, Schema $toSchema)
5929     {
5930         $diff = new SchemaDiff();
5931
5932         $foreignKeysToTable = array();
5933
5934         foreach ( $toSchema->getTables() AS $tableName => $table ) {
5935             if ( !$fromSchema->hasTable($tableName) ) {
5936                 $diff->newTables[$tableName] = $table;
5937             } else {
5938                 $tableDifferences = $this->diffTable( $fromSchema->getTable($tableName), $table );
5939                 if ( $tableDifferences !== false ) {
5940                     $diff->changedTables[$tableName] = $tableDifferences;
5941                 }
5942             }
5943         }
5944
5945         /* Check if there are tables removed */
5946         foreach ( $fromSchema->getTables() AS $tableName => $table ) {
5947             if ( !$toSchema->hasTable($tableName) ) {
5948                 $diff->removedTables[$tableName] = $table;
5949             }
5950
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();
5956                 }
5957                 $foreignKeysToTable[$foreignTable][] = $foreignKey;
5958             }
5959         }
5960
5961         foreach ($diff->removedTables AS $tableName => $table) {
5962             if (isset($foreignKeysToTable[$tableName])) {
5963                 $diff->orphanedForeignKeys = array_merge($diff->orphanedForeignKeys, $foreignKeysToTable[$tableName]);
5964             }
5965         }
5966
5967         foreach ( $toSchema->getSequences() AS $sequenceName => $sequence) {
5968             if (!$fromSchema->hasSequence($sequenceName)) {
5969                 $diff->newSequences[] = $sequence;
5970             } else {
5971                 if ($this->diffSequence($sequence, $fromSchema->getSequence($sequenceName))) {
5972                     $diff->changedSequences[] = $fromSchema->getSequence($sequenceName);
5973                 }
5974             }
5975         }
5976
5977         foreach ($fromSchema->getSequences() AS $sequenceName => $sequence) {
5978             if (!$toSchema->hasSequence($sequenceName)) {
5979                 $diff->removedSequences[] = $sequence;
5980             }
5981         }
5982
5983         return $diff;
5984     }
5985
5986     /**
5987      *
5988      * @param Sequence $sequence1
5989      * @param Sequence $sequence2
5990      */
5991     public function diffSequence(Sequence $sequence1, Sequence $sequence2)
5992     {
5993         if($sequence1->getAllocationSize() != $sequence2->getAllocationSize()) {
5994             return true;
5995         }
5996
5997         if($sequence1->getInitialValue() != $sequence2->getInitialValue()) {
5998             return true;
5999         }
6000
6001         return false;
6002     }
6003
6004     /**
6005      * Returns the difference between the tables $table1 and $table2.
6006      *
6007      * If there are no differences this method returns the boolean false.
6008      *
6009      * @param Table $table1
6010      * @param Table $table2
6011      *
6012      * @return bool|TableDiff
6013      */
6014     public function diffTable(Table $table1, Table $table2)
6015     {
6016         $changes = 0;
6017         $tableDifferences = new TableDiff($table1->getName());
6018
6019         $table1Columns = $table1->getColumns();
6020         $table2Columns = $table2->getColumns();
6021
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;
6026                 $changes++;
6027             }
6028         }
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;
6033                 $changes++;
6034             }
6035         }
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;
6042                     $changes++;
6043                 }
6044             }
6045         }
6046
6047         $this->detectColumnRenamings($tableDifferences);
6048
6049         $table1Indexes = $table1->getIndexes();
6050         $table2Indexes = $table2->getIndexes();
6051
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]);
6057                 } else {
6058                     if ($index1Name == $index2Name) {
6059                         $tableDifferences->changedIndexes[$index2Name] = $table2Indexes[$index2Name];
6060                         unset($table1Indexes[$index1Name]);
6061                         unset($table2Indexes[$index2Name]);
6062                         $changes++;
6063                     }
6064                 }
6065             }
6066         }
6067
6068         foreach ($table1Indexes AS $index1Name => $index1Definition) {
6069             $tableDifferences->removedIndexes[$index1Name] = $index1Definition;
6070             $changes++;
6071         }
6072
6073         foreach ($table2Indexes AS $index2Name => $index2Definition) {
6074             $tableDifferences->addedIndexes[$index2Name] = $index2Definition;
6075             $changes++;
6076         }
6077
6078         $fromFkeys = $table1->getForeignKeys();
6079         $toFkeys = $table2->getForeignKeys();
6080
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]);
6086                 } else {
6087                     if (strtolower($constraint1->getName()) == strtolower($constraint2->getName())) {
6088                         $tableDifferences->changedForeignKeys[] = $constraint2;
6089                         $changes++;
6090                         unset($fromFkeys[$key1]);
6091                         unset($toFkeys[$key2]);
6092                     }
6093                 }
6094             }
6095         }
6096
6097         foreach ($fromFkeys AS $key1 => $constraint1) {
6098             $tableDifferences->removedForeignKeys[] = $constraint1;
6099             $changes++;
6100         }
6101
6102         foreach ($toFkeys AS $key2 => $constraint2) {
6103             $tableDifferences->addedForeignKeys[] = $constraint2;
6104             $changes++;
6105         }
6106
6107         return $changes ? $tableDifferences : false;
6108     }
6109
6110     /**
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.
6113      * 
6114      * @param TableDiff $tableDifferences
6115      */
6116     private function detectColumnRenamings(TableDiff $tableDifferences)
6117     {
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);
6123                 }
6124             }
6125         }
6126
6127         foreach ($renameCandidates AS $candidate => $candidateColumns) {
6128             if (count($candidateColumns) == 1) {
6129                 list($removedColumn, $addedColumn) = $candidateColumns[0];
6130
6131                 $tableDifferences->renamedColumns[$removedColumn->getName()] = $addedColumn;
6132                 unset($tableDifferences->addedColumns[$addedColumnName]);
6133                 unset($tableDifferences->removedColumns[$removedColumnName]);
6134             }
6135         }
6136     }
6137
6138     /**
6139      * @param ForeignKeyConstraint $key1
6140      * @param ForeignKeyConstraint $key2
6141      * @return bool
6142      */
6143     public function diffForeignKey(ForeignKeyConstraint $key1, ForeignKeyConstraint $key2)
6144     {
6145         if (array_map('strtolower', $key1->getLocalColumns()) != array_map('strtolower', $key2->getLocalColumns())) {
6146             return true;
6147         }
6148         
6149         if (array_map('strtolower', $key1->getForeignColumns()) != array_map('strtolower', $key2->getForeignColumns())) {
6150             return true;
6151         }
6152
6153         if ($key1->onUpdate() != $key2->onUpdate()) {
6154             return true;
6155         }
6156
6157         if ($key1->onDelete() != $key2->onDelete()) {
6158             return true;
6159         }
6160
6161         return false;
6162     }
6163
6164     /**
6165      * Returns the difference between the fields $field1 and $field2.
6166      *
6167      * If there are differences this method returns $field2, otherwise the
6168      * boolean false.
6169      *
6170      * @param Column $column1
6171      * @param Column $column2
6172      *
6173      * @return array
6174      */
6175     public function diffColumn(Column $column1, Column $column2)
6176     {
6177         $changedProperties = array();
6178         if ( $column1->getType() != $column2->getType() ) {
6179             $changedProperties[] = 'type';
6180         }
6181
6182         if ($column1->getNotnull() != $column2->getNotnull()) {
6183             $changedProperties[] = 'notnull';
6184         }
6185
6186         if ($column1->getDefault() != $column2->getDefault()) {
6187             $changedProperties[] = 'default';
6188         }
6189
6190         if ($column1->getUnsigned() != $column2->getUnsigned()) {
6191             $changedProperties[] = 'unsigned';
6192         }
6193
6194         if ($column1->getType() instanceof \Doctrine\DBAL\Types\StringType) {
6195             if ($column1->getLength() != $column2->getLength()) {
6196                 $changedProperties[] = 'length';
6197             }
6198
6199             if ($column1->getFixed() != $column2->getFixed()) {
6200                 $changedProperties[] = 'fixed';
6201             }
6202         }
6203
6204         if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) {
6205             if ($column1->getPrecision() != $column2->getPrecision()) {
6206                 $changedProperties[] = 'precision';
6207             }
6208             if ($column1->getScale() != $column2->getScale()) {
6209                 $changedProperties[] = 'scale';
6210             }
6211         }
6212
6213         if ($column1->getAutoincrement() != $column2->getAutoincrement()) {
6214             $changedProperties[] = 'autoincrement';
6215         }
6216
6217         return $changedProperties;
6218     }
6219
6220     /**
6221      * Finds the difference between the indexes $index1 and $index2.
6222      *
6223      * Compares $index1 with $index2 and returns $index2 if there are any
6224      * differences or false in case there are no differences.
6225      *
6226      * @param Index $index1
6227      * @param Index $index2
6228      * @return bool
6229      */
6230     public function diffIndex(Index $index1, Index $index2)
6231     {
6232         if ($index1->isFullfilledBy($index2) && $index2->isFullfilledBy($index1)) {
6233             return false;
6234         }
6235         return true;
6236     }
6237 }
6238 <?php
6239 /*
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.
6251  *
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>.
6255  */
6256
6257 namespace Doctrine\DBAL\Schema;
6258
6259 use Doctrine\DBAL\Schema\Visitor\Visitor;
6260
6261 class Index extends AbstractAsset implements Constraint
6262 {
6263     /**
6264      * @var array
6265      */
6266     protected $_columns;
6267
6268     /**
6269      * @var bool
6270      */
6271     protected $_isUnique = false;
6272
6273     /**
6274      * @var bool
6275      */
6276     protected $_isPrimary = false;
6277
6278     /**
6279      * @param string $indexName
6280      * @param array $column
6281      * @param bool $isUnique
6282      * @param bool $isPrimary
6283      */
6284     public function __construct($indexName, array $columns, $isUnique=false, $isPrimary=false)
6285     {
6286         $isUnique = ($isPrimary)?true:$isUnique;
6287
6288         $this->_setName($indexName);
6289         $this->_isUnique = $isUnique;
6290         $this->_isPrimary = $isPrimary;
6291
6292         foreach($columns AS $column) {
6293             $this->_addColumn($column);
6294         }
6295     }
6296
6297     /**
6298      * @param string $column
6299      */
6300     protected function _addColumn($column)
6301     {
6302         if(is_string($column)) {
6303             $this->_columns[] = strtolower($column);
6304         } else {
6305             throw new \InvalidArgumentException("Expecting a string as Index Column");
6306         }
6307     }
6308
6309     /**
6310      * @return array
6311      */
6312     public function getColumns()
6313     {
6314         return $this->_columns;
6315     }
6316
6317     /**
6318      * @return bool
6319      */
6320     public function isUnique()
6321     {
6322         return $this->_isUnique;
6323     }
6324
6325     /**
6326      * @return bool
6327      */
6328     public function isPrimary()
6329     {
6330         return $this->_isPrimary;
6331     }
6332
6333     /**
6334      * @param  string $columnName
6335      * @param  int $pos
6336      * @return bool
6337      */
6338     public function hasColumnAtPosition($columnName, $pos=0)
6339     {
6340         $columnName = strtolower($columnName);
6341         $indexColumns = \array_map('strtolower', $this->getColumns());
6342         return \array_search($columnName, $indexColumns) === $pos;
6343     }
6344
6345     /**
6346      * Check if this index exactly spans the given column names in the correct order.
6347      *
6348      * @param array $columnNames
6349      * @return boolean
6350      */
6351     public function spansColumns(array $columnNames)
6352     {
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;
6357             }
6358         }
6359         return $sameColumns;
6360     }
6361
6362     /**
6363      * Check if the other index already fullfills all the indexing and constraint needs of the current one.
6364      *
6365      * @param Index $other
6366      * @return bool
6367      */
6368     public function isFullfilledBy(Index $other)
6369     {
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())) {
6373             return false;
6374         }
6375
6376         // Check if columns are the same, and even in the same order
6377         $sameColumns = $this->spansColumns($other->getColumns());
6378
6379         if ($sameColumns) {
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.
6385                 return true;
6386             } else if ($other->isPrimary() != $this->isPrimary()) {
6387                 return false;
6388             } else if ($other->isUnique() != $this->isUnique()) {
6389                 return false;
6390             }
6391             return true;
6392         }
6393         return false;
6394     }
6395
6396     /**
6397      * Detect if the other index is a non-unique, non primary index that can be overwritten by this one.
6398      *
6399      * @param Index $other
6400      * @return bool
6401      */
6402     public function overrules(Index $other)
6403     {
6404         if ($other->isPrimary() || $other->isUnique()) {
6405             return false;
6406         }
6407
6408         if ($this->spansColumns($other->getColumns()) && ($this->isPrimary() || $this->isUnique())) {
6409             return true;
6410         }
6411         return false;
6412     }
6413 }<?php
6414 /*
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.
6426  *
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>.
6430  */
6431
6432 namespace Doctrine\DBAL\Schema;
6433
6434 use Doctrine\DBAL\Types;
6435 use Doctrine\DBAL\DBALException;
6436 use Doctrine\DBAL\Platforms\AbstractPlatform;
6437
6438 /**
6439  * Base class for schema managers. Schema managers are used to inspect and/or
6440  * modify the database schema/structure.
6441  *
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$
6449  * @since       2.0
6450  */
6451 abstract class AbstractSchemaManager
6452 {
6453     /**
6454      * Holds instance of the Doctrine connection for this schema manager
6455      *
6456      * @var \Doctrine\DBAL\Connection
6457      */
6458     protected $_conn;
6459
6460     /**
6461      * Holds instance of the database platform used for this schema manager
6462      *
6463      * @var \Doctrine\DBAL\Platforms\AbstractPlatform
6464      */
6465     protected $_platform;
6466
6467     /**
6468      * Constructor. Accepts the Connection instance to manage the schema for
6469      *
6470      * @param \Doctrine\DBAL\Connection $conn
6471      */
6472     public function __construct(\Doctrine\DBAL\Connection $conn)
6473     {
6474         $this->_conn = $conn;
6475         $this->_platform = $this->_conn->getDatabasePlatform();
6476     }
6477
6478     /**
6479      * Return associated platform.
6480      *
6481      * @return \Doctrine\DBAL\Platform\AbstractPlatform
6482      */
6483     public function getDatabasePlatform()
6484     {
6485         return $this->_platform;
6486     }
6487
6488     /**
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.
6493      *
6494      * <code>
6495      * $result = $sm->tryMethod('dropView', 'view_name');
6496      * </code>
6497      *
6498      * @return mixed
6499      */
6500     public function tryMethod()
6501     {
6502         $args = func_get_args();
6503         $method = $args[0];
6504         unset($args[0]);
6505         $args = array_values($args);
6506
6507         try {
6508             return call_user_func_array(array($this, $method), $args);
6509         } catch (\Exception $e) {
6510             return false;
6511         }
6512     }
6513
6514     /**
6515      * List the available databases for this connection
6516      *
6517      * @return array $databases
6518      */
6519     public function listDatabases()
6520     {
6521         $sql = $this->_platform->getListDatabasesSQL();
6522
6523         $databases = $this->_conn->fetchAll($sql);
6524
6525         return $this->_getPortableDatabasesList($databases);
6526     }
6527
6528     /**
6529      * List the available sequences for this connection
6530      *
6531      * @return Sequence[]
6532      */
6533     public function listSequences($database = null)
6534     {
6535         if (is_null($database)) {
6536             $database = $this->_conn->getDatabase();
6537         }
6538         $sql = $this->_platform->getListSequencesSQL($database);
6539
6540         $sequences = $this->_conn->fetchAll($sql);
6541
6542         return $this->_getPortableSequencesList($sequences);
6543     }
6544
6545     /**
6546      * List the columns for a given table.
6547      *
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.
6554      *
6555      * @param string $table The name of the table.
6556      * @return Column[]
6557      */
6558     public function listTableColumns($table)
6559     {
6560         $sql = $this->_platform->getListTableColumnsSQL($table);
6561
6562         $tableColumns = $this->_conn->fetchAll($sql);
6563
6564         return $this->_getPortableTableColumnList($tableColumns);
6565     }
6566
6567     /**
6568      * List the indexes for a given table returning an array of Index instances.
6569      *
6570      * Keys of the portable indexes list are all lower-cased.
6571      *
6572      * @param string $table The name of the table
6573      * @return Index[] $tableIndexes
6574      */
6575     public function listTableIndexes($table)
6576     {
6577         $sql = $this->_platform->getListTableIndexesSQL($table);
6578
6579         $tableIndexes = $this->_conn->fetchAll($sql);
6580
6581         return $this->_getPortableTableIndexesList($tableIndexes, $table);
6582     }
6583
6584     /**
6585      * Return true if all the given tables exist.
6586      * 
6587      * @param array $tableNames
6588      * @return bool
6589      */
6590     public function tablesExist($tableNames)
6591     {
6592         $tableNames = array_map('strtolower', (array)$tableNames);
6593         return count($tableNames) == count(\array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
6594     }
6595
6596
6597     /**
6598      * Return a list of all tables in the current database
6599      *
6600      * @return array
6601      */
6602     public function listTableNames()
6603     {
6604         $sql = $this->_platform->getListTablesSQL();
6605
6606         $tables = $this->_conn->fetchAll($sql);
6607
6608         return $this->_getPortableTablesList($tables);
6609     }
6610
6611     /**
6612      * List the tables for this connection
6613      *
6614      * @return Table[]
6615      */
6616     public function listTables()
6617     {
6618         $tableNames = $this->listTableNames();
6619
6620         $tables = array();
6621         foreach ($tableNames AS $tableName) {
6622             $tables[] = $this->listTableDetails($tableName);
6623         }
6624
6625         return $tables;
6626     }
6627
6628     /**
6629      * @param  string $tableName
6630      * @return Table
6631      */
6632     public function listTableDetails($tableName)
6633     {
6634         $columns = $this->listTableColumns($tableName);
6635         $foreignKeys = array();
6636         if ($this->_platform->supportsForeignKeyConstraints()) {
6637             $foreignKeys = $this->listTableForeignKeys($tableName);
6638         }
6639         $indexes = $this->listTableIndexes($tableName);
6640
6641         return new Table($tableName, $columns, $indexes, $foreignKeys, false, array());
6642     }
6643
6644     /**
6645      * List the views this connection has
6646      *
6647      * @return View[]
6648      */
6649     public function listViews()
6650     {
6651         $database = $this->_conn->getDatabase();
6652         $sql = $this->_platform->getListViewsSQL($database);
6653         $views = $this->_conn->fetchAll($sql);
6654
6655         return $this->_getPortableViewsList($views);
6656     }
6657
6658     /**
6659      * List the foreign keys for the given table
6660      *
6661      * @param string $table  The name of the table
6662      * @return ForeignKeyConstraint[]
6663      */
6664     public function listTableForeignKeys($table, $database = null)
6665     {
6666         if (is_null($database)) {
6667             $database = $this->_conn->getDatabase();
6668         }
6669         $sql = $this->_platform->getListTableForeignKeysSQL($table, $database);
6670         $tableForeignKeys = $this->_conn->fetchAll($sql);
6671
6672         return $this->_getPortableTableForeignKeysList($tableForeignKeys);
6673     }
6674
6675     /* drop*() Methods */
6676
6677     /**
6678      * Drops a database.
6679      * 
6680      * NOTE: You can not drop the database this SchemaManager is currently connected to.
6681      *
6682      * @param string $database The name of the database to drop
6683      */
6684     public function dropDatabase($database)
6685     {
6686         $this->_execSql($this->_platform->getDropDatabaseSQL($database));
6687     }
6688
6689     /**
6690      * Drop the given table
6691      *
6692      * @param string $table The name of the table to drop
6693      */
6694     public function dropTable($table)
6695     {
6696         $this->_execSql($this->_platform->getDropTableSQL($table));
6697     }
6698
6699     /**
6700      * Drop the index from the given table
6701      *
6702      * @param Index|string $index  The name of the index
6703      * @param string|Table $table The name of the table
6704      */
6705     public function dropIndex($index, $table)
6706     {
6707         if($index instanceof Index) {
6708             $index = $index->getName();
6709         }
6710
6711         $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
6712     }
6713
6714     /**
6715      * Drop the constraint from the given table
6716      *
6717      * @param Constraint $constraint
6718      * @param string $table   The name of the table
6719      */
6720     public function dropConstraint(Constraint $constraint, $table)
6721     {
6722         $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
6723     }
6724
6725     /**
6726      * Drops a foreign key from a table.
6727      *
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
6731      */
6732     public function dropForeignKey($foreignKey, $table)
6733     {
6734         $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
6735     }
6736
6737     /**
6738      * Drops a sequence with a given name.
6739      *
6740      * @param string $name The name of the sequence to drop.
6741      */
6742     public function dropSequence($name)
6743     {
6744         $this->_execSql($this->_platform->getDropSequenceSQL($name));
6745     }
6746
6747     /**
6748      * Drop a view
6749      *
6750      * @param string $name The name of the view
6751      * @return boolean $result
6752      */
6753     public function dropView($name)
6754     {
6755         $this->_execSql($this->_platform->getDropViewSQL($name));
6756     }
6757
6758     /* create*() Methods */
6759
6760     /**
6761      * Creates a new database.
6762      *
6763      * @param string $database The name of the database to create.
6764      */
6765     public function createDatabase($database)
6766     {
6767         $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
6768     }
6769
6770     /**
6771      * Create a new table.
6772      *
6773      * @param Table $table
6774      * @param int $createFlags
6775      */
6776     public function createTable(Table $table)
6777     {
6778         $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
6779         $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
6780     }
6781
6782     /**
6783      * Create a new sequence
6784      *
6785      * @param Sequence $sequence
6786      * @throws Doctrine\DBAL\ConnectionException     if something fails at database level
6787      */
6788     public function createSequence($sequence)
6789     {
6790         $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
6791     }
6792
6793     /**
6794      * Create a constraint on a table
6795      *
6796      * @param Constraint $constraint
6797      * @param string|Table $table
6798      */
6799     public function createConstraint(Constraint $constraint, $table)
6800     {
6801         $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table));
6802     }
6803
6804     /**
6805      * Create a new index on a table
6806      *
6807      * @param Index     $index
6808      * @param string    $table         name of the table on which the index is to be created
6809      */
6810     public function createIndex(Index $index, $table)
6811     {
6812         $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
6813     }
6814
6815     /**
6816      * Create a new foreign key
6817      *
6818      * @param ForeignKeyConstraint  $foreignKey    ForeignKey instance
6819      * @param string|Table          $table         name of the table on which the foreign key is to be created
6820      */
6821     public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
6822     {
6823         $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
6824     }
6825
6826     /**
6827      * Create a new view
6828      *
6829      * @param View $view
6830      */
6831     public function createView(View $view)
6832     {
6833         $this->_execSql($this->_platform->getCreateViewSQL($view->getName(), $view->getSql()));
6834     }
6835
6836     /* dropAndCreate*() Methods */
6837
6838     /**
6839      * Drop and create a constraint
6840      *
6841      * @param Constraint    $constraint
6842      * @param string        $table
6843      * @see dropConstraint()
6844      * @see createConstraint()
6845      */
6846     public function dropAndCreateConstraint(Constraint $constraint, $table)
6847     {
6848         $this->tryMethod('dropConstraint', $constraint, $table);
6849         $this->createConstraint($constraint, $table);
6850     }
6851
6852     /**
6853      * Drop and create a new index on a table
6854      *
6855      * @param string|Table $table         name of the table on which the index is to be created
6856      * @param Index $index
6857      */
6858     public function dropAndCreateIndex(Index $index, $table)
6859     {
6860         $this->tryMethod('dropIndex', $index->getName(), $table);
6861         $this->createIndex($index, $table);
6862     }
6863
6864     /**
6865      * Drop and create a new foreign key
6866      *
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
6869      */
6870     public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
6871     {
6872         $this->tryMethod('dropForeignKey', $foreignKey, $table);
6873         $this->createForeignKey($foreignKey, $table);
6874     }
6875
6876     /**
6877      * Drop and create a new sequence
6878      *
6879      * @param Sequence $sequence
6880      * @throws Doctrine\DBAL\ConnectionException     if something fails at database level
6881      */
6882     public function dropAndCreateSequence(Sequence $sequence)
6883     {
6884         $this->tryMethod('createSequence', $seqName, $start, $allocationSize);
6885         $this->createSequence($seqName, $start, $allocationSize);
6886     }
6887
6888     /**
6889      * Drop and create a new table.
6890      *
6891      * @param Table $table
6892      */
6893     public function dropAndCreateTable(Table $table)
6894     {
6895         $this->tryMethod('dropTable', $table->getName());
6896         $this->createTable($table);
6897     }
6898
6899     /**
6900      * Drop and creates a new database.
6901      *
6902      * @param string $database The name of the database to create.
6903      */
6904     public function dropAndCreateDatabase($database)
6905     {
6906         $this->tryMethod('dropDatabase', $database);
6907         $this->createDatabase($database);
6908     }
6909
6910     /**
6911      * Drop and create a new view
6912      *
6913      * @param View $view
6914      */
6915     public function dropAndCreateView(View $view)
6916     {
6917         $this->tryMethod('dropView', $view->getName());
6918         $this->createView($view);
6919     }
6920
6921     /* alterTable() Methods */
6922
6923     /**
6924      * Alter an existing tables schema
6925      *
6926      * @param TableDiff $tableDiff
6927      */
6928     public function alterTable(TableDiff $tableDiff)
6929     {
6930         $queries = $this->_platform->getAlterTableSQL($tableDiff);
6931         if (is_array($queries) && count($queries)) {
6932             foreach ($queries AS $ddlQuery) {
6933                 $this->_execSql($ddlQuery);
6934             }
6935         }
6936     }
6937
6938     /**
6939      * Rename a given table to another name
6940      *
6941      * @param string $name     The current name of the table
6942      * @param string $newName  The new name of the table
6943      */
6944     public function renameTable($name, $newName)
6945     {
6946         $tableDiff = new TableDiff($name);
6947         $tableDiff->newName = $newName;
6948         $this->alterTable($tableDiff);
6949     }
6950
6951     /**
6952      * Methods for filtering return values of list*() methods to convert
6953      * the native DBMS data definition to a portable Doctrine definition
6954      */
6955
6956     protected function _getPortableDatabasesList($databases)
6957     {
6958         $list = array();
6959         foreach ($databases as $key => $value) {
6960             if ($value = $this->_getPortableDatabaseDefinition($value)) {
6961                 $list[] = $value;
6962             }
6963         }
6964         return $list;
6965     }
6966
6967     protected function _getPortableDatabaseDefinition($database)
6968     {
6969         return $database;
6970     }
6971
6972     protected function _getPortableFunctionsList($functions)
6973     {
6974         $list = array();
6975         foreach ($functions as $key => $value) {
6976             if ($value = $this->_getPortableFunctionDefinition($value)) {
6977                 $list[] = $value;
6978             }
6979         }
6980         return $list;
6981     }
6982
6983     protected function _getPortableFunctionDefinition($function)
6984     {
6985         return $function;
6986     }
6987
6988     protected function _getPortableTriggersList($triggers)
6989     {
6990         $list = array();
6991         foreach ($triggers as $key => $value) {
6992             if ($value = $this->_getPortableTriggerDefinition($value)) {
6993                 $list[] = $value;
6994             }
6995         }
6996         return $list;
6997     }
6998
6999     protected function _getPortableTriggerDefinition($trigger)
7000     {
7001         return $trigger;
7002     }
7003
7004     protected function _getPortableSequencesList($sequences)
7005     {
7006         $list = array();
7007         foreach ($sequences as $key => $value) {
7008             if ($value = $this->_getPortableSequenceDefinition($value)) {
7009                 $list[] = $value;
7010             }
7011         }
7012         return $list;
7013     }
7014
7015     /**
7016      * @param array $sequence
7017      * @return Sequence
7018      */
7019     protected function _getPortableSequenceDefinition($sequence)
7020     {
7021         throw DBALException::notSupported('Sequences');
7022     }
7023
7024     /**
7025      * Independent of the database the keys of the column list result are lowercased.
7026      *
7027      * The name of the created column instance however is kept in its case.
7028      *
7029      * @param  array $tableColumns
7030      * @return array
7031      */
7032     protected function _getPortableTableColumnList($tableColumns)
7033     {
7034         $list = array();
7035         foreach ($tableColumns as $key => $column) {
7036             if ($column = $this->_getPortableTableColumnDefinition($column)) {
7037                 $name = strtolower($column->getName());
7038                 $list[$name] = $column;
7039             }
7040         }
7041         return $list;
7042     }
7043
7044     /**
7045      * Get Table Column Definition
7046      *
7047      * @param array $tableColumn
7048      * @return Column
7049      */
7050     abstract protected function _getPortableTableColumnDefinition($tableColumn);
7051
7052     /**
7053      * Aggregate and group the index results according to the required data result.
7054      *
7055      * @param  array $tableIndexRows
7056      * @param  string $tableName
7057      * @return array
7058      */
7059     protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null)
7060     {
7061         $result = array();
7062         foreach($tableIndexRows AS $tableIndex) {
7063             $indexName = $keyName = $tableIndex['key_name'];
7064             if($tableIndex['primary']) {
7065                 $keyName = 'primary';
7066             }
7067             $keyName = strtolower($keyName);
7068
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'],
7075                 );
7076             } else {
7077                 $result[$keyName]['columns'][] = $tableIndex['column_name'];
7078             }
7079         }
7080
7081         $indexes = array();
7082         foreach($result AS $indexKey => $data) {
7083             $indexes[$indexKey] = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']);
7084         }
7085
7086         return $indexes;
7087     }
7088
7089     protected function _getPortableTablesList($tables)
7090     {
7091         $list = array();
7092         foreach ($tables as $key => $value) {
7093             if ($value = $this->_getPortableTableDefinition($value)) {
7094                 $list[] = $value;
7095             }
7096         }
7097         return $list;
7098     }
7099
7100     protected function _getPortableTableDefinition($table)
7101     {
7102         return $table;
7103     }
7104
7105     protected function _getPortableUsersList($users)
7106     {
7107         $list = array();
7108         foreach ($users as $key => $value) {
7109             if ($value = $this->_getPortableUserDefinition($value)) {
7110                 $list[] = $value;
7111             }
7112         }
7113         return $list;
7114     }
7115
7116     protected function _getPortableUserDefinition($user)
7117     {
7118         return $user;
7119     }
7120
7121     protected function _getPortableViewsList($views)
7122     {
7123         $list = array();
7124         foreach ($views as $key => $value) {
7125             if ($view = $this->_getPortableViewDefinition($value)) {
7126                 $viewName = strtolower($view->getName());
7127                 $list[$viewName] = $view;
7128             }
7129         }
7130         return $list;
7131     }
7132
7133     protected function _getPortableViewDefinition($view)
7134     {
7135         return false;
7136     }
7137
7138     protected function _getPortableTableForeignKeysList($tableForeignKeys)
7139     {
7140         $list = array();
7141         foreach ($tableForeignKeys as $key => $value) {
7142             if ($value = $this->_getPortableTableForeignKeyDefinition($value)) {
7143                 $list[] = $value;
7144             }
7145         }
7146         return $list;
7147     }
7148
7149     protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
7150     {
7151         return $tableForeignKey;
7152     }
7153
7154     protected function _execSql($sql)
7155     {
7156         foreach ((array) $sql as $query) {
7157             $this->_conn->executeUpdate($query);
7158         }
7159     }
7160
7161     /**
7162      * Create a schema instance for the current database.
7163      * 
7164      * @return Schema
7165      */
7166     public function createSchema()
7167     {
7168         $sequences = array();
7169         if($this->_platform->supportsSequences()) {
7170             $sequences = $this->listSequences();
7171         }
7172         $tables = $this->listTables();
7173
7174         return new Schema($tables, $sequences, $this->createSchemaConfig());
7175     }
7176
7177     /**
7178      * Create the configuration for this schema.
7179      *
7180      * @return SchemaConfig
7181      */
7182     public function createSchemaConfig()
7183     {
7184         $schemaConfig = new SchemaConfig();
7185         $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
7186
7187         return $schemaConfig;
7188     }
7189 }<?php
7190 /*
7191  *  $Id$
7192  *
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.
7204  *
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>.
7208  */
7209
7210 namespace Doctrine\DBAL\Schema;
7211
7212 /**
7213  * The abstract asset allows to reset the name of all assets without publishing this to the public userland.
7214  *
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
7217  *
7218  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7219  * @link    www.doctrine-project.org
7220  * @since   2.0
7221  * @version $Revision$
7222  * @author  Benjamin Eberlei <kontakt@beberlei.de>
7223  */
7224 abstract class AbstractAsset
7225 {
7226     /**
7227      * @var string
7228      */
7229     protected $_name;
7230
7231     /**
7232      * Set name of this asset
7233      *
7234      * @param string $name
7235      */
7236     protected function _setName($name)
7237     {
7238         $this->_name = $name;
7239     }
7240
7241     /**
7242      * Return name of this schema asset.
7243      * 
7244      * @return string
7245      */
7246     public function getName()
7247     {
7248         return $this->_name;
7249     }
7250
7251     /**
7252      * Generate an identifier from a list of column names obeying a certain string length.
7253      *
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
7256      * very long names.
7257      *
7258      * @param  array $columnNames
7259      * @param  string $postfix
7260      * @param  int $maxSize
7261      * @return string
7262      */
7263     protected function _generateIdentifierName($columnNames, $postfix='', $maxSize=30)
7264     {
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));
7269         }, $columnNames);
7270         $parts[] = $postfix;
7271
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);
7276
7277         if (is_numeric(substr($identifier, 0, 1))) {
7278             $identifier = "i" . substr($identifier, 0, strlen($identifier)-1);
7279         }
7280
7281         return $identifier;
7282     }
7283 }<?php
7284 /*
7285  *  $Id: Schema.php 6876 2009-12-06 23:11:35Z beberlei $
7286  *
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.
7298  *
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>.
7302  */
7303
7304 namespace Doctrine\DBAL\Schema;
7305
7306 /**
7307  * Configuration for a Schema
7308  *
7309  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7310  * @link    www.doctrine-project.org
7311  * @since   2.0
7312  * @version $Revision$
7313  * @author  Benjamin Eberlei <kontakt@beberlei.de>
7314  */
7315 class SchemaConfig
7316 {
7317     /**
7318      * @var bool
7319      */
7320     protected $_hasExplicitForeignKeyIndexes = false;
7321
7322     /**
7323      * @var int
7324      */
7325     protected $_maxIdentifierLength = 63;
7326
7327     /**
7328      * @return bool
7329      */
7330     public function hasExplicitForeignKeyIndexes()
7331     {
7332         return $this->_hasExplicitForeignKeyIndexes;
7333     }
7334
7335     /**
7336      * @param bool $flag
7337      */
7338     public function setExplicitForeignKeyIndexes($flag)
7339     {
7340         $this->_hasExplicitForeignKeyIndexes = (bool)$flag;
7341     }
7342
7343     /**
7344      * @param int $length
7345      */
7346     public function setMaxIdentifierLength($length)
7347     {
7348         $this->_maxIdentifierLength = (int)$length;
7349     }
7350
7351     /**
7352      * @return int
7353      */
7354     public function getMaxIdentifierLength()
7355     {
7356         return $this->_maxIdentifierLength;
7357     }
7358 }<?php
7359 /*
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.
7371  *
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>.
7375  */
7376
7377 namespace Doctrine\DBAL\Schema;
7378
7379 use \Doctrine\DBAL\Types\Type;
7380 use Doctrine\DBAL\Schema\Visitor\Visitor;
7381
7382 /**
7383  * Object representation of a database column
7384  *
7385  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7386  * @link    www.doctrine-project.org
7387  * @since   2.0
7388  * @version $Revision$
7389  * @author  Benjamin Eberlei <kontakt@beberlei.de>
7390  */
7391 class Column extends AbstractAsset
7392 {
7393     /**
7394      * @var \Doctrine\DBAL\Types\Type
7395      */
7396     protected $_type;
7397
7398     /**
7399      * @var int
7400      */
7401     protected $_length = null;
7402
7403     /**
7404      * @var int
7405      */
7406     protected $_precision = 0;
7407
7408     /**
7409      * @var int
7410      */
7411     protected $_scale = 0;
7412
7413     /**
7414      * @var bool
7415      */
7416     protected $_unsigned = false;
7417
7418     /**
7419      * @var bool
7420      */
7421     protected $_fixed = false;
7422
7423     /**
7424      * @var bool
7425      */
7426     protected $_notnull = true;
7427
7428     /**
7429      * @var string
7430      */
7431     protected $_default = null;
7432
7433     /**
7434      * @var bool
7435      */
7436     protected $_autoincrement = false;
7437
7438     /**
7439      * @var array
7440      */
7441     protected $_platformOptions = array();
7442
7443     /**
7444      * @var string
7445      */
7446     protected $_columnDefinition = null;
7447
7448     /**
7449      * Create a new Column
7450      * 
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
7459      * @param int $scale
7460      * @param array $platformOptions
7461      */
7462     public function __construct($columnName, Type $type, array $options=array())
7463     {
7464         $this->_setName($columnName);
7465         $this->setType($type);
7466         $this->setOptions($options);
7467     }
7468
7469     /**
7470      * @param array $options
7471      * @return Column
7472      */
7473     public function setOptions(array $options)
7474     {
7475         foreach ($options AS $name => $value) {
7476             $method = "set".$name;
7477             if (method_exists($this, $method)) {
7478                 $this->$method($value);
7479             }
7480         }
7481         return $this;
7482     }
7483
7484     /**
7485      * @param Type $type
7486      * @return Column
7487      */
7488     public function setType(Type $type)
7489     {
7490         $this->_type = $type;
7491         return $this;
7492     }
7493
7494     /**
7495      * @param int $length
7496      * @return Column
7497      */
7498     public function setLength($length)
7499     {
7500         if($length !== null) {
7501             $this->_length = (int)$length;
7502         } else {
7503             $this->_length = null;
7504         }
7505         return $this;
7506     }
7507
7508     /**
7509      * @param int $precision
7510      * @return Column
7511      */
7512     public function setPrecision($precision)
7513     {
7514         $this->_precision = (int)$precision;
7515         return $this;
7516     }
7517
7518     /**
7519      * @param  int $scale
7520      * @return Column
7521      */
7522     public function setScale($scale)
7523     {
7524         $this->_scale = $scale;
7525         return $this;
7526     }
7527
7528     /**
7529      *
7530      * @param  bool $unsigned
7531      * @return Column
7532      */
7533     public function setUnsigned($unsigned)
7534     {
7535         $this->_unsigned = (bool)$unsigned;
7536         return $this;
7537     }
7538
7539     /**
7540      *
7541      * @param  bool $fixed
7542      * @return Column
7543      */
7544     public function setFixed($fixed)
7545     {
7546         $this->_fixed = (bool)$fixed;
7547         return $this;
7548     }
7549
7550     /**
7551      * @param  bool $notnull
7552      * @return Column
7553      */
7554     public function setNotnull($notnull)
7555     {
7556         $this->_notnull = (bool)$notnull;
7557         return $this;
7558     }
7559
7560     /**
7561      *
7562      * @param  mixed $default
7563      * @return Column
7564      */
7565     public function setDefault($default)
7566     {
7567         $this->_default = $default;
7568         return $this;
7569     }
7570
7571     /**
7572      *
7573      * @param array $platformOptions
7574      * @return Column
7575      */
7576     public function setPlatformOptions(array $platformOptions)
7577     {
7578         $this->_platformOptions = $platformOptions;
7579         return $this;
7580     }
7581
7582     /**
7583      *
7584      * @param  string $name
7585      * @param  mixed $value
7586      * @return Column
7587      */
7588     public function setPlatformOption($name, $value)
7589     {
7590         $this->_platformOptions[$name] = $value;
7591         return $this;
7592     }
7593
7594     /**
7595      *
7596      * @param  string
7597      * @return Column
7598      */
7599     public function setColumnDefinition($value)
7600     {
7601         $this->_columnDefinition = $value;
7602         return $this;
7603     }
7604
7605     public function getType()
7606     {
7607         return $this->_type;
7608     }
7609
7610     public function getLength()
7611     {
7612         return $this->_length;
7613     }
7614
7615     public function getPrecision()
7616     {
7617         return $this->_precision;
7618     }
7619
7620     public function getScale()
7621     {
7622         return $this->_scale;
7623     }
7624
7625     public function getUnsigned()
7626     {
7627         return $this->_unsigned;
7628     }
7629
7630     public function getFixed()
7631     {
7632         return $this->_fixed;
7633     }
7634
7635     public function getNotnull()
7636     {
7637         return $this->_notnull;
7638     }
7639
7640     public function getDefault()
7641     {
7642         return $this->_default;
7643     }
7644
7645     public function getPlatformOptions()
7646     {
7647         return $this->_platformOptions;
7648     }
7649
7650     public function hasPlatformOption($name)
7651     {
7652         return isset($this->_platformOptions[$name]);
7653     }
7654
7655     public function getPlatformOption($name)
7656     {
7657         return $this->_platformOptions[$name];
7658     }
7659
7660     public function getColumnDefinition()
7661     {
7662         return $this->_columnDefinition;
7663     }
7664
7665     public function getAutoincrement()
7666     {
7667         return $this->_autoincrement;
7668     }
7669
7670     public function setAutoincrement($flag)
7671     {
7672         $this->_autoincrement = $flag;
7673         return $this;
7674     }
7675
7676     /**
7677      * @param Visitor $visitor
7678      */
7679     public function visit(\Doctrine\DBAL\Schema\Visitor $visitor)
7680     {
7681         $visitor->accept($this);
7682     }
7683
7684     /**
7685      * @return array
7686      */
7687     public function toArray()
7688     {
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);
7702     }
7703 }<?php
7704 /*
7705  *  $Id$
7706  *
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.
7718  *
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>.
7722  */
7723
7724 namespace Doctrine\DBAL\Schema;
7725
7726 /**
7727  * Marker interface for contraints
7728  *
7729  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7730  * @link    www.doctrine-project.org
7731  * @since   2.0
7732  * @version $Revision$
7733  * @author  Benjamin Eberlei <kontakt@beberlei.de>
7734  */
7735 interface Constraint
7736 {
7737     public function getName();
7738
7739     public function getColumns();
7740 }<?php
7741 /*
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.
7753  *
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>.
7757  */
7758
7759 namespace Doctrine\DBAL\Schema;
7760
7761 use \Doctrine\DBAL\Platforms\AbstractPlatform;
7762
7763 /**
7764  * Schema Diff
7765  *
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
7770  * @since   2.0
7771  * @version $Revision$
7772  * @author  Benjamin Eberlei <kontakt@beberlei.de>
7773  */
7774 class SchemaDiff
7775 {
7776     /**
7777      * All added tables
7778      *
7779      * @var array(string=>ezcDbSchemaTable)
7780      */
7781     public $newTables = array();
7782
7783     /**
7784      * All changed tables
7785      *
7786      * @var array(string=>ezcDbSchemaTableDiff)
7787      */
7788     public $changedTables = array();
7789
7790     /**
7791      * All removed tables
7792      *
7793      * @var array(string=>Table)
7794      */
7795     public $removedTables = array();
7796
7797     /**
7798      * @var array
7799      */
7800     public $newSequences = array();
7801
7802     /**
7803      * @var array
7804      */
7805     public $changedSequences = array();
7806
7807     /**
7808      * @var array
7809      */
7810     public $removedSequences = array();
7811
7812     /**
7813      * @var array
7814      */
7815     public $orphanedForeignKeys = array();
7816
7817     /**
7818      * Constructs an SchemaDiff object.
7819      *
7820      * @param array(string=>Table)      $newTables
7821      * @param array(string=>TableDiff)  $changedTables
7822      * @param array(string=>bool)       $removedTables
7823      */
7824     public function __construct($newTables = array(), $changedTables = array(), $removedTables = array())
7825     {
7826         $this->newTables = $newTables;
7827         $this->changedTables = $changedTables;
7828         $this->removedTables = $removedTables;
7829     }
7830
7831     /**
7832      * The to save sql mode ensures that the following things don't happen:
7833      *
7834      * 1. Tables are deleted
7835      * 2. Sequences are deleted
7836      * 3. Foreign Keys which reference tables that would otherwise be deleted.
7837      *
7838      * This way it is ensured that assets are deleted which might not be relevant to the metadata schema at all.
7839      *
7840      * @param AbstractPlatform $platform
7841      * @return array
7842      */
7843     public function toSaveSql(AbstractPlatform $platform)
7844     {
7845         return $this->_toSql($platform, true);
7846     }
7847
7848     /**
7849      * @param AbstractPlatform $platform
7850      * @return array
7851      */
7852     public function toSql(AbstractPlatform $platform)
7853     {
7854         return $this->_toSql($platform, false);
7855     }
7856
7857     /**
7858      * @param AbstractPlatform $platform
7859      * @param bool $saveMode
7860      * @return array
7861      */
7862     protected function _toSql(AbstractPlatform $platform, $saveMode = false)
7863     {
7864         $sql = array();
7865
7866         if ($platform->supportsForeignKeyConstraints() && $saveMode == false) {
7867             foreach ($this->orphanedForeignKeys AS $orphanedForeignKey) {
7868                 $sql[] = $platform->getDropForeignKeySQL($orphanedForeignKey, $orphanedForeignKey->getLocalTableName());
7869             }
7870         }
7871
7872         if ($platform->supportsSequences() == true) {
7873             foreach ($this->changedSequences AS $sequence) {
7874                 $sql[] = $platform->getDropSequenceSQL($sequence);
7875                 $sql[] = $platform->getCreateSequenceSQL($sequence);
7876             }
7877
7878             if ($saveMode === false) {
7879                 foreach ($this->removedSequences AS $sequence) {
7880                     $sql[] = $platform->getDropSequenceSQL($sequence);
7881                 }
7882             }
7883
7884             foreach ($this->newSequences AS $sequence) {
7885                 $sql[] = $platform->getCreateSequenceSQL($sequence);
7886             }
7887         }
7888
7889         $foreignKeySql = array();
7890         foreach ($this->newTables AS $table) {
7891             $sql = array_merge(
7892                 $sql,
7893                 $platform->getCreateTableSQL($table, AbstractPlatform::CREATE_INDEXES)
7894             );
7895
7896             if ($platform->supportsForeignKeyConstraints()) {
7897                 foreach ($table->getForeignKeys() AS $foreignKey) {
7898                     $foreignKeySql[] = $platform->getCreateForeignKeySQL($foreignKey, $table);
7899                 }
7900             }
7901         }
7902         $sql = array_merge($sql, $foreignKeySql);
7903
7904         if ($saveMode === false) {
7905             foreach ($this->removedTables AS $table) {
7906                 $sql[] = $platform->getDropTableSQL($table);
7907             }
7908         }
7909
7910         foreach ($this->changedTables AS $tableDiff) {
7911             $sql = array_merge($sql, $platform->getAlterTableSQL($tableDiff));
7912         }
7913
7914         return $sql;
7915     }
7916 }<?php
7917 /*
7918  *  $Id$
7919  *
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.
7931  *
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>.
7935  */
7936
7937 namespace Doctrine\DBAL\Schema;
7938
7939 use Doctrine\DBAL\Schema\Visitor\CreateSchemaSqlCollector;
7940 use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector;
7941 use Doctrine\DBAL\Schema\Visitor\Visitor;
7942
7943 /**
7944  * Object representation of a database schema
7945  *
7946  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
7947  * @link    www.doctrine-project.org
7948  * @since   2.0
7949  * @version $Revision$
7950  * @author  Benjamin Eberlei <kontakt@beberlei.de>
7951  */
7952 class Schema extends AbstractAsset
7953 {
7954     /**
7955      * @var array
7956      */
7957     protected $_tables = array();
7958     
7959     /**
7960      * @var array
7961      */
7962     protected $_sequences = array();
7963
7964     /**
7965      * @var SchemaConfig
7966      */
7967     protected $_schemaConfig = false;
7968
7969     /**
7970      * @param array $tables
7971      * @param array $sequences
7972      * @param array $views
7973      * @param array $triggers
7974      * @param SchemaConfig $schemaConfig
7975      */
7976     public function __construct(array $tables=array(), array $sequences=array(), SchemaConfig $schemaConfig=null)
7977     {
7978         if ($schemaConfig == null) {
7979             $schemaConfig = new SchemaConfig();
7980         }
7981         $this->_schemaConfig = $schemaConfig;
7982
7983         foreach ($tables AS $table) {
7984             $this->_addTable($table);
7985         }
7986         foreach ($sequences AS $sequence) {
7987             $this->_addSequence($sequence);
7988         }
7989     }
7990
7991     /**
7992      * @return bool
7993      */
7994     public function hasExplicitForeignKeyIndexes()
7995     {
7996         return $this->_schemaConfig->hasExplicitForeignKeyIndexes();
7997     }
7998
7999     /**
8000      * @param Table $table
8001      */
8002     protected function _addTable(Table $table)
8003     {
8004         $tableName = strtolower($table->getName());
8005         if(isset($this->_tables[$tableName])) {
8006             throw SchemaException::tableAlreadyExists($tableName);
8007         }
8008
8009         $this->_tables[$tableName] = $table;
8010         $table->setSchemaConfig($this->_schemaConfig);
8011     }
8012
8013     /**
8014      * @param Sequence $sequence
8015      */
8016     protected function _addSequence(Sequence $sequence)
8017     {
8018         $seqName = strtolower($sequence->getName());
8019         if (isset($this->_sequences[$seqName])) {
8020             throw SchemaException::sequenceAlreadyExists($seqName);
8021         }
8022         $this->_sequences[$seqName] = $sequence;
8023     }
8024
8025     /**
8026      * Get all tables of this schema.
8027      * 
8028      * @return array
8029      */
8030     public function getTables()
8031     {
8032         return $this->_tables;
8033     }
8034
8035     /**
8036      * @param string $tableName
8037      * @return Table
8038      */
8039     public function getTable($tableName)
8040     {
8041         $tableName = strtolower($tableName);
8042         if (!isset($this->_tables[$tableName])) {
8043             throw SchemaException::tableDoesNotExist($tableName);
8044         }
8045
8046         return $this->_tables[$tableName];
8047     }
8048
8049     /**
8050      * Does this schema have a table with the given name?
8051      * 
8052      * @param  string $tableName
8053      * @return Schema
8054      */
8055     public function hasTable($tableName)
8056     {
8057         $tableName = strtolower($tableName);
8058         return isset($this->_tables[$tableName]);
8059     }
8060
8061     /**
8062      * @param  string $sequenceName
8063      * @return bool
8064      */
8065     public function hasSequence($sequenceName)
8066     {
8067         $sequenceName = strtolower($sequenceName);
8068         return isset($this->_sequences[$sequenceName]);
8069     }
8070
8071     /**
8072      * @throws SchemaException
8073      * @param  string $sequenceName
8074      * @return Doctrine\DBAL\Schema\Sequence
8075      */
8076     public function getSequence($sequenceName)
8077     {
8078         $sequenceName = strtolower($sequenceName);
8079         if(!$this->hasSequence($sequenceName)) {
8080             throw SchemaException::sequenceDoesNotExist($sequenceName);
8081         }
8082         return $this->_sequences[$sequenceName];
8083     }
8084
8085     /**
8086      * @return Doctrine\DBAL\Schema\Sequence[]
8087      */
8088     public function getSequences()
8089     {
8090         return $this->_sequences;
8091     }
8092
8093     /**
8094      * Create a new table
8095      * 
8096      * @param  string $tableName
8097      * @return Table
8098      */
8099     public function createTable($tableName)
8100     {
8101         $table = new Table($tableName);
8102         $this->_addTable($table);
8103         return $table;
8104     }
8105
8106     /**
8107      * Rename a table
8108      *
8109      * @param string $oldTableName
8110      * @param string $newTableName
8111      * @return Schema
8112      */
8113     public function renameTable($oldTableName, $newTableName)
8114     {
8115         $table = $this->getTable($oldTableName);
8116         $table->_setName($newTableName);
8117
8118         $this->dropTable($oldTableName);
8119         $this->_addTable($table);
8120         return $this;
8121     }
8122
8123     /**
8124      * Drop a table from the schema.
8125      *
8126      * @param string $tableName
8127      * @return Schema
8128      */
8129     public function dropTable($tableName)
8130     {
8131         $tableName = strtolower($tableName);
8132         $table = $this->getTable($tableName);
8133         unset($this->_tables[$tableName]);
8134         return $this;
8135     }
8136
8137     /**
8138      * Create a new sequence
8139      * 
8140      * @param  string $sequenceName
8141      * @param  int $allocationSize
8142      * @param  int $initialValue
8143      * @return Sequence
8144      */
8145     public function createSequence($sequenceName, $allocationSize=1, $initialValue=1)
8146     {
8147         $seq = new Sequence($sequenceName, $allocationSize, $initialValue);
8148         $this->_addSequence($seq);
8149         return $seq;
8150     }
8151
8152     /**
8153      * @param string $sequenceName
8154      * @return Schema
8155      */
8156     public function dropSequence($sequenceName)
8157     {
8158         $sequenceName = strtolower($sequenceName);
8159         unset($this->_sequences[$sequenceName]);
8160         return $this;
8161     }
8162
8163     /**
8164      * Return an array of necessary sql queries to create the schema on the given platform.
8165      *
8166      * @param AbstractPlatform $platform
8167      * @return array
8168      */
8169     public function toSql(\Doctrine\DBAL\Platforms\AbstractPlatform $platform)
8170     {
8171         $sqlCollector = new CreateSchemaSqlCollector($platform);
8172         $this->visit($sqlCollector);
8173
8174         return $sqlCollector->getQueries();
8175     }
8176
8177     /**
8178      * Return an array of necessary sql queries to drop the schema on the given platform.
8179      *
8180      * @param AbstractPlatform $platform
8181      * @return array
8182      */
8183     public function toDropSql(\Doctrine\DBAL\Platforms\AbstractPlatform $platform)
8184     {
8185         $dropSqlCollector = new DropSchemaSqlCollector($platform);
8186         $this->visit($dropSqlCollector);
8187
8188         return $dropSqlCollector->getQueries();
8189     }
8190
8191     /**
8192      * @param Schema $toSchema
8193      * @param AbstractPlatform $platform
8194      */
8195     public function getMigrateToSql(Schema $toSchema, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
8196     {
8197         $comparator = new Comparator();
8198         $schemaDiff = $comparator->compare($this, $toSchema);
8199         return $schemaDiff->toSql($platform);
8200     }
8201
8202     /**
8203      * @param Schema $fromSchema
8204      * @param AbstractPlatform $platform
8205      */
8206     public function getMigrateFromSql(Schema $fromSchema, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
8207     {
8208         $comparator = new Comparator();
8209         $schemaDiff = $comparator->compare($fromSchema, $this);
8210         return $schemaDiff->toSql($platform);
8211     }
8212
8213     /**
8214      * @param Visitor $visitor
8215      */
8216     public function visit(Visitor $visitor)
8217     {
8218         $visitor->acceptSchema($this);
8219         
8220         foreach ($this->_tables AS $table) {
8221             $table->visit($visitor);
8222         }
8223         foreach ($this->_sequences AS $sequence) {
8224             $sequence->visit($visitor);
8225         }
8226     }
8227
8228     /**
8229      * Cloning a Schema triggers a deep clone of all related assets.
8230      *
8231      * @return void
8232      */
8233     public function __clone()
8234     {
8235         foreach ($this->_tables AS $k => $table) {
8236             $this->_tables[$k] = clone $table;
8237         }
8238         foreach ($this->_sequences AS $k => $sequence) {
8239             $this->_sequences[$k] = clone $sequence;
8240         }
8241     }
8242 }
8243 <?php
8244 /*
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.
8256  *
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>.
8260  */
8261
8262 namespace Doctrine\DBAL\Schema;
8263
8264 /**
8265  * xxx
8266  *
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$
8272  * @since       2.0
8273  */
8274 class MsSqlSchemaManager extends AbstractSchemaManager
8275 {
8276
8277     /**
8278      * @override
8279      */
8280     protected function _getPortableTableColumnDefinition($tableColumn)
8281     {
8282         $dbType = strtolower($tableColumn['TYPE_NAME']);
8283
8284         $autoincrement = false;
8285         if (stripos($dbType, 'identity')) {
8286             $dbType = trim(str_ireplace('identity', '', $dbType));
8287             $autoincrement = true;
8288         }
8289
8290         $type = array();
8291         $unsigned = $fixed = null;
8292
8293         if (!isset($tableColumn['name'])) {
8294             $tableColumn['name'] = '';
8295         }
8296
8297         $default = $tableColumn['COLUMN_DEF'];
8298
8299         while ($default != ($default2 = preg_replace("/^\((.*)\)$/", '$1', $default))) {
8300             $default = $default2;
8301         }
8302
8303         $length = (int) $tableColumn['LENGTH'];
8304
8305         $type = $this->_platform->getDoctrineTypeMapping($dbType);
8306         switch ($type) {
8307             case 'char':
8308                 if ($tableColumn['LENGTH'] == '1') {
8309                     $type = 'boolean';
8310                     if (preg_match('/^(is|has)/', $tableColumn['name'])) {
8311                         $type = array_reverse($type);
8312                     }
8313                 }
8314                 $fixed = true;
8315                 break;
8316             case 'text':
8317                 $fixed = false;
8318                 break;
8319         }
8320         switch ($dbType) {
8321             case 'nchar':
8322             case 'nvarchar':
8323             case 'ntext':
8324                 // Unicode data requires 2 bytes per character
8325                 $length = $length / 2;
8326                 break;
8327         }
8328
8329         $options = array(
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,
8338         );
8339
8340         return new Column($tableColumn['COLUMN_NAME'], \Doctrine\DBAL\Types\Type::getType($type), $options);
8341     }
8342
8343     /**
8344      * @override
8345      */
8346     protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null)
8347     {
8348         $result = array();
8349         foreach ($tableIndexRows AS $tableIndex) {
8350             $indexName = $keyName = $tableIndex['index_name'];
8351             if (strpos($tableIndex['index_description'], 'primary key') !== false) {
8352                 $keyName = 'primary';
8353             }
8354             $keyName = strtolower($keyName);
8355
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,
8361             );
8362         }
8363
8364         $indexes = array();
8365         foreach ($result AS $indexKey => $data) {
8366             $indexes[$indexKey] = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']);
8367         }
8368
8369         return $indexes;
8370     }
8371
8372     /**
8373      * @override
8374      */
8375     public function _getPortableTableForeignKeyDefinition($tableForeignKey)
8376     {
8377         return new ForeignKeyConstraint(
8378                 (array) $tableForeignKey['ColumnName'],
8379                 $tableForeignKey['ReferenceTableName'],
8380                 (array) $tableForeignKey['ReferenceColumnName'],
8381                 $tableForeignKey['ForeignKey'],
8382                 array(
8383                     'onUpdate' => str_replace('_', ' ', $tableForeignKey['update_referential_action_desc']),
8384                     'onDelete' => str_replace('_', ' ', $tableForeignKey['delete_referential_action_desc']),
8385                 )
8386         );
8387     }
8388
8389     /**
8390      * @override
8391      */
8392     protected function _getPortableTableDefinition($table)
8393     {
8394         return $table['name'];
8395     }
8396
8397     /**
8398      * @override
8399      */
8400     protected function _getPortableDatabaseDefinition($database)
8401     {
8402         return $database['name'];
8403     }
8404
8405     /**
8406      * @override
8407      */
8408     protected function _getPortableViewDefinition($view)
8409     {
8410         // @todo
8411         return new View($view['name'], null);
8412     }
8413
8414 }<?php
8415 /*
8416  *  $Id$
8417  *
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.
8429  *
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>.
8433  */
8434
8435 namespace Doctrine\DBAL\Schema\Visitor;
8436
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;
8445
8446 /**
8447  * Schema Visitor used for Validation or Generation purposes.
8448  *
8449  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
8450  * @link    www.doctrine-project.org
8451  * @since   2.0
8452  * @version $Revision$
8453  * @author  Benjamin Eberlei <kontakt@beberlei.de>
8454  */
8455 interface Visitor
8456 {
8457     /**
8458      * @param Schema $schema
8459      */
8460     public function acceptSchema(Schema $schema);
8461
8462     /**
8463      * @param Table $table
8464      */
8465     public function acceptTable(Table $table);
8466
8467     /**
8468      * @param Column $column
8469      */
8470     public function acceptColumn(Table $table, Column $column);
8471
8472     /**
8473      * @param Table $localTable
8474      * @param ForeignKeyConstraint $fkConstraint
8475      */
8476     public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint);
8477
8478     /**
8479      * @param Table $table
8480      * @param Index $index
8481      */
8482     public function acceptIndex(Table $table, Index $index);
8483
8484     /**
8485      * @param Sequence $sequence
8486      */
8487     public function acceptSequence(Sequence $sequence);
8488 }<?php
8489 /*
8490  *  $Id$
8491  *
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.
8503  *
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>.
8507  */
8508
8509 namespace Doctrine\DBAL\Schema\Visitor;
8510
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;
8519
8520 class CreateSchemaSqlCollector implements Visitor
8521 {
8522     /**
8523      * @var array
8524      */
8525     private $_createTableQueries = array();
8526
8527     /**
8528      * @var array
8529      */
8530     private $_createSequenceQueries = array();
8531
8532     /**
8533      * @var array
8534      */
8535     private $_createFkConstraintQueries = array();
8536
8537     /**
8538      *
8539      * @var \Doctrine\DBAL\Platforms\AbstractPlatform
8540      */
8541     private $_platform = null;
8542
8543     /**
8544      * @param AbstractPlatform $platform
8545      */
8546     public function __construct(AbstractPlatform $platform)
8547     {
8548         $this->_platform = $platform;
8549     }
8550
8551     /**
8552      * @param Schema $schema
8553      */
8554     public function acceptSchema(Schema $schema)
8555     {
8556
8557     }
8558
8559     /**
8560      * Generate DDL Statements to create the accepted table with all its dependencies.
8561      *
8562      * @param Table $table
8563      */
8564     public function acceptTable(Table $table)
8565     {
8566         $this->_createTableQueries = array_merge($this->_createTableQueries,
8567             $this->_platform->getCreateTableSQL($table)
8568         );
8569     }
8570
8571     public function acceptColumn(Table $table, Column $column)
8572     {
8573         
8574     }
8575
8576     /**
8577      * @param Table $localTable
8578      * @param ForeignKeyConstraint $fkConstraint
8579      */
8580     public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint)
8581     {
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())
8586             );
8587         }
8588     }
8589
8590     /**
8591      * @param Table $table
8592      * @param Index $index
8593      */
8594     public function acceptIndex(Table $table, Index $index)
8595     {
8596         
8597     }
8598
8599     /**
8600      * @param Sequence $sequence
8601      */
8602     public function acceptSequence(Sequence $sequence)
8603     {
8604         $this->_createSequenceQueries = array_merge(
8605             $this->_createSequenceQueries, (array)$this->_platform->getCreateSequenceSQL($sequence)
8606         );
8607     }
8608
8609     /**
8610      * @return array
8611      */
8612     public function resetQueries()
8613     {
8614         $this->_createTableQueries = array();
8615         $this->_createSequenceQueries = array();
8616         $this->_createFkConstraintQueries = array();
8617     }
8618
8619     /**
8620      * Get all queries collected so far.
8621      *
8622      * @return array
8623      */
8624     public function getQueries()
8625     {
8626         return array_merge(
8627             $this->_createTableQueries,
8628             $this->_createSequenceQueries,
8629             $this->_createFkConstraintQueries
8630         );
8631     }
8632 }<?php
8633 /*
8634  *  $Id$
8635  *
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.
8647  *
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>.
8651  */
8652
8653 namespace Doctrine\DBAL\Schema\Visitor;
8654
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;
8663
8664 /**
8665  * Gather SQL statements that allow to completly drop the current schema.
8666  *
8667  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
8668  * @link    www.doctrine-project.org
8669  * @since   2.0
8670  * @version $Revision$
8671  * @author  Benjamin Eberlei <kontakt@beberlei.de>
8672  */
8673 class DropSchemaSqlCollector implements Visitor
8674 {
8675     /**
8676      * @var array
8677      */
8678     private $_constraints = array();
8679     
8680     /**
8681      * @var array
8682      */
8683     private $_sequences = array();
8684
8685     /**
8686      * @var array
8687      */
8688     private $_tables = array();
8689
8690     /**
8691      *
8692      * @var \Doctrine\DBAL\Platforms\AbstractPlatform
8693      */
8694     private $_platform = null;
8695
8696     /**
8697      * @param AbstractPlatform $platform
8698      */
8699     public function __construct(AbstractPlatform $platform)
8700     {
8701         $this->_platform = $platform;
8702     }
8703
8704     /**
8705      * @param Schema $schema
8706      */
8707     public function acceptSchema(Schema $schema)
8708     {
8709         
8710     }
8711
8712     /**
8713      * @param Table $table
8714      */
8715     public function acceptTable(Table $table)
8716     {
8717         $this->_tables[] = $this->_platform->getDropTableSQL($table->getName());
8718     }
8719
8720     /**
8721      * @param Column $column
8722      */
8723     public function acceptColumn(Table $table, Column $column)
8724     {
8725         
8726     }
8727
8728     /**
8729      * @param Table $localTable
8730      * @param ForeignKeyConstraint $fkConstraint
8731      */
8732     public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint)
8733     {
8734         if (strlen($fkConstraint->getName()) == 0) {
8735             throw SchemaException::namedForeignKeyRequired($localTable, $fkConstraint);
8736         }
8737
8738         $this->_constraints[] = $this->_platform->getDropForeignKeySQL($fkConstraint->getName(), $localTable->getName());
8739     }
8740
8741     /**
8742      * @param Table $table
8743      * @param Index $index
8744      */
8745     public function acceptIndex(Table $table, Index $index)
8746     {
8747         
8748     }
8749
8750     /**
8751      * @param Sequence $sequence
8752      */
8753     public function acceptSequence(Sequence $sequence)
8754     {
8755         $this->_sequences[] = $this->_platform->getDropSequenceSQL($sequence->getName());
8756     }
8757
8758     /**
8759      * @return array
8760      */
8761     public function clearQueries()
8762     {
8763         $this->_constraints = $this->_sequences = $this->_tables = array();
8764     }
8765
8766     /**
8767      * @return array
8768      */
8769     public function getQueries()
8770     {
8771         return array_merge($this->_constraints, $this->_tables, $this->_sequences);
8772     }
8773 }
8774 <?php
8775 /*
8776  *  $Id$
8777  *
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.
8789  *
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>.
8793  */
8794
8795 namespace Doctrine\DBAL\Schema;
8796
8797 use Doctrine\DBAL\Schema\Visitor\Visitor;
8798
8799 class ForeignKeyConstraint extends AbstractAsset implements Constraint
8800 {
8801     /**
8802      * @var Table
8803      */
8804     protected $_localTable;
8805
8806     /**
8807      * @var array
8808      */
8809     protected $_localColumnNames;
8810
8811     /**
8812      * @var string
8813      */
8814     protected $_foreignTableName;
8815
8816     /**
8817      * @var array
8818      */
8819     protected $_foreignColumnNames;
8820
8821     /**
8822      * @var string
8823      */
8824     protected $_cascade = '';
8825
8826     /**
8827      * @var array
8828      */
8829     protected $_options;
8830
8831     /**
8832      *
8833      * @param array $localColumnNames
8834      * @param string $foreignTableName
8835      * @param array $foreignColumnNames
8836      * @param string $cascade
8837      * @param string|null $name
8838      */
8839     public function __construct(array $localColumnNames, $foreignTableName, array $foreignColumnNames, $name=null, array $options=array())
8840     {
8841         $this->_setName($name);
8842         $this->_localColumnNames = $localColumnNames;
8843         $this->_foreignTableName = $foreignTableName;
8844         $this->_foreignColumnNames = $foreignColumnNames;
8845         $this->_options = $options;
8846     }
8847
8848     /**
8849      * @return string
8850      */
8851     public function getLocalTableName()
8852     {
8853         return $this->_localTable->getName();
8854     }
8855
8856     /**
8857      * @param Table $table
8858      */
8859     public function setLocalTable(Table $table)
8860     {
8861         $this->_localTable = $table;
8862     }
8863
8864     /**
8865      * @return array
8866      */
8867     public function getLocalColumns()
8868     {
8869         return $this->_localColumnNames;
8870     }
8871
8872     public function getColumns()
8873     {
8874         return $this->_localColumnNames;
8875     }
8876
8877     /**
8878      * @return string
8879      */
8880     public function getForeignTableName()
8881     {
8882         return $this->_foreignTableName;
8883     }
8884
8885     /**
8886      * @return array
8887      */
8888     public function getForeignColumns()
8889     {
8890         return $this->_foreignColumnNames;
8891     }
8892
8893     public function hasOption($name)
8894     {
8895         return isset($this->_options[$name]);
8896     }
8897
8898     public function getOption($name)
8899     {
8900         return $this->_options[$name];
8901     }
8902
8903     /**
8904      * Foreign Key onUpdate status
8905      *
8906      * @return string|null
8907      */
8908     public function onUpdate()
8909     {
8910         return $this->_onEvent('onUpdate');
8911     }
8912
8913     /**
8914      * Foreign Key onDelete status
8915      *
8916      * @return string|null
8917      */
8918     public function onDelete()
8919     {
8920         return $this->_onEvent('onDelete');
8921     }
8922
8923     /**
8924      * @param  string $event
8925      * @return string|null
8926      */
8927     private function _onEvent($event)
8928     {
8929         if (isset($this->_options[$event])) {
8930             $onEvent = strtoupper($this->_options[$event]);
8931             if (!in_array($onEvent, array('NO ACTION', 'RESTRICT'))) {
8932                 return $onEvent;
8933             }
8934         }
8935         return false;
8936     }
8937 }
8938 <?php
8939 /*
8940  *  $Id$
8941  *
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.
8953  *
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>.
8957  */
8958
8959 namespace Doctrine\DBAL\Schema;
8960
8961 use Doctrine\DBAL\Types\Type;
8962 use Doctrine\DBAL\Schema\Visitor\Visitor;
8963 use Doctrine\DBAL\DBALException;
8964
8965 /**
8966  * Object Representation of a table
8967  *
8968  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
8969  * @link    www.doctrine-project.org
8970  * @since   2.0
8971  * @version $Revision$
8972  * @author  Benjamin Eberlei <kontakt@beberlei.de>
8973  */
8974 class Table extends AbstractAsset
8975 {
8976     /**
8977      * @var string
8978      */
8979     protected $_name = null;
8980
8981     /**
8982      * @var array
8983      */
8984     protected $_columns = array();
8985
8986     /**
8987      * @var array
8988      */
8989     protected $_indexes = array();
8990
8991     /**
8992      * @var string
8993      */
8994     protected $_primaryKeyName = false;
8995
8996     /**
8997      * @var array
8998      */
8999     protected $_fkConstraints = array();
9000
9001     /**
9002      * @var array
9003      */
9004     protected $_options = array();
9005
9006     /**
9007      * @var SchemaConfig
9008      */
9009     protected $_schemaConfig = null;
9010
9011     /**
9012      *
9013      * @param string $tableName
9014      * @param array $columns
9015      * @param array $indexes
9016      * @param array $fkConstraints
9017      * @param int $idGeneratorType
9018      * @param array $options
9019      */
9020     public function __construct($tableName, array $columns=array(), array $indexes=array(), array $fkConstraints=array(), $idGeneratorType = 0, array $options=array())
9021     {
9022         if (strlen($tableName) == 0) {
9023             throw DBALException::invalidTableName($tableName);
9024         }
9025
9026         $this->_setName($tableName);
9027         $this->_idGeneratorType = $idGeneratorType;
9028         
9029         foreach ($columns AS $column) {
9030             $this->_addColumn($column);
9031         }
9032         
9033         foreach ($indexes AS $idx) {
9034             $this->_addIndex($idx);
9035         }
9036
9037         foreach ($fkConstraints AS $constraint) {
9038             $this->_addForeignKeyConstraint($constraint);
9039         }
9040
9041         $this->_options = $options;
9042     }
9043
9044     /**
9045      * @param SchemaConfig $schemaConfig
9046      */
9047     public function setSchemaConfig(SchemaConfig $schemaConfig)
9048     {
9049         $this->_schemaConfig = $schemaConfig;
9050     }
9051
9052     /**
9053      * @return int
9054      */
9055     protected function _getMaxIdentifierLength()
9056     {
9057         if ($this->_schemaConfig instanceof SchemaConfig) {
9058             return $this->_schemaConfig->getMaxIdentifierLength();
9059         } else {
9060             return 63;
9061         }
9062     }
9063
9064     /**
9065      * Set Primary Key
9066      *
9067      * @param array $columns
9068      * @param string $indexName
9069      * @return Table
9070      */
9071     public function setPrimaryKey(array $columns, $indexName = false)
9072     {
9073         $primaryKey = $this->_createIndex($columns, $indexName ?: "primary", true, true);
9074
9075         foreach ($columns AS $columnName) {
9076             $column = $this->getColumn($columnName);
9077             $column->setNotnull(true);
9078         }
9079
9080         return $primaryKey;
9081     }
9082
9083     /**
9084      * @param array $columnNames
9085      * @param string $indexName
9086      * @return Table
9087      */
9088     public function addIndex(array $columnNames, $indexName = null)
9089     {
9090         if($indexName == null) {
9091             $indexName = $this->_generateIdentifierName(
9092                 array_merge(array($this->getName()), $columnNames), "idx", $this->_getMaxIdentifierLength()
9093             );
9094         }
9095
9096         return $this->_createIndex($columnNames, $indexName, false, false);
9097     }
9098
9099     /**
9100      *
9101      * @param array $columnNames
9102      * @param string $indexName
9103      * @return Table
9104      */
9105     public function addUniqueIndex(array $columnNames, $indexName = null)
9106     {
9107         if ($indexName == null) {
9108             $indexName = $this->_generateIdentifierName(
9109                 array_merge(array($this->getName()), $columnNames), "uniq", $this->_getMaxIdentifierLength()
9110             );
9111         }
9112
9113         return $this->_createIndex($columnNames, $indexName, true, false);
9114     }
9115
9116     /**
9117      * Check if an index begins in the order of the given columns.
9118      *
9119      * @param  array $columnsNames
9120      * @return bool
9121      */
9122     public function columnsAreIndexed(array $columnsNames)
9123     {
9124         foreach ($this->getIndexes() AS $index) {
9125             /* @var $index Index */
9126             if ($index->spansColumns($columnsNames)) {
9127                 return true;
9128             }
9129         }
9130         return false;
9131     }
9132
9133     /**
9134      *
9135      * @param array $columnNames
9136      * @param string $indexName
9137      * @param bool $isUnique
9138      * @param bool $isPrimary
9139      * @return Table
9140      */
9141     private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary)
9142     {
9143         if (preg_match('(([^a-zA-Z0-9_]+))', $indexName)) {
9144             throw SchemaException::indexNameInvalid($indexName);
9145         }
9146
9147         foreach ($columnNames AS $columnName => $indexColOptions) {
9148             if (is_numeric($columnName) && is_string($indexColOptions)) {
9149                 $columnName = $indexColOptions;
9150             }
9151
9152             if ( ! $this->hasColumn($columnName)) {
9153                 throw SchemaException::columnDoesNotExist($columnName, $this->_name);
9154             }
9155         }
9156         $this->_addIndex(new Index($indexName, $columnNames, $isUnique, $isPrimary));
9157         return $this;
9158     }
9159
9160     /**
9161      * @param string $columnName
9162      * @param string $columnType
9163      * @param array $options
9164      * @return Column
9165      */
9166     public function addColumn($columnName, $typeName, array $options=array())
9167     {
9168         $column = new Column($columnName, Type::getType($typeName), $options);
9169
9170         $this->_addColumn($column);
9171         return $column;
9172     }
9173
9174     /**
9175      * Rename Column
9176      *
9177      * @param string $oldColumnName
9178      * @param string $newColumnName
9179      * @return Table
9180      */
9181     public function renameColumn($oldColumnName, $newColumnName)
9182     {
9183         $column = $this->getColumn($oldColumnName);
9184         $this->dropColumn($oldColumnName);
9185
9186         $column->_setName($newColumnName);
9187         return $this;
9188     }
9189
9190     /**
9191      * Change Column Details
9192      * 
9193      * @param string $columnName
9194      * @param array $options
9195      * @return Table
9196      */
9197     public function changeColumn($columnName, array $options)
9198     {
9199         $column = $this->getColumn($columnName);
9200         $column->setOptions($options);
9201         return $this;
9202     }
9203
9204     /**
9205      * Drop Column from Table
9206      * 
9207      * @param string $columnName
9208      * @return Table
9209      */
9210     public function dropColumn($columnName)
9211     {
9212         $columnName = strtolower($columnName);
9213         $column = $this->getColumn($columnName);
9214         unset($this->_columns[$columnName]);
9215         return $this;
9216     }
9217
9218
9219     /**
9220      * Add a foreign key constraint
9221      *
9222      * Name is inferred from the local columns
9223      *
9224      * @param Table $foreignTable
9225      * @param array $localColumns
9226      * @param array $foreignColumns
9227      * @param array $options
9228      * @return Table
9229      */
9230     public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array())
9231     {
9232         $name = $this->_generateIdentifierName(array_merge((array)$this->getName(), $localColumnNames), "fk", $this->_getMaxIdentifierLength());
9233         return $this->addNamedForeignKeyConstraint($name, $foreignTable, $localColumnNames, $foreignColumnNames, $options);
9234     }
9235
9236     /**
9237      * Add a foreign key constraint
9238      *
9239      * Name is to be generated by the database itsself.
9240      *
9241      * @param Table $foreignTable
9242      * @param array $localColumns
9243      * @param array $foreignColumns
9244      * @param array $options
9245      * @return Table
9246      */
9247     public function addUnnamedForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array())
9248     {
9249         return $this->addNamedForeignKeyConstraint(null, $foreignTable, $localColumnNames, $foreignColumnNames, $options);
9250     }
9251
9252     /**
9253      * Add a foreign key constraint with a given name
9254      *
9255      * @param string $name
9256      * @param Table $foreignTable
9257      * @param array $localColumns
9258      * @param array $foreignColumns
9259      * @param array $options
9260      * @return Table
9261      */
9262     public function addNamedForeignKeyConstraint($name, $foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array())
9263     {
9264         if ($foreignTable instanceof Table) {
9265             $foreignTableName = $foreignTable->getName();
9266
9267             foreach ($foreignColumnNames AS $columnName) {
9268                 if ( ! $foreignTable->hasColumn($columnName)) {
9269                     throw SchemaException::columnDoesNotExist($columnName, $foreignTable->getName());
9270                 }
9271             }
9272         } else {
9273             $foreignTableName = $foreignTable;
9274         }
9275
9276         foreach ($localColumnNames AS $columnName) {
9277             if ( ! $this->hasColumn($columnName)) {
9278                 throw SchemaException::columnDoesNotExist($columnName, $this->_name);
9279             }
9280         }
9281         
9282         $constraint = new ForeignKeyConstraint(
9283             $localColumnNames, $foreignTableName, $foreignColumnNames, $name, $options
9284         );
9285         $this->_addForeignKeyConstraint($constraint);
9286
9287         return $this;
9288     }
9289
9290     /**
9291      * @param string $name
9292      * @param string $value
9293      * @return Table
9294      */
9295     public function addOption($name, $value)
9296     {
9297         $this->_options[$name] = $value;
9298         return $this;
9299     }
9300
9301     /**
9302      * @param Column $column
9303      */
9304     protected function _addColumn(Column $column)
9305     {
9306         $columnName = $column->getName();
9307         $columnName = strtolower($columnName);
9308
9309         if (isset($this->_columns[$columnName])) {
9310             throw SchemaException::columnAlreadyExists($this->getName(), $columnName);
9311         }
9312
9313         $this->_columns[$columnName] = $column;
9314     }
9315
9316     /**
9317      * Add index to table
9318      * 
9319      * @param Index $indexCandidate
9320      * @return Table
9321      */
9322     protected function _addIndex(Index $indexCandidate)
9323     {
9324         // check for duplicates
9325         foreach ($this->_indexes AS $existingIndex) {
9326             if ($indexCandidate->isFullfilledBy($existingIndex)) {
9327                 return $this;
9328             }
9329         }
9330
9331         $indexName = $indexCandidate->getName();
9332         $indexName = strtolower($indexName);
9333
9334         if (isset($this->_indexes[$indexName]) || ($this->_primaryKeyName != false && $indexCandidate->isPrimary())) {
9335             throw SchemaException::indexAlreadyExists($indexName, $this->_name);
9336         }
9337
9338         // remove overruled indexes
9339         foreach ($this->_indexes AS $idxKey => $existingIndex) {
9340             if ($indexCandidate->overrules($existingIndex)) {
9341                 unset($this->_indexes[$idxKey]);
9342             }
9343         }
9344
9345         if ($indexCandidate->isPrimary()) {
9346             $this->_primaryKeyName = $indexName;
9347         }
9348
9349         $this->_indexes[$indexName] = $indexCandidate;
9350         return $this;
9351     }
9352
9353     /**
9354      * @param ForeignKeyConstraint $constraint
9355      */
9356     protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint)
9357     {
9358         $constraint->setLocalTable($this);
9359         
9360         if(strlen($constraint->getName())) {
9361             $name = $constraint->getName();
9362         } else {
9363             $name = $this->_generateIdentifierName(
9364                 array_merge((array)$this->getName(), $constraint->getLocalColumns()), "fk", $this->_getMaxIdentifierLength()
9365             );
9366         }
9367         $name = strtolower($name);
9368
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());
9374     }
9375
9376     /**
9377      * Does Table have a foreign key constraint with the given name?
9378      *      *
9379      * @param  string $constraintName
9380      * @return bool
9381      */
9382     public function hasForeignKey($constraintName)
9383     {
9384         $constraintName = strtolower($constraintName);
9385         return isset($this->_fkConstraints[$constraintName]);
9386     }
9387
9388     /**
9389      * @param string $constraintName
9390      * @return ForeignKeyConstraint
9391      */
9392     public function getForeignKey($constraintName)
9393     {
9394         $constraintName = strtolower($constraintName);
9395         if(!$this->hasForeignKey($constraintName)) {
9396             throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name);
9397         }
9398
9399         return $this->_fkConstraints[$constraintName];
9400     }
9401
9402     /**
9403      * @return Column[]
9404      */
9405     public function getColumns()
9406     {
9407         $columns = $this->_columns;
9408
9409         $pkCols = array();
9410         $fkCols = array();
9411
9412         if ($this->hasIndex($this->_primaryKeyName)) {
9413             $pkCols = $this->getPrimaryKey()->getColumns();
9414         }
9415         foreach ($this->getForeignKeys() AS $fk) {
9416             /* @var $fk ForeignKeyConstraint */
9417             $fkCols = array_merge($fkCols, $fk->getColumns());
9418         }
9419         $colNames = array_unique(array_merge($pkCols, $fkCols, array_keys($columns)));
9420
9421         uksort($columns, function($a, $b) use($colNames) {
9422             return (array_search($a, $colNames) >= array_search($b, $colNames));
9423         });
9424         return $columns;
9425     }
9426
9427
9428     /**
9429      * Does this table have a column with the given name?
9430      *
9431      * @param  string $columnName
9432      * @return bool
9433      */
9434     public function hasColumn($columnName)
9435     {
9436         $columnName = strtolower($columnName);
9437         return isset($this->_columns[$columnName]);
9438     }
9439
9440     /**
9441      * Get a column instance
9442      * 
9443      * @param  string $columnName
9444      * @return Column
9445      */
9446     public function getColumn($columnName)
9447     {
9448         $columnName = strtolower($columnName);
9449         if (!$this->hasColumn($columnName)) {
9450             throw SchemaException::columnDoesNotExist($columnName, $this->_name);
9451         }
9452
9453         return $this->_columns[$columnName];
9454     }
9455
9456     /**
9457      * @return Index
9458      */
9459     public function getPrimaryKey()
9460     {
9461         return $this->getIndex($this->_primaryKeyName);
9462     }
9463
9464     /**
9465      * @param  string $indexName
9466      * @return bool
9467      */
9468     public function hasIndex($indexName)
9469     {
9470         $indexName = strtolower($indexName);
9471         return (isset($this->_indexes[$indexName]));
9472     }
9473
9474     /**
9475      * @param  string $indexName
9476      * @return Index
9477      */
9478     public function getIndex($indexName)
9479     {
9480         $indexName = strtolower($indexName);
9481         if (!$this->hasIndex($indexName)) {
9482             throw SchemaException::indexDoesNotExist($indexName, $this->_name);
9483         }
9484         return $this->_indexes[$indexName];
9485     }
9486
9487     /**
9488      * @return array
9489      */
9490     public function getIndexes()
9491     {
9492         return $this->_indexes;
9493     }
9494
9495     /**
9496      * Get Constraints
9497      *
9498      * @return array
9499      */
9500     public function getForeignKeys()
9501     {
9502         return $this->_fkConstraints;
9503     }
9504
9505     public function hasOption($name)
9506     {
9507         return isset($this->_options[$name]);
9508     }
9509
9510     public function getOption($name)
9511     {
9512         return $this->_options[$name];
9513     }
9514
9515     public function getOptions()
9516     {
9517         return $this->_options;
9518     }
9519
9520     /**
9521      * @param Visitor $visitor
9522      */
9523     public function visit(Visitor $visitor)
9524     {
9525         $visitor->acceptTable($this);
9526
9527         foreach ($this->getColumns() AS $column) {
9528             $visitor->acceptColumn($this, $column);
9529         }
9530
9531         foreach ($this->getIndexes() AS $index) {
9532             $visitor->acceptIndex($this, $index);
9533         }
9534
9535         foreach ($this->getForeignKeys() AS $constraint) {
9536             $visitor->acceptForeignKey($this, $constraint);
9537         }
9538     }
9539
9540     /**
9541      * Clone of a Table triggers a deep clone of all affected assets
9542      */
9543     public function __clone()
9544     {
9545         foreach ($this->_columns AS $k => $column) {
9546             $this->_columns[$k] = clone $column;
9547         }
9548         foreach ($this->_indexes AS $k => $index) {
9549             $this->_indexes[$k] = clone $index;
9550         }
9551         foreach ($this->_fkConstraints AS $k => $fk) {
9552             $this->_fkConstraints[$k] = clone $fk;
9553             $this->_fkConstraints[$k]->setLocalTable($this);
9554         }
9555     }
9556 }<?php
9557 /*
9558  *  $Id$
9559  *
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.
9571  *
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>.
9575  */
9576
9577 namespace Doctrine\DBAL\Schema;
9578
9579 /**
9580  * Table Diff
9581  *
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
9586  * @since   2.0
9587  * @version $Revision$
9588  * @author  Benjamin Eberlei <kontakt@beberlei.de>
9589  */
9590 class TableDiff
9591 {
9592     /**
9593      * @var string
9594      */
9595     public $name = null;
9596
9597     /**
9598      * @var string
9599      */
9600     public $newName = false;
9601
9602     /**
9603      * All added fields
9604      *
9605      * @var array(string=>Column)
9606      */
9607     public $addedColumns;
9608
9609     /**
9610      * All changed fields
9611      *
9612      * @var array(string=>Column)
9613      */
9614     public $changedColumns = array();
9615
9616     /**
9617      * All removed fields
9618      *
9619      * @var array(string=>bool)
9620      */
9621     public $removedColumns = array();
9622
9623     /**
9624      * Columns that are only renamed from key to column instance name.
9625      *
9626      * @var array(string=>Column)
9627      */
9628     public $renamedColumns = array();
9629
9630     /**
9631      * All added indexes
9632      *
9633      * @var array(string=>Index)
9634      */
9635     public $addedIndexes = array();
9636
9637     /**
9638      * All changed indexes
9639      *
9640      * @var array(string=>Index)
9641      */
9642     public $changedIndexes = array();
9643
9644     /**
9645      * All removed indexes
9646      *
9647      * @var array(string=>bool)
9648      */
9649     public $removedIndexes = array();
9650
9651     /**
9652      * All added foreign key definitions
9653      *
9654      * @var array
9655      */
9656     public $addedForeignKeys = array();
9657
9658     /**
9659      * All changed foreign keys
9660      *
9661      * @var array
9662      */
9663     public $changedForeignKeys = array();
9664
9665     /**
9666      * All removed foreign keys
9667      *
9668      * @var array
9669      */
9670     public $removedForeignKeys = array();
9671
9672     /**
9673      * Constructs an TableDiff object.
9674      *
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
9681      */
9682     public function __construct($tableName, $addedColumns = array(),
9683         $changedColumns = array(), $removedColumns = array(), $addedIndexes = array(),
9684         $changedIndexes = array(), $removedIndexes = array())
9685     {
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;
9693     }
9694 }<?php
9695 /*
9696  *  $Id$
9697  *
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.
9709  *
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>.
9713  */
9714
9715 namespace Doctrine\DBAL\Schema;
9716
9717 /**
9718  * Oracle Schema Manager
9719  *
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$
9725  * @since       2.0
9726  */
9727 class OracleSchemaManager extends AbstractSchemaManager
9728 {
9729     protected function _getPortableViewDefinition($view)
9730     {
9731         $view = \array_change_key_case($view, CASE_LOWER);
9732
9733         return new View($view['view_name'], $view['text']);
9734     }
9735
9736     protected function _getPortableUserDefinition($user)
9737     {
9738         $user = \array_change_key_case($user, CASE_LOWER);
9739
9740         return array(
9741             'user' => $user['username'],
9742         );
9743     }
9744
9745     protected function _getPortableTableDefinition($table)
9746     {
9747         $table = \array_change_key_case($table, CASE_LOWER);
9748
9749         return $table['table_name'];
9750     }
9751
9752     /**
9753      * @license New BSD License
9754      * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
9755      * @param  array $tableIndexes
9756      * @param  string $tableName
9757      * @return array
9758      */
9759     protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
9760     {
9761         $indexBuffer = array();
9762         foreach ( $tableIndexes as $tableIndex ) {
9763             $tableIndex = \array_change_key_case($tableIndex, CASE_LOWER);
9764
9765             $keyName = strtolower($tableIndex['name']);
9766
9767             if ( strtolower($tableIndex['is_primary']) == "p" ) {
9768                 $keyName = 'primary';
9769                 $buffer['primary'] = true;
9770                 $buffer['non_unique'] = false;
9771             } else {
9772                 $buffer['primary'] = false;
9773                 $buffer['non_unique'] = ( $tableIndex['is_unique'] == 0 ) ? true : false;
9774             }
9775             $buffer['key_name'] = $keyName;
9776             $buffer['column_name'] = $tableIndex['column_name'];
9777             $indexBuffer[] = $buffer;
9778         }
9779         return parent::_getPortableTableIndexesList($indexBuffer, $tableName);
9780     }
9781
9782     protected function _getPortableTableColumnDefinition($tableColumn)
9783     {
9784         $tableColumn = \array_change_key_case($tableColumn, CASE_LOWER);
9785         
9786         $dbType = strtolower($tableColumn['data_type']);
9787         if(strpos($dbType, "timestamp(") === 0) {
9788             if (strpos($dbType, "WITH TIME ZONE")) {
9789                 $dbType = "timestamptz";
9790             } else {
9791                 $dbType = "timestamp";
9792             }
9793         }
9794
9795         $type = array();
9796         $length = $unsigned = $fixed = null;
9797         if ( ! empty($tableColumn['data_length'])) {
9798             $length = $tableColumn['data_length'];
9799         }
9800
9801         if ( ! isset($tableColumn['column_name'])) {
9802             $tableColumn['column_name'] = '';
9803         }
9804
9805         if (stripos($tableColumn['data_default'], 'NULL') !== null) {
9806             $tableColumn['data_default'] = null;
9807         }
9808
9809         $precision = null;
9810         $scale = null;
9811
9812         $type = $this->_platform->getDoctrineTypeMapping($dbType);
9813         switch ($dbType) {
9814             case 'number':
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) {
9820                         $type = 'boolean';
9821                     } else {
9822                         $type = 'decimal';
9823                     }
9824                 }
9825                 $length = null;
9826                 break;
9827             case 'pls_integer':
9828             case 'binary_integer':
9829                 $length = null;
9830                 break;
9831             case 'varchar':
9832             case 'varchar2':
9833             case 'nvarchar2':
9834                 $fixed = false;
9835                 break;
9836             case 'char':
9837             case 'nchar':
9838                 $fixed = true;
9839                 break;
9840             case 'date':
9841             case 'timestamp':
9842                 $length = null;
9843                 break;
9844             case 'float':
9845                 $precision = $tableColumn['data_precision'];
9846                 $scale = $tableColumn['data_scale'];
9847                 $length = null;
9848                 break;
9849             case 'clob':
9850             case 'nclob':
9851                 $length = null;
9852                 break;
9853             case 'blob':
9854             case 'raw':
9855             case 'long raw':
9856             case 'bfile':
9857                 $length = null;
9858                 break;
9859             case 'rowid':
9860             case 'urowid':
9861             default:
9862                 $length = null;
9863         }
9864
9865         $options = array(
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,
9872             'scale'      => $scale,
9873             'platformDetails' => array(),
9874         );
9875
9876         return new Column($tableColumn['column_name'], \Doctrine\DBAL\Types\Type::getType($type), $options);
9877     }
9878
9879     protected function _getPortableTableForeignKeysList($tableForeignKeys)
9880     {
9881         $list = array();
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;
9887                 }
9888
9889                 $list[$value['constraint_name']] = array(
9890                     'name' => $value['constraint_name'],
9891                     'local' => array(),
9892                     'foreign' => array(),
9893                     'foreignTable' => $value['references_table'],
9894                     'onDelete' => $value['delete_rule'],
9895                 );
9896             }
9897             $list[$value['constraint_name']]['local'][$value['position']] = $value['local_column'];
9898             $list[$value['constraint_name']]['foreign'][$value['position']] = $value['foreign_column'];
9899         }
9900
9901         $result = array();
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'])
9907             );
9908         }
9909
9910         return $result;
9911     }
9912
9913     protected function _getPortableSequenceDefinition($sequence)
9914     {
9915         $sequence = \array_change_key_case($sequence, CASE_LOWER);
9916         return new Sequence($sequence['sequence_name'], $sequence['increment_by'], $sequence['min_value']);
9917     }
9918
9919     protected function _getPortableFunctionDefinition($function)
9920     {
9921         $function = \array_change_key_case($function, CASE_LOWER);
9922         return $function['name'];
9923     }
9924
9925     protected function _getPortableDatabaseDefinition($database)
9926     {
9927         $database = \array_change_key_case($database, CASE_LOWER);
9928         return $database['username'];
9929     }
9930
9931     public function createDatabase($database = null)
9932     {
9933         if (is_null($database)) {
9934             $database = $this->_conn->getDatabase();
9935         }
9936
9937         $params = $this->_conn->getParams();
9938         $username   = $database;
9939         $password   = $params['password'];
9940
9941         $query  = 'CREATE USER ' . $username . ' IDENTIFIED BY ' . $password;
9942         $result = $this->_conn->executeUpdate($query);
9943
9944         $query = 'GRANT CREATE SESSION, CREATE TABLE, UNLIMITED TABLESPACE, CREATE SEQUENCE, CREATE TRIGGER TO ' . $username;
9945         $result = $this->_conn->executeUpdate($query);
9946
9947         return true;
9948     }
9949
9950     public function dropAutoincrement($table)
9951     {
9952         $sql = $this->_platform->getDropAutoincrementSql($table);
9953         foreach ($sql as $query) {
9954             $this->_conn->executeUpdate($query);
9955         }
9956
9957         return true;
9958     }
9959
9960     public function dropTable($name)
9961     {
9962         $this->dropAutoincrement($name);
9963
9964         return parent::dropTable($name);
9965     }
9966 }<?php
9967 /*
9968  *  $Id$
9969  *
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.
9981  *
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>.
9985  */
9986
9987 namespace Doctrine\DBAL\Schema;
9988
9989 use Doctrine\DBAL\Schema\Visitor\Visitor;
9990
9991 /**
9992  * Sequence Structure
9993  *
9994  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
9995  * @link    www.doctrine-project.org
9996  * @since   2.0
9997  * @version $Revision$
9998  * @author  Benjamin Eberlei <kontakt@beberlei.de>
9999  */
10000 class Sequence extends AbstractAsset
10001 {
10002     /**
10003      * @var int
10004      */
10005     protected $_allocationSize = 1;
10006
10007     /**
10008      * @var int
10009      */
10010     protected $_initialValue = 1;
10011
10012     /**
10013      *
10014      * @param string $name
10015      * @param int $allocationSize
10016      * @param int $initialValue
10017      */
10018     public function __construct($name, $allocationSize=1, $initialValue=1)
10019     {
10020         $this->_setName($name);
10021         $this->_allocationSize = (is_numeric($allocationSize))?$allocationSize:1;
10022         $this->_initialValue = (is_numeric($initialValue))?$initialValue:1;
10023     }
10024
10025     public function getAllocationSize()
10026     {
10027         return $this->_allocationSize;
10028     }
10029
10030     public function getInitialValue()
10031     {
10032         return $this->_initialValue;
10033     }
10034
10035     /**
10036      * @param Visitor $visitor
10037      */
10038     public function visit(Visitor $visitor)
10039     {
10040         $visitor->acceptSequence($this);
10041     }
10042 }
10043 <?php
10044 /*
10045  *  $Id$
10046  *
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.
10058  *
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>.
10062  */
10063
10064 namespace Doctrine\DBAL\Schema;
10065
10066 /**
10067  * Represent the change of a column
10068  *
10069  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
10070  * @link    www.doctrine-project.org
10071  * @since   2.0
10072  * @version $Revision$
10073  * @author Benjamin Eberlei <kontakt@beberlei.de>
10074  */
10075 class ColumnDiff
10076 {
10077     public $oldColumnName;
10078
10079     /**
10080      * @var Column
10081      */
10082     public $column;
10083
10084     /**
10085      * @var array
10086      */
10087     public $changedProperties = array();
10088
10089     public function __construct($oldColumnName, Column $column, array $changedProperties = array())
10090     {
10091         $this->oldColumnName = $oldColumnName;
10092         $this->column = $column;
10093         $this->changedProperties = $changedProperties;
10094     }
10095
10096     public function hasChanged($propertyName)
10097     {
10098         return in_array($propertyName, $this->changedProperties);
10099     }
10100 }<?php
10101
10102 namespace Doctrine\DBAL\Schema;
10103
10104 class SchemaException extends \Doctrine\DBAL\DBALException
10105 {
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;
10116
10117     /**
10118      * @param string $tableName
10119      * @return SchemaException
10120      */
10121     static public function tableDoesNotExist($tableName)
10122     {
10123         return new self("There is no table with name '".$tableName."' in the schema.", self::TABLE_DOESNT_EXIST);
10124     }
10125
10126     /**
10127      * @param string $indexName
10128      * @return SchemaException
10129      */
10130     static public function indexNameInvalid($indexName)
10131     {
10132         return new self("Invalid index-name $indexName given, has to be [a-zA-Z0-9_]", self::INDEX_INVALID_NAME);
10133     }
10134
10135     /**
10136      * @param string $indexName
10137      * @return SchemaException
10138      */
10139     static public function indexDoesNotExist($indexName, $table)
10140     {
10141         return new self("Index '$indexName' does not exist on table '$table'.", self::INDEX_DOESNT_EXIST);
10142     }
10143
10144     /**
10145      * @param string $indexName
10146      * @return SchemaException
10147      */
10148     static public function indexAlreadyExists($indexName, $table)
10149     {
10150         return new self("An index with name '$indexName' was already defined on table '$table'.", self::INDEX_ALREADY_EXISTS);
10151     }
10152
10153     /**
10154      * @param string $columnName
10155      * @return SchemaException
10156      */
10157     static public function columnDoesNotExist($columnName, $table)
10158     {
10159         return new self("There is no column with name '$columnName' on table '$table'.", self::COLUMN_DOESNT_EXIST);
10160     }
10161
10162     /**
10163      *
10164      * @param  string $tableName
10165      * @return SchemaException
10166      */
10167     static public function tableAlreadyExists($tableName)
10168     {
10169         return new self("The table with name '".$tableName."' already exists.", self::TABLE_ALREADY_EXISTS);
10170     }
10171
10172     /**
10173      *
10174      * @param string $tableName
10175      * @param string $columnName
10176      * @return SchemaException
10177      */
10178     static public function columnAlreadyExists($tableName, $columnName)
10179     {
10180         return new self(
10181             "The column '".$columnName."' on table '".$tableName."' already exists.", self::COLUMN_ALREADY_EXISTS
10182         );
10183     }
10184
10185     /**
10186      * @param string $sequenceName
10187      * @return SchemaException
10188      */
10189     static public function sequenceAlreadyExists($sequenceName)
10190     {
10191         return new self("The sequence '".$sequenceName."' already exists.", self::SEQUENCE_ALREADY_EXISTS);
10192     }
10193
10194     /**
10195      * @param string $sequenceName
10196      * @return SchemaException
10197      */
10198     static public function sequenceDoesNotExist($sequenceName)
10199     {
10200         return new self("There exists no sequence with the name '".$sequenceName."'.", self::SEQUENCE_DOENST_EXIST);
10201     }
10202
10203     /**
10204      * @param  string $fkName
10205      * @return SchemaException
10206      */
10207     static public function foreignKeyDoesNotExist($fkName, $table)
10208     {
10209         return new self("There exists no foreign key with the name '$fkName' on table '$table'.", self::FOREIGNKEY_DOESNT_EXIST);
10210     }
10211
10212     static public function namedForeignKeyRequired(Table $localTable, ForeignKeyConstraint $foreignKey)
10213     {
10214         return new self(
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 ".
10218             "unnamed."
10219         );
10220     }
10221
10222     static public function alterTableChangeNotSupported($changeName) {
10223         return new self ("Alter table change not supported, given '$changeName'");
10224     }
10225 }<?php
10226 /*
10227  *  $Id$
10228  *
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.
10240  *
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>.
10244 */
10245
10246 namespace Doctrine\DBAL;
10247
10248 /**
10249  * Contains all DBAL LockModes
10250  *
10251  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
10252  * @link        www.doctrine-project.com
10253  * @since       1.0
10254  * @version     $Revision$
10255  * @author      Benjamin Eberlei <kontakt@beberlei.de>
10256  * @author      Roman Borschel <roman@code-factory.org>
10257  */
10258 class LockMode
10259 {
10260     const NONE = 0;
10261     const OPTIMISTIC = 1;
10262     const PESSIMISTIC_READ = 2;
10263     const PESSIMISTIC_WRITE = 4;
10264
10265     final private function __construct() { }
10266 }<?php
10267 /*
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.
10279  *
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>.
10283  */
10284
10285 namespace Doctrine\DBAL;
10286
10287 /**
10288  * Driver interface.
10289  * Interface that all DBAL drivers must implement.
10290  *
10291  * @since 2.0
10292  */
10293 interface Driver
10294 {
10295     /**
10296      * Attempts to create a connection with the database.
10297      *
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.
10303      */
10304     public function connect(array $params, $username = null, $password = null, array $driverOptions = array());
10305
10306     /**
10307      * Gets the DatabasePlatform instance that provides all the metadata about
10308      * the platform this driver connects to.
10309      *
10310      * @return Doctrine\DBAL\Platforms\AbstractPlatform The database platform.
10311      */
10312     public function getDatabasePlatform();
10313
10314     /**
10315      * Gets the SchemaManager that can be used to inspect and change the underlying
10316      * database schema of the platform this driver connects to.
10317      *
10318      * @param  Doctrine\DBAL\Connection $conn
10319      * @return Doctrine\DBAL\SchemaManager
10320      */
10321     public function getSchemaManager(Connection $conn);
10322
10323     /**
10324      * Gets the name of the driver.
10325      *
10326      * @return string The name of the driver.
10327      */
10328     public function getName();
10329
10330     /**
10331      * Get the name of the database connected to for this driver.
10332      *
10333      * @param  Doctrine\DBAL\Connection $conn
10334      * @return string $database
10335      */
10336     public function getDatabase(Connection $conn);
10337 }<?php
10338 /*
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.
10350  *
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>.
10354  */
10355
10356 namespace Doctrine\DBAL\Platforms;
10357
10358 use Doctrine\DBAL\Schema\TableDiff,
10359     Doctrine\DBAL\Schema\Table;
10360
10361 /**
10362  * PostgreSqlPlatform.
10363  *
10364  * @since 2.0
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
10369  */
10370 class PostgreSqlPlatform extends AbstractPlatform
10371 {
10372     /**
10373      * Returns part of a string.
10374      *
10375      * Note: Not SQL92, but common functionality.
10376      *
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.
10381      * @override
10382      */
10383     public function getSubstringExpression($value, $from, $len = null)
10384     {
10385         if ($len === null) {
10386             return 'SUBSTR(' . $value . ', ' . $from . ')';
10387         } else {
10388             return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
10389         }
10390     }
10391
10392     /**
10393      * Returns the SQL string to return the current system date and time.
10394      *
10395      * @return string
10396      */
10397     public function getNowExpression()
10398     {
10399         return 'LOCALTIMESTAMP(0)';
10400     }
10401
10402     /**
10403      * regexp
10404      *
10405      * @return string           the regular expression operator
10406      * @override
10407      */
10408     public function getRegexpExpression()
10409     {
10410         return 'SIMILAR TO';
10411     }
10412
10413     /**
10414      * returns the position of the first occurrence of substring $substr in string $str
10415      *
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
10419      * @return integer
10420      */
10421     public function getLocateExpression($str, $substr, $startPos = false)
10422     {
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';
10426         } else {
10427             return 'POSITION('.$substr.' IN '.$str.')';
10428         }
10429     }
10430     
10431     /**
10432      * parses a literal boolean value and returns
10433      * proper sql equivalent
10434      *
10435      * @param string $value     boolean value to be parsed
10436      * @return string           parsed boolean value
10437      */
10438     /*public function parseBoolean($value)
10439     {
10440         return $value;
10441     }*/
10442     
10443     /**
10444      * Whether the platform supports sequences.
10445      * Postgres has native support for sequences.
10446      *
10447      * @return boolean
10448      */
10449     public function supportsSequences()
10450     {
10451         return true;
10452     }
10453     
10454     /**
10455      * Whether the platform supports database schemas.
10456      * 
10457      * @return boolean
10458      */
10459     public function supportsSchemas()
10460     {
10461         return true;
10462     }
10463     
10464     /**
10465      * Whether the platform supports identity columns.
10466      * Postgres supports these through the SERIAL keyword.
10467      *
10468      * @return boolean
10469      */
10470     public function supportsIdentityColumns()
10471     {
10472         return true;
10473     }
10474     
10475     /**
10476      * Whether the platform prefers sequences for ID generation.
10477      *
10478      * @return boolean
10479      */
10480     public function prefersSequences()
10481     {
10482         return true;
10483     }
10484
10485     public function getListDatabasesSQL()
10486     {
10487         return 'SELECT datname FROM pg_database';
10488     }
10489
10490     public function getListSequencesSQL($database)
10491     {
10492         return "SELECT
10493                     relname
10494                 FROM
10495                    pg_class
10496                 WHERE relkind = 'S' AND relnamespace IN
10497                     (SELECT oid FROM pg_namespace
10498                         WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema')";
10499     }
10500
10501     public function getListTablesSQL()
10502     {
10503         return "SELECT
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_)'
10510                 UNION
10511                 SELECT c.relname AS table_name
10512                 FROM pg_class c
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_'";
10517     }
10518
10519     public function getListViewsSQL($database)
10520     {
10521         return 'SELECT viewname, definition FROM pg_views';
10522     }
10523
10524     public function getListTableForeignKeysSQL($table, $database = null)
10525     {
10526         return "SELECT r.conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef
10527                   FROM pg_catalog.pg_constraint r
10528                   WHERE r.conrelid =
10529                   (
10530                       SELECT c.oid
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)
10534                   )
10535                   AND r.contype = 'f'";
10536     }
10537
10538     public function getCreateViewSQL($name, $sql)
10539     {
10540         return 'CREATE VIEW ' . $name . ' AS ' . $sql;
10541     }
10542
10543     public function getDropViewSQL($name)
10544     {
10545         return 'DROP VIEW '. $name;
10546     }
10547
10548     public function getListTableConstraintsSQL($table)
10549     {
10550         return "SELECT
10551                     relname
10552                 FROM
10553                     pg_class
10554                 WHERE oid IN (
10555                     SELECT indexrelid
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')
10560                         )";
10561     }
10562
10563     /**
10564      * @license New BSD License
10565      * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
10566      * @param  string $table
10567      * @return string
10568      */
10569     public function getListTableIndexesSQL($table)
10570     {
10571         return "SELECT relname, pg_index.indisunique, pg_index.indisprimary,
10572                        pg_index.indkey, pg_index.indrelid
10573                  FROM pg_class, pg_index
10574                  WHERE oid IN (
10575                     SELECT indexrelid
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";
10579     }
10580
10581     public function getListTableColumnsSQL($table)
10582     {
10583         return "SELECT
10584                     a.attnum,
10585                     a.attname AS field,
10586                     t.typname AS type,
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,
10592                     (SELECT 't'
10593                      FROM pg_index
10594                      WHERE c.oid = pg_index.indrelid
10595                         AND pg_index.indkey[0] = a.attnum
10596                         AND pg_index.indisprimary = 't'
10597                     ) AS pri,
10598                     (SELECT pg_attrdef.adsrc
10599                      FROM pg_attrdef
10600                      WHERE c.oid = pg_attrdef.adrelid
10601                         AND pg_attrdef.adnum=a.attnum
10602                     ) AS default
10603                     FROM pg_attribute a, pg_class c, pg_type t
10604                     WHERE c.relname = '$table'
10605                         AND a.attnum > 0
10606                         AND a.attrelid = c.oid
10607                         AND a.atttypid = t.oid
10608                     ORDER BY a.attnum";
10609     }
10610     
10611     /**
10612      * create a new database
10613      *
10614      * @param string $name name of the database that should be created
10615      * @throws PDOException
10616      * @return void
10617      * @override
10618      */
10619     public function getCreateDatabaseSQL($name)
10620     {
10621         return 'CREATE DATABASE ' . $name;
10622     }
10623
10624     /**
10625      * drop an existing database
10626      *
10627      * @param string $name name of the database that should be dropped
10628      * @throws PDOException
10629      * @access public
10630      */
10631     public function getDropDatabaseSQL($name)
10632     {
10633         return 'DROP DATABASE ' . $name;
10634     }
10635
10636     /**
10637      * Return the FOREIGN KEY query section dealing with non-standard options
10638      * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
10639      *
10640      * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey         foreign key definition
10641      * @return string
10642      * @override
10643      */
10644     public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey)
10645     {
10646         $query = '';
10647         if ($foreignKey->hasOption('match')) {
10648             $query .= ' MATCH ' . $foreignKey->getOption('match');
10649         }
10650         $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
10651         if ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) {
10652             $query .= ' DEFERRABLE';
10653         } else {
10654             $query .= ' NOT DEFERRABLE';
10655         }
10656         if ($foreignKey->hasOption('feferred') && $foreignKey->getOption('feferred') !== false) {
10657             $query .= ' INITIALLY DEFERRED';
10658         } else {
10659             $query .= ' INITIALLY IMMEDIATE';
10660         }
10661         return $query;
10662     }
10663     
10664     /**
10665      * generates the sql for altering an existing table on postgresql
10666      *
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()
10673      * @return array
10674      * @override
10675      */
10676     public function getAlterTableSQL(TableDiff $diff)
10677     {
10678         $sql = array();
10679
10680         foreach ($diff->addedColumns as $column) {
10681             $query = 'ADD ' . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
10682             $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
10683         }
10684
10685         foreach ($diff->removedColumns as $column) {
10686             $query = 'DROP ' . $column->getName();
10687             $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
10688         }
10689
10690         foreach ($diff->changedColumns AS $columnDiff) {
10691             $oldColumnName = $columnDiff->oldColumnName;
10692             $column = $columnDiff->column;
10693             
10694             if ($columnDiff->hasChanged('type')) {
10695                 $type = $column->getType();
10696
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;
10700             }
10701             if ($columnDiff->hasChanged('default')) {
10702                 $query = 'ALTER ' . $oldColumnName . ' SET ' . $this->getDefaultValueDeclarationSQL($column->toArray());
10703                 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
10704             }
10705             if ($columnDiff->hasChanged('notnull')) {
10706                 $query = 'ALTER ' . $oldColumnName . ' ' . ($column->getNotNull() ? 'SET' : 'DROP') . ' NOT NULL';
10707                 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
10708             }
10709             if ($columnDiff->hasChanged('autoincrement')) {
10710                 if ($column->getAutoincrement()) {
10711                     // add autoincrement
10712                     $seqName = $diff->name . '_' . $oldColumnName . '_seq';
10713
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;
10718                 } else {
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;
10722                 }
10723             }
10724         }
10725
10726         foreach ($diff->renamedColumns as $oldColumnName => $column) {
10727             $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName . ' TO ' . $column->getName();
10728         }
10729
10730         if ($diff->newName !== false) {
10731             $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName;
10732         }
10733
10734         $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
10735
10736         return $sql;
10737     }
10738     
10739     /**
10740      * Gets the SQL to create a sequence on this platform.
10741      *
10742      * @param \Doctrine\DBAL\Schema\Sequence $sequence
10743      * @return string
10744      */
10745     public function getCreateSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
10746     {
10747         return 'CREATE SEQUENCE ' . $sequence->getName() .
10748                ' INCREMENT BY ' . $sequence->getAllocationSize() .
10749                ' MINVALUE ' . $sequence->getInitialValue() .
10750                ' START ' . $sequence->getInitialValue();
10751     }
10752     
10753     /**
10754      * Drop existing sequence
10755      * @param  \Doctrine\DBAL\Schema\Sequence $sequence
10756      * @return string
10757      */
10758     public function getDropSequenceSQL($sequence)
10759     {
10760         if ($sequence instanceof \Doctrine\DBAL\Schema\Sequence) {
10761             $sequence = $sequence->getName();
10762         }
10763         return 'DROP SEQUENCE ' . $sequence;
10764     }
10765
10766     /**
10767      * @param  ForeignKeyConstraint|string $foreignKey
10768      * @param  Table|string $table
10769      * @return string
10770      */
10771     public function getDropForeignKeySQL($foreignKey, $table)
10772     {
10773         return $this->getDropConstraintSQL($foreignKey, $table);
10774     }
10775     
10776     /**
10777      * Gets the SQL used to create a table.
10778      *
10779      * @param unknown_type $tableName
10780      * @param array $columns
10781      * @param array $options
10782      * @return unknown
10783      */
10784     protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
10785     {
10786         $queryFields = $this->getColumnDeclarationListSQL($columns);
10787
10788         if (isset($options['primary']) && ! empty($options['primary'])) {
10789             $keyColumns = array_unique(array_values($options['primary']));
10790             $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
10791         }
10792
10793         $query = 'CREATE TABLE ' . $tableName . ' (' . $queryFields . ')';
10794
10795         $sql[] = $query;
10796
10797         if (isset($options['indexes']) && ! empty($options['indexes'])) {
10798             foreach ($options['indexes'] AS $index) {
10799                 $sql[] = $this->getCreateIndexSQL($index, $tableName);
10800             }
10801         }
10802
10803         if (isset($options['foreignKeys'])) {
10804             foreach ((array) $options['foreignKeys'] as $definition) {
10805                 $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
10806             }
10807         }
10808
10809         return $sql;
10810     }
10811     
10812     /**
10813      * Postgres wants boolean values converted to the strings 'true'/'false'.
10814      *
10815      * @param array $item
10816      * @override
10817      */
10818     public function convertBooleans($item)
10819     {
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';
10824                 }
10825             }
10826         } else {
10827            if (is_bool($item) || is_numeric($item)) {
10828                $item = ($item) ? 'true' : 'false';
10829            }
10830         }
10831         return $item;
10832     }
10833
10834     public function getSequenceNextValSQL($sequenceName)
10835     {
10836         return "SELECT NEXTVAL('" . $sequenceName . "')";
10837     }
10838
10839     public function getSetTransactionIsolationSQL($level)
10840     {
10841         return 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL '
10842                 . $this->_getTransactionIsolationLevelSQL($level);
10843     }
10844     
10845     /**
10846      * @override
10847      */
10848     public function getBooleanTypeDeclarationSQL(array $field)
10849     {
10850         return 'BOOLEAN';
10851     }
10852
10853     /**
10854      * @override
10855      */
10856     public function getIntegerTypeDeclarationSQL(array $field)
10857     {
10858         if ( ! empty($field['autoincrement'])) {
10859             return 'SERIAL';
10860         }
10861         
10862         return 'INT';
10863     }
10864
10865     /**
10866      * @override
10867      */
10868     public function getBigIntTypeDeclarationSQL(array $field)
10869     {
10870         if ( ! empty($field['autoincrement'])) {
10871             return 'BIGSERIAL';
10872         }
10873         return 'BIGINT';
10874     }
10875
10876     /**
10877      * @override
10878      */
10879     public function getSmallIntTypeDeclarationSQL(array $field)
10880     {
10881         return 'SMALLINT';
10882     }
10883
10884     /**
10885      * @override
10886      */
10887     public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
10888     {
10889         return 'TIMESTAMP(0) WITHOUT TIME ZONE';
10890     }
10891
10892     /**
10893      * @override
10894      */
10895     public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
10896     {
10897         return 'TIMESTAMP(0) WITH TIME ZONE';
10898     }
10899     
10900     /**
10901      * @override
10902      */
10903     public function getDateTypeDeclarationSQL(array $fieldDeclaration)
10904     {
10905         return 'DATE';
10906     }
10907
10908     /**
10909      * @override
10910      */
10911     public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
10912     {
10913         return 'TIME(0) WITHOUT TIME ZONE';
10914     }
10915
10916     /**
10917      * @override
10918      */
10919     protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
10920     {
10921         return '';
10922     }
10923
10924     /**
10925      * Gets the SQL snippet used to declare a VARCHAR column on the MySql platform.
10926      *
10927      * @params array $field
10928      * @override
10929      */
10930     public function getVarcharTypeDeclarationSQL(array $field)
10931     {
10932         if ( ! isset($field['length'])) {
10933             if (array_key_exists('default', $field)) {
10934                 $field['length'] = $this->getVarcharMaxLength();
10935             } else {
10936                 $field['length'] = false;
10937             }
10938         }
10939
10940         $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
10941         $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
10942
10943         return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
10944                 : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
10945     }
10946     
10947     /** @override */
10948     public function getClobTypeDeclarationSQL(array $field)
10949     {
10950         return 'TEXT';
10951     }
10952
10953     /**
10954      * Get the platform name for this instance
10955      *
10956      * @return string
10957      */
10958     public function getName()
10959     {
10960         return 'postgresql';
10961     }
10962     
10963     /**
10964      * Gets the character casing of a column in an SQL result set.
10965      * 
10966      * PostgreSQL returns all column names in SQL result sets in lowercase.
10967      * 
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.
10970      */
10971     public function getSQLResultCasing($column)
10972     {
10973         return strtolower($column);
10974     }
10975     
10976     public function getDateTimeTzFormatString()
10977     {
10978         return 'Y-m-d H:i:sO';
10979     }
10980
10981     /**
10982      * Get the insert sql for an empty insert statement
10983      *
10984      * @param string $tableName 
10985      * @param string $identifierColumnName 
10986      * @return string $sql
10987      */
10988     public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName)
10989     {
10990         return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)';
10991     }
10992
10993     /**
10994      * @inheritdoc
10995      */
10996     public function getTruncateTableSQL($tableName, $cascade = false)
10997     {
10998         return 'TRUNCATE '.$tableName.' '.($cascade)?'CASCADE':'';
10999     }
11000
11001     public function getReadLockSQL()
11002     {
11003         return 'FOR SHARE';
11004     }
11005
11006     protected function initializeDoctrineTypeMappings()
11007     {
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',
11022             'text'          => 'text',
11023             'varchar'       => 'string',
11024             'interval'      => 'string',
11025             '_varchar'      => 'string',
11026             'char'          => 'string',
11027             'bpchar'        => 'string',
11028             'date'          => 'date',
11029             'datetime'      => 'datetime',
11030             'timestamp'     => 'datetime',
11031             'timestamptz'   => 'datetimetz',
11032             'time'          => 'time',
11033             'timetz'        => 'time',
11034             'float'         => 'float',
11035             'float4'        => 'float',
11036             'float8'        => 'float',
11037             'double'        => 'float',
11038             'double precision' => 'float',
11039             'real'          => 'float',
11040             'decimal'       => 'decimal',
11041             'money'         => 'decimal',
11042             'numeric'       => 'decimal',
11043             'year'          => 'date',
11044         );
11045     }
11046 }
11047 <?php
11048
11049 /*
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.
11061  *
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>.
11065  */
11066
11067 namespace Doctrine\DBAL\Platforms;
11068
11069 use Doctrine\DBAL\Schema\TableDiff;
11070 use Doctrine\DBAL\DBALException;
11071 use Doctrine\DBAL\Schema\Index, Doctrine\DBAL\Schema\Table;
11072
11073 /**
11074  * The MsSqlPlatform provides the behavior, features and SQL dialect of the
11075  * MySQL database platform.
11076  *
11077  * @since 2.0
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
11082  */
11083 class MsSqlPlatform extends AbstractPlatform
11084 {
11085
11086     /**
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.
11090      *
11091      * @return boolean
11092      * @override
11093      */
11094     public function prefersIdentityColumns()
11095     {
11096         return true;
11097     }
11098
11099     /**
11100      * Whether the platform supports identity columns.
11101      * MsSql supports this through AUTO_INCREMENT columns.
11102      *
11103      * @return boolean
11104      * @override
11105      */
11106     public function supportsIdentityColumns()
11107     {
11108         return true;
11109     }
11110
11111     /**
11112      * Whether the platform supports releasing savepoints.
11113      *
11114      * @return boolean
11115      */
11116     public function supportsReleaseSavepoints()
11117     {
11118         return false;
11119     }
11120
11121     /**
11122      * create a new database
11123      *
11124      * @param string $name name of the database that should be created
11125      * @return string
11126      * @override
11127      */
11128     public function getCreateDatabaseSQL($name)
11129     {
11130         return 'CREATE DATABASE ' . $name;
11131     }
11132
11133     /**
11134      * drop an existing database
11135      *
11136      * @param string $name name of the database that should be dropped
11137      * @return string
11138      * @override
11139      */
11140     public function getDropDatabaseSQL($name)
11141     {
11142         // @todo do we really need to force drop?
11143         return 'ALTER DATABASE [' . $name . ']
11144 SET SINGLE_USER
11145 WITH ROLLBACK IMMEDIATE;
11146 DROP DATABASE ' . $name . ';';
11147     }
11148
11149     /**
11150      * @override
11151      */
11152     public function quoteIdentifier($str)
11153     {
11154         return '[' . $str . ']';
11155     }
11156
11157     /**
11158      * @override
11159      */
11160     public function getDropForeignKeySQL($foreignKey, $table)
11161     {
11162         if ($foreignKey instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) {
11163             $foreignKey = $foreignKey->getName();
11164         }
11165
11166         if ($table instanceof \Doctrine\DBAL\Schema\Table) {
11167             $table = $table->getName();
11168         }
11169
11170         return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey;
11171     }
11172
11173     /**
11174      * @override
11175      */
11176     public function getDropIndexSQL($index, $table=null)
11177     {
11178         if ($index instanceof \Doctrine\DBAL\Schema\Index) {
11179             $index_ = $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.');
11183         }
11184
11185         if (!isset($table)) {
11186             return 'DROP INDEX ' . $index;
11187         } else {
11188             if ($table instanceof \Doctrine\DBAL\Schema\Table) {
11189                 $table = $table->getName();
11190             }
11191
11192             return "IF EXISTS (SELECT * FROM sysobjects WHERE name = '$index')
11193                                                 ALTER TABLE " . $this->quoteIdentifier($table) . " DROP CONSTRAINT " . $this->quoteIdentifier($index) . "
11194                                         ELSE
11195                                                 DROP INDEX " . $this->quoteIdentifier($index) . " ON " . $this->quoteIdentifier($table);
11196         }
11197     }
11198
11199     /**
11200      * @override
11201      */
11202     public function getCreateTableSQL(Table $table, $createFlags=self::CREATE_INDEXES)
11203     {
11204         $sql = parent::getCreateTableSQL($table, $createFlags);
11205
11206         $primary = array();
11207
11208         foreach ($table->getIndexes() AS $index) {
11209             /* @var $index Index */
11210             if ($index->isPrimary()) {
11211                 $primary = $index->getColumns();
11212             }
11213         }
11214
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]);
11220                 }
11221             }
11222         }
11223
11224         return $sql;
11225     }
11226
11227     /**
11228      * @override
11229      */
11230     protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
11231     {
11232         $columnListSql = $this->getColumnDeclarationListSQL($columns);
11233
11234         if (isset($options['uniqueConstraints']) && !empty($options['uniqueConstraints'])) {
11235             foreach ($options['uniqueConstraints'] as $name => $definition) {
11236                 $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
11237             }
11238         }
11239
11240         if (isset($options['primary']) && !empty($options['primary'])) {
11241             $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
11242         }
11243
11244         $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
11245
11246         $check = $this->getCheckDeclarationSQL($columns);
11247         if (!empty($check)) {
11248             $query .= ', ' . $check;
11249         }
11250         $query .= ')';
11251
11252         $sql[] = $query;
11253
11254         if (isset($options['indexes']) && !empty($options['indexes'])) {
11255             foreach ($options['indexes'] AS $index) {
11256                 $sql[] = $this->getCreateIndexSQL($index, $tableName);
11257             }
11258         }
11259
11260         if (isset($options['foreignKeys'])) {
11261             foreach ((array) $options['foreignKeys'] AS $definition) {
11262                 $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
11263             }
11264         }
11265
11266         return $sql;
11267     }
11268
11269     /**
11270      * @override
11271      */
11272     public function getAlterTableSQL(TableDiff $diff)
11273     {
11274         $queryParts = array();
11275         if ($diff->newName !== false) {
11276             $queryParts[] = 'RENAME TO ' . $diff->newName;
11277         }
11278
11279         foreach ($diff->addedColumns AS $fieldName => $column) {
11280             $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
11281         }
11282
11283         foreach ($diff->removedColumns AS $column) {
11284             $queryParts[] = 'DROP COLUMN ' . $column->getName();
11285         }
11286
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());
11292         }
11293
11294         foreach ($diff->renamedColumns AS $oldColumnName => $column) {
11295             $queryParts[] = 'CHANGE ' . $oldColumnName . ' '
11296                     . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
11297         }
11298
11299         $sql = array();
11300
11301         foreach ($queryParts as $query) {
11302             $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
11303         }
11304
11305         $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
11306
11307         return $sql;
11308     }
11309
11310     /**
11311      * @override
11312      */
11313     public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName)
11314     {
11315         return 'INSERT INTO ' . $quotedTableName . ' DEFAULT VALUES';
11316     }
11317
11318     /**
11319      * @override
11320      */
11321     public function getShowDatabasesSQL()
11322     {
11323         return 'SHOW DATABASES';
11324     }
11325
11326     /**
11327      * @override
11328      */
11329     public function getListTablesSQL()
11330     {
11331         return "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
11332     }
11333
11334     /**
11335      * @override
11336      */
11337     public function getListTableColumnsSQL($table)
11338     {
11339         return 'exec sp_columns @table_name = ' . $table;
11340     }
11341
11342     /**
11343      * @override
11344      */
11345     public function getListTableForeignKeysSQL($table, $database = null)
11346     {
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 . "'";
11361     }
11362
11363     /**
11364      * @override
11365      */
11366     public function getListTableIndexesSQL($table)
11367     {
11368         return "exec sp_helpindex '" . $table . "'";
11369     }
11370
11371     /**
11372      * @override
11373      */
11374     public function getCreateViewSQL($name, $sql)
11375     {
11376         return 'CREATE VIEW ' . $name . ' AS ' . $sql;
11377     }
11378
11379     /**
11380      * @override
11381      */
11382     public function getListViewsSQL($database)
11383     {
11384         return "SELECT name FROM sysobjects WHERE type = 'V' ORDER BY name";
11385     }
11386
11387     /**
11388      * @override
11389      */
11390     public function getDropViewSQL($name)
11391     {
11392         return 'DROP VIEW ' . $name;
11393     }
11394
11395     /**
11396      * Returns the regular expression operator.
11397      *
11398      * @return string
11399      * @override
11400      */
11401     public function getRegexpExpression()
11402     {
11403         return 'RLIKE';
11404     }
11405
11406     /**
11407      * Returns global unique identifier
11408      *
11409      * @return string to get global unique identifier
11410      * @override
11411      */
11412     public function getGuidExpression()
11413     {
11414         return 'UUID()';
11415     }
11416
11417     /**
11418      * @override
11419      */
11420     public function getLocateExpression($str, $substr, $startPos = false)
11421     {
11422         if ($startPos == false) {
11423             return 'CHARINDEX(' . $substr . ', ' . $str . ')';
11424         } else {
11425             return 'CHARINDEX(' . $substr . ', ' . $str . ', ' . $startPos . ')';
11426         }
11427     }
11428
11429     /**
11430      * @override
11431      */
11432     public function getModExpression($expression1, $expression2)
11433     {
11434         return $expression1 . ' % ' . $expression2;
11435     }
11436
11437     /**
11438      * @override
11439      */
11440     public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
11441     {
11442         // @todo
11443         $trimFn = '';
11444         $trimChar = ($char != false) ? (', ' . $char) : '';
11445
11446         if ($pos == self::TRIM_LEADING) {
11447             $trimFn = 'LTRIM';
11448         } else if ($pos == self::TRIM_TRAILING) {
11449             $trimFn = 'RTRIM';
11450         } else {
11451             return 'LTRIM(RTRIM(' . $str . '))';
11452         }
11453
11454         return $trimFn . '(' . $str . ')';
11455     }
11456
11457     /**
11458      * @override
11459      */
11460     public function getConcatExpression()
11461     {
11462         $args = func_get_args();
11463         return '(' . implode(' + ', $args) . ')';
11464     }
11465
11466     public function getListDatabasesSQL()
11467     {
11468         return 'SELECT * FROM SYS.DATABASES';
11469     }
11470
11471     /**
11472      * @override
11473      */
11474     public function getSubstringExpression($value, $from, $len = null)
11475     {
11476         if (!is_null($len)) {
11477             return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $len . ')';
11478         }
11479         return 'SUBSTRING(' . $value . ', ' . $from . ', LEN(' . $value . ') - ' . $from . ' + 1)';
11480     }
11481
11482     /**
11483      * @override
11484      */
11485     public function getLengthExpression($column)
11486     {
11487         return 'LEN(' . $column . ')';
11488     }
11489
11490     /**
11491      * @override
11492      */
11493     public function getSetTransactionIsolationSQL($level)
11494     {
11495         return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level);
11496     }
11497
11498     /**
11499      * @override
11500      */
11501     public function getIntegerTypeDeclarationSQL(array $field)
11502     {
11503         return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
11504     }
11505
11506     /**
11507      * @override
11508      */
11509     public function getBigIntTypeDeclarationSQL(array $field)
11510     {
11511         return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
11512     }
11513
11514     /**
11515      * @override
11516      */
11517     public function getSmallIntTypeDeclarationSQL(array $field)
11518     {
11519         return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
11520     }
11521
11522     /** @override */
11523     public function getVarcharTypeDeclarationSQL(array $field)
11524     {
11525         if (!isset($field['length'])) {
11526             if (array_key_exists('default', $field)) {
11527                 $field['length'] = $this->getVarcharMaxLength();
11528             } else {
11529                 $field['length'] = false;
11530             }
11531         }
11532
11533         $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
11534         $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
11535
11536         return $fixed ? ($length ? 'NCHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'NVARCHAR(' . $length . ')' : 'NTEXT');
11537     }
11538
11539     /** @override */
11540     public function getClobTypeDeclarationSQL(array $field)
11541     {
11542         return 'TEXT';
11543     }
11544
11545     /**
11546      * @override
11547      */
11548     protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
11549     {
11550         $autoinc = '';
11551         if (!empty($columnDef['autoincrement'])) {
11552             $autoinc = ' IDENTITY';
11553         }
11554         $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : '';
11555
11556         return $unsigned . $autoinc;
11557     }
11558
11559     /**
11560      * @override
11561      */
11562     public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
11563     {
11564         // 6 - microseconds precision length
11565         return 'DATETIME2(6)';
11566     }
11567
11568     /**
11569      * @override
11570      */
11571     public function getDateTypeDeclarationSQL(array $fieldDeclaration)
11572     {
11573         return 'DATE';
11574     }
11575
11576     /**
11577      * @override
11578      */
11579     public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
11580     {
11581         return 'TIME(0)';
11582     }
11583
11584     /**
11585      * @override
11586      */
11587     public function getBooleanTypeDeclarationSQL(array $field)
11588     {
11589         return 'BIT';
11590     }
11591
11592     /**
11593      * Adds an adapter-specific LIMIT clause to the SELECT statement.
11594      *
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
11599      * @return string
11600      */
11601     public function modifyLimitQuery($query, $limit, $offset = null)
11602     {
11603         if ($limit > 0) {
11604             $count = intval($limit);
11605             $offset = intval($offset);
11606
11607             if ($offset < 0) {
11608                 throw new Doctrine_Connection_Exception("LIMIT argument offset=$offset is not valid");
11609             }
11610
11611             if ($offset == 0) {
11612                 $query = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . $count . ' ', $query);
11613             } else {
11614                 $orderby = stristr($query, 'ORDER BY');
11615
11616                 if (!$orderby) {
11617                     $over = 'ORDER BY (SELECT 0)';
11618                 } else {
11619                     $over = preg_replace('/\"[^,]*\".\"([^,]*)\"/i', '"inner_tbl"."$1"', $orderby);
11620                 }
11621
11622                 // Remove ORDER BY clause from $query
11623                 $query = preg_replace('/\s+ORDER BY(.*)/', '', $query);
11624
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";
11627
11628                 $start = $offset + 1;
11629                 $end = $offset + $count;
11630
11631                 $query = "WITH outer_tbl AS ($query) SELECT * FROM outer_tbl WHERE \"doctrine_rownum\" BETWEEN $start AND $end";
11632             }
11633         }
11634
11635         return $query;
11636     }
11637
11638     /**
11639      * @override
11640      */
11641     public function convertBooleans($item)
11642     {
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';
11647                 }
11648             }
11649         } else {
11650             if (is_bool($item) || is_numeric($item)) {
11651                 $item = ($item) ? 'TRUE' : 'FALSE';
11652             }
11653         }
11654         return $item;
11655     }
11656
11657     /**
11658      * @override
11659      */
11660     public function getCreateTemporaryTableSnippetSQL()
11661     {
11662         return "CREATE TABLE";
11663     }
11664
11665     /**
11666      * @override
11667      */
11668     public function getTemporaryTableName($tableName)
11669     {
11670         return '#' . $tableName;
11671     }
11672
11673     /**
11674      * @override
11675      */
11676     public function getDateTimeFormatString()
11677     {
11678         return 'Y-m-d H:i:s.u';
11679     }
11680
11681     /**
11682      * @override
11683      */
11684     public function getDateTimeTzFormatString()
11685     {
11686         return $this->getDateTimeFormatString();
11687     }
11688
11689     /**
11690      * Get the platform name for this instance
11691      *
11692      * @return string
11693      */
11694     public function getName()
11695     {
11696         return 'mssql';
11697     }
11698
11699     protected function initializeDoctrineTypeMappings()
11700     {
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',
11712             'real'              => 'float',
11713             'double'            => 'float',
11714             'double precision'  => 'float',
11715             'date'              => 'date',
11716             'datetimeoffset'    => 'datetimetz',
11717             'datetime2'         => 'datetime',
11718             'smalldatetime'     => 'datetime',
11719             'datetime'          => 'datetime',
11720             'time'              => 'time',
11721             'char'              => 'string',
11722             'varchar'           => 'string',
11723             'text'              => 'text',
11724             'nchar'             => 'string',
11725             'nvarchar'          => 'string',
11726             'ntext'             => 'text',
11727             'binary'            => 'text',
11728             'varbinary'         => 'text',
11729             'image'             => 'text',
11730         );
11731     }
11732
11733     /**
11734      * Generate SQL to create a new savepoint
11735      *
11736      * @param string $savepoint
11737      * @return string
11738      */
11739     public function createSavePoint($savepoint)
11740     {
11741         return 'SAVE TRANSACTION ' . $savepoint;
11742     }
11743
11744     /**
11745      * Generate SQL to release a savepoint
11746      *
11747      * @param string $savepoint
11748      * @return string
11749      */
11750     public function releaseSavePoint($savepoint)
11751     {
11752         return '';
11753     }
11754
11755     /**
11756      * Generate SQL to rollback a savepoint
11757      *
11758      * @param string $savepoint
11759      * @return string
11760      */
11761     public function rollbackSavePoint($savepoint)
11762     {
11763         return 'ROLLBACK TRANSACTION ' . $savepoint;
11764     }
11765 }
11766 <?php
11767 /*
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.
11779  *
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>.
11783  */
11784
11785 namespace Doctrine\DBAL\Platforms;
11786
11787 use Doctrine\DBAL\Schema\TableDiff;
11788
11789 /**
11790  * OraclePlatform.
11791  *
11792  * @since 2.0
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>
11796  */
11797 class OraclePlatform extends AbstractPlatform
11798 {
11799     /**
11800      * return string to call a function to get a substring inside an SQL statement
11801      *
11802      * Note: Not SQL92, but common functionality.
11803      *
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
11808      * @override
11809      */
11810     public function getSubstringExpression($value, $position, $length = null)
11811     {
11812         if ($length !== null) {
11813             return "SUBSTR($value, $position, $length)";
11814         }
11815
11816         return "SUBSTR($value, $position)";
11817     }
11818
11819     /**
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)
11825      *
11826      * @return string to call a variable with the current timestamp
11827      * @override
11828      */
11829     public function getNowExpression($type = 'timestamp')
11830     {
11831         switch ($type) {
11832             case 'date':
11833             case 'time':
11834             case 'timestamp':
11835             default:
11836                 return 'TO_CHAR(CURRENT_TIMESTAMP, \'YYYY-MM-DD HH24:MI:SS\')';
11837         }
11838     }
11839
11840     /**
11841      * returns the position of the first occurrence of substring $substr in string $str
11842      *
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
11846      * @return integer
11847      */
11848     public function getLocateExpression($str, $substr, $startPos = false)
11849     {
11850         if ($startPos == false) {
11851             return 'INSTR('.$str.', '.$substr.')';
11852         } else {
11853             return 'INSTR('.$str.', '.$substr.', '.$startPos.')';
11854         }
11855     }
11856
11857     /**
11858      * Returns global unique identifier
11859      *
11860      * @return string to get global unique identifier
11861      * @override
11862      */
11863     public function getGuidExpression()
11864     {
11865         return 'SYS_GUID()';
11866     }
11867     
11868     /**
11869      * Gets the SQL used to create a sequence that starts with a given value
11870      * and increments by the given allocation size.
11871      *
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()}
11875      *
11876      * @param \Doctrine\DBAL\Schema\Sequence $sequence
11877      * @return string
11878      */
11879     public function getCreateSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
11880     {
11881         return 'CREATE SEQUENCE ' . $sequence->getName() .
11882                ' START WITH ' . $sequence->getInitialValue() .
11883                ' MINVALUE ' . $sequence->getInitialValue() . 
11884                ' INCREMENT BY ' . $sequence->getAllocationSize();
11885     }
11886
11887     /**
11888      * {@inheritdoc}
11889      *
11890      * @param string $sequenceName
11891      * @override
11892      */
11893     public function getSequenceNextValSQL($sequenceName)
11894     {
11895         return 'SELECT ' . $sequenceName . '.nextval FROM DUAL';
11896     }
11897     
11898     /**
11899      * {@inheritdoc}
11900      *
11901      * @param integer $level
11902      * @override
11903      */
11904     public function getSetTransactionIsolationSQL($level)
11905     {
11906         return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level);
11907     }
11908
11909     protected function _getTransactionIsolationLevelSQL($level)
11910     {
11911         switch ($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';
11919             default:
11920                 return parent::_getTransactionIsolationLevelSQL($level);
11921         }
11922     }
11923     
11924     /**
11925      * @override
11926      */
11927     public function getBooleanTypeDeclarationSQL(array $field)
11928     {
11929         return 'NUMBER(1)';
11930     }
11931
11932     /**
11933      * @override
11934      */
11935     public function getIntegerTypeDeclarationSQL(array $field)
11936     {
11937         return 'NUMBER(10)';
11938     }
11939
11940     /**
11941      * @override
11942      */
11943     public function getBigIntTypeDeclarationSQL(array $field)
11944     {
11945         return 'NUMBER(20)';
11946     }
11947
11948     /**
11949      * @override
11950      */
11951     public function getSmallIntTypeDeclarationSQL(array $field)
11952     {
11953         return 'NUMBER(5)';
11954     }
11955
11956     /**
11957      * @override
11958      */
11959     public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
11960     {
11961         return 'TIMESTAMP(0)';
11962     }
11963
11964     /**
11965      * @override
11966      */
11967     public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
11968     {
11969         return 'TIMESTAMP(0) WITH TIME ZONE';
11970     }
11971
11972     /**
11973      * @override
11974      */
11975     public function getDateTypeDeclarationSQL(array $fieldDeclaration)
11976     {
11977         return 'DATE';
11978     }
11979
11980     /**
11981      * @override
11982      */
11983     public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
11984     {
11985         return 'DATE';
11986     }
11987
11988     /**
11989      * @override
11990      */
11991     protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
11992     {
11993         return '';
11994     }
11995
11996     /**
11997      * Gets the SQL snippet used to declare a VARCHAR column on the Oracle platform.
11998      *
11999      * @params array $field
12000      * @override
12001      */
12002     public function getVarcharTypeDeclarationSQL(array $field)
12003     {
12004         if ( ! isset($field['length'])) {
12005             if (array_key_exists('default', $field)) {
12006                 $field['length'] = $this->getVarcharMaxLength();
12007             } else {
12008                 $field['length'] = false;
12009             }
12010         }
12011
12012         $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
12013         $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
12014
12015         return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(2000)')
12016                 : ($length ? 'VARCHAR2(' . $length . ')' : 'VARCHAR2(4000)');
12017     }
12018     
12019     /** @override */
12020     public function getClobTypeDeclarationSQL(array $field)
12021     {
12022         return 'CLOB';
12023     }
12024
12025     public function getListDatabasesSQL()
12026     {
12027         return 'SELECT username FROM all_users';
12028     }
12029
12030     public function getListSequencesSQL($database)
12031     {
12032         return "SELECT sequence_name, min_value, increment_by FROM sys.all_sequences ".
12033                "WHERE SEQUENCE_OWNER = '".strtoupper($database)."'";
12034     }
12035
12036     /**
12037      *
12038      * @param string $table
12039      * @param array $columns
12040      * @param array $options
12041      * @return array
12042      */
12043     protected function _getCreateTableSQL($table, array $columns, array $options = array())
12044     {
12045         $indexes = isset($options['indexes']) ? $options['indexes'] : array();
12046         $options['indexes'] = array();
12047         $sql = parent::_getCreateTableSQL($table, $columns, $options);
12048
12049         foreach ($columns as $name => $column) {
12050             if (isset($column['sequence'])) {
12051                 $sql[] = $this->getCreateSequenceSQL($column['sequence'], 1);
12052             }
12053
12054             if (isset($column['autoincrement']) && $column['autoincrement'] ||
12055                (isset($column['autoinc']) && $column['autoinc'])) {           
12056                 $sql = array_merge($sql, $this->getCreateAutoincrementSql($name, $table));
12057             }
12058         }
12059         
12060         if (isset($indexes) && ! empty($indexes)) {
12061             foreach ($indexes as $indexName => $index) {
12062                 $sql[] = $this->getCreateIndexSQL($index, $table);
12063             }
12064         }
12065
12066         return $sql;
12067     }
12068
12069     /**
12070      * @license New BSD License
12071      * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaOracleReader.html
12072      * @param  string $table
12073      * @return string
12074      */
12075     public function getListTableIndexesSQL($table)
12076     {
12077         $table = strtoupper($table);
12078         
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";
12087     }
12088
12089     public function getListTablesSQL()
12090     {
12091         return 'SELECT * FROM sys.user_tables';
12092     }
12093
12094     public function getListViewsSQL($database)
12095     {
12096         return 'SELECT view_name, text FROM sys.user_views';
12097     }
12098
12099     public function getCreateViewSQL($name, $sql)
12100     {
12101         return 'CREATE VIEW ' . $name . ' AS ' . $sql;
12102     }
12103
12104     public function getDropViewSQL($name)
12105     {
12106         return 'DROP VIEW '. $name;
12107     }
12108
12109     public function getCreateAutoincrementSql($name, $table, $start = 1)
12110     {
12111         $table = strtoupper($table);
12112         $sql   = array();
12113
12114         $indexName  = $table . '_AI_PK';
12115         $definition = array(
12116             'primary' => true,
12117             'columns' => array($name => true),
12118         );
12119
12120         $idx = new \Doctrine\DBAL\Schema\Index($indexName, array($name), true, true);
12121
12122         $sql[] = 'DECLARE
12123   constraints_Count NUMBER;
12124 BEGIN
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).'\';
12128   END IF;
12129 END;';   
12130
12131         $sequenceName = $table . '_SEQ';
12132         $sequence = new \Doctrine\DBAL\Schema\Sequence($sequenceName, $start);
12133         $sql[] = $this->getCreateSequenceSQL($sequence);
12134
12135         $triggerName  = $table . '_AI_PK';
12136         $sql[] = 'CREATE TRIGGER ' . $triggerName . '
12137    BEFORE INSERT
12138    ON ' . $table . '
12139    FOR EACH ROW
12140 DECLARE
12141    last_Sequence NUMBER;
12142    last_InsertID NUMBER;
12143 BEGIN
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;
12147    ELSE
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;
12154       END LOOP;
12155    END IF;
12156 END;';
12157         return $sql;
12158     }
12159
12160     public function getDropAutoincrementSql($table)
12161     {
12162         $table = strtoupper($table);
12163         $trigger = $table . '_AI_PK';
12164
12165         if ($trigger) {
12166             $sql[] = 'DROP TRIGGER ' . $trigger;
12167             $sql[] = $this->getDropSequenceSQL($table.'_SEQ');
12168
12169             $indexName = $table . '_AI_PK';
12170             $sql[] = $this->getDropConstraintSQL($indexName, $table);
12171         }
12172
12173         return $sql;
12174     }
12175
12176     public function getListTableForeignKeysSQL($table)
12177     {
12178         $table = strtoupper($table);
12179
12180         return "SELECT alc.constraint_name,
12181           alc.DELETE_RULE,
12182           alc.search_condition,
12183           cols.column_name \"local_column\",
12184           cols.position,
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."'";
12201     }
12202
12203     public function getListTableConstraintsSQL($table)
12204     {
12205         $table = strtoupper($table);
12206         return 'SELECT * FROM user_constraints WHERE table_name = \'' . $table . '\'';
12207     }
12208
12209     public function getListTableColumnsSQL($table)
12210     {
12211         $table = strtoupper($table);
12212         return "SELECT * FROM all_tab_columns WHERE table_name = '" . $table . "' ORDER BY column_name";
12213     }
12214
12215     /**
12216      *
12217      * @param  \Doctrine\DBAL\Schema\Sequence $sequence
12218      * @return string
12219      */
12220     public function getDropSequenceSQL($sequence)
12221     {
12222         if ($sequence instanceof \Doctrine\DBAL\Schema\Sequence) {
12223             $sequence = $sequence->getName();
12224         }
12225
12226         return 'DROP SEQUENCE ' . $sequence;
12227     }
12228
12229     /**
12230      * @param  ForeignKeyConstraint|string $foreignKey
12231      * @param  Table|string $table
12232      * @return string
12233      */
12234     public function getDropForeignKeySQL($foreignKey, $table)
12235     {
12236         if ($foreignKey instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) {
12237             $foreignKey = $foreignKey->getName();
12238         }
12239
12240         if ($table instanceof \Doctrine\DBAL\Schema\Table) {
12241             $table = $table->getName();
12242         }
12243
12244         return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey;
12245     }
12246
12247     public function getDropDatabaseSQL($database)
12248     {
12249         return 'DROP USER ' . $database . ' CASCADE';
12250     }
12251
12252     /**
12253      * Gets the sql statements for altering an existing table.
12254      *
12255      * The method returns an array of sql statements, since some platforms need several statements.
12256      *
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.
12262      * @return array
12263      */
12264     public function getAlterTableSQL(TableDiff $diff)
12265     {
12266         $sql = array();
12267
12268         $fields = array();
12269         foreach ($diff->addedColumns AS $column) {
12270             $fields[] = $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
12271         }
12272         if (count($fields)) {
12273             $sql[] = 'ALTER TABLE ' . $diff->name . ' ADD (' . implode(', ', $fields) . ')';
12274         }
12275
12276         $fields = array();
12277         foreach ($diff->changedColumns AS $columnDiff) {
12278             $column = $columnDiff->column;
12279             $fields[] = $column->getName(). ' ' . $this->getColumnDeclarationSQL('', $column->toArray());
12280         }
12281         if (count($fields)) {
12282             $sql[] = 'ALTER TABLE ' . $diff->name . ' MODIFY (' . implode(', ', $fields) . ')';
12283         }
12284
12285         foreach ($diff->renamedColumns AS $oldColumnName => $column) {
12286             $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName .' TO ' . $column->getName();
12287         }
12288
12289         $fields = array();
12290         foreach ($diff->removedColumns AS $column) {
12291             $fields[] = $column->getName();
12292         }
12293         if (count($fields)) {
12294             $sql[] = 'ALTER TABLE ' . $diff->name . ' DROP COLUMN ' . implode(', ', $fields);
12295         }
12296
12297         if ($diff->newName !== false) {
12298             $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName;
12299         }
12300
12301         $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
12302
12303         return $sql;
12304     }
12305
12306     /**
12307      * Whether the platform prefers sequences for ID generation.
12308      *
12309      * @return boolean
12310      */
12311     public function prefersSequences()
12312     {
12313         return true;
12314     }
12315
12316     /**
12317      * Get the platform name for this instance
12318      *
12319      * @return string
12320      */
12321     public function getName()
12322     {
12323         return 'oracle';
12324     }
12325
12326     /**
12327      * Adds an driver-specific LIMIT clause to the query
12328      *
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
12333      */
12334     public function modifyLimitQuery($query, $limit, $offset = null)
12335     {
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";
12341             }
12342             if ($limit > 0) {
12343                 $max = $offset + $limit;
12344                 $column = '*';
12345                 if ($offset > 0) {
12346                     $min = $offset + 1;
12347                     $query = 'SELECT b.'.$column.' FROM ('.
12348                                  'SELECT a.*, ROWNUM AS doctrine_rownum FROM ('
12349                                    . $query . ') a '.
12350                               ') b '.
12351                               'WHERE doctrine_rownum BETWEEN ' . $min .  ' AND ' . $max;
12352                 } else {
12353                     $query = 'SELECT a.'.$column.' FROM (' . $query .') a WHERE ROWNUM <= ' . $max;
12354                 }
12355             }
12356         }
12357         return $query;
12358     }
12359     
12360     /**
12361      * Gets the character casing of a column in an SQL result set of this platform.
12362      * 
12363      * Oracle returns all column names in SQL result sets in uppercase.
12364      * 
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.
12367      */
12368     public function getSQLResultCasing($column)
12369     {
12370         return strtoupper($column);
12371     }
12372     
12373     public function getCreateTemporaryTableSnippetSQL()
12374     {
12375         return "CREATE GLOBAL TEMPORARY TABLE";
12376     }
12377     
12378     public function getDateTimeTzFormatString()
12379     {
12380         return 'Y-m-d H:i:sP';
12381     }
12382
12383     public function getDateFormatString()
12384     {
12385         return 'Y-m-d 00:00:00';
12386     }
12387
12388     public function getTimeFormatString()
12389     {
12390         return '1900-01-01 H:i:s';
12391     }
12392     
12393     public function fixSchemaElementName($schemaElementName)
12394     {
12395         if (strlen($schemaElementName) > 30) {
12396             // Trim it
12397             return substr($schemaElementName, 0, 30);
12398         }
12399         return $schemaElementName;
12400     }
12401
12402     /**
12403      * Maximum length of any given databse identifier, like tables or column names.
12404      *
12405      * @return int
12406      */
12407     public function getMaxIdentifierLength()
12408     {
12409         return 30;
12410     }
12411
12412     /**
12413      * Whether the platform supports sequences.
12414      *
12415      * @return boolean
12416      */
12417     public function supportsSequences()
12418     {
12419         return true;
12420     }
12421
12422     public function supportsForeignKeyOnUpdate()
12423     {
12424         return false;
12425     }
12426
12427     /**
12428      * Whether the platform supports releasing savepoints.
12429      *
12430      * @return boolean
12431      */
12432     public function supportsReleaseSavepoints()
12433     {
12434         return false;
12435     }
12436
12437     /**
12438      * @inheritdoc
12439      */
12440     public function getTruncateTableSQL($tableName, $cascade = false)
12441     {
12442         return 'TRUNCATE TABLE '.$tableName;
12443     }
12444
12445     /**
12446      * This is for test reasons, many vendors have special requirements for dummy statements.
12447      *
12448      * @return string
12449      */
12450     public function getDummySelectSQL()
12451     {
12452         return 'SELECT 1 FROM DUAL';
12453     }
12454
12455     protected function initializeDoctrineTypeMappings()
12456     {
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',
12472             'clob'              => 'text',
12473             'nclob'             => 'text',
12474             'rowid'             => 'string',
12475             'urowid'            => 'string'
12476         );
12477     }
12478
12479     /**
12480      * Generate SQL to release a savepoint
12481      *
12482      * @param string $savepoint
12483      * @return string
12484      */
12485     public function releaseSavePoint($savepoint)
12486     {
12487         return '';
12488     }
12489 }
12490 <?php
12491 /*
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.
12503  *
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>.
12507 */
12508
12509 namespace Doctrine\DBAL\Platforms;
12510
12511 use Doctrine\DBAL\DBALException;
12512 use Doctrine\DBAL\Schema\Index;
12513 use Doctrine\DBAL\Schema\TableDiff;
12514
12515 class DB2Platform extends AbstractPlatform
12516 {
12517     public function initializeDoctrineTypeMappings()
12518     {
12519         $this->doctrineTypeMapping = array(
12520             'smallint'      => 'smallint',
12521             'bigint'        => 'bigint',
12522             'integer'       => 'integer',
12523             'time'          => 'time',
12524             'date'          => 'date',
12525             'varchar'       => 'string',
12526             'character'     => 'string',
12527             'clob'          => 'text',
12528             'decimal'       => 'decimal',
12529             'double'        => 'decimal',
12530             'real'          => 'decimal',
12531             'timestamp'     => 'datetime',
12532         );
12533     }
12534
12535     /**
12536      * Gets the SQL snippet used to declare a VARCHAR column type.
12537      *
12538      * @param array $field
12539      */
12540     public function getVarcharTypeDeclarationSQL(array $field)
12541     {
12542         if ( ! isset($field['length'])) {
12543             if (array_key_exists('default', $field)) {
12544                 $field['length'] = $this->getVarcharMaxLength();
12545             } else {
12546                 $field['length'] = false;
12547             }
12548         }
12549
12550         $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
12551         $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
12552
12553         return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
12554                 : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)');
12555     }
12556
12557     /**
12558      * Gets the SQL snippet used to declare a CLOB column type.
12559      *
12560      * @param array $field
12561      */
12562     public function getClobTypeDeclarationSQL(array $field)
12563     {
12564         // todo clob(n) with $field['length'];
12565         return 'CLOB(1M)';
12566     }
12567
12568     /**
12569      * Gets the name of the platform.
12570      *
12571      * @return string
12572      */
12573     public function getName()
12574     {
12575         return 'db2';
12576     }
12577
12578
12579     /**
12580      * Gets the SQL snippet that declares a boolean column.
12581      *
12582      * @param array $columnDef
12583      * @return string
12584      */
12585     public function getBooleanTypeDeclarationSQL(array $columnDef)
12586     {
12587         return 'SMALLINT';
12588     }
12589
12590     /**
12591      * Gets the SQL snippet that declares a 4 byte integer column.
12592      *
12593      * @param array $columnDef
12594      * @return string
12595      */
12596     public function getIntegerTypeDeclarationSQL(array $columnDef)
12597     {
12598         return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
12599     }
12600
12601     /**
12602      * Gets the SQL snippet that declares an 8 byte integer column.
12603      *
12604      * @param array $columnDef
12605      * @return string
12606      */
12607     public function getBigIntTypeDeclarationSQL(array $columnDef)
12608     {
12609         return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
12610     }
12611
12612     /**
12613      * Gets the SQL snippet that declares a 2 byte integer column.
12614      *
12615      * @param array $columnDef
12616      * @return string
12617      */
12618     public function getSmallIntTypeDeclarationSQL(array $columnDef)
12619     {
12620         return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef);
12621     }
12622
12623     /**
12624      * Gets the SQL snippet that declares common properties of an integer column.
12625      *
12626      * @param array $columnDef
12627      * @return string
12628      */
12629     protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
12630     {
12631         $autoinc = '';
12632         if ( ! empty($columnDef['autoincrement'])) {
12633             $autoinc = ' GENERATED BY DEFAULT AS IDENTITY';
12634         }
12635         return $autoinc;
12636     }
12637
12638     /**
12639      * Obtain DBMS specific SQL to be used to create datetime fields in
12640      * statements like CREATE TABLE
12641      *
12642      * @param array $fieldDeclaration
12643      * @return string
12644      */
12645     public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
12646     {
12647         if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) {
12648             return "TIMESTAMP(0) WITH DEFAULT";
12649         }
12650
12651         return 'TIMESTAMP(0)';
12652     }
12653
12654     /**
12655      * Obtain DBMS specific SQL to be used to create date fields in statements
12656      * like CREATE TABLE.
12657      *
12658      * @param array $fieldDeclaration
12659      * @return string
12660      */
12661     public function getDateTypeDeclarationSQL(array $fieldDeclaration)
12662     {
12663         return 'DATE';
12664     }
12665
12666     /**
12667      * Obtain DBMS specific SQL to be used to create time fields in statements
12668      * like CREATE TABLE.
12669      *
12670      * @param array $fieldDeclaration
12671      * @return string
12672      */
12673     public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
12674     {
12675         return 'TIME';
12676     }
12677
12678     public function getListDatabasesSQL()
12679     {
12680         throw DBALException::notSupported(__METHOD__);
12681     }
12682
12683     public function getListSequencesSQL($database)
12684     {
12685         throw DBALException::notSupported(__METHOD__);
12686     }
12687
12688     public function getListTableConstraintsSQL($table)
12689     {
12690         throw DBALException::notSupported(__METHOD__);
12691     }
12692
12693     /**
12694      * This code fragment is originally from the Zend_Db_Adapter_Db2 class.
12695      *
12696      * @license New BSD License
12697      * @param  string $table
12698      * @return string
12699      */
12700     public function getListTableColumnsSQL($table)
12701     {
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";
12714     }
12715
12716     public function getListTablesSQL()
12717     {
12718         return "SELECT NAME FROM SYSIBM.SYSTABLES WHERE TYPE = 'T'";
12719     }
12720
12721     public function getListUsersSQL()
12722     {
12723         throw DBALException::notSupported(__METHOD__);
12724     }
12725
12726     /**
12727      * Get the SQL to list all views of a database or user.
12728      *
12729      * @param string $database
12730      * @return string
12731      */
12732     public function getListViewsSQL($database)
12733     {
12734         return "SELECT NAME, TEXT FROM SYSIBM.SYSVIEWS";
12735     }
12736
12737     public function getListTableIndexesSQL($table)
12738     {
12739         return "SELECT NAME, COLNAMES, UNIQUERULE FROM SYSIBM.SYSINDEXES WHERE TBNAME = UPPER('" . $table . "')";
12740     }
12741
12742     public function getListTableForeignKeysSQL($table)
12743     {
12744         return "SELECT TBNAME, RELNAME, REFTBNAME, DELETERULE, UPDATERULE, FKCOLNAMES, PKCOLNAMES ".
12745                "FROM SYSIBM.SYSRELS WHERE TBNAME = UPPER('".$table."')";
12746     }
12747
12748     public function getCreateViewSQL($name, $sql)
12749     {
12750         return "CREATE VIEW ".$name." AS ".$sql;
12751     }
12752
12753     public function getDropViewSQL($name)
12754     {
12755         return "DROP VIEW ".$name;
12756     }
12757
12758     public function getDropSequenceSQL($sequence)
12759     {
12760         throw DBALException::notSupported(__METHOD__);
12761     }
12762
12763     public function getSequenceNextValSQL($sequenceName)
12764     {
12765         throw DBALException::notSupported(__METHOD__);
12766     }
12767
12768     public function getCreateDatabaseSQL($database)
12769     {
12770         return "CREATE DATABASE ".$database;
12771     }
12772
12773     public function getDropDatabaseSQL($database)
12774     {
12775         return "DROP DATABASE ".$database.";";
12776     }
12777
12778     public function supportsCreateDropDatabase()
12779     {
12780         return false;
12781     }
12782
12783     /**
12784      * Whether the platform supports releasing savepoints.
12785      *
12786      * @return boolean
12787      */
12788     public function supportsReleaseSavepoints()
12789     {
12790         return false;
12791     }
12792
12793     /**
12794      * Gets the SQL specific for the platform to get the current date.
12795      *
12796      * @return string
12797      */
12798     public function getCurrentDateSQL()
12799     {
12800         return 'VALUES CURRENT DATE';
12801     }
12802
12803     /**
12804      * Gets the SQL specific for the platform to get the current time.
12805      *
12806      * @return string
12807      */
12808     public function getCurrentTimeSQL()
12809     {
12810         return 'VALUES CURRENT TIME';
12811     }
12812
12813     /**
12814      * Gets the SQL specific for the platform to get the current timestamp
12815      *
12816      * @return string
12817      */
12818
12819     public function getCurrentTimestampSQL()
12820     {
12821         return "VALUES CURRENT TIMESTAMP";
12822     }
12823
12824     /**
12825      * Obtain DBMS specific SQL code portion needed to set an index
12826      * declaration to be used in statements like CREATE TABLE.
12827      *
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
12831      */
12832     public function getIndexDeclarationSQL($name, Index $index)
12833     {
12834         return $this->getUniqueConstraintDeclarationSQL($name, $index);
12835     }
12836
12837     /**
12838      * @param string $tableName
12839      * @param array $columns
12840      * @param array $options
12841      * @return array
12842      */
12843     protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
12844     {
12845         $indexes = array();
12846         if (isset($options['indexes'])) {
12847             $indexes = $options['indexes'];
12848         }
12849         $options['indexes'] = array();
12850         
12851         $sqls = parent::_getCreateTableSQL($tableName, $columns, $options);
12852
12853         foreach ($indexes as $index => $definition) {
12854             $sqls[] = $this->getCreateIndexSQL($definition, $tableName);
12855         }
12856         return $sqls;
12857     }
12858
12859     /**
12860      * Gets the SQL to alter an existing table.
12861      *
12862      * @param TableDiff $diff
12863      * @return array
12864      */
12865     public function getAlterTableSQL(TableDiff $diff)
12866     {
12867         $sql = array();
12868
12869         $queryParts = array();
12870         foreach ($diff->addedColumns AS $fieldName => $column) {
12871             $queryParts[] = 'ADD COLUMN ' . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
12872         }
12873
12874         foreach ($diff->removedColumns AS $column) {
12875             $queryParts[] =  'DROP COLUMN ' . $column->getName();
12876         }
12877
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());
12883         }
12884
12885         foreach ($diff->renamedColumns AS $oldColumnName => $column) {
12886             $queryParts[] =  'RENAME ' . $oldColumnName . ' TO ' . $column->getName();
12887         }
12888
12889         if (count($queryParts) > 0) {
12890             $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(" ", $queryParts);
12891         }
12892
12893         $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
12894
12895         if ($diff->newName !== false) {
12896             $sql[] =  'RENAME TABLE TO ' . $diff->newName;
12897         }
12898
12899         return $sql;
12900     }
12901
12902     public function getDefaultValueDeclarationSQL($field)
12903     {
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";
12913             } else {
12914                 $field['default'] = '';
12915             }
12916         }
12917
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";
12922             }
12923         }
12924
12925         return parent::getDefaultValueDeclarationSQL($field);
12926     }
12927
12928     /**
12929      * Get the insert sql for an empty insert statement
12930      *
12931      * @param string $tableName
12932      * @param string $identifierColumnName
12933      * @return string $sql
12934      */
12935     public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName)
12936     {
12937         return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (DEFAULT)';
12938     }
12939
12940     public function getCreateTemporaryTableSnippetSQL()
12941     {
12942         return "DECLARE GLOBAL TEMPORARY TABLE";
12943     }
12944
12945     /**
12946      * DB2 automatically moves temporary tables into the SESSION. schema.
12947      *
12948      * @param  string $tableName
12949      * @return string
12950      */
12951     public function getTemporaryTableName($tableName)
12952     {
12953         return "SESSION." . $tableName;
12954     }
12955
12956     public function modifyLimitQuery($query, $limit, $offset = null)
12957     {
12958         if ($limit === null && $offset === null) {
12959             return $query;
12960         }
12961
12962         $limit = (int)$limit;
12963         $offset = (int)(($offset)?:0);
12964
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);
12968         return $sql;
12969     }
12970
12971     /**
12972      * returns the position of the first occurrence of substring $substr in string $str
12973      *
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
12977      * @return integer
12978      */
12979     public function getLocateExpression($str, $substr, $startPos = false)
12980     {
12981         if ($startPos == false) {
12982             return 'LOCATE(' . $substr . ', ' . $str . ')';
12983         } else {
12984             return 'LOCATE(' . $substr . ', ' . $str . ', '.$startPos.')';
12985         }
12986     }
12987
12988     /**
12989      * return string to call a function to get a substring inside an SQL statement
12990      *
12991      * Note: Not SQL92, but common functionality.
12992      *
12993      * SQLite only supports the 2 parameter variant of this function
12994      *
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
12998      * @return string
12999      */
13000     public function getSubstringExpression($value, $from, $len = null)
13001     {
13002         if ($len === null)
13003             return 'SUBSTR(' . $value . ', ' . $from . ')';
13004         else {
13005             return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
13006         }
13007     }
13008
13009     public function supportsIdentityColumns()
13010     {
13011         return true;
13012     }
13013
13014     public function prefersIdentityColumns()
13015     {
13016         return true;
13017     }
13018
13019     /**
13020      * Gets the character casing of a column in an SQL result set of this platform.
13021      *
13022      * DB2 returns all column names in SQL result sets in uppercase.
13023      *
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.
13026      */
13027     public function getSQLResultCasing($column)
13028     {
13029         return strtoupper($column);
13030     }
13031
13032     public function getForUpdateSQL()
13033     {
13034         return ' WITH RR USE AND KEEP UPDATE LOCKS';
13035     }
13036
13037     public function getDummySelectSQL()
13038     {
13039         return 'SELECT 1 FROM sysibm.sysdummy1';
13040     }
13041
13042     /**
13043      * DB2 supports savepoints, but they work semantically different than on other vendor platforms.
13044      *
13045      * TODO: We have to investigate how to get DB2 up and running with savepoints.
13046      *
13047      * @return bool
13048      */
13049     public function supportsSavepoints()
13050     {
13051         return false;
13052     }
13053 }<?php
13054 /*
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.
13066  *
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>.
13070  */
13071
13072 namespace Doctrine\DBAL\Platforms;
13073
13074 use Doctrine\DBAL\DBALException,
13075     Doctrine\DBAL\Schema\TableDiff;
13076
13077 /**
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.
13081  *
13082  * @since 2.0
13083  * @author Roman Borschel <roman@code-factory.org>
13084  * @author Benjamin Eberlei <kontakt@beberlei.de>
13085  * @todo Rename: MySQLPlatform
13086  */
13087 class MySqlPlatform extends AbstractPlatform
13088 {
13089     /**
13090      * Gets the character used for identifier quoting.
13091      *
13092      * @return string
13093      * @override
13094      */
13095     public function getIdentifierQuoteCharacter()
13096     {
13097         return '`';
13098     }
13099     
13100     /**
13101      * Returns the regular expression operator.
13102      *
13103      * @return string
13104      * @override
13105      */
13106     public function getRegexpExpression()
13107     {
13108         return 'RLIKE';
13109     }
13110
13111     /**
13112      * Returns global unique identifier
13113      *
13114      * @return string to get global unique identifier
13115      * @override
13116      */
13117     public function getGuidExpression()
13118     {
13119         return 'UUID()';
13120     }
13121
13122     /**
13123      * returns the position of the first occurrence of substring $substr in string $str
13124      *
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
13128      * @return integer
13129      */
13130     public function getLocateExpression($str, $substr, $startPos = false)
13131     {
13132         if ($startPos == false) {
13133             return 'LOCATE(' . $substr . ', ' . $str . ')';
13134         } else {
13135             return 'LOCATE(' . $substr . ', ' . $str . ', '.$startPos.')';
13136         }
13137     }
13138
13139     /**
13140      * Returns a series of strings concatinated
13141      *
13142      * concat() accepts an arbitrary number of parameters. Each parameter
13143      * must contain an expression or an array with expressions.
13144      *
13145      * @param string|array(string) strings that will be concatinated.
13146      * @override
13147      */
13148     public function getConcatExpression()
13149     {
13150         $args = func_get_args();
13151         return 'CONCAT(' . join(', ', (array) $args) . ')';
13152     }
13153
13154     public function getListDatabasesSQL()
13155     {
13156         return 'SHOW DATABASES';
13157     }
13158
13159     public function getListTableConstraintsSQL($table)
13160     {
13161         return 'SHOW INDEX FROM ' . $table;
13162     }
13163
13164     public function getListTableIndexesSQL($table)
13165     {
13166         return 'SHOW INDEX FROM ' . $table;
13167     }
13168
13169     public function getListViewsSQL($database)
13170     {
13171         return "SELECT * FROM information_schema.VIEWS WHERE TABLE_SCHEMA = '".$database."'";
13172     }
13173
13174     public function getListTableForeignKeysSQL($table, $database = null)
13175     {
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'";
13182
13183         if ($database) {
13184             $sql .= " AND k.table_schema = '$database' /*!50116 AND c.constraint_schema = '$database' */";
13185         }
13186
13187         $sql .= " AND k.`REFERENCED_COLUMN_NAME` is not NULL";
13188
13189         return $sql;
13190     }
13191
13192     public function getCreateViewSQL($name, $sql)
13193     {
13194         return 'CREATE VIEW ' . $name . ' AS ' . $sql;
13195     }
13196
13197     public function getDropViewSQL($name)
13198     {
13199         return 'DROP VIEW '. $name;
13200     }
13201
13202     /**
13203      * Gets the SQL snippet used to declare a VARCHAR column on the MySql platform.
13204      *
13205      * @params array $field
13206      */
13207     public function getVarcharTypeDeclarationSQL(array $field)
13208     {
13209         if ( ! isset($field['length'])) {
13210             if (array_key_exists('default', $field)) {
13211                 $field['length'] = $this->getVarcharMaxLength();
13212             } else {
13213                 $field['length'] = false;
13214             }
13215         }
13216
13217         $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
13218         $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
13219
13220         return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
13221                 : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)');
13222     }
13223
13224     /** @override */
13225     public function getClobTypeDeclarationSQL(array $field)
13226     {
13227         if ( ! empty($field['length']) && is_numeric($field['length'])) {
13228             $length = $field['length'];
13229             if ($length <= 255) {
13230                 return 'TINYTEXT';
13231             } else if ($length <= 65532) {
13232                 return 'TEXT';
13233             } else if ($length <= 16777215) {
13234                 return 'MEDIUMTEXT';
13235             }
13236         }
13237         return 'LONGTEXT';
13238     }
13239
13240     /**
13241      * @override
13242      */
13243     public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
13244     {
13245         if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) {
13246             return 'TIMESTAMP';
13247         } else {
13248             return 'DATETIME';
13249         }
13250     }
13251     
13252     /**
13253      * @override
13254      */
13255     public function getDateTypeDeclarationSQL(array $fieldDeclaration)
13256     {
13257         return 'DATE';
13258     }
13259
13260     /**
13261      * @override
13262      */
13263     public function getTimeTypeDeclarationSQL(array $fieldDeclaration) 
13264     {
13265         return 'TIME';
13266     }   
13267
13268     /**
13269      * @override
13270      */
13271     public function getBooleanTypeDeclarationSQL(array $field)
13272     {
13273         return 'TINYINT(1)';
13274     }
13275
13276     /**
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.
13279      *
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.
13283      */
13284     public function getCollationFieldDeclaration($collation)
13285     {
13286         return 'COLLATE ' . $collation;
13287     }
13288     
13289     /**
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.
13293      *
13294      * @return boolean
13295      * @override
13296      */
13297     public function prefersIdentityColumns()
13298     {
13299         return true;
13300     }
13301     
13302     /**
13303      * Whether the platform supports identity columns.
13304      * MySql supports this through AUTO_INCREMENT columns.
13305      *
13306      * @return boolean
13307      * @override
13308      */
13309     public function supportsIdentityColumns()
13310     {
13311         return true;
13312     }
13313
13314     public function getShowDatabasesSQL()
13315     {
13316         return 'SHOW DATABASES';
13317     }
13318     
13319     public function getListTablesSQL()
13320     {
13321         return 'SHOW FULL TABLES WHERE Table_type = "BASE TABLE"';
13322     }
13323
13324     public function getListTableColumnsSQL($table)
13325     {
13326         return 'DESCRIBE ' . $table;
13327     }
13328
13329     /**
13330      * create a new database
13331      *
13332      * @param string $name name of the database that should be created
13333      * @return string
13334      * @override
13335      */
13336     public function getCreateDatabaseSQL($name)
13337     {
13338         return 'CREATE DATABASE ' . $name;
13339     }
13340     
13341     /**
13342      * drop an existing database
13343      *
13344      * @param string $name name of the database that should be dropped
13345      * @return string
13346      * @override
13347      */
13348     public function getDropDatabaseSQL($name)
13349     {
13350         return 'DROP DATABASE ' . $name;
13351     }
13352     
13353     /**
13354      * create a new table
13355      *
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.
13361      *                          array(
13362      *                              'id' => array(
13363      *                                  'type' => 'integer',
13364      *                                  'unsigned' => 1
13365      *                                  'notnull' => 1
13366      *                                  'default' => 0
13367      *                              ),
13368      *                              'name' => array(
13369      *                                  'type' => 'text',
13370      *                                  'length' => 12
13371      *                              ),
13372      *                              'password' => array(
13373      *                                  'type' => 'text',
13374      *                                  'length' => 12
13375      *                              )
13376      *                          );
13377      * @param array $options  An associative array of table options:
13378      *                          array(
13379      *                              'comment' => 'Foo',
13380      *                              'charset' => 'utf8',
13381      *                              'collate' => 'utf8_unicode_ci',
13382      *                              'type'    => 'innodb',
13383      *                          );
13384      *
13385      * @return void
13386      * @override
13387      */
13388     protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
13389     {
13390         $queryFields = $this->getColumnDeclarationListSQL($columns);
13391
13392         if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
13393             foreach ($options['uniqueConstraints'] as $index => $definition) {
13394                 $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition);
13395             }
13396         }
13397
13398         // add all indexes
13399         if (isset($options['indexes']) && ! empty($options['indexes'])) {
13400             foreach($options['indexes'] as $index => $definition) {
13401                 $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
13402             }
13403         }
13404
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) . ')';
13409         }
13410
13411         $query = 'CREATE ';
13412         if (!empty($options['temporary'])) {
13413             $query .= 'TEMPORARY ';
13414         }
13415         $query.= 'TABLE ' . $tableName . ' (' . $queryFields . ')';
13416
13417         $optionStrings = array();
13418
13419         if (isset($options['comment'])) {
13420             $optionStrings['comment'] = 'COMMENT = ' . $this->quote($options['comment'], 'text');
13421         }
13422         if (isset($options['charset'])) {
13423             $optionStrings['charset'] = 'DEFAULT CHARACTER SET ' . $options['charset'];
13424             if (isset($options['collate'])) {
13425                 $optionStrings['charset'] .= ' COLLATE ' . $options['collate'];
13426             }
13427         }
13428
13429         // get the type of the table
13430         if (isset($options['engine'])) {
13431             $optionStrings[] = 'ENGINE = ' . $options['engine'];
13432         } else {
13433             // default to innodb
13434             $optionStrings[] = 'ENGINE = InnoDB';
13435         }
13436         
13437         if ( ! empty($optionStrings)) {
13438             $query.= ' '.implode(' ', $optionStrings);
13439         }
13440         $sql[] = $query;
13441
13442         if (isset($options['foreignKeys'])) {
13443             foreach ((array) $options['foreignKeys'] as $definition) {
13444                 $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
13445             }
13446         }
13447         
13448         return $sql;
13449     }
13450     
13451     /**
13452      * Gets the SQL to alter an existing table.
13453      *
13454      * @param TableDiff $diff
13455      * @return array
13456      */
13457     public function getAlterTableSQL(TableDiff $diff)
13458     {
13459         $queryParts = array();
13460         if ($diff->newName !== false) {
13461             $queryParts[] =  'RENAME TO ' . $diff->newName;
13462         }
13463
13464         foreach ($diff->addedColumns AS $fieldName => $column) {
13465             $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
13466         }
13467
13468         foreach ($diff->removedColumns AS $column) {
13469             $queryParts[] =  'DROP ' . $column->getName();
13470         }
13471
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());
13477         }
13478
13479         foreach ($diff->renamedColumns AS $oldColumnName => $column) {
13480             $queryParts[] =  'CHANGE ' . $oldColumnName . ' '
13481                     . $this->getColumnDeclarationSQL($column->getName(), $column->toArray());
13482         }
13483
13484         $sql = array();
13485         if (count($queryParts) > 0) {
13486             $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(", ", $queryParts);
13487         }
13488         $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
13489         return $sql;
13490     }
13491     
13492     /**
13493      * Obtain DBMS specific SQL code portion needed to declare an integer type
13494      * field to be used in statements like CREATE TABLE.
13495      *
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:
13501      *
13502      *                       unsigned
13503      *                        Boolean flag that indicates whether the field
13504      *                        should be declared as unsigned integer if
13505      *                        possible.
13506      *
13507      *                       default
13508      *                        Integer value to be used as default for this
13509      *                        field.
13510      *
13511      *                       notnull
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.
13516      * @override
13517      */
13518     public function getIntegerTypeDeclarationSQL(array $field)
13519     {
13520         return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
13521     }
13522
13523     /** @override */
13524     public function getBigIntTypeDeclarationSQL(array $field)
13525     {
13526         return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
13527     }
13528
13529     /** @override */
13530     public function getSmallIntTypeDeclarationSQL(array $field)
13531     {
13532         return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
13533     }
13534
13535     /** @override */
13536     protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
13537     {
13538         $autoinc = '';
13539         if ( ! empty($columnDef['autoincrement'])) {
13540             $autoinc = ' AUTO_INCREMENT';
13541         }
13542         $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : '';
13543
13544         return $unsigned . $autoinc;
13545     }
13546     
13547     /**
13548      * Return the FOREIGN KEY query section dealing with non-standard options
13549      * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
13550      *
13551      * @param ForeignKeyConstraint $foreignKey
13552      * @return string
13553      * @override
13554      */
13555     public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey)
13556     {
13557         $query = '';
13558         if ($foreignKey->hasOption('match')) {
13559             $query .= ' MATCH ' . $foreignKey->getOption('match');
13560         }
13561         $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
13562         return $query;
13563     }
13564     
13565     /**
13566      * Gets the SQL to drop an index of a table.
13567      *
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
13570      * @override
13571      */
13572     public function getDropIndexSQL($index, $table=null)
13573     {
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.');
13578         }
13579         
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.');
13584         }
13585
13586         return 'DROP INDEX ' . $index . ' ON ' . $table;
13587     }
13588     
13589     /**
13590      * Gets the SQL to drop a table.
13591      *
13592      * @param string $table The name of table to drop.
13593      * @override
13594      */
13595     public function getDropTableSQL($table)
13596     {
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.');
13601         }
13602
13603         return 'DROP TABLE ' . $table;
13604     }
13605
13606     public function getSetTransactionIsolationSQL($level)
13607     {
13608         return 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level);
13609     }
13610
13611     /**
13612      * Get the platform name for this instance.
13613      *
13614      * @return string
13615      */
13616     public function getName()
13617     {
13618         return 'mysql';
13619     }
13620
13621     public function getReadLockSQL()
13622     {
13623         return 'LOCK IN SHARE MODE';
13624     }
13625
13626     protected function initializeDoctrineTypeMappings()
13627     {
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',
13638             'text'          => 'text',
13639             'varchar'       => 'string',
13640             'string'        => 'string',
13641             'char'          => 'string',
13642             'date'          => 'date',
13643             'datetime'      => 'datetime',
13644             'timestamp'     => 'datetime',
13645             'time'          => 'time',
13646             'float'         => 'decimal',
13647             'double'        => 'decimal',
13648             'real'          => 'decimal',
13649             'decimal'       => 'decimal',
13650             'numeric'       => 'decimal',
13651             'year'          => 'date',
13652         );
13653     }
13654 }
13655 <?php
13656 /*
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.
13668  *
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>.
13672  */
13673
13674 namespace Doctrine\DBAL\Platforms;
13675
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;
13683
13684 /**
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.
13688  *
13689  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
13690  * @link    www.doctrine-project.org
13691  * @since   2.0
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.
13699  */
13700 abstract class AbstractPlatform
13701 {
13702     /**
13703      * @var int
13704      */
13705     const CREATE_INDEXES = 1;
13706
13707     /**
13708      * @var int
13709      */
13710     const CREATE_FOREIGNKEYS = 2;
13711
13712     /**
13713      * @var int
13714      */
13715     const TRIM_UNSPECIFIED = 0;
13716
13717     /**
13718      * @var int
13719      */
13720     const TRIM_LEADING = 1;
13721
13722     /**
13723      * @var int
13724      */
13725     const TRIM_TRAILING = 2;
13726
13727     /**
13728      * @var int
13729      */
13730     const TRIM_BOTH = 3;
13731
13732     /**
13733      * @var array
13734      */
13735     protected $doctrineTypeMapping = null;
13736
13737     /**
13738      * Constructor.
13739      */
13740     public function __construct() {}
13741
13742     /**
13743      * Gets the SQL snippet that declares a boolean column.
13744      *
13745      * @param array $columnDef
13746      * @return string
13747      */
13748     abstract public function getBooleanTypeDeclarationSQL(array $columnDef);
13749
13750     /**
13751      * Gets the SQL snippet that declares a 4 byte integer column.
13752      *
13753      * @param array $columnDef
13754      * @return string
13755      */
13756     abstract public function getIntegerTypeDeclarationSQL(array $columnDef);
13757
13758     /**
13759      * Gets the SQL snippet that declares an 8 byte integer column.
13760      *
13761      * @param array $columnDef
13762      * @return string
13763      */
13764     abstract public function getBigIntTypeDeclarationSQL(array $columnDef);
13765
13766     /**
13767      * Gets the SQL snippet that declares a 2 byte integer column.
13768      *
13769      * @param array $columnDef
13770      * @return string
13771      */
13772     abstract public function getSmallIntTypeDeclarationSQL(array $columnDef);
13773
13774     /**
13775      * Gets the SQL snippet that declares common properties of an integer column.
13776      *
13777      * @param array $columnDef
13778      * @return string
13779      */
13780     abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef);
13781
13782     /**
13783      * Lazy load Doctrine Type Mappings
13784      *
13785      * @return void
13786      */
13787     abstract protected function initializeDoctrineTypeMappings();
13788
13789     /**
13790      * Gets the SQL snippet used to declare a VARCHAR column type.
13791      *
13792      * @param array $field
13793      */
13794     abstract public function getVarcharTypeDeclarationSQL(array $field);
13795
13796     /**
13797      * Gets the SQL snippet used to declare a CLOB column type.
13798      *
13799      * @param array $field
13800      */
13801     abstract public function getClobTypeDeclarationSQL(array $field);
13802
13803     /**
13804      * Gets the name of the platform.
13805      *
13806      * @return string
13807      */
13808     abstract public function getName();
13809
13810     /**
13811      * Register a doctrine type to be used in conjunction with a column type of this platform.
13812      *
13813      * @param string $dbType
13814      * @param string $doctrineType
13815      */
13816     public function registerDoctrineTypeMapping($dbType, $doctrineType)
13817     {
13818         if ($this->doctrineTypeMapping === null) {
13819             $this->initializeDoctrineTypeMappings();
13820         }
13821
13822         if (!Types\Type::hasType($doctrineType)) {
13823             throw DBALException::typeNotFound($doctrineType);
13824         }
13825
13826         $dbType = strtolower($dbType);
13827         $this->doctrineTypeMapping[$dbType] = $doctrineType;
13828     }
13829
13830     /**
13831      * Get the Doctrine type that is mapped for the given database column type.
13832      * 
13833      * @param  string $dbType
13834      * @return string
13835      */
13836     public function getDoctrineTypeMapping($dbType)
13837     {
13838         if ($this->doctrineTypeMapping === null) {
13839             $this->initializeDoctrineTypeMappings();
13840         }
13841         
13842         $dbType = strtolower($dbType);
13843         if (isset($this->doctrineTypeMapping[$dbType])) {
13844             return $this->doctrineTypeMapping[$dbType];
13845         } else {
13846             throw new \Doctrine\DBAL\DBALException("Unknown database type ".$dbType." requested, " . get_class($this) . " may not support it.");
13847         }
13848     }
13849
13850     /**
13851      * Check if a database type is currently supported by this platform.
13852      *
13853      * @param string $dbType
13854      * @return bool
13855      */
13856     public function hasDoctrineTypeMappingFor($dbType)
13857     {
13858         if ($this->doctrineTypeMapping === null) {
13859             $this->initializeDoctrineTypeMappings();
13860         }
13861
13862         $dbType = strtolower($dbType);
13863         return isset($this->doctrineTypeMapping[$dbType]);
13864     }
13865
13866     /**
13867      * Gets the character used for identifier quoting.
13868      *
13869      * @return string
13870      */
13871     public function getIdentifierQuoteCharacter()
13872     {
13873         return '"';
13874     }
13875
13876     /**
13877      * Gets the string portion that starts an SQL comment.
13878      *
13879      * @return string
13880      */
13881     public function getSqlCommentStartString()
13882     {
13883         return "--";
13884     }
13885
13886     /**
13887      * Gets the string portion that ends an SQL comment.
13888      *
13889      * @return string
13890      */
13891     public function getSqlCommentEndString()
13892     {
13893         return "\n";
13894     }
13895
13896     /**
13897      * Gets the maximum length of a varchar field.
13898      *
13899      * @return integer
13900      */
13901     public function getVarcharMaxLength()
13902     {
13903         return 255;
13904     }
13905
13906     /**
13907      * Gets all SQL wildcard characters of the platform.
13908      *
13909      * @return array
13910      */
13911     public function getWildcards()
13912     {
13913         return array('%', '_');
13914     }
13915
13916     /**
13917      * Returns the regular expression operator.
13918      *
13919      * @return string
13920      */
13921     public function getRegexpExpression()
13922     {
13923         throw DBALException::notSupported(__METHOD__);
13924     }
13925
13926     /**
13927      * Returns the average value of a column
13928      *
13929      * @param string $column    the column to use
13930      * @return string           generated sql including an AVG aggregate function
13931      */
13932     public function getAvgExpression($column)
13933     {
13934         return 'AVG(' .  $column . ')';
13935     }
13936
13937     /**
13938      * Returns the number of rows (without a NULL value) of a column
13939      *
13940      * If a '*' is used instead of a column the number of selected rows
13941      * is returned.
13942      *
13943      * @param string|integer $column    the column to use
13944      * @return string                   generated sql including a COUNT aggregate function
13945      */
13946     public function getCountExpression($column)
13947     {
13948         return 'COUNT(' . $column . ')';
13949     }
13950
13951     /**
13952      * Returns the highest value of a column
13953      *
13954      * @param string $column    the column to use
13955      * @return string           generated sql including a MAX aggregate function
13956      */
13957     public function getMaxExpression($column)
13958     {
13959         return 'MAX(' . $column . ')';
13960     }
13961
13962     /**
13963      * Returns the lowest value of a column
13964      *
13965      * @param string $column the column to use
13966      * @return string
13967      */
13968     public function getMinExpression($column)
13969     {
13970         return 'MIN(' . $column . ')';
13971     }
13972
13973     /**
13974      * Returns the total sum of a column
13975      *
13976      * @param string $column the column to use
13977      * @return string
13978      */
13979     public function getSumExpression($column)
13980     {
13981         return 'SUM(' . $column . ')';
13982     }
13983
13984     // scalar functions
13985
13986     /**
13987      * Returns the md5 sum of a field.
13988      *
13989      * Note: Not SQL92, but common functionality
13990      *
13991      * @return string
13992      */
13993     public function getMd5Expression($column)
13994     {
13995         return 'MD5(' . $column . ')';
13996     }
13997
13998     /**
13999      * Returns the length of a text field.
14000      *
14001      * @param string $expression1
14002      * @param string $expression2
14003      * @return string
14004      */
14005     public function getLengthExpression($column)
14006     {
14007         return 'LENGTH(' . $column . ')';
14008     }
14009
14010     /**
14011      * Rounds a numeric field to the number of decimals specified.
14012      *
14013      * @param string $expression1
14014      * @param string $expression2
14015      * @return string
14016      */
14017     public function getRoundExpression($column, $decimals = 0)
14018     {
14019         return 'ROUND(' . $column . ', ' . $decimals . ')';
14020     }
14021
14022     /**
14023      * Returns the remainder of the division operation
14024      * $expression1 / $expression2.
14025      *
14026      * @param string $expression1
14027      * @param string $expression2
14028      * @return string
14029      */
14030     public function getModExpression($expression1, $expression2)
14031     {
14032         return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
14033     }
14034
14035     /**
14036      * Trim a string, leading/trailing/both and with a given char which defaults to space.
14037      *
14038      * @param string $str
14039      * @param int $pos
14040      * @param string $char has to be quoted already
14041      * @return string
14042      */
14043     public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
14044     {
14045         $posStr = '';
14046         $trimChar = ($char != false) ? $char . ' FROM ' : '';
14047         
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;
14054         }
14055
14056         return 'TRIM(' . $posStr . $str . ')';
14057     }
14058
14059     /**
14060      * rtrim
14061      * returns the string $str with proceeding space characters removed
14062      *
14063      * @param string $str       literal string or column name
14064      * @return string
14065      */
14066     public function getRtrimExpression($str)
14067     {
14068         return 'RTRIM(' . $str . ')';
14069     }
14070
14071     /**
14072      * ltrim
14073      * returns the string $str with leading space characters removed
14074      *
14075      * @param string $str       literal string or column name
14076      * @return string
14077      */
14078     public function getLtrimExpression($str)
14079     {
14080         return 'LTRIM(' . $str . ')';
14081     }
14082
14083     /**
14084      * upper
14085      * Returns the string $str with all characters changed to
14086      * uppercase according to the current character set mapping.
14087      *
14088      * @param string $str       literal string or column name
14089      * @return string
14090      */
14091     public function getUpperExpression($str)
14092     {
14093         return 'UPPER(' . $str . ')';
14094     }
14095
14096     /**
14097      * lower
14098      * Returns the string $str with all characters changed to
14099      * lowercase according to the current character set mapping.
14100      *
14101      * @param string $str       literal string or column name
14102      * @return string
14103      */
14104     public function getLowerExpression($str)
14105     {
14106         return 'LOWER(' . $str . ')';
14107     }
14108
14109     /**
14110      * returns the position of the first occurrence of substring $substr in string $str
14111      *
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
14115      * @return integer
14116      */
14117     public function getLocateExpression($str, $substr, $startPos = false)
14118     {
14119         throw DBALException::notSupported(__METHOD__);
14120     }
14121
14122     /**
14123      * Returns the current system date.
14124      *
14125      * @return string
14126      */
14127     public function getNowExpression()
14128     {
14129         return 'NOW()';
14130     }
14131
14132     /**
14133      * return string to call a function to get a substring inside an SQL statement
14134      *
14135      * Note: Not SQL92, but common functionality.
14136      *
14137      * SQLite only supports the 2 parameter variant of this function
14138      *
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
14142      * @return string
14143      */
14144     public function getSubstringExpression($value, $from, $len = null)
14145     {
14146         if ($len === null)
14147             return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
14148         else {
14149             return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $len . ')';
14150         }
14151     }
14152
14153     /**
14154      * Returns a series of strings concatinated
14155      *
14156      * concat() accepts an arbitrary number of parameters. Each parameter
14157      * must contain an expression
14158      *
14159      * @param string $arg1, $arg2 ... $argN     strings that will be concatinated.
14160      * @return string
14161      */
14162     public function getConcatExpression()
14163     {
14164         return join(' || ' , func_get_args());
14165     }
14166
14167     /**
14168      * Returns the SQL for a logical not.
14169      *
14170      * Example:
14171      * <code>
14172      * $q = new Doctrine_Query();
14173      * $e = $q->expr;
14174      * $q->select('*')->from('table')
14175      *   ->where($e->eq('id', $e->not('null'));
14176      * </code>
14177      *
14178      * @return string a logical expression
14179      */
14180     public function getNotExpression($expression)
14181     {
14182         return 'NOT(' . $expression . ')';
14183     }
14184
14185     /**
14186      * Returns the SQL to check if a value is one in a set of
14187      * given values.
14188      *
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.
14193      *
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
14197      */
14198     public function getInExpression($column, $values)
14199     {
14200         if ( ! is_array($values)) {
14201             $values = array($values);
14202         }
14203         $values = $this->getIdentifiers($values);
14204
14205         if (count($values) == 0) {
14206             throw \InvalidArgumentException('Values must not be empty.');
14207         }
14208         return $column . ' IN (' . implode(', ', $values) . ')';
14209     }
14210
14211     /**
14212      * Returns SQL that checks if a expression is null.
14213      *
14214      * @param string $expression the expression that should be compared to null
14215      * @return string logical expression
14216      */
14217     public function getIsNullExpression($expression)
14218     {
14219         return $expression . ' IS NULL';
14220     }
14221
14222     /**
14223      * Returns SQL that checks if a expression is not null.
14224      *
14225      * @param string $expression the expression that should be compared to null
14226      * @return string logical expression
14227      */
14228     public function getIsNotNullExpression($expression)
14229     {
14230         return $expression . ' IS NOT NULL';
14231     }
14232
14233     /**
14234      * Returns SQL that checks if an expression evaluates to a value between
14235      * two values.
14236      *
14237      * The parameter $expression is checked if it is between $value1 and $value2.
14238      *
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().
14242      *
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
14247      */
14248     public function getBetweenExpression($expression, $value1, $value2)
14249     {
14250         return $expression . ' BETWEEN ' .$value1 . ' AND ' . $value2;
14251     }
14252
14253     public function getAcosExpression($value)
14254     {
14255         return 'ACOS(' . $value . ')';
14256     }
14257
14258     public function getSinExpression($value)
14259     {
14260         return 'SIN(' . $value . ')';
14261     }
14262
14263     public function getPiExpression()
14264     {
14265         return 'PI()';
14266     }
14267
14268     public function getCosExpression($value)
14269     {
14270         return 'COS(' . $value . ')';
14271     }
14272
14273     public function getForUpdateSQL()
14274     {
14275         return 'FOR UPDATE';
14276     }
14277
14278     /**
14279      * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification.
14280      *
14281      * @param  string $fromClause
14282      * @param  int $lockMode
14283      * @return string
14284      */
14285     public function appendLockHint($fromClause, $lockMode)
14286     {
14287         return $fromClause;
14288     }
14289
14290     /**
14291      * Get the sql snippet to append to any SELECT statement which locks rows in shared read lock.
14292      *
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.
14295      *
14296      * @return string
14297      */
14298     public function getReadLockSQL()
14299     {
14300         return $this->getForUpdateSQL();
14301     }
14302
14303     /**
14304      * Get the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows.
14305      *
14306      * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ASNI SQL standard.
14307      *
14308      * @return string
14309      */
14310     public function getWriteLockSQL()
14311     {
14312         return $this->getForUpdateSQL();
14313     }
14314
14315     public function getDropDatabaseSQL($database)
14316     {
14317         return 'DROP DATABASE ' . $database;
14318     }
14319
14320     /**
14321      * Drop a Table
14322      * 
14323      * @param  Table|string $table
14324      * @return string
14325      */
14326     public function getDropTableSQL($table)
14327     {
14328         if ($table instanceof \Doctrine\DBAL\Schema\Table) {
14329             $table = $table->getName();
14330         }
14331
14332         return 'DROP TABLE ' . $table;
14333     }
14334
14335     /**
14336      * Drop index from a table
14337      *
14338      * @param Index|string $name
14339      * @param string|Table $table
14340      * @return string
14341      */
14342     public function getDropIndexSQL($index, $table=null)
14343     {
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.');
14348         }
14349
14350         return 'DROP INDEX ' . $index;
14351     }
14352
14353     /**
14354      * Get drop constraint sql
14355      * 
14356      * @param  \Doctrine\DBAL\Schema\Constraint $constraint
14357      * @param  string|Table $table
14358      * @return string
14359      */
14360     public function getDropConstraintSQL($constraint, $table)
14361     {
14362         if ($constraint instanceof \Doctrine\DBAL\Schema\Constraint) {
14363             $constraint = $constraint->getName();
14364         }
14365
14366         if ($table instanceof \Doctrine\DBAL\Schema\Table) {
14367             $table = $table->getName();
14368         }
14369
14370         return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint;
14371     }
14372
14373     /**
14374      * @param  ForeignKeyConstraint|string $foreignKey
14375      * @param  Table|string $table
14376      * @return string
14377      */
14378     public function getDropForeignKeySQL($foreignKey, $table)
14379     {
14380         if ($foreignKey instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) {
14381             $foreignKey = $foreignKey->getName();
14382         }
14383
14384         if ($table instanceof \Doctrine\DBAL\Schema\Table) {
14385             $table = $table->getName();
14386         }
14387
14388         return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey;
14389     }
14390
14391     /**
14392      * Gets the SQL statement(s) to create a table with the specified name, columns and constraints
14393      * on this platform.
14394      *
14395      * @param string $table The name of the table.
14396      * @param int $createFlags
14397      * @return array The sequence of SQL statements.
14398      */
14399     public function getCreateTableSQL(Table $table, $createFlags=self::CREATE_INDEXES)
14400     {
14401         if ( ! is_int($createFlags)) {
14402             throw new \InvalidArgumentException("Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.");
14403         }
14404
14405         if (count($table->getColumns()) == 0) {
14406             throw DBALException::noColumnsSpecifiedForTable($table->getName());
14407         }
14408
14409         $tableName = $table->getName();
14410         $options = $table->getOptions();
14411         $options['uniqueConstraints'] = array();
14412         $options['indexes'] = array();
14413         $options['primary'] = array();
14414
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();
14420                 } else {
14421                     $options['indexes'][$index->getName()] = $index;
14422                 }
14423             }
14424         }
14425
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;
14438             }
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();
14444
14445             if(in_array($column->getName(), $options['primary'])) {
14446                 $columnData['primary'] = true;
14447             }
14448
14449             $columns[$columnData['name']] = $columnData;
14450         }
14451
14452         if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) {
14453             $options['foreignKeys'] = array();
14454             foreach ($table->getForeignKeys() AS $fkConstraint) {
14455                 $options['foreignKeys'][] = $fkConstraint;
14456             }
14457         }
14458
14459         return $this->_getCreateTableSQL($tableName, $columns, $options);
14460     }
14461
14462     /**
14463      * @param string $tableName
14464      * @param array $columns
14465      * @param array $options
14466      * @return array
14467      */
14468     protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
14469     {
14470         $columnListSql = $this->getColumnDeclarationListSQL($columns);
14471         
14472         if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
14473             foreach ($options['uniqueConstraints'] as $name => $definition) {
14474                 $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
14475             }
14476         }
14477         
14478         if (isset($options['primary']) && ! empty($options['primary'])) {
14479             $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
14480         }
14481
14482         if (isset($options['indexes']) && ! empty($options['indexes'])) {
14483             foreach($options['indexes'] as $index => $definition) {
14484                 $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
14485             }
14486         }
14487
14488         $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;
14489
14490         $check = $this->getCheckDeclarationSQL($columns);
14491         if ( ! empty($check)) {
14492             $query .= ', ' . $check;
14493         }
14494         $query .= ')';
14495
14496         $sql[] = $query;
14497
14498         if (isset($options['foreignKeys'])) {
14499             foreach ((array) $options['foreignKeys'] AS $definition) {
14500                 $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
14501             }
14502         }
14503
14504         return $sql;
14505     }
14506     
14507     public function getCreateTemporaryTableSnippetSQL()
14508     {
14509         return "CREATE TEMPORARY TABLE";
14510     }
14511
14512     /**
14513      * Gets the SQL to create a sequence on this platform.
14514      *
14515      * @param \Doctrine\DBAL\Schema\Sequence $sequence
14516      * @throws DBALException
14517      */
14518     public function getCreateSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
14519     {
14520         throw DBALException::notSupported(__METHOD__);
14521     }
14522
14523     /**
14524      * Gets the SQL to create a constraint on a table on this platform.
14525      *
14526      * @param Constraint $constraint
14527      * @param string|Table $table
14528      * @return string
14529      */
14530     public function getCreateConstraintSQL(\Doctrine\DBAL\Schema\Constraint $constraint, $table)
14531     {
14532         if ($table instanceof \Doctrine\DBAL\Schema\Table) {
14533             $table = $table->getName();
14534         }
14535
14536         $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getName();
14537
14538         $columns = array();
14539         foreach ($constraint->getColumns() as $column) {
14540             $columns[] = $column;
14541         }
14542         $columnList = '('. implode(', ', $columns) . ')';
14543
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';
14550             } else {
14551                 throw new \InvalidArgumentException(
14552                     'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().'
14553                 );
14554             }
14555         } else if ($constraint instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) {
14556             $query .= ' FOREIGN KEY';
14557
14558             $foreignColumns = array();
14559             foreach ($constraint->getForeignColumns() AS $column) {
14560                 $foreignColumns[] = $column;
14561             }
14562             
14563             $referencesClause = ' REFERENCES '.$constraint->getForeignTableName(). ' ('.implode(', ', $foreignColumns).')';
14564         }
14565         $query .= ' '.$columnList.$referencesClause;
14566
14567         return $query;
14568     }
14569
14570     /**
14571      * Gets the SQL to create an index on a table on this platform.
14572      *
14573      * @param Index $index
14574      * @param string|Table $table name of the table on which the index is to be created
14575      * @return string
14576      */
14577     public function getCreateIndexSQL(Index $index, $table)
14578     {
14579         if ($table instanceof Table) {
14580             $table = $table->getName();
14581         }
14582         $name = $index->getName();
14583         $columns = $index->getColumns();
14584
14585         if (count($columns) == 0) {
14586             throw new \InvalidArgumentException("Incomplete definition. 'columns' required.");
14587         }
14588
14589         $type = '';
14590         if ($index->isUnique()) {
14591             $type = 'UNIQUE ';
14592         }
14593
14594         $query = 'CREATE ' . $type . 'INDEX ' . $name . ' ON ' . $table;
14595
14596         $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')';
14597
14598         return $query;
14599     }
14600
14601     /**
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.
14604      *
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.
14608      *
14609      * @param string $str           identifier name to be quoted
14610      * @return string               quoted identifier string
14611      */
14612     public function quoteIdentifier($str)
14613     {
14614         $c = $this->getIdentifierQuoteCharacter();
14615
14616         return $c . $str . $c;
14617     }
14618
14619     /**
14620      * Create a new foreign key
14621      *
14622      * @param ForeignKeyConstraint  $foreignKey    ForeignKey instance
14623      * @param string|Table          $table         name of the table on which the foreign key is to be created
14624      * @return string
14625      */
14626     public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table)
14627     {
14628         if ($table instanceof \Doctrine\DBAL\Schema\Table) {
14629             $table = $table->getName();
14630         }
14631
14632         $query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey);
14633
14634         return $query;
14635     }
14636
14637     /**
14638      * Gets the sql statements for altering an existing table.
14639      *
14640      * The method returns an array of sql statements, since some platforms need several statements.
14641      *
14642      * @param TableDiff $diff
14643      * @return array
14644      */
14645     public function getAlterTableSQL(TableDiff $diff)
14646     {
14647         throw DBALException::notSupported(__METHOD__);
14648     }
14649
14650     /**
14651      * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions.
14652      *
14653      * @param TableDiff $diff
14654      * @return array
14655      */
14656     protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff)
14657     {
14658         if ($diff->newName !== false) {
14659             $tableName = $diff->newName;
14660         } else {
14661             $tableName = $diff->name;
14662         }
14663
14664         $sql = array();
14665         if ($this->supportsForeignKeyConstraints()) {
14666             foreach ($diff->removedForeignKeys AS $foreignKey) {
14667                 $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
14668             }
14669             foreach ($diff->addedForeignKeys AS $foreignKey) {
14670                 $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
14671             }
14672             foreach ($diff->changedForeignKeys AS $foreignKey) {
14673                 $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName);
14674                 $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName);
14675             }
14676         }
14677
14678         foreach ($diff->addedIndexes AS $index) {
14679             $sql[] = $this->getCreateIndexSQL($index, $tableName);
14680         }
14681         foreach ($diff->removedIndexes AS $index) {
14682             $sql[] = $this->getDropIndexSQL($index, $tableName);
14683         }
14684         foreach ($diff->changedIndexes AS $index) {
14685             $sql[] = $this->getDropIndexSQL($index, $tableName);
14686             $sql[] = $this->getCreateIndexSQL($index, $tableName);
14687         }
14688
14689         return $sql;
14690     }
14691
14692     /**
14693      * Get declaration of a number of fields in bulk
14694      *
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:
14700      *
14701      *      length
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.
14705      *
14706      *      default
14707      *          Text value to be used as default for this field.
14708      *
14709      *      notnull
14710      *          Boolean flag that indicates whether this field is constrained
14711      *          to not be set to null.
14712      *      charset
14713      *          Text value with the default CHARACTER SET for this field.
14714      *      collation
14715      *          Text value with the default COLLATION for this field.
14716      *      unique
14717      *          unique constraint
14718      *
14719      * @return string
14720      */
14721     public function getColumnDeclarationListSQL(array $fields)
14722     {
14723         $queryFields = array();
14724         foreach ($fields as $fieldName => $field) {
14725             $query = $this->getColumnDeclarationSQL($fieldName, $field);
14726             $queryFields[] = $query;
14727         }
14728         return implode(', ', $queryFields);
14729     }
14730
14731     /**
14732      * Obtain DBMS specific SQL code portion needed to declare a generic type
14733      * field to be used in statements like CREATE TABLE.
14734      *
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:
14739      *
14740      *      length
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.
14744      *
14745      *      default
14746      *          Text value to be used as default for this field.
14747      *
14748      *      notnull
14749      *          Boolean flag that indicates whether this field is constrained
14750      *          to not be set to null.
14751      *      charset
14752      *          Text value with the default CHARACTER SET for this field.
14753      *      collation
14754      *          Text value with the default COLLATION for this field.
14755      *      unique
14756      *          unique constraint
14757      *      check
14758      *          column check constraint
14759      *      columnDefinition
14760      *          a string that defines the complete column
14761      *
14762      * @return string  DBMS specific SQL code portion that should be used to declare the column.
14763      */
14764     public function getColumnDeclarationSQL($name, array $field)
14765     {
14766         if (isset($field['columnDefinition'])) {
14767             $columnDef = $this->getCustomTypeDeclarationSQL($field);
14768         } else {
14769             $default = $this->getDefaultValueDeclarationSQL($field);
14770
14771             $charset = (isset($field['charset']) && $field['charset']) ?
14772                     ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : '';
14773
14774             $collation = (isset($field['collation']) && $field['collation']) ?
14775                     ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
14776
14777             $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : '';
14778
14779             $unique = (isset($field['unique']) && $field['unique']) ?
14780                     ' ' . $this->getUniqueFieldDeclarationSQL() : '';
14781
14782             $check = (isset($field['check']) && $field['check']) ?
14783                     ' ' . $field['check'] : '';
14784
14785             $typeDecl = $field['type']->getSqlDeclaration($field, $this);
14786             $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
14787         }
14788
14789         return $name . ' ' . $columnDef;
14790     }
14791     
14792     /**
14793      * Gets the SQL snippet that declares a floating point column of arbitrary precision.
14794      *
14795      * @param array $columnDef
14796      * @return string
14797      */
14798     public function getDecimalTypeDeclarationSQL(array $columnDef) 
14799     {
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'];
14804         
14805         return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')';
14806     }
14807
14808     /**
14809      * Obtain DBMS specific SQL code portion needed to set a default value
14810      * declaration to be used in statements like CREATE TABLE.
14811      *
14812      * @param array $field      field definition array
14813      * @return string           DBMS specific SQL code portion needed to set a default value
14814      */
14815     public function getDefaultValueDeclarationSQL($field)
14816     {
14817         $default = empty($field['notnull']) ? ' DEFAULT NULL' : '';
14818
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();
14826                 }
14827             }
14828         }
14829         return $default;
14830     }
14831
14832     /**
14833      * Obtain DBMS specific SQL code portion needed to set a CHECK constraint
14834      * declaration to be used in statements like CREATE TABLE.
14835      *
14836      * @param array $definition     check definition
14837      * @return string               DBMS specific SQL code portion needed to set a CHECK constraint
14838      */
14839     public function getCheckDeclarationSQL(array $definition)
14840     {
14841         $constraints = array();
14842         foreach ($definition as $field => $def) {
14843             if (is_string($def)) {
14844                 $constraints[] = 'CHECK (' . $def . ')';
14845             } else {
14846                 if (isset($def['min'])) {
14847                     $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')';
14848                 }
14849
14850                 if (isset($def['max'])) {
14851                     $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')';
14852                 }
14853             }
14854         }
14855
14856         return implode(', ', $constraints);
14857     }
14858     
14859     /**
14860      * Obtain DBMS specific SQL code portion needed to set a unique
14861      * constraint declaration to be used in statements like CREATE TABLE.
14862      *
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
14867      */
14868     public function getUniqueConstraintDeclarationSQL($name, Index $index)
14869     {
14870         if (count($index->getColumns()) == 0) {
14871             throw \InvalidArgumentException("Incomplete definition. 'columns' required.");
14872         }
14873         
14874         return 'CONSTRAINT ' . $name . ' UNIQUE ('
14875              . $this->getIndexFieldDeclarationListSQL($index->getColumns()) 
14876              . ')';
14877     }
14878
14879     /**
14880      * Obtain DBMS specific SQL code portion needed to set an index
14881      * declaration to be used in statements like CREATE TABLE.
14882      *
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
14886      */
14887     public function getIndexDeclarationSQL($name, Index $index)
14888     {
14889         $type = '';
14890
14891         if($index->isUnique()) {
14892             $type = 'UNIQUE ';
14893         }
14894
14895         if (count($index->getColumns()) == 0) {
14896             throw \InvalidArgumentException("Incomplete definition. 'columns' required.");
14897         }
14898
14899         return $type . 'INDEX ' . $name . ' ('
14900              . $this->getIndexFieldDeclarationListSQL($index->getColumns()) 
14901              . ')';
14902     }
14903
14904     /**
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.
14909      *
14910      * @return string
14911      */
14912     public function getCustomTypeDeclarationSQL(array $columnDef)
14913     {
14914         return $columnDef['columnDefinition'];
14915     }
14916
14917     /**
14918      * getIndexFieldDeclarationList
14919      * Obtain DBMS specific SQL code portion needed to set an index
14920      * declaration to be used in statements like CREATE TABLE.
14921      *
14922      * @return string
14923      */
14924     public function getIndexFieldDeclarationListSQL(array $fields)
14925     {
14926         $ret = array();
14927         foreach ($fields as $field => $definition) {
14928             if (is_array($definition)) {
14929                 $ret[] = $field;
14930             } else {
14931                 $ret[] = $definition;
14932             }
14933         }
14934         return implode(', ', $ret);
14935     }
14936
14937     /**
14938      * A method to return the required SQL string that fits between CREATE ... TABLE
14939      * to create the table as a temporary table.
14940      *
14941      * Should be overridden in driver classes to return the correct string for the
14942      * specific database type.
14943      *
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".
14947      *
14948      * @return string The string required to be placed between "CREATE" and "TABLE"
14949      *                to generate a temporary table, if possible.
14950      */
14951     public function getTemporaryTableSQL()
14952     {
14953         return 'TEMPORARY';
14954     }
14955
14956     /**
14957      * Some vendors require temporary table names to be qualified specially.
14958      *
14959      * @param  string $tableName
14960      * @return string
14961      */
14962     public function getTemporaryTableName($tableName)
14963     {
14964         return $tableName;
14965     }
14966
14967     /**
14968      * Get sql query to show a list of database.
14969      *
14970      * @return string
14971      */
14972     public function getShowDatabasesSQL()
14973     {
14974         throw DBALException::notSupported(__METHOD__);
14975     }
14976
14977     /**
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.
14980      *
14981      * @param array $definition         an associative array with the following structure:
14982      *          name                    optional constraint name
14983      *
14984      *          local                   the local field(s)
14985      *
14986      *          foreign                 the foreign reference field(s)
14987      *
14988      *          foreignTable            the name of the foreign table
14989      *
14990      *          onDelete                referential delete action
14991      *
14992      *          onUpdate                referential update action
14993      *
14994      *          deferred                deferred constraint checking
14995      *
14996      * The onDelete and onUpdate keys accept the following values:
14997      *
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.
15002      *
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.
15006      *
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.
15009      *
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.
15012      *
15013      * SET DEFAULT
15014      *
15015      * @return string  DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
15016      *                 of a field declaration.
15017      */
15018     public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey)
15019     {
15020         $sql  = $this->getForeignKeyBaseDeclarationSQL($foreignKey);
15021         $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey);
15022
15023         return $sql;
15024     }
15025
15026     /**
15027      * Return the FOREIGN KEY query section dealing with non-standard options
15028      * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
15029      *
15030      * @param ForeignKeyConstraint $foreignKey     foreign key definition
15031      * @return string
15032      */
15033     public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey)
15034     {
15035         $query = '';
15036         if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) {
15037             $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate'));
15038         }
15039         if ($foreignKey->hasOption('onDelete')) {
15040             $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete'));
15041         }
15042         return $query;
15043     }
15044
15045     /**
15046      * returns given referential action in uppercase if valid, otherwise throws
15047      * an exception
15048      *
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
15052      */
15053     public function getForeignKeyReferentialActionSQL($action)
15054     {
15055         $upper = strtoupper($action);
15056         switch ($upper) {
15057             case 'CASCADE':
15058             case 'SET NULL':
15059             case 'NO ACTION':
15060             case 'RESTRICT':
15061             case 'SET DEFAULT':
15062                 return $upper;
15063             break;
15064             default:
15065                 throw \InvalidArgumentException('Invalid foreign key action: ' . $upper);
15066         }
15067     }
15068
15069     /**
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.
15072      *
15073      * @param ForeignKeyConstraint $foreignKey
15074      * @return string
15075      */
15076     public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey)
15077     {
15078         $sql = '';
15079         if (strlen($foreignKey->getName())) {
15080             $sql .= 'CONSTRAINT ' . $foreignKey->getName() . ' ';
15081         }
15082         $sql .= 'FOREIGN KEY (';
15083
15084         if (count($foreignKey->getLocalColumns()) == 0) {
15085             throw new \InvalidArgumentException("Incomplete definition. 'local' required.");
15086         }
15087         if (count($foreignKey->getForeignColumns()) == 0) {
15088             throw new \InvalidArgumentException("Incomplete definition. 'foreign' required.");
15089         }
15090         if (strlen($foreignKey->getForeignTableName()) == 0) {
15091             throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required.");
15092         }
15093
15094         $sql .= implode(', ', $foreignKey->getLocalColumns())
15095               . ') REFERENCES '
15096               . $foreignKey->getForeignTableName() . '('
15097               . implode(', ', $foreignKey->getForeignColumns()) . ')';
15098
15099         return $sql;
15100     }
15101
15102     /**
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.
15105      *
15106      * @return string  DBMS specific SQL code portion needed to set the UNIQUE constraint
15107      *                 of a field declaration.
15108      */
15109     public function getUniqueFieldDeclarationSQL()
15110     {
15111         return 'UNIQUE';
15112     }
15113
15114     /**
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.
15117      *
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.
15121      */
15122     public function getColumnCharsetDeclarationSQL($charset)
15123     {
15124         return '';
15125     }
15126
15127     /**
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.
15130      *
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.
15134      */
15135     public function getColumnCollationDeclarationSQL($collation)
15136     {
15137         return '';
15138     }
15139
15140     /**
15141      * Whether the platform prefers sequences for ID generation.
15142      * Subclasses should override this method to return TRUE if they prefer sequences.
15143      *
15144      * @return boolean
15145      */
15146     public function prefersSequences()
15147     {
15148         return false;
15149     }
15150
15151     /**
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.
15154      *
15155      * @return boolean
15156      */
15157     public function prefersIdentityColumns()
15158     {
15159         return false;
15160     }
15161
15162     /**
15163      * Some platforms need the boolean values to be converted.
15164      * 
15165      * The default conversion in this implementation converts to integers (false => 0, true => 1).
15166      *
15167      * @param mixed $item
15168      */
15169     public function convertBooleans($item)
15170     {
15171         if (is_array($item)) {
15172             foreach ($item as $k => $value) {
15173                 if (is_bool($value)) {
15174                     $item[$k] = (int) $value;
15175                 }
15176             }
15177         } else if (is_bool($item)) {
15178             $item = (int) $item;
15179         }
15180         return $item;
15181     }
15182
15183     /**
15184      * Gets the SQL statement specific for the platform to set the charset.
15185      *
15186      * This function is MySQL specific and required by
15187      * {@see \Doctrine\DBAL\Connection::setCharset($charset)}
15188      *
15189      * @param string $charset
15190      * @return string
15191      */
15192     public function getSetCharsetSQL($charset)
15193     {
15194         return "SET NAMES '".$charset."'";
15195     }
15196
15197     /**
15198      * Gets the SQL specific for the platform to get the current date.
15199      *
15200      * @return string
15201      */
15202     public function getCurrentDateSQL()
15203     {
15204         return 'CURRENT_DATE';
15205     }
15206
15207     /**
15208      * Gets the SQL specific for the platform to get the current time.
15209      *
15210      * @return string
15211      */
15212     public function getCurrentTimeSQL()
15213     {
15214         return 'CURRENT_TIME';
15215     }
15216
15217     /**
15218      * Gets the SQL specific for the platform to get the current timestamp
15219      *
15220      * @return string
15221      */
15222     public function getCurrentTimestampSQL()
15223     {
15224         return 'CURRENT_TIMESTAMP';
15225     }
15226
15227     /**
15228      * Get sql for transaction isolation level Connection constant
15229      *
15230      * @param integer $level
15231      */
15232     protected function _getTransactionIsolationLevelSQL($level)
15233     {
15234         switch ($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';
15243             default:
15244                 throw new \InvalidArgumentException('Invalid isolation level:' . $level);
15245         }
15246     }
15247
15248     public function getListDatabasesSQL()
15249     {
15250         throw DBALException::notSupported(__METHOD__);
15251     }
15252
15253     public function getListSequencesSQL($database)
15254     {
15255         throw DBALException::notSupported(__METHOD__);
15256     }
15257
15258     public function getListTableConstraintsSQL($table)
15259     {
15260         throw DBALException::notSupported(__METHOD__);
15261     }
15262
15263     public function getListTableColumnsSQL($table)
15264     {
15265         throw DBALException::notSupported(__METHOD__);
15266     }
15267
15268     public function getListTablesSQL()
15269     {
15270         throw DBALException::notSupported(__METHOD__);
15271     }
15272
15273     public function getListUsersSQL()
15274     {
15275         throw DBALException::notSupported(__METHOD__);
15276     }
15277
15278     /**
15279      * Get the SQL to list all views of a database or user.
15280      *
15281      * @param string $database
15282      * @return string
15283      */
15284     public function getListViewsSQL($database)
15285     {
15286         throw DBALException::notSupported(__METHOD__);
15287     }
15288
15289     public function getListTableIndexesSQL($table)
15290     {
15291         throw DBALException::notSupported(__METHOD__);
15292     }
15293
15294     public function getListTableForeignKeysSQL($table)
15295     {
15296         throw DBALException::notSupported(__METHOD__);
15297     }
15298
15299     public function getCreateViewSQL($name, $sql)
15300     {
15301         throw DBALException::notSupported(__METHOD__);
15302     }
15303
15304     public function getDropViewSQL($name)
15305     {
15306         throw DBALException::notSupported(__METHOD__);
15307     }
15308
15309     public function getDropSequenceSQL($sequence)
15310     {
15311         throw DBALException::notSupported(__METHOD__);
15312     }
15313
15314     public function getSequenceNextValSQL($sequenceName)
15315     {
15316         throw DBALException::notSupported(__METHOD__);
15317     }
15318
15319     public function getCreateDatabaseSQL($database)
15320     {
15321         throw DBALException::notSupported(__METHOD__);
15322     }
15323
15324     /**
15325      * Get sql to set the transaction isolation level
15326      *
15327      * @param integer $level
15328      */
15329     public function getSetTransactionIsolationSQL($level)
15330     {
15331         throw DBALException::notSupported(__METHOD__);
15332     }
15333
15334     /**
15335      * Obtain DBMS specific SQL to be used to create datetime fields in 
15336      * statements like CREATE TABLE
15337      *
15338      * @param array $fieldDeclaration 
15339      * @return string
15340      */
15341     public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
15342     {
15343         throw DBALException::notSupported(__METHOD__);
15344     }
15345
15346     /**
15347      * Obtain DBMS specific SQL to be used to create datetime with timezone offset fields.
15348      * 
15349      * @param array $fieldDeclaration
15350      */
15351     public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
15352     {
15353         return $this->getDateTimeTypeDeclarationSQL($fieldDeclaration);
15354     }
15355     
15356     
15357     /**
15358      * Obtain DBMS specific SQL to be used to create date fields in statements
15359      * like CREATE TABLE.
15360      * 
15361      * @param array $fieldDeclaration
15362      * @return string
15363      */
15364     public function getDateTypeDeclarationSQL(array $fieldDeclaration)
15365     {
15366         throw DBALException::notSupported(__METHOD__);
15367     }
15368
15369     /**
15370      * Obtain DBMS specific SQL to be used to create time fields in statements
15371      * like CREATE TABLE.
15372      *
15373      * @param array $fieldDeclaration
15374      * @return string
15375      */
15376     public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
15377     {
15378         throw DBALException::notSupported(__METHOD__);
15379     }
15380
15381     public function getFloatDeclarationSQL(array $fieldDeclaration)
15382     {
15383         return 'DOUBLE PRECISION';
15384     }
15385
15386     /**
15387      * Gets the default transaction isolation level of the platform.
15388      *
15389      * @return integer The default isolation level.
15390      * @see Doctrine\DBAL\Connection\TRANSACTION_* constants.
15391      */
15392     public function getDefaultTransactionIsolationLevel()
15393     {
15394         return Connection::TRANSACTION_READ_COMMITTED;
15395     }
15396
15397     /* supports*() metods */
15398
15399     /**
15400      * Whether the platform supports sequences.
15401      *
15402      * @return boolean
15403      */
15404     public function supportsSequences()
15405     {
15406         return false;
15407     }
15408
15409     /**
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.
15413      *
15414      * @return boolean
15415      */
15416     public function supportsIdentityColumns()
15417     {
15418         return false;
15419     }
15420
15421     /**
15422      * Whether the platform supports indexes.
15423      *
15424      * @return boolean
15425      */
15426     public function supportsIndexes()
15427     {
15428         return true;
15429     }
15430
15431     public function supportsAlterTable()
15432     {
15433         return true;
15434     }
15435
15436     /**
15437      * Whether the platform supports transactions.
15438      *
15439      * @return boolean
15440      */
15441     public function supportsTransactions()
15442     {
15443         return true;
15444     }
15445
15446     /**
15447      * Whether the platform supports savepoints.
15448      *
15449      * @return boolean
15450      */
15451     public function supportsSavepoints()
15452     {
15453         return true;
15454     }
15455
15456     /**
15457      * Whether the platform supports releasing savepoints.
15458      *
15459      * @return boolean
15460      */
15461     public function supportsReleaseSavepoints()
15462     {
15463         return $this->supportsSavepoints();
15464     }
15465
15466     /**
15467      * Whether the platform supports primary key constraints.
15468      *
15469      * @return boolean
15470      */
15471     public function supportsPrimaryConstraints()
15472     {
15473         return true;
15474     }
15475
15476     /**
15477      * Does the platform supports foreign key constraints?
15478      *
15479      * @return boolean
15480      */
15481     public function supportsForeignKeyConstraints()
15482     {
15483         return true;
15484     }
15485
15486     /**
15487      * Does this platform supports onUpdate in foreign key constraints?
15488      * 
15489      * @return bool
15490      */
15491     public function supportsForeignKeyOnUpdate()
15492     {
15493         return ($this->supportsForeignKeyConstraints() && true);
15494     }
15495     
15496     /**
15497      * Whether the platform supports database schemas.
15498      * 
15499      * @return boolean
15500      */
15501     public function supportsSchemas()
15502     {
15503         return false;
15504     }
15505
15506     /**
15507      * Some databases don't allow to create and drop databases at all or only with certain tools.
15508      *
15509      * @return bool
15510      */
15511     public function supportsCreateDropDatabase()
15512     {
15513         return true;
15514     }
15515
15516     /**
15517      * Whether the platform supports getting the affected rows of a recent
15518      * update/delete type query.
15519      *
15520      * @return boolean
15521      */
15522     public function supportsGettingAffectedRows()
15523     {
15524         return true;
15525     }
15526
15527     public function getIdentityColumnNullInsertSQL()
15528     {
15529         return "";
15530     }
15531
15532     /**
15533      * Gets the format string, as accepted by the date() function, that describes
15534      * the format of a stored datetime value of this platform.
15535      * 
15536      * @return string The format string.
15537      */
15538     public function getDateTimeFormatString()
15539     {
15540         return 'Y-m-d H:i:s';
15541     }
15542
15543     /**
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.
15546      *
15547      * @return string The format string.
15548      */
15549     public function getDateTimeTzFormatString()
15550     {
15551         return 'Y-m-d H:i:s';
15552     }
15553
15554     /**
15555      * Gets the format string, as accepted by the date() function, that describes
15556      * the format of a stored date value of this platform.
15557      * 
15558      * @return string The format string.
15559      */
15560     public function getDateFormatString()
15561     {
15562         return 'Y-m-d';
15563     }
15564     
15565     /**
15566      * Gets the format string, as accepted by the date() function, that describes
15567      * the format of a stored time value of this platform.
15568      * 
15569      * @return string The format string.
15570      */
15571     public function getTimeFormatString()
15572     {
15573         return 'H:i:s';
15574     }
15575
15576     public function modifyLimitQuery($query, $limit, $offset = null)
15577     {
15578         if ( ! is_null($limit)) {
15579             $query .= ' LIMIT ' . $limit;
15580         }
15581
15582         if ( ! is_null($offset)) {
15583             $query .= ' OFFSET ' . $offset;
15584         }
15585
15586         return $query;
15587     }
15588     
15589     /**
15590      * Gets the character casing of a column in an SQL result set of this platform.
15591      * 
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.
15594      */
15595     public function getSQLResultCasing($column)
15596     {
15597         return $column;
15598     }
15599     
15600     /**
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.
15603      * 
15604      * @param string $schemaName
15605      * @return string
15606      */
15607     public function fixSchemaElementName($schemaElementName)
15608     {
15609         return $schemaElementName;
15610     }
15611
15612     /**
15613      * Maximum length of any given databse identifier, like tables or column names.
15614      * 
15615      * @return int
15616      */
15617     public function getMaxIdentifierLength()
15618     {
15619         return 63;
15620     }
15621
15622     /**
15623      * Get the insert sql for an empty insert statement
15624      *
15625      * @param string $tableName 
15626      * @param string $identifierColumnName 
15627      * @return string $sql
15628      */
15629     public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName)
15630     {
15631         return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (null)';
15632     }
15633
15634     /**
15635      * Generate a Truncate Table SQL statement for a given table.
15636      *
15637      * Cascade is not supported on many platforms but would optionally cascade the truncate by
15638      * following the foreign keys.
15639      *
15640      * @param  string $tableName
15641      * @param  bool $cascade
15642      * @return string
15643      */
15644     public function getTruncateTableSQL($tableName, $cascade = false)
15645     {
15646         return 'TRUNCATE '.$tableName;
15647     }
15648
15649     /**
15650      * This is for test reasons, many vendors have special requirements for dummy statements.
15651      * 
15652      * @return string
15653      */
15654     public function getDummySelectSQL()
15655     {
15656         return 'SELECT 1';
15657     }
15658
15659     /**
15660      * Generate SQL to create a new savepoint
15661      *
15662      * @param string $savepoint
15663      * @return string
15664      */
15665     public function createSavePoint($savepoint)
15666     {
15667         return 'SAVEPOINT ' . $savepoint;
15668     }
15669
15670     /**
15671      * Generate SQL to release a savepoint
15672      *
15673      * @param string $savepoint
15674      * @return string
15675      */
15676     public function releaseSavePoint($savepoint)
15677     {
15678         return 'RELEASE SAVEPOINT ' . $savepoint;
15679     }
15680
15681     /**
15682      * Generate SQL to rollback a savepoint
15683      *
15684      * @param string $savepoint
15685      * @return string
15686      */
15687     public function rollbackSavePoint($savepoint)
15688     {
15689         return 'ROLLBACK TO SAVEPOINT ' . $savepoint;
15690     }
15691 }<?php
15692 /*
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.
15704  *
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>.
15708  */
15709
15710 namespace Doctrine\DBAL\Platforms;
15711
15712 use Doctrine\DBAL\DBALException;
15713
15714 /**
15715  * The SqlitePlatform class describes the specifics and dialects of the SQLite
15716  * database platform.
15717  *
15718  * @since 2.0
15719  * @author Roman Borschel <roman@code-factory.org>
15720  * @author Benjamin Eberlei <kontakt@beberlei.de>
15721  * @todo Rename: SQLitePlatform
15722  */
15723 class SqlitePlatform extends AbstractPlatform
15724 {
15725     /**
15726      * returns the regular expression operator
15727      *
15728      * @return string
15729      * @override
15730      */
15731     public function getRegexpExpression()
15732     {
15733         return 'RLIKE';
15734     }
15735
15736     /**
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.
15739      *
15740      * @return string       sqlite function as string
15741      * @override
15742      */
15743     public function getNowExpression($type = 'timestamp')
15744     {
15745         switch ($type) {
15746             case 'time':
15747                 return 'time(\'now\')';
15748             case 'date':
15749                 return 'date(\'now\')';
15750             case 'timestamp':
15751             default:
15752                 return 'datetime(\'now\')';
15753         }
15754     }
15755
15756     /**
15757      * Trim a string, leading/trailing/both and with a given char which defaults to space.
15758      *
15759      * @param string $str
15760      * @param int $pos
15761      * @param string $char
15762      * @return string
15763      */
15764     public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false)
15765     {
15766         $trimFn = '';
15767         $trimChar = ($char != false) ? (', ' . $char) : '';
15768
15769         if ($pos == self::TRIM_LEADING) {
15770             $trimFn = 'LTRIM';
15771         } else if($pos == self::TRIM_TRAILING) {
15772             $trimFn = 'RTRIM';
15773         } else {
15774             $trimFn = 'TRIM';
15775         }
15776
15777         return $trimFn . '(' . $str . $trimChar . ')';
15778     }
15779
15780     /**
15781      * return string to call a function to get a substring inside an SQL statement
15782      *
15783      * Note: Not SQL92, but common functionality.
15784      *
15785      * SQLite only supports the 2 parameter variant of this function
15786      *
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
15791      * @override
15792      */
15793     public function getSubstringExpression($value, $position, $length = null)
15794     {
15795         if ($length !== null) {
15796             return 'SUBSTR(' . $value . ', ' . $position . ', ' . $length . ')';
15797         }
15798         return 'SUBSTR(' . $value . ', ' . $position . ', LENGTH(' . $value . '))';
15799     }
15800
15801     /**
15802      * returns the position of the first occurrence of substring $substr in string $str
15803      *
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
15807      * @return integer
15808      */
15809     public function getLocateExpression($str, $substr, $startPos = false)
15810     {
15811         if ($startPos == false) {
15812             return 'LOCATE('.$str.', '.$substr.')';
15813         } else {
15814             return 'LOCATE('.$str.', '.$substr.', '.$startPos.')';
15815         }
15816     }
15817
15818     protected function _getTransactionIsolationLevelSQL($level)
15819     {
15820         switch ($level) {
15821             case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED:
15822                 return 0;
15823             case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED:
15824             case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ:
15825             case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE:
15826                 return 1;
15827             default:
15828                 return parent::_getTransactionIsolationLevelSQL($level);
15829         }
15830     }
15831
15832     public function getSetTransactionIsolationSQL($level)
15833     {
15834         return 'PRAGMA read_uncommitted = ' . $this->_getTransactionIsolationLevelSQL($level);
15835     }
15836
15837     /** 
15838      * @override 
15839      */
15840     public function prefersIdentityColumns()
15841     {
15842         return true;
15843     }
15844     
15845     /** 
15846      * @override 
15847      */
15848     public function getBooleanTypeDeclarationSQL(array $field)
15849     {
15850         return 'BOOLEAN';
15851     }
15852
15853     /** 
15854      * @override 
15855      */
15856     public function getIntegerTypeDeclarationSQL(array $field)
15857     {
15858         return $this->_getCommonIntegerTypeDeclarationSQL($field);
15859     }
15860
15861     /** 
15862      * @override 
15863      */
15864     public function getBigIntTypeDeclarationSQL(array $field)
15865     {
15866         return $this->_getCommonIntegerTypeDeclarationSQL($field);
15867     }
15868
15869     /** 
15870      * @override 
15871      */
15872     public function getTinyIntTypeDeclarationSql(array $field)
15873     {
15874         return $this->_getCommonIntegerTypeDeclarationSQL($field);
15875     }
15876
15877     /** 
15878      * @override 
15879      */
15880     public function getSmallIntTypeDeclarationSQL(array $field)
15881     {
15882         return $this->_getCommonIntegerTypeDeclarationSQL($field);
15883     }
15884
15885     /** 
15886      * @override 
15887      */
15888     public function getMediumIntTypeDeclarationSql(array $field)
15889     {
15890         return $this->_getCommonIntegerTypeDeclarationSQL($field);
15891     }
15892
15893     /** 
15894      * @override 
15895      */
15896     public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
15897     {
15898         return 'DATETIME';
15899     }
15900     
15901     /**
15902      * @override
15903      */
15904     public function getDateTypeDeclarationSQL(array $fieldDeclaration)
15905     {
15906         return 'DATE';
15907     }
15908
15909     /**
15910      * @override
15911      */
15912     public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
15913     {
15914         return 'TIME';
15915     }
15916
15917     /** 
15918      * @override 
15919      */
15920     protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
15921     {
15922         $autoinc = ! empty($columnDef['autoincrement']) ? ' AUTOINCREMENT' : '';
15923         $pk = ! empty($columnDef['primary']) && ! empty($autoinc) ? ' PRIMARY KEY' : '';
15924
15925         return 'INTEGER' . $pk . $autoinc;
15926     }
15927
15928     /**
15929      * create a new table
15930      *
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.
15936      *                          array(
15937      *                              'id' => array(
15938      *                                  'type' => 'integer',
15939      *                                  'unsigned' => 1
15940      *                                  'notnull' => 1
15941      *                                  'default' => 0
15942      *                              ),
15943      *                              'name' => array(
15944      *                                  'type' => 'text',
15945      *                                  'length' => 12
15946      *                              ),
15947      *                              'password' => array(
15948      *                                  'type' => 'text',
15949      *                                  'length' => 12
15950      *                              )
15951      *                          );
15952      * @param array $options  An associative array of table options:
15953      *
15954      * @return void
15955      * @override
15956      */
15957     protected function _getCreateTableSQL($name, array $columns, array $options = array())
15958     {
15959         $queryFields = $this->getColumnDeclarationListSQL($columns);
15960
15961         $autoinc = false;
15962         foreach($columns as $field) {
15963             if (isset($field['autoincrement']) && $field['autoincrement']) {
15964                 $autoinc = true;
15965                 break;
15966             }
15967         }
15968
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).')';
15973         }
15974
15975         $query[] = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')';
15976
15977         if (isset($options['indexes']) && ! empty($options['indexes'])) {
15978             foreach ($options['indexes'] as $index => $indexDef) {
15979                 $query[] = $this->getCreateIndexSQL($indexDef, $name);
15980             }
15981         }
15982         if (isset($options['unique']) && ! empty($options['unique'])) {
15983             foreach ($options['unique'] as $index => $indexDef) {
15984                 $query[] = $this->getCreateIndexSQL($indexDef, $name);
15985             }
15986         }
15987         return $query;
15988     }
15989
15990     /**
15991      * {@inheritdoc}
15992      */
15993     public function getVarcharTypeDeclarationSQL(array $field)
15994     {
15995         if ( ! isset($field['length'])) {
15996             if (array_key_exists('default', $field)) {
15997                 $field['length'] = $this->getVarcharMaxLength();
15998             } else {
15999                 $field['length'] = false;
16000             }
16001         }
16002         $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
16003         $fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
16004
16005         return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
16006                 : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
16007     }
16008     
16009     public function getClobTypeDeclarationSQL(array $field)
16010     {
16011         return 'CLOB';
16012     }
16013
16014     public function getListTableConstraintsSQL($table)
16015     {
16016         return "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = '$table' AND sql NOT NULL ORDER BY name";
16017     }
16018
16019     public function getListTableColumnsSQL($table)
16020     {
16021         return "PRAGMA table_info($table)";
16022     }
16023
16024     public function getListTableIndexesSQL($table)
16025     {
16026         return "PRAGMA index_list($table)";
16027     }
16028
16029     public function getListTablesSQL()
16030     {
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";
16034     }
16035
16036     public function getListViewsSQL($database)
16037     {
16038         return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL";
16039     }
16040
16041     public function getCreateViewSQL($name, $sql)
16042     {
16043         return 'CREATE VIEW ' . $name . ' AS ' . $sql;
16044     }
16045
16046     public function getDropViewSQL($name)
16047     {
16048         return 'DROP VIEW '. $name;
16049     }
16050
16051     /**
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...
16055      *
16056      * @return boolean FALSE
16057      * @override
16058      */
16059     public function supportsForeignKeyConstraints()
16060     {
16061         return false;
16062     }
16063
16064     public function supportsAlterTable()
16065     {
16066         return false;
16067     }
16068
16069     public function supportsIdentityColumns()
16070     {
16071         return true;
16072     }
16073
16074     /**
16075      * Get the platform name for this instance
16076      *
16077      * @return string
16078      */
16079     public function getName()
16080     {
16081         return 'sqlite';
16082     }
16083
16084     /**
16085      * @inheritdoc
16086      */
16087     public function getTruncateTableSQL($tableName, $cascade = false)
16088     {
16089         return 'DELETE FROM '.$tableName;
16090     }
16091
16092     /**
16093      * User-defined function for Sqlite that is used with PDO::sqliteCreateFunction()
16094      *
16095      * @param  int|float $value
16096      * @return float
16097      */
16098     static public function udfSqrt($value)
16099     {
16100         return sqrt($value);
16101     }
16102
16103     /**
16104      * User-defined function for Sqlite that implements MOD(a, b)
16105      */
16106     static public function udfMod($a, $b)
16107     {
16108         return ($a % $b);
16109     }
16110
16111     /**
16112      * @param string $str
16113      * @param string $substr
16114      * @param int $offset
16115      */
16116     static public function udfLocate($str, $substr, $offset = 0)
16117     {
16118         $pos = strpos($str, $substr, $offset);
16119         if ($pos !== false) {
16120             return $pos+1;
16121         }
16122         return 0;
16123     }
16124
16125     public function getForUpdateSql()
16126     {
16127         return '';
16128     }
16129
16130     protected function initializeDoctrineTypeMappings()
16131     {
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',
16142             'clob'          => 'text',
16143             'tinytext'      => 'text',
16144             'mediumtext'    => 'text',
16145             'longtext'      => 'text',
16146             'text'          => 'text',
16147             'varchar'       => 'string',
16148             'varchar2'      => 'string',
16149             'nvarchar'      => 'string',
16150             'image'         => 'string',
16151             'ntext'         => 'string',
16152             'char'          => 'string',
16153             'date'          => 'date',
16154             'datetime'      => 'datetime',
16155             'timestamp'     => 'datetime',
16156             'time'          => 'time',
16157             'float'         => 'float',
16158             'double'        => 'float',
16159             'real'          => 'float',
16160             'decimal'       => 'decimal',
16161             'numeric'       => 'decimal',
16162         );
16163     }
16164 }
16165 <?php
16166 /*
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.
16178  *
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>.
16182  */
16183  
16184 namespace Doctrine\DBAL;
16185
16186 /**
16187  * Class to store and retrieve the version of Doctrine
16188  *
16189  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
16190  * @link    www.doctrine-project.org
16191  * @since   2.0
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>
16197  */
16198 class Version
16199 {
16200     /**
16201      * Current Doctrine Version
16202      */
16203     const VERSION = '2.0.0RC1-DEV';
16204
16205     /**
16206      * Compares a Doctrine version with the current one.
16207      *
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.
16211      */
16212     public static function compare($version)
16213     {
16214         $currentVersion = str_replace(' ', '', strtolower(self::VERSION));
16215         $version = str_replace(' ', '', $version);
16216
16217         return version_compare($version, $currentVersion);
16218     }
16219 }<?php
16220 /*
16221  *  $Id: Exception.php 4628 2008-07-04 16:32:19Z romanb $
16222  *
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.
16234  *
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>.
16238  */
16239
16240 namespace Doctrine\DBAL;
16241
16242 /**
16243  * Doctrine\DBAL\ConnectionException
16244  *
16245  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
16246  * @link        www.doctrine-project.org
16247  * @since       2.0
16248  * @version     $Revision: 4628 $
16249  * @author      Jonathan H. Wage <jonwage@gmail.com
16250  */
16251 class ConnectionException extends DBALException
16252 {
16253     public static function commitFailedRollbackOnly()
16254     {
16255         return new self("Transaction commit failed because the transaction has been marked for rollback only.");
16256     }
16257     
16258     public static function noActiveTransaction()
16259     {
16260         return new self("There is no active transaction.");
16261     }
16262
16263     public static function savepointsNotSupported()
16264     {
16265         return new self("Savepoints are not supported by this driver.");
16266     }
16267
16268     public static function mayNotAlterNestedTransactionWithSavepointsInTransaction()
16269     {
16270         return new self("May not alter the nested transaction with savepoints behavior while a transaction is open.");
16271     }
16272 }<?php
16273 /*
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.
16285  *
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>.
16289  */
16290
16291 namespace Doctrine\DBAL;
16292
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;
16298
16299 /**
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.
16303  *
16304  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
16305  * @link    www.doctrine-project.org
16306  * @since   2.0
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>
16314  */
16315 class Connection implements DriverConnection
16316 {
16317     /**
16318      * Constant for transaction isolation level READ UNCOMMITTED.
16319      */
16320     const TRANSACTION_READ_UNCOMMITTED = 1;
16321     
16322     /**
16323      * Constant for transaction isolation level READ COMMITTED.
16324      */
16325     const TRANSACTION_READ_COMMITTED = 2;
16326     
16327     /**
16328      * Constant for transaction isolation level REPEATABLE READ.
16329      */
16330     const TRANSACTION_REPEATABLE_READ = 3;
16331     
16332     /**
16333      * Constant for transaction isolation level SERIALIZABLE.
16334      */
16335     const TRANSACTION_SERIALIZABLE = 4;
16336
16337     /**
16338      * The wrapped driver connection.
16339      *
16340      * @var Doctrine\DBAL\Driver\Connection
16341      */
16342     protected $_conn;
16343
16344     /**
16345      * @var Doctrine\DBAL\Configuration
16346      */
16347     protected $_config;
16348
16349     /**
16350      * @var Doctrine\Common\EventManager
16351      */
16352     protected $_eventManager;
16353
16354     /**
16355      * Whether or not a connection has been established.
16356      *
16357      * @var boolean
16358      */
16359     private $_isConnected = false;
16360
16361     /**
16362      * The transaction nesting level.
16363      *
16364      * @var integer
16365      */
16366     private $_transactionNestingLevel = 0;
16367
16368     /**
16369      * The currently active transaction isolation level.
16370      *
16371      * @var integer
16372      */
16373     private $_transactionIsolationLevel;
16374
16375     /**
16376      * If nested transations should use savepoints
16377      *
16378      * @var integer
16379      */
16380     private $_nestTransactionsWithSavepoints;
16381
16382     /**
16383      * The parameters used during creation of the Connection instance.
16384      *
16385      * @var array
16386      */
16387     private $_params = array();
16388
16389     /**
16390      * The DatabasePlatform object that provides information about the
16391      * database platform used by the connection.
16392      *
16393      * @var Doctrine\DBAL\Platforms\AbstractPlatform
16394      */
16395     protected $_platform;
16396
16397     /**
16398      * The schema manager.
16399      *
16400      * @var Doctrine\DBAL\Schema\SchemaManager
16401      */
16402     protected $_schemaManager;
16403
16404     /**
16405      * The used DBAL driver.
16406      *
16407      * @var Doctrine\DBAL\Driver
16408      */
16409     protected $_driver;
16410     
16411     /**
16412      * Flag that indicates whether the current transaction is marked for rollback only.
16413      * 
16414      * @var boolean
16415      */
16416     private $_isRollbackOnly = false;
16417
16418     /**
16419      * Initializes a new instance of the Connection class.
16420      *
16421      * @param array $params  The connection parameters.
16422      * @param Driver $driver
16423      * @param Configuration $config
16424      * @param EventManager $eventManager
16425      */
16426     public function __construct(array $params, Driver $driver, Configuration $config = null,
16427             EventManager $eventManager = null)
16428     {
16429         $this->_driver = $driver;
16430         $this->_params = $params;
16431
16432         if (isset($params['pdo'])) {
16433             $this->_conn = $params['pdo'];
16434             $this->_isConnected = true;
16435         }
16436
16437         // Create default config and event manager if none given
16438         if ( ! $config) {
16439             $config = new Configuration();
16440         }
16441         
16442         if ( ! $eventManager) {
16443             $eventManager = new EventManager();
16444         }
16445
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'];
16452         } else {
16453             throw DBALException::invalidPlatformSpecified();
16454         }
16455         $this->_transactionIsolationLevel = $this->_platform->getDefaultTransactionIsolationLevel();
16456     }
16457
16458     /**
16459      * Gets the parameters used during instantiation.
16460      *
16461      * @return array $params
16462      */
16463     public function getParams()
16464     {
16465         return $this->_params;
16466     }
16467
16468     /**
16469      * Gets the name of the database this Connection is connected to.
16470      *
16471      * @return string $database
16472      */
16473     public function getDatabase()
16474     {
16475         return $this->_driver->getDatabase($this);
16476     }
16477     
16478     /**
16479      * Gets the hostname of the currently connected database.
16480      * 
16481      * @return string
16482      */
16483     public function getHost()
16484     {
16485         return isset($this->_params['host']) ? $this->_params['host'] : null;
16486     }
16487     
16488     /**
16489      * Gets the port of the currently connected database.
16490      * 
16491      * @return mixed
16492      */
16493     public function getPort()
16494     {
16495         return isset($this->_params['port']) ? $this->_params['port'] : null;
16496     }
16497     
16498     /**
16499      * Gets the username used by this connection.
16500      * 
16501      * @return string
16502      */
16503     public function getUsername()
16504     {
16505         return isset($this->_params['user']) ? $this->_params['user'] : null;
16506     }
16507     
16508     /**
16509      * Gets the password used by this connection.
16510      * 
16511      * @return string
16512      */
16513     public function getPassword()
16514     {
16515         return isset($this->_params['password']) ? $this->_params['password'] : null;
16516     }
16517
16518     /**
16519      * Gets the DBAL driver instance.
16520      *
16521      * @return Doctrine\DBAL\Driver
16522      */
16523     public function getDriver()
16524     {
16525         return $this->_driver;
16526     }
16527
16528     /**
16529      * Gets the Configuration used by the Connection.
16530      *
16531      * @return Doctrine\DBAL\Configuration
16532      */
16533     public function getConfiguration()
16534     {
16535         return $this->_config;
16536     }
16537
16538     /**
16539      * Gets the EventManager used by the Connection.
16540      *
16541      * @return Doctrine\Common\EventManager
16542      */
16543     public function getEventManager()
16544     {
16545         return $this->_eventManager;
16546     }
16547
16548     /**
16549      * Gets the DatabasePlatform for the connection.
16550      *
16551      * @return Doctrine\DBAL\Platforms\AbstractPlatform
16552      */
16553     public function getDatabasePlatform()
16554     {
16555         return $this->_platform;
16556     }
16557
16558     /**
16559      * Establishes the connection with the database.
16560      *
16561      * @return boolean TRUE if the connection was successfully established, FALSE if
16562      *                 the connection is already open.
16563      */
16564     public function connect()
16565     {
16566         if ($this->_isConnected) return false;
16567
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;
16573
16574         $this->_conn = $this->_driver->connect($this->_params, $user, $password, $driverOptions);
16575         $this->_isConnected = true;
16576
16577         if ($this->_eventManager->hasListeners(Events::postConnect)) {
16578             $eventArgs = new Event\ConnectionEventArgs($this);
16579             $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
16580         }
16581
16582         return true;
16583     }
16584
16585     /**
16586      * Prepares and executes an SQL query and returns the first row of the result
16587      * as an associative array.
16588      * 
16589      * @param string $statement The SQL query.
16590      * @param array $params The query parameters.
16591      * @return array
16592      */
16593     public function fetchAssoc($statement, array $params = array())
16594     {
16595         return $this->executeQuery($statement, $params)->fetch(PDO::FETCH_ASSOC);
16596     }
16597
16598     /**
16599      * Prepares and executes an SQL query and returns the first row of the result
16600      * as a numerically indexed array.
16601      *
16602      * @param string $statement         sql query to be executed
16603      * @param array $params             prepared statement params
16604      * @return array
16605      */
16606     public function fetchArray($statement, array $params = array())
16607     {
16608         return $this->executeQuery($statement, $params)->fetch(PDO::FETCH_NUM);
16609     }
16610
16611     /**
16612      * Prepares and executes an SQL query and returns the value of a single column
16613      * of the first row of the result.
16614      * 
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
16618      * @return mixed
16619      */
16620     public function fetchColumn($statement, array $params = array(), $colnum = 0)
16621     {
16622         return $this->executeQuery($statement, $params)->fetchColumn($colnum);
16623     }
16624
16625     /**
16626      * Whether an actual connection to the database is established.
16627      *
16628      * @return boolean
16629      */
16630     public function isConnected()
16631     {
16632         return $this->_isConnected;
16633     }
16634
16635     /**
16636      * Checks whether a transaction is currently active.
16637      * 
16638      * @return boolean TRUE if a transaction is currently active, FALSE otherwise.
16639      */
16640     public function isTransactionActive()
16641     {
16642         return $this->_transactionNestingLevel > 0;
16643     }
16644
16645     /**
16646      * Executes an SQL DELETE statement on a table.
16647      *
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.
16651      */
16652     public function delete($tableName, array $identifier)
16653     {
16654         $this->connect();
16655
16656         $criteria = array();
16657
16658         foreach (array_keys($identifier) as $columnName) {
16659             $criteria[] = $columnName . ' = ?';
16660         }
16661
16662         $query = 'DELETE FROM ' . $tableName . ' WHERE ' . implode(' AND ', $criteria);
16663
16664         return $this->executeUpdate($query, array_values($identifier));
16665     }
16666
16667     /**
16668      * Closes the connection.
16669      *
16670      * @return void
16671      */
16672     public function close()
16673     {
16674         unset($this->_conn);
16675         
16676         $this->_isConnected = false;
16677     }
16678
16679     /**
16680      * Sets the transaction isolation level.
16681      *
16682      * @param integer $level The level to set.
16683      */
16684     public function setTransactionIsolation($level)
16685     {
16686         $this->_transactionIsolationLevel = $level;
16687         
16688         return $this->executeUpdate($this->_platform->getSetTransactionIsolationSQL($level));
16689     }
16690
16691     /**
16692      * Gets the currently active transaction isolation level.
16693      *
16694      * @return integer The current transaction isolation level.
16695      */
16696     public function getTransactionIsolation()
16697     {
16698         return $this->_transactionIsolationLevel;
16699     }
16700
16701     /**
16702      * Executes an SQL UPDATE statement on a table.
16703      *
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.
16707      */
16708     public function update($tableName, array $data, array $identifier)
16709     {
16710         $this->connect();
16711         $set = array();
16712         foreach ($data as $columnName => $value) {
16713             $set[] = $columnName . ' = ?';
16714         }
16715
16716         $params = array_merge(array_values($data), array_values($identifier));
16717
16718         $sql  = 'UPDATE ' . $tableName . ' SET ' . implode(', ', $set)
16719                 . ' WHERE ' . implode(' = ? AND ', array_keys($identifier))
16720                 . ' = ?';
16721
16722         return $this->executeUpdate($sql, $params);
16723     }
16724
16725     /**
16726      * Inserts a table row with specified data.
16727      *
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.
16731      */
16732     public function insert($tableName, array $data)
16733     {
16734         $this->connect();
16735
16736         // column names are specified as array keys
16737         $cols = array();
16738         $placeholders = array();
16739         
16740         foreach ($data as $columnName => $value) {
16741             $cols[] = $columnName;
16742             $placeholders[] = '?';
16743         }
16744
16745         $query = 'INSERT INTO ' . $tableName
16746                . ' (' . implode(', ', $cols) . ')'
16747                . ' VALUES (' . implode(', ', $placeholders) . ')';
16748
16749         return $this->executeUpdate($query, array_values($data));
16750     }
16751
16752     /**
16753      * Sets the given charset on the current connection.
16754      *
16755      * @param string $charset The charset to set.
16756      */
16757     public function setCharset($charset)
16758     {
16759         $this->executeUpdate($this->_platform->getSetCharsetSQL($charset));
16760     }
16761
16762     /**
16763      * Quote a string so it can be safely used as a table or column name, even if
16764      * it is a reserved name.
16765      *
16766      * Delimiting style depends on the underlying database platform that is being used.
16767      *
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.
16771      *
16772      * @param string $str The name to be quoted.
16773      * @return string The quoted name.
16774      */
16775     public function quoteIdentifier($str)
16776     {
16777         return $this->_platform->quoteIdentifier($str);
16778     }
16779
16780     /**
16781      * Quotes a given input parameter.
16782      *
16783      * @param mixed $input Parameter to be quoted.
16784      * @param string $type Type of the parameter.
16785      * @return string The quoted parameter.
16786      */
16787     public function quote($input, $type = null)
16788     {
16789         $this->connect();
16790         
16791         return $this->_conn->quote($input, $type);
16792     }
16793
16794     /**
16795      * Prepares and executes an SQL query and returns the result as an associative array.
16796      *
16797      * @param string $sql The SQL query.
16798      * @param array $params The query parameters.
16799      * @return array
16800      */
16801     public function fetchAll($sql, array $params = array())
16802     {
16803         return $this->executeQuery($sql, $params)->fetchAll(PDO::FETCH_ASSOC);
16804     }
16805
16806     /**
16807      * Prepares an SQL statement.
16808      *
16809      * @param string $statement The SQL statement to prepare.
16810      * @return Doctrine\DBAL\Driver\Statement The prepared statement.
16811      */
16812     public function prepare($statement)
16813     {
16814         $this->connect();
16815
16816         return new Statement($statement, $this);
16817     }
16818
16819     /**
16820      * Executes an, optionally parameterized, SQL query.
16821      *
16822      * If the query is parameterized, a prepared statement is used.
16823      * If an SQLLogger is configured, the execution is logged.
16824      *
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.
16829      */
16830     public function executeQuery($query, array $params = array(), $types = array())
16831     {
16832         $this->connect();
16833
16834         $hasLogger = $this->_config->getSQLLogger() !== null;
16835         if ($hasLogger) {
16836             $this->_config->getSQLLogger()->startQuery($query, $params, $types);
16837         }
16838
16839         if ($params) {
16840             $stmt = $this->_conn->prepare($query);
16841             if ($types) {
16842                 $this->_bindTypedValues($stmt, $params, $types);
16843                 $stmt->execute();
16844             } else {
16845                 $stmt->execute($params);
16846             }
16847         } else {
16848             $stmt = $this->_conn->query($query);
16849         }
16850
16851         if ($hasLogger) {
16852             $this->_config->getSQLLogger()->stopQuery();
16853         }
16854
16855         return $stmt;
16856     }
16857
16858     /**
16859      * Executes an, optionally parameterized, SQL query and returns the result,
16860      * applying a given projection/transformation function on each row of the result.
16861      *
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.
16868      */
16869     public function project($query, array $params, Closure $function)
16870     {
16871         $result = array();
16872         $stmt = $this->executeQuery($query, $params ?: array());
16873
16874         while ($row = $stmt->fetch()) {
16875             $result[] = $function($row);
16876         }
16877
16878         $stmt->closeCursor();
16879
16880         return $result;
16881     }
16882
16883     /**
16884      * Executes an SQL statement, returning a result set as a Statement object.
16885      * 
16886      * @param string $statement
16887      * @param integer $fetchType
16888      * @return Doctrine\DBAL\Driver\Statement
16889      */
16890     public function query()
16891     {
16892         $this->connect();
16893
16894         return call_user_func_array(array($this->_conn, 'query'), func_get_args());
16895     }
16896
16897     /**
16898      * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
16899      * and returns the number of affected rows.
16900      * 
16901      * This method supports PDO binding types as well as DBAL mapping types.
16902      *
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.
16908      */
16909     public function executeUpdate($query, array $params = array(), array $types = array())
16910     {
16911         $this->connect();
16912
16913         $hasLogger = $this->_config->getSQLLogger() !== null;
16914         if ($hasLogger) {
16915             $this->_config->getSQLLogger()->startQuery($query, $params, $types);
16916         }
16917
16918         if ($params) {
16919             $stmt = $this->_conn->prepare($query);
16920             if ($types) {
16921                 $this->_bindTypedValues($stmt, $params, $types);
16922                 $stmt->execute();
16923             } else {
16924                 $stmt->execute($params);
16925             }
16926             $result = $stmt->rowCount();
16927         } else {
16928             $result = $this->_conn->exec($query);
16929         }
16930
16931         if ($hasLogger) {
16932             $this->_config->getSQLLogger()->stopQuery();
16933         }
16934
16935         return $result;
16936     }
16937
16938     /**
16939      * Execute an SQL statement and return the number of affected rows.
16940      * 
16941      * @param string $statement
16942      * @return integer The number of affected rows.
16943      */
16944     public function exec($statement)
16945     {
16946         $this->connect();
16947         return $this->_conn->exec($statement);
16948     }
16949
16950     /**
16951      * Returns the current transaction nesting level.
16952      *
16953      * @return integer The nesting level. A value of 0 means there's no active transaction.
16954      */
16955     public function getTransactionNestingLevel()
16956     {
16957         return $this->_transactionNestingLevel;
16958     }
16959
16960     /**
16961      * Fetch the SQLSTATE associated with the last database operation.
16962      *
16963      * @return integer The last error code.
16964      */
16965     public function errorCode()
16966     {
16967         $this->connect();
16968         return $this->_conn->errorCode();
16969     }
16970
16971     /**
16972      * Fetch extended error information associated with the last database operation.
16973      *
16974      * @return array The last error information.
16975      */
16976     public function errorInfo()
16977     {
16978         $this->connect();
16979         return $this->_conn->errorInfo();
16980     }
16981
16982     /**
16983      * Returns the ID of the last inserted row, or the last value from a sequence object,
16984      * depending on the underlying driver.
16985      *
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.
16989      *
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.
16992      */
16993     public function lastInsertId($seqName = null)
16994     {
16995         $this->connect();
16996         return $this->_conn->lastInsertId($seqName);
16997     }
16998
16999     /**
17000      * Executes a function in a transaction.
17001      *
17002      * The function gets passed this Connection instance as an (optional) parameter.
17003      *
17004      * If an exception occurs during execution of the function or transaction commit,
17005      * the transaction is rolled back and the exception re-thrown.
17006      *
17007      * @param Closure $func The function to execute transactionally.
17008      */
17009     public function transactional(Closure $func)
17010     {
17011         $this->beginTransaction();
17012         try {
17013             $func($this);
17014             $this->commit();
17015         } catch (Exception $e) {
17016             $this->rollback();
17017             throw $e;
17018         }
17019     }
17020
17021     /**
17022      * Set if nested transactions should use savepoints
17023      *
17024      * @param boolean
17025      * @return void
17026      */
17027     public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints)
17028     {
17029         if ($this->_transactionNestingLevel > 0) {
17030             throw ConnectionException::mayNotAlterNestedTransactionWithSavepointsInTransaction();
17031         }
17032
17033         if (!$this->_platform->supportsSavepoints()) {
17034             throw ConnectionException::savepointsNotSupported();
17035         }
17036
17037         $this->_nestTransactionsWithSavepoints = $nestTransactionsWithSavepoints;
17038     }
17039
17040     /**
17041      * Get if nested transactions should use savepoints
17042      *
17043      * @return boolean
17044      */
17045     public function getNestTransactionsWithSavepoints()
17046     {
17047         return $this->_nestTransactionsWithSavepoints;
17048     }
17049
17050     /**
17051      * Returns the savepoint name to use for nested transactions are false if they are not supported
17052      * "savepointFormat" parameter is not set
17053      *
17054      * @return mixed a string with the savepoint name or false
17055      */
17056     protected function _getNestedTransactionSavePointName()
17057     {
17058         return 'DOCTRINE2_SAVEPOINT_'.$this->_transactionNestingLevel;
17059     }
17060
17061     /**
17062      * Starts a transaction by suspending auto-commit mode.
17063      *
17064      * @return void
17065      */
17066     public function beginTransaction()
17067     {
17068         $this->connect();
17069
17070         ++$this->_transactionNestingLevel;
17071
17072         if ($this->_transactionNestingLevel == 1) {
17073             $this->_conn->beginTransaction();
17074         } else if ($this->_nestTransactionsWithSavepoints) {
17075             $this->createSavepoint($this->_getNestedTransactionSavePointName());
17076         }
17077     }
17078
17079     /**
17080      * Commits the current transaction.
17081      *
17082      * @return void
17083      * @throws ConnectionException If the commit failed due to no active transaction or
17084      *                             because the transaction was marked for rollback only.
17085      */
17086     public function commit()
17087     {
17088         if ($this->_transactionNestingLevel == 0) {
17089             throw ConnectionException::noActiveTransaction();
17090         }
17091         if ($this->_isRollbackOnly) {
17092             throw ConnectionException::commitFailedRollbackOnly();
17093         }
17094
17095         $this->connect();
17096
17097         if ($this->_transactionNestingLevel == 1) {
17098             $this->_conn->commit();
17099         } else if ($this->_nestTransactionsWithSavepoints) {
17100             $this->releaseSavepoint($this->_getNestedTransactionSavePointName());
17101         }
17102
17103         --$this->_transactionNestingLevel;
17104     }
17105
17106     /**
17107      * Cancel any database changes done during the current transaction.
17108      *
17109      * this method can be listened with onPreTransactionRollback and onTransactionRollback
17110      * eventlistener methods
17111      *
17112      * @throws ConnectionException If the rollback operation failed.
17113      */
17114     public function rollback()
17115     {
17116         if ($this->_transactionNestingLevel == 0) {
17117             throw ConnectionException::noActiveTransaction();
17118         }
17119
17120         $this->connect();
17121
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;
17129         } else {
17130             $this->_isRollbackOnly = true;
17131             --$this->_transactionNestingLevel;
17132         }
17133     }
17134
17135     /**
17136      * createSavepoint
17137      * creates a new savepoint
17138      *
17139      * @param string $savepoint     name of a savepoint to set
17140      * @return void
17141      */
17142     public function createSavepoint($savepoint)
17143     {
17144         if (!$this->_platform->supportsSavepoints()) {
17145             throw ConnectionException::savepointsNotSupported();
17146         }
17147
17148         $this->_conn->exec($this->_platform->createSavePoint($savepoint));
17149     }
17150
17151     /**
17152      * releaseSavePoint
17153      * releases given savepoint
17154      *
17155      * @param string $savepoint     name of a savepoint to release
17156      * @return void
17157      */
17158     public function releaseSavepoint($savepoint)
17159     {
17160         if (!$this->_platform->supportsSavepoints()) {
17161             throw ConnectionException::savepointsNotSupported();
17162         }
17163
17164         if ($this->_platform->supportsReleaseSavepoints()) {
17165             $this->_conn->exec($this->_platform->releaseSavePoint($savepoint));
17166         }
17167     }
17168
17169     /**
17170      * rollbackSavePoint
17171      * releases given savepoint
17172      *
17173      * @param string $savepoint     name of a savepoint to rollback to
17174      * @return void
17175      */
17176     public function rollbackSavepoint($savepoint)
17177     {
17178         if (!$this->_platform->supportsSavepoints()) {
17179             throw ConnectionException::savepointsNotSupported();
17180         }
17181
17182         $this->_conn->exec($this->_platform->rollbackSavePoint($savepoint));
17183     }
17184
17185     /**
17186      * Gets the wrapped driver connection.
17187      *
17188      * @return Doctrine\DBAL\Driver\Connection
17189      */
17190     public function getWrappedConnection()
17191     {
17192         $this->connect();
17193
17194         return $this->_conn;
17195     }
17196
17197     /**
17198      * Gets the SchemaManager that can be used to inspect or change the
17199      * database schema through the connection.
17200      *
17201      * @return Doctrine\DBAL\Schema\SchemaManager
17202      */
17203     public function getSchemaManager()
17204     {
17205         if ( ! $this->_schemaManager) {
17206             $this->_schemaManager = $this->_driver->getSchemaManager($this);
17207         }
17208
17209         return $this->_schemaManager;
17210     }
17211
17212     /**
17213      * Marks the current transaction so that the only possible
17214      * outcome for the transaction to be rolled back.
17215      * 
17216      * @throws ConnectionException If no transaction is active.
17217      */
17218     public function setRollbackOnly()
17219     {
17220         if ($this->_transactionNestingLevel == 0) {
17221             throw ConnectionException::noActiveTransaction();
17222         }
17223         $this->_isRollbackOnly = true;
17224     }
17225
17226     /**
17227      * Check whether the current transaction is marked for rollback only.
17228      * 
17229      * @return boolean
17230      * @throws ConnectionException If no transaction is active.
17231      */
17232     public function isRollbackOnly()
17233     {
17234         if ($this->_transactionNestingLevel == 0) {
17235             throw ConnectionException::noActiveTransaction();
17236         }
17237         return $this->_isRollbackOnly;
17238     }
17239
17240     /**
17241      * Converts a given value to its database representation according to the conversion
17242      * rules of a specific DBAL mapping type.
17243      * 
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.
17247      */
17248     public function convertToDatabaseValue($value, $type)
17249     {
17250         return Type::getType($type)->convertToDatabaseValue($value, $this->_platform);
17251     }
17252
17253     /**
17254      * Converts a given value to its PHP representation according to the conversion
17255      * rules of a specific DBAL mapping type.
17256      * 
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.
17260      */
17261     public function convertToPHPValue($value, $type)
17262     {
17263         return Type::getType($type)->convertToPHPValue($value, $this->_platform);
17264     }
17265
17266     /**
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.
17269      * 
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.
17275      */
17276     private function _bindTypedValues($stmt, array $params, array $types)
17277     {
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;
17282             $bindIndex = 1;
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);
17289                     }
17290                     if ($type instanceof Type) {
17291                         $value = $type->convertToDatabaseValue($value, $this->_platform);
17292                         $bindingType = $type->getBindingType();
17293                     } else {
17294                         $bindingType = $type; // PDO::PARAM_* constants
17295                     }
17296                     $stmt->bindValue($bindIndex, $value, $bindingType);
17297                 } else {
17298                     $stmt->bindValue($bindIndex, $value);
17299                 }
17300                 ++$bindIndex;
17301             }
17302         } else {
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);
17309                     }
17310                     if ($type instanceof Type) {
17311                         $value = $type->convertToDatabaseValue($value, $this->_platform);
17312                         $bindingType = $type->getBindingType();
17313                     } else {
17314                         $bindingType = $type; // PDO::PARAM_* constants
17315                     }
17316                     $stmt->bindValue($name, $value, $bindingType);
17317                 } else {
17318                     $stmt->bindValue($name, $value);
17319                 }
17320             }
17321         }
17322     }
17323 }<?php
17324 /*
17325  *  $Id$
17326  *
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.
17338  *
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>.
17342  */
17343
17344 namespace Doctrine\DBAL\Logging;
17345
17346 /**
17347  * A SQL logger that logs to the standard output using echo/var_dump.
17348  * 
17349  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17350  * @link    www.doctrine-project.org
17351  * @since   2.0
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>
17357  */
17358 class EchoSQLLogger implements SQLLogger
17359 {
17360     /**
17361      * {@inheritdoc}
17362      */
17363     public function startQuery($sql, array $params = null, array $types = null)
17364     {
17365         echo $sql . PHP_EOL;
17366
17367         if ($params) {
17368             var_dump($params);
17369         }
17370
17371         if ($types) {
17372             var_dump($types);
17373         }
17374     }
17375
17376     /**
17377      * {@inheritdoc}
17378      */
17379     public function stopQuery()
17380     {
17381
17382     }
17383 }<?php
17384 /*
17385  *  $Id$
17386  *
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.
17398  *
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>.
17402  */
17403
17404 namespace Doctrine\DBAL\Logging;
17405
17406 /**
17407  * Includes executed SQLs in a Debug Stack
17408  *
17409  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17410  * @link    www.doctrine-project.org
17411  * @since   2.0
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>
17417  */
17418 class DebugStack implements SQLLogger
17419 {
17420     /** @var array $queries Executed SQL queries. */
17421     public $queries = array();
17422
17423     /** @var boolean $enabled If Debug Stack is enabled (log queries) or not. */
17424     public $enabled = true;
17425
17426     public $start = null;
17427
17428     /**
17429      * {@inheritdoc}
17430      */
17431     public function startQuery($sql, array $params = null, array $types = null)
17432     {
17433         if ($this->enabled) {
17434             $this->start = microtime(true);
17435             $this->queries[] = array('sql' => $sql, 'params' => $params, 'types' => $types, 'executionMS' => 0);
17436         }
17437     }
17438
17439     /**
17440      * {@inheritdoc}
17441      */
17442     public function stopQuery()
17443     {
17444         $this->queries[(count($this->queries)-1)]['executionMS'] = microtime(true) - $this->start;
17445     }
17446 }
17447
17448 <?php
17449 /*
17450  *  $Id$
17451  *
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.
17463  *
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>.
17467  */
17468
17469 namespace Doctrine\DBAL\Logging;
17470
17471 /**
17472  * Interface for SQL loggers.
17473  *
17474  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17475  * @link    www.doctrine-project.org
17476  * @since   2.0
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>
17482  */
17483 interface SQLLogger
17484 {
17485     /**
17486      * Logs a SQL statement somewhere.
17487      *
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.
17491      * @return void
17492      */
17493     public function startQuery($sql, array $params = null, array $types = null);
17494
17495     /**
17496      * Mark the last started query as stopped. This can be used for timing of queries.
17497      *
17498      * @return void
17499      */
17500     public function stopQuery();
17501 }<?php
17502 /*
17503  *  $Id$
17504  *
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.
17516  *
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>.
17520  */
17521
17522 namespace Doctrine\DBAL\Tools\Console\Command;
17523
17524 use Symfony\Component\Console\Input\InputArgument,
17525     Symfony\Component\Console;
17526
17527 /**
17528  * Task for executing arbitrary SQL that can come from a file or directly from
17529  * the command line.
17530  *
17531  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17532  * @link    www.doctrine-project.org
17533  * @since   2.0
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>
17539  */
17540 class ImportCommand extends Console\Command\Command
17541 {
17542     /**
17543      * @see Console\Command\Command
17544      */
17545     protected function configure()
17546     {
17547         $this
17548         ->setName('dbal:import')
17549         ->setDescription('Import SQL file(s) directly to Database.')
17550         ->setDefinition(array(
17551             new InputArgument(
17552                 'file', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'File path(s) of SQL to be executed.'
17553             )
17554         ))
17555         ->setHelp(<<<EOT
17556 Import SQL file(s) directly to Database.
17557 EOT
17558         );
17559     }
17560
17561     /**
17562      * @see Console\Command\Command
17563      */
17564     protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
17565     {
17566         $conn = $this->getHelper('db')->getConnection();
17567
17568         if (($fileNames = $input->getArgument('file')) !== null)  {
17569             foreach ((array) $fileNames as $fileName) {
17570                 $fileName = realpath($fileName);
17571
17572                 if ( ! file_exists($fileName)) {
17573                     throw new \InvalidArgumentException(
17574                         sprintf("SQL file '<info>%s</info>' does not exist.", $fileName)
17575                     );
17576                 } else if ( ! is_readable($fileName)) {
17577                     throw new \InvalidArgumentException(
17578                         sprintf("SQL file '<info>%s</info>' does not have read permissions.", $fileName)
17579                     );
17580                 }
17581
17582                 $output->write(sprintf("Processing file '<info>%s</info>'... ", $fileName));
17583                 $sql = file_get_contents($fileName);
17584
17585                 if ($conn instanceof \Doctrine\DBAL\Driver\PDOConnection) {
17586                     // PDO Drivers
17587                     try {
17588                         $lines = 0;
17589
17590                         $stmt = $conn->prepare($sql);
17591                         $stmt->execute();
17592
17593                         do {
17594                             // Required due to "MySQL has gone away!" issue
17595                             $stmt->fetch();
17596                             $stmt->closeCursor();
17597
17598                             $lines++;
17599                         } while ($stmt->nextRowset());
17600
17601                         $output->write(sprintf('%d statements executed!', $lines) . PHP_EOL);
17602                     } catch (\PDOException $e) {
17603                         $output->write('error!' . PHP_EOL);
17604
17605                         throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
17606                     }
17607                 } else {
17608                     // Non-PDO Drivers (ie. OCI8 driver)
17609                     $stmt = $conn->prepare($sql);
17610                     $rs = $stmt->execute();
17611
17612                     if ($rs) {
17613                         $printer->writeln('OK!');
17614                     } else {
17615                         $error = $stmt->errorInfo();
17616
17617                         $output->write('error!' . PHP_EOL);
17618
17619                         throw new \RuntimeException($error[2], $error[0]);
17620                     }
17621
17622                     $stmt->closeCursor();
17623                 }
17624             }
17625         }
17626     }
17627 }
17628 <?php
17629 /*
17630  *  $Id$
17631  *
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.
17643  *
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>.
17647  */
17648
17649 namespace Doctrine\DBAL\Tools\Console\Command;
17650
17651 use Symfony\Component\Console\Input\InputArgument,
17652     Symfony\Component\Console\Input\InputOption,
17653     Symfony\Component\Console;
17654
17655 /**
17656  * Task for executing arbitrary SQL that can come from a file or directly from
17657  * the command line.
17658  * 
17659  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17660  * @link    www.doctrine-project.org
17661  * @since   2.0
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>
17667  */
17668 class RunSqlCommand extends Console\Command\Command
17669 {
17670     /**
17671      * @see Console\Command\Command
17672      */
17673     protected function configure()
17674     {
17675         $this
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)
17681         ))
17682         ->setHelp(<<<EOT
17683 Executes arbitrary SQL directly from the command line.
17684 EOT
17685         );
17686     }
17687
17688     /**
17689      * @see Console\Command\Command
17690      */
17691     protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
17692     {
17693         $conn = $this->getHelper('db')->getConnection();
17694
17695         if (($sql = $input->getArgument('sql')) === null) {
17696             throw new \RuntimeException("Argument 'SQL' is required in order to execute this command correctly.");
17697         }
17698
17699         $depth = $input->getOption('depth');
17700
17701         if ( ! is_numeric($depth)) {
17702             throw new \LogicException("Option 'depth' must contains an integer value");
17703         }
17704         
17705         if (preg_match('/^select/i', $sql)) {
17706            $resultSet = $conn->fetchAll($sql);
17707         } else {
17708             $resultSet = $conn->executeUpdate($sql);
17709         }
17710
17711         \Doctrine\Common\Util\Debug::dump($resultSet, (int) $depth);
17712     }
17713 }
17714 <?php
17715 /*
17716  *  $Id$
17717  *
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.
17729  *
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>.
17733  */
17734
17735 namespace Doctrine\DBAL\Tools\Console\Helper;
17736
17737 use Symfony\Component\Console\Helper\Helper,
17738     Doctrine\DBAL\Connection;
17739
17740 /**
17741  * Doctrine CLI Connection Helper.
17742  *
17743  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
17744  * @link    www.doctrine-project.org
17745  * @since   2.0
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>
17751  */
17752 class ConnectionHelper extends Helper
17753 {
17754     /**
17755      * Doctrine Database Connection
17756      * @var Connection
17757      */
17758     protected $_connection;
17759
17760     /**
17761      * Constructor
17762      *
17763      * @param Connection $connection Doctrine Database Connection
17764      */
17765     public function __construct(Connection $connection)
17766     {
17767         $this->_connection = $connection;
17768     }
17769
17770     /**
17771      * Retrieves Doctrine Database Connection
17772      *
17773      * @return Connection
17774      */
17775     public function getConnection()
17776     {
17777         return $this->_connection;
17778     }
17779
17780     /**
17781      * @see Helper
17782      */
17783     public function getName()
17784     {
17785         return 'connection';
17786     }
17787 }
17788 <?php
17789 /*
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.
17801  *
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>.
17805  */
17806
17807
17808 namespace Doctrine\DBAL\Types;
17809
17810 use Doctrine\DBAL\Platforms\AbstractPlatform;
17811
17812 /**
17813  * Variable DateTime Type using date_create() instead of DateTime::createFromFormat()
17814  *
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.
17818  *
17819  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
17820  * @link        www.doctrine-project.com
17821  * @since       2.0
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>
17826  */
17827 class VarDateTimeType extends DateTimeType
17828 {
17829     /**
17830      * @throws ConversionException
17831      * @param string $value
17832      * @param AbstractPlatform $platform
17833      * @return DateTime
17834      */
17835     public function convertToPHPValue($value, AbstractPlatform $platform)
17836     {
17837         if ($value === null) {
17838             return null;
17839         }
17840
17841         $val = date_create($value);
17842         if (!$val) {
17843             throw ConversionException::conversionFailed($value, $this->getName());
17844         }
17845         return $val;
17846     }
17847 }<?php
17848 /*
17849  *  $Id$
17850  *
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.
17862  *
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>.
17866  */
17867
17868 namespace Doctrine\DBAL\Types;
17869
17870 use Doctrine\DBAL\Platforms\AbstractPlatform;
17871
17872 /**
17873  * Type that maps an SQL INT to a PHP integer.
17874  *
17875  * @author Roman Borschel <roman@code-factory.org>
17876  * @since 2.0
17877  */
17878 class IntegerType extends Type
17879 {
17880     public function getName()
17881     {
17882         return Type::INTEGER;
17883     }
17884
17885     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
17886     {
17887         return $platform->getIntegerTypeDeclarationSQL($fieldDeclaration);
17888     }
17889
17890     public function convertToPHPValue($value, AbstractPlatform $platform)
17891     {
17892         return (null === $value) ? null : (int) $value;
17893     }
17894
17895     public function getBindingType()
17896     {
17897         return \PDO::PARAM_INT;
17898     }
17899 }<?php
17900 /*
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.
17912  *
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>.
17916  */
17917
17918 namespace Doctrine\DBAL\Types;
17919
17920 use Doctrine\DBAL\Platforms\AbstractPlatform;
17921
17922 /**
17923  * Type that maps an SQL DATE to a PHP Date object.
17924  *
17925  * @since 2.0
17926  */
17927 class DateType extends Type
17928 {
17929     public function getName()
17930     {
17931         return Type::DATE;
17932     }
17933
17934     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
17935     {
17936         return $platform->getDateTypeDeclarationSQL($fieldDeclaration);
17937     }
17938
17939     public function convertToDatabaseValue($value, AbstractPlatform $platform)
17940     {
17941         return ($value !== null) 
17942             ? $value->format($platform->getDateFormatString()) : null;
17943     }
17944     
17945     public function convertToPHPValue($value, AbstractPlatform $platform)
17946     {
17947         if ($value === null) {
17948             return null;
17949         }
17950
17951         $val = \DateTime::createFromFormat('!'.$platform->getDateFormatString(), $value);
17952         if (!$val) {
17953             throw ConversionException::conversionFailed($value, $this->getName());
17954         }
17955         return $val;
17956     }
17957 }<?php
17958 /*
17959  *  $Id$
17960  *
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.
17972  *
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>.
17976  */
17977
17978 namespace Doctrine\DBAL\Types;
17979
17980 use Doctrine\DBAL\Platforms\AbstractPlatform,
17981     Doctrine\DBAL\DBALException;
17982
17983 /**
17984  * The base class for so-called Doctrine mapping types.
17985  *
17986  * A Type object is obtained by calling the static {@link getType()} method.
17987  *
17988  * @author Roman Borschel <roman@code-factory.org>
17989  * @since 2.0
17990  */
17991 abstract class Type
17992 {
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';
18007
18008     /** Map of already instantiated type objects. One instance per type (flyweight). */
18009     private static $_typeObjects = array();
18010
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',
18027     );
18028
18029     /* Prevent instantiation and force use of the factory method. */
18030     final private function __construct() {}
18031
18032     /**
18033      * Converts a value from its PHP representation to its database representation
18034      * of this type.
18035      *
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.
18039      */
18040     public function convertToDatabaseValue($value, AbstractPlatform $platform)
18041     {
18042         return $value;
18043     }
18044
18045     /**
18046      * Converts a value from its database representation to its PHP representation
18047      * of this type.
18048      *
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.
18052      */
18053     public function convertToPHPValue($value, AbstractPlatform $platform)
18054     {
18055         return $value;
18056     }
18057
18058     /**
18059      * Gets the default length of this type.
18060      *
18061      * @todo Needed?
18062      */
18063     public function getDefaultLength(AbstractPlatform $platform)
18064     {
18065         return null;
18066     }
18067
18068     /**
18069      * Gets the SQL declaration snippet for a field of this type.
18070      *
18071      * @param array $fieldDeclaration The field declaration.
18072      * @param AbstractPlatform $platform The currently used database platform.
18073      */
18074     abstract public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform);
18075
18076     /**
18077      * Gets the name of this type.
18078      *
18079      * @return string
18080      * @todo Needed?
18081      */
18082     abstract public function getName();
18083
18084     /**
18085      * Factory method to create type instances.
18086      * Type instances are implemented as flyweights.
18087      *
18088      * @static
18089      * @throws DBALException
18090      * @param string $name The name of the type (as returned by getName()).
18091      * @return Doctrine\DBAL\Types\Type
18092      */
18093     public static function getType($name)
18094     {
18095         if ( ! isset(self::$_typeObjects[$name])) {
18096             if ( ! isset(self::$_typesMap[$name])) {
18097                 throw DBALException::unknownColumnType($name);
18098             }
18099             self::$_typeObjects[$name] = new self::$_typesMap[$name]();
18100         }
18101
18102         return self::$_typeObjects[$name];
18103     }
18104
18105     /**
18106      * Adds a custom type to the type map.
18107      *
18108      * @static
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
18112      */
18113     public static function addType($name, $className)
18114     {
18115         if (isset(self::$_typesMap[$name])) {
18116             throw DBALException::typeExists($name);
18117         }
18118
18119         self::$_typesMap[$name] = $className;
18120     }
18121
18122     /**
18123      * Checks if exists support for a type.
18124      *
18125      * @static
18126      * @param string $name Name of the type
18127      * @return boolean TRUE if type is supported; FALSE otherwise
18128      */
18129     public static function hasType($name)
18130     {
18131         return isset(self::$_typesMap[$name]);
18132     }
18133
18134     /**
18135      * Overrides an already defined type to use a different implementation.
18136      *
18137      * @static
18138      * @param string $name
18139      * @param string $className
18140      * @throws DBALException
18141      */
18142     public static function overrideType($name, $className)
18143     {
18144         if ( ! isset(self::$_typesMap[$name])) {
18145             throw DBALException::typeNotFound($name);
18146         }
18147
18148         self::$_typesMap[$name] = $className;
18149     }
18150
18151     /**
18152      * Gets the (preferred) binding type for values of this type that
18153      * can be used when binding parameters to prepared statements.
18154      * 
18155      * This method should return one of the PDO::PARAM_* constants, that is, one of:
18156      * 
18157      * PDO::PARAM_BOOL
18158      * PDO::PARAM_NULL
18159      * PDO::PARAM_INT
18160      * PDO::PARAM_STR
18161      * PDO::PARAM_LOB
18162      * 
18163      * @return integer
18164      */
18165     public function getBindingType()
18166     {
18167         return \PDO::PARAM_STR;
18168     }
18169
18170     /**
18171      * Get the types array map which holds all registered types and the corresponding
18172      * type class
18173      *
18174      * @return array $typesMap
18175      */
18176     public static function getTypesMap()
18177     {
18178         return self::$_typesMap;
18179     }
18180
18181     public function __toString()
18182     {
18183         $e = explode('\\', get_class($this));
18184         return str_replace('Type', '', end($e));
18185     }
18186 }<?php
18187 /*
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.
18199  *
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>.
18203  */
18204
18205
18206 namespace Doctrine\DBAL\Types;
18207
18208 use Doctrine\DBAL\Platforms\AbstractPlatform;
18209
18210 class FloatType extends Type
18211 {
18212     public function getName()
18213     {
18214         return Type::FLOAT;
18215     }
18216
18217     /**
18218      * @param array $fieldDeclaration
18219      * @param AbstractPlatform $platform
18220      * @return string
18221      */
18222     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18223     {
18224         return $platform->getFloatDeclarationSQL($fieldDeclaration);
18225     }
18226
18227     /**
18228      * Converts a value from its database representation to its PHP representation
18229      * of this type.
18230      *
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.
18234      */
18235     public function convertToPHPValue($value, AbstractPlatform $platform)
18236     {
18237         return (null === $value) ? null : (double) $value;
18238     }
18239 }
18240 <?php
18241 /*
18242  *  $Id$
18243  *
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.
18255  *
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>.
18259  */
18260
18261 namespace Doctrine\DBAL\Types;
18262
18263 use Doctrine\DBAL\Platforms\AbstractPlatform;
18264
18265 /**
18266  * Type that maps a database SMALLINT to a PHP integer.
18267  *
18268  * @author robo
18269  */
18270 class SmallIntType extends Type
18271 {
18272     public function getName()
18273     {
18274         return Type::SMALLINT;
18275     }
18276
18277     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18278     {
18279         return $platform->getSmallIntTypeDeclarationSQL($fieldDeclaration);
18280     }
18281
18282     public function convertToPHPValue($value, AbstractPlatform $platform)
18283     {
18284         return (null === $value) ? null : (int) $value;
18285     }
18286
18287     public function getBindingType()
18288     {
18289         return \PDO::PARAM_INT;
18290     }
18291 }<?php
18292 /*
18293  *  $Id$
18294  *
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.
18306  *
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>.
18310  */
18311
18312 namespace Doctrine\DBAL\Types;
18313
18314 use Doctrine\DBAL\Platforms\AbstractPlatform;
18315
18316 /**
18317  * Type that maps a database BIGINT to a PHP string.
18318  *
18319  * @author robo
18320  * @since 2.0
18321  */
18322 class BigIntType extends Type
18323 {
18324     public function getName()
18325     {
18326         return Type::BIGINT;
18327     }
18328
18329     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18330     {
18331         return $platform->getBigIntTypeDeclarationSQL($fieldDeclaration);
18332     }
18333
18334     public function getBindingType()
18335     {
18336         return \PDO::PARAM_INT;
18337     }
18338 }<?php
18339 /*
18340  *  $Id$
18341  *
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.
18353  *
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>.
18357  */
18358
18359 namespace Doctrine\DBAL\Types;
18360
18361 use Doctrine\DBAL\Platforms\AbstractPlatform;
18362
18363 /**
18364  * Type that maps an SQL VARCHAR to a PHP string.
18365  *
18366  * @since 2.0
18367  */
18368 class StringType extends Type
18369 {
18370     /** @override */
18371     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18372     {
18373         return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
18374     }
18375
18376     /** @override */
18377     public function getDefaultLength(AbstractPlatform $platform)
18378     {
18379         return $platform->getVarcharDefaultLength();
18380     }
18381
18382     /** @override */
18383     public function getName()
18384     {
18385         return Type::STRING;
18386     }
18387 }<?php
18388
18389 namespace Doctrine\DBAL\Types;
18390
18391 /**
18392  * Type that maps a PHP object to a clob SQL type.
18393  *
18394  * @since 2.0
18395  */
18396 class ObjectType extends Type
18397 {
18398     public function getSQLDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18399     {
18400         return $platform->getClobTypeDeclarationSQL($fieldDeclaration);
18401     }
18402
18403     public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18404     {
18405         return serialize($value);
18406     }
18407
18408     public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18409     {
18410         if ($value === null) {
18411             return null;
18412         }
18413
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());
18418         }
18419         return $val;
18420     }
18421
18422     public function getName()
18423     {
18424         return Type::OBJECT;
18425     }
18426 }<?php
18427 /*
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.
18439  *
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>.
18443  */
18444
18445
18446 namespace Doctrine\DBAL\Types;
18447
18448 use Doctrine\DBAL\Platforms\AbstractPlatform;
18449
18450 /**
18451  * DateTime type saving additional timezone information.
18452  *
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.
18459  *
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
18464  * attached.
18465  *
18466  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
18467  * @link        www.doctrine-project.com
18468  * @since       1.0
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>
18473  */
18474 class DateTimeTzType extends Type
18475 {
18476     public function getName()
18477     {
18478         return Type::DATETIMETZ;
18479     }
18480     
18481     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18482     {
18483         return $platform->getDateTimeTzTypeDeclarationSQL($fieldDeclaration);
18484     }
18485
18486     public function convertToDatabaseValue($value, AbstractPlatform $platform)
18487     {
18488         return ($value !== null)
18489             ? $value->format($platform->getDateTimeTzFormatString()) : null;
18490     }
18491
18492     public function convertToPHPValue($value, AbstractPlatform $platform)
18493     {
18494         if ($value === null) {
18495             return null;
18496         }
18497
18498         $val = \DateTime::createFromFormat($platform->getDateTimeTzFormatString(), $value);
18499         if (!$val) {
18500             throw ConversionException::conversionFailed($value, $this->getName());
18501         }
18502         return $val;
18503     }
18504 }<?php
18505 /*
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.
18517  *
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>.
18521  */
18522
18523
18524 /**
18525  * Conversion Exception is thrown when the database to PHP conversion fails
18526  *
18527  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
18528  * @link        www.doctrine-project.com
18529  * @since       2.0
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>
18534  */
18535 namespace Doctrine\DBAL\Types;
18536
18537 class ConversionException extends \Doctrine\DBAL\DBALException
18538 {
18539     /**
18540      * Thrown when a Database to Doctrine Type Conversion fails.
18541      * 
18542      * @param  string $value
18543      * @param  string $toType
18544      * @return ConversionException
18545      */
18546     static public function conversionFailed($value, $toType)
18547     {
18548         $value = (strlen($value) > 32) ? substr($value, 0, 20) . "..." : $value;
18549         return new self('Could not convert database value "' . $value . '" to Doctrine Type ' . $toType);
18550     }
18551 }<?php
18552 /*
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.
18564  *
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>.
18568  */
18569
18570 namespace Doctrine\DBAL\Types;
18571
18572 use Doctrine\DBAL\Platforms\AbstractPlatform;
18573
18574 /**
18575  * Type that maps an SQL DATETIME/TIMESTAMP to a PHP DateTime object.
18576  *
18577  * @since 2.0
18578  */
18579 class DateTimeType extends Type
18580 {
18581     public function getName()
18582     {
18583         return Type::DATETIME;
18584     }
18585
18586     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18587     {
18588         return $platform->getDateTimeTypeDeclarationSQL($fieldDeclaration);
18589     }
18590
18591     public function convertToDatabaseValue($value, AbstractPlatform $platform)
18592     {
18593         return ($value !== null)
18594             ? $value->format($platform->getDateTimeFormatString()) : null;
18595     }
18596     
18597     public function convertToPHPValue($value, AbstractPlatform $platform)
18598     {
18599         if ($value === null) {
18600             return null;
18601         }
18602
18603         $val = \DateTime::createFromFormat($platform->getDateTimeFormatString(), $value);
18604         if (!$val) {
18605             throw ConversionException::conversionFailed($value, $this->getName());
18606         }
18607         return $val;
18608     }
18609 }<?php
18610 /*
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.
18622  *
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>.
18626  */
18627
18628 namespace Doctrine\DBAL\Types;
18629
18630 use Doctrine\DBAL\Platforms\AbstractPlatform;
18631
18632 /**
18633  * Type that maps an SQL DECIMAL to a PHP double.
18634  *
18635  * @since 2.0
18636  */
18637 class DecimalType extends Type
18638 {
18639     public function getName()
18640     {
18641         return Type::DECIMAL;
18642     }
18643
18644     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18645     {
18646         return $platform->getDecimalTypeDeclarationSQL($fieldDeclaration);
18647     }
18648
18649     public function convertToPHPValue($value, AbstractPlatform $platform)
18650     {
18651         return (null === $value) ? null : (double) $value;
18652     }
18653 }<?php
18654 /*
18655  *  $Id$
18656  *
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.
18668  *
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>.
18672  */
18673
18674 namespace Doctrine\DBAL\Types;
18675
18676 use Doctrine\DBAL\Platforms\AbstractPlatform;
18677
18678 /**
18679  * Type that maps an SQL CLOB to a PHP string.
18680  *
18681  * @since 2.0
18682  */
18683 class TextType extends Type
18684 {
18685     /** @override */
18686     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18687     {
18688         return $platform->getClobTypeDeclarationSQL($fieldDeclaration);
18689     }
18690
18691     /**
18692      * Converts a value from its database representation to its PHP representation
18693      * of this type.
18694      *
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.
18698      */
18699     public function convertToPHPValue($value, AbstractPlatform $platform)
18700     {
18701         return (is_resource($value)) ? stream_get_contents($value) : $value;
18702     }
18703
18704     public function getName()
18705     {
18706         return Type::TEXT;
18707     }
18708 }<?php
18709 /*
18710  *  $Id$
18711  *
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.
18723  *
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>.
18727  */
18728
18729 namespace Doctrine\DBAL\Types;
18730
18731 /**
18732  * Type that maps a PHP array to a clob SQL type.
18733  *
18734  * @since 2.0
18735  */
18736 class ArrayType extends Type
18737 {
18738     public function getSQLDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18739     {
18740         return $platform->getClobTypeDeclarationSQL($fieldDeclaration);
18741     }
18742
18743     public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18744     {
18745         return serialize($value);
18746     }
18747
18748     public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
18749     {
18750         if ($value === null) {
18751             return null;
18752         }
18753
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());
18758         }
18759         return $val;
18760     }
18761
18762     public function getName()
18763     {
18764         return Type::TARRAY;
18765     }
18766 }<?php
18767 /*
18768  *  $Id$
18769  *
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.
18781  *
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>.
18785  */
18786
18787 namespace Doctrine\DBAL\Types;
18788
18789 use Doctrine\DBAL\Platforms\AbstractPlatform;
18790
18791 /**
18792  * Type that maps an SQL boolean to a PHP boolean.
18793  *
18794  * @since 2.0
18795  */
18796 class BooleanType extends Type
18797 {
18798     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18799     {
18800         return $platform->getBooleanTypeDeclarationSQL($fieldDeclaration);
18801     }
18802
18803     public function convertToDatabaseValue($value, AbstractPlatform $platform)
18804     {
18805         return $platform->convertBooleans($value);
18806     }
18807     
18808     public function convertToPHPValue($value, AbstractPlatform $platform)
18809     {
18810         return (null === $value) ? null : (bool) $value;
18811     }
18812
18813     public function getName()
18814     {
18815         return Type::BOOLEAN;
18816     }
18817
18818     public function getBindingType()
18819     {
18820         return \PDO::PARAM_BOOL;
18821     }
18822 }<?php
18823 /*
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.
18835  *
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>.
18839  */
18840
18841 namespace Doctrine\DBAL\Types;
18842
18843 use Doctrine\DBAL\Platforms\AbstractPlatform;
18844
18845 /**
18846  * Type that maps an SQL TIME to a PHP DateTime object.
18847  *
18848  * @since 2.0
18849  */
18850 class TimeType extends Type
18851 {
18852     public function getName()
18853     {
18854         return Type::TIME;
18855     }
18856
18857     /**
18858      * {@inheritdoc}
18859      */
18860     public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
18861     {
18862         return $platform->getTimeTypeDeclarationSQL($fieldDeclaration);
18863     }
18864
18865     /**
18866      * {@inheritdoc}
18867      */
18868     public function convertToDatabaseValue($value, AbstractPlatform $platform)
18869     {
18870         return ($value !== null) 
18871             ? $value->format($platform->getTimeFormatString()) : null;
18872     }
18873
18874     /**
18875      * {@inheritdoc}
18876      */
18877     public function convertToPHPValue($value, AbstractPlatform $platform)
18878     {
18879         if ($value === null) {
18880             return null;
18881         }
18882
18883         $val = \DateTime::createFromFormat($platform->getTimeFormatString(), $value);
18884         if (!$val) {
18885             throw ConversionException::conversionFailed($value, $this->getName());
18886         }
18887         return $val;
18888     }
18889 }<?php
18890 /*
18891  *  $Id$
18892  *
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.
18904  *
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>.
18908 */
18909
18910 namespace Doctrine\DBAL\Event;
18911
18912 use Doctrine\Common\EventArgs,
18913     Doctrine\DBAL\Connection;
18914
18915 /**
18916  * Event Arguments used when a Driver connection is established inside Doctrine\DBAL\Connection.
18917  *
18918  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
18919  * @link        www.doctrine-project.com
18920  * @since       1.0
18921  * @version     $Revision$
18922  * @author      Benjamin Eberlei <kontakt@beberlei.de>
18923  */
18924 class ConnectionEventArgs extends EventArgs
18925 {
18926     /**
18927      * @var Connection
18928      */
18929     private $_connection = null;
18930
18931     public function __construct(Connection $connection)
18932     {
18933         $this->_connection = $connection;
18934     }
18935
18936     /**
18937      * @return Doctrine\DBAL\Connection
18938      */
18939     public function getConnection()
18940     {
18941         return $this->_connection;
18942     }
18943
18944     /**
18945      * @return Doctrine\DBAL\Driver
18946      */
18947     public function getDriver()
18948     {
18949         return $this->_connection->getDriver();
18950     }
18951
18952     /**
18953      * @return Doctrine\DBAL\Platforms\AbstractPlatform
18954      */
18955     public function getDatabasePlatform()
18956     {
18957         return $this->_connection->getDatabasePlatform();
18958     }
18959
18960     /**
18961      * @return Doctrine\DBAL\Schema\AbstractSchemaManager
18962      */
18963     public function getSchemaManager()
18964     {
18965         return $this->_connection->getSchemaManager();
18966     }
18967 }
18968 <?php
18969 /*
18970  *  $Id$
18971  *
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.
18983  *
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>.
18987 */
18988
18989 namespace Doctrine\DBAL\Event\Listeners;
18990
18991 use Doctrine\DBAL\Event\ConnectionEventArgs;
18992 use Doctrine\DBAL\Events;
18993 use Doctrine\Common\EventSubscriber;
18994
18995 /**
18996  * MySQL Session Init Event Subscriber which allows to set the Client Encoding of the Connection
18997  *
18998  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
18999  * @link        www.doctrine-project.com
19000  * @since       1.0
19001  * @version     $Revision$
19002  * @author      Benjamin Eberlei <kontakt@beberlei.de>
19003  */
19004 class MysqlSessionInit implements EventSubscriber
19005 {
19006     /**
19007      * @var string
19008      */
19009     private $_charset;
19010
19011     /**
19012      * @var string
19013      */
19014     private $_collation;
19015
19016     /**
19017      * Configure Charset and Collation options of MySQL Client for each Connection
19018      *
19019      * @param string $charset
19020      * @param string $collation
19021      */
19022     public function __construct($charset = 'utf8', $collation = false)
19023     {
19024         $this->_charset = $charset;
19025         $this->_collation = $collation;
19026     }
19027
19028     /**
19029      * @param ConnectionEventArgs $args
19030      * @return void
19031      */
19032     public function postConnect(ConnectionEventArgs $args)
19033     {
19034         $collation = ($this->_collation) ? " COLLATE ".$this->_collation : "";
19035         $args->getConnection()->executeUpdate("SET NAMES ".$this->_charset . $collation);
19036     }
19037
19038     public function getSubscribedEvents()
19039     {
19040         return array(Events::postConnect);
19041     }
19042 }<?php
19043 /*
19044  *  $Id$
19045  *
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.
19057  *
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>.
19061 */
19062
19063 namespace Doctrine\DBAL\Event\Listeners;
19064
19065 use Doctrine\DBAL\Event\ConnectionEventArgs;
19066 use Doctrine\DBAL\Events;
19067 use Doctrine\Common\EventSubscriber;
19068
19069 /**
19070  * Should be used when Oracle Server default enviroment does not match the Doctrine requirements.
19071  *
19072  * The following enviroment variables are required for the Doctrine default date format:
19073  *
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"
19078  *
19079  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
19080  * @link        www.doctrine-project.com
19081  * @since       1.0
19082  * @version     $Revision$
19083  * @author      Benjamin Eberlei <kontakt@beberlei.de>
19084  */
19085 class OracleSessionInit implements EventSubscriber
19086 {
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",
19092     );
19093
19094     /**
19095      * @param array $oracleSessionVars
19096      */
19097     public function __construct(array $oracleSessionVars = array())
19098     {
19099         $this->_defaultSessionVars = array_merge($this->_defaultSessionVars, $oracleSessionVars);
19100     }
19101
19102     /**
19103      * @param ConnectionEventArgs $args
19104      * @return void
19105      */
19106     public function postConnect(ConnectionEventArgs $args)
19107     {
19108         if (count($this->_defaultSessionVars)) {
19109             array_change_key_case($this->_defaultSessionVars, \CASE_UPPER);
19110             $vars = array();
19111             foreach ($this->_defaultSessionVars AS $option => $value) {
19112                 $vars[] = $option." = '".$value."'";
19113             }
19114             $sql = "ALTER SESSION SET ".implode(" ", $vars);
19115             $args->getConnection()->executeUpdate($sql);
19116         }
19117     }
19118
19119     public function getSubscribedEvents()
19120     {
19121         return array(Events::postConnect);
19122     }
19123 }
19124 <?php
19125 /*
19126  *  $Id$
19127  *
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.
19139  *
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>.
19143  */
19144
19145 namespace Doctrine\Common;
19146
19147 /**
19148  * EventArgs is the base class for classes containing event data.
19149  *
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}.
19153  *
19154  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
19155  * @link    www.doctrine-project.org
19156  * @since   2.0
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>
19161  */
19162 class EventArgs
19163 {
19164     /**
19165      * @var EventArgs Single instance of EventArgs
19166      * @static
19167      */
19168     private static $_emptyEventArgsInstance;
19169
19170     /**
19171      * Gets the single, empty and immutable EventArgs instance.
19172      *
19173      * This instance will be used when events are dispatched without any parameter,
19174      * like this: EventManager::dispatchEvent('eventname');
19175      *
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)
19178      *
19179      * @see EventManager::dispatchEvent
19180      * @link http://msdn.microsoft.com/en-us/library/system.eventargs.aspx
19181      * @static
19182      * @return EventArgs
19183      */
19184     public static function getEmptyInstance()
19185     {
19186         if ( ! self::$_emptyEventArgsInstance) {
19187             self::$_emptyEventArgsInstance = new EventArgs;
19188         }
19189
19190         return self::$_emptyEventArgsInstance;
19191     }
19192 }
19193 <?php
19194 /*
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.
19206  *
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>.
19210  */
19211
19212 namespace Doctrine\Common;
19213
19214 /**
19215  * Base exception class for package Doctrine\Common
19216  * @author heinrich
19217  *
19218  */
19219 class CommonException extends \Exception {
19220 }<?php
19221 /*
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.
19233  *
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>.
19237  */
19238
19239 namespace Doctrine\Common\Annotations;
19240
19241 use Closure,
19242     ReflectionClass,
19243     ReflectionMethod, 
19244     ReflectionProperty,
19245     Doctrine\Common\Cache\Cache;
19246
19247 /**
19248  * A reader for docblock annotations.
19249  * 
19250  * @since   2.0
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>
19255  */
19256 class AnnotationReader
19257 {
19258     /**
19259      * Cache salt
19260      *
19261      * @var string
19262      * @static
19263      */
19264     private static $CACHE_SALT = '@<Annot>';
19265     
19266     /**
19267      * Annotations Parser
19268      *
19269      * @var Doctrine\Common\Annotations\Parser
19270      */
19271     private $parser;
19272     
19273     /**
19274      * Cache mechanism to store processed Annotations
19275      *
19276      * @var Doctrine\Common\Cache\Cache
19277      */
19278     private $cache;
19279     
19280     /**
19281      * Constructor. Initializes a new AnnotationReader that uses the given Cache provider.
19282      * 
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.
19285      */
19286     public function __construct(Cache $cache = null, Parser $parser = null)
19287     {
19288         $this->parser = $parser ?: new Parser;
19289         $this->cache = $cache ?: new \Doctrine\Common\Cache\ArrayCache;
19290     }
19291
19292     /**
19293      * Sets the default namespace that the AnnotationReader should assume for annotations
19294      * with not fully qualified names.
19295      * 
19296      * @param string $defaultNamespace
19297      */
19298     public function setDefaultAnnotationNamespace($defaultNamespace)
19299     {
19300         $this->parser->setDefaultAnnotationNamespace($defaultNamespace);
19301     }
19302
19303     /**
19304      * Sets the custom function to use for creating new annotations on the
19305      * underlying parser.
19306      *
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.
19312      *
19313      * @param Closure $func
19314      */
19315     public function setAnnotationCreationFunction(Closure $func)
19316     {
19317         $this->parser->setAnnotationCreationFunction($func);
19318     }
19319
19320     /**
19321      * Sets an alias for an annotation namespace.
19322      * 
19323      * @param $namespace
19324      * @param $alias
19325      */
19326     public function setAnnotationNamespaceAlias($namespace, $alias)
19327     {
19328         $this->parser->setAnnotationNamespaceAlias($namespace, $alias);
19329     }
19330
19331     /**
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.
19334      *
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.
19339      */
19340     public function setAutoloadAnnotations($bool)
19341     {
19342         $this->parser->setAutoloadAnnotations($bool);
19343     }
19344
19345     /**
19346      * Gets a flag whether to try to autoload annotation classes.
19347      *
19348      * @see setAutoloadAnnotations
19349      * @return boolean
19350      */
19351     public function getAutoloadAnnotations()
19352     {
19353         return $this->parser->getAutoloadAnnotations();
19354     }
19355
19356     /**
19357      * Gets the annotations applied to a class.
19358      * 
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.
19362      */
19363     public function getClassAnnotations(ReflectionClass $class)
19364     {
19365         $cacheKey = $class->getName() . self::$CACHE_SALT;
19366
19367         // Attempt to grab data from cache
19368         if (($data = $this->cache->fetch($cacheKey)) !== false) {
19369             return $data;
19370         }
19371         
19372         $annotations = $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
19373         $this->cache->save($cacheKey, $annotations, null);
19374         
19375         return $annotations;
19376     }
19377
19378     /**
19379      * Gets a class annotation.
19380      * 
19381      * @param $class
19382      * @param string $annotation The name of the annotation.
19383      * @return The Annotation or NULL, if the requested annotation does not exist.
19384      */
19385     public function getClassAnnotation(ReflectionClass $class, $annotation)
19386     {
19387         $annotations = $this->getClassAnnotations($class);
19388
19389         return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
19390     }
19391     
19392     /**
19393      * Gets the annotations applied to a property.
19394      * 
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.
19399      */
19400     public function getPropertyAnnotations(ReflectionProperty $property)
19401     {
19402         $cacheKey = $property->getDeclaringClass()->getName() . '$' . $property->getName() . self::$CACHE_SALT;
19403
19404         // Attempt to grab data from cache
19405         if (($data = $this->cache->fetch($cacheKey)) !== false) {
19406             return $data;
19407         }
19408         
19409         $context = 'property ' . $property->getDeclaringClass()->getName() . "::\$" . $property->getName();
19410         $annotations = $this->parser->parse($property->getDocComment(), $context);
19411         $this->cache->save($cacheKey, $annotations, null);
19412         
19413         return $annotations;
19414     }
19415     
19416     /**
19417      * Gets a property annotation.
19418      * 
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.
19422      */
19423     public function getPropertyAnnotation(ReflectionProperty $property, $annotation)
19424     {
19425         $annotations = $this->getPropertyAnnotations($property);
19426
19427         return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
19428     }
19429     
19430     /**
19431      * Gets the annotations applied to a method.
19432      * 
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.
19437      */
19438     public function getMethodAnnotations(ReflectionMethod $method)
19439     {
19440         $cacheKey = $method->getDeclaringClass()->getName() . '#' . $method->getName() . self::$CACHE_SALT;
19441
19442         // Attempt to grab data from cache
19443         if (($data = $this->cache->fetch($cacheKey)) !== false) {
19444             return $data;
19445         } 
19446
19447         $context = 'method ' . $method->getDeclaringClass()->getName() . '::' . $method->getName() . '()';
19448         $annotations = $this->parser->parse($method->getDocComment(), $context);
19449         $this->cache->save($cacheKey, $annotations, null);
19450         
19451         return $annotations;
19452     }
19453     
19454     /**
19455      * Gets a method annotation.
19456      * 
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.
19460      */
19461     public function getMethodAnnotation(ReflectionMethod $method, $annotation)
19462     {
19463         $annotations = $this->getMethodAnnotations($method);
19464         
19465         return isset($annotations[$annotation]) ? $annotations[$annotation] : null;
19466     }
19467 }<?php
19468 /*
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.
19480  *
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>.
19484  */
19485
19486 namespace Doctrine\Common\Annotations;
19487
19488 /**
19489  * Description of AnnotationException
19490  *
19491  * @since   2.0
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>
19496  */
19497 class AnnotationException extends \Exception
19498 {
19499     /**
19500      * Creates a new AnnotationException describing a Syntax error.
19501      *
19502      * @param string $message Exception message
19503      * @return AnnotationException
19504      */
19505     public static function syntaxError($message)
19506     {
19507         return new self('[Syntax Error] ' . $message);
19508     }
19509
19510     /**
19511      * Creates a new AnnotationException describing a Semantical error.
19512      *
19513      * @param string $message Exception message
19514      * @return AnnotationException
19515      */
19516     public static function semanticalError($message)
19517     {
19518         return new self('[Semantical Error] ' . $message);
19519     }
19520 }<?php
19521 /*
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.
19533  *
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>.
19537  */
19538
19539 namespace Doctrine\Common\Annotations;
19540
19541 use Closure, Doctrine\Common\ClassLoader;
19542
19543 /**
19544  * A simple parser for docblock annotations.
19545  *
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.
19550  *
19551  * @since 2.0
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>
19556  */
19557 class Parser
19558 {
19559     /**
19560      * Some common tags that are stripped prior to parsing in order to reduce parsing overhead.
19561      *
19562      * @var array
19563      */
19564     private static $strippedTags = array(
19565         "{@internal", "{@inheritdoc", "{@link"
19566     );
19567
19568     /**
19569      * The lexer.
19570      *
19571      * @var Doctrine\Common\Annotations\Lexer
19572      */
19573     private $lexer;
19574
19575     /**
19576      * Flag to control if the current annotation is nested or not.
19577      *
19578      * @var boolean
19579      */
19580     protected $isNestedAnnotation = false;
19581
19582     /**
19583      * Default namespace for annotations.
19584      *
19585      * @var string
19586      */
19587     private $defaultAnnotationNamespace = '';
19588
19589     /**
19590      * Hashmap to store namespace aliases.
19591      *
19592      * @var array
19593      */
19594     private $namespaceAliases = array();
19595
19596     /**
19597      * @var string
19598      */
19599     private $context = '';
19600
19601     /**
19602      * @var boolean Whether to try to autoload annotations that are not yet defined.
19603      */
19604     private $autoloadAnnotations = false;
19605
19606     /**
19607      * @var Closure The custom function used to create new annotations, if any.
19608      */
19609     private $annotationCreationFunction;
19610
19611     /**
19612      * Constructs a new AnnotationParser.
19613      */
19614     public function __construct(Lexer $lexer = null)
19615     {
19616         $this->lexer = $lexer ?: new Lexer;
19617     }
19618
19619     /**
19620      * Gets the lexer used by this parser.
19621      * 
19622      * @return Lexer The lexer.
19623      */
19624     public function getLexer()
19625     {
19626         return $this->lexer;
19627     }
19628
19629     /**
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.
19632      *
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.
19637      */
19638     public function setAutoloadAnnotations($bool)
19639     {
19640         $this->autoloadAnnotations = $bool;
19641     }
19642
19643     /**
19644      * Sets the custom function to use for creating new annotations.
19645      *
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.
19651      *
19652      * Whenever the function returns NULL for an annotation, the implementation falls
19653      * back to the default annotation creation process.
19654      *
19655      * @param Closure $func
19656      */
19657     public function setAnnotationCreationFunction(Closure $func)
19658     {
19659         $this->annotationCreationFunction = $func;
19660     }
19661
19662     /**
19663      * Gets a flag whether to try to autoload annotation classes.
19664      *
19665      * @see setAutoloadAnnotations
19666      * @return boolean
19667      */
19668     public function getAutoloadAnnotations()
19669     {
19670         return $this->autoloadAnnotations;
19671     }
19672
19673     /**
19674      * Sets the default namespace that is assumed for an annotation that does not
19675      * define a namespace prefix.
19676      *
19677      * @param string $defaultNamespace
19678      */
19679     public function setDefaultAnnotationNamespace($defaultNamespace)
19680     {
19681         $this->defaultAnnotationNamespace = $defaultNamespace;
19682     }
19683
19684     /**
19685      * Sets an alias for an annotation namespace.
19686      *
19687      * @param string $namespace
19688      * @param string $alias
19689      */
19690     public function setAnnotationNamespaceAlias($namespace, $alias)
19691     {
19692         $this->namespaceAliases[$alias] = $namespace;
19693     }
19694
19695     /**
19696      * Gets the namespace alias mappings used by this parser.
19697      *
19698      * @return array The namespace alias mappings.
19699      */
19700     public function getNamespaceAliases()
19701     {
19702         return $this->namespaceAliases;
19703     }
19704
19705     /**
19706      * Parses the given docblock string for annotations.
19707      *
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.
19711      */
19712     public function parse($docBlockString, $context='')
19713     {
19714         $this->context = $context;
19715
19716         // Strip out some known inline tags.
19717         $input = str_replace(self::$strippedTags, '', $docBlockString);
19718
19719         // Cut of the beginning of the input until the first '@'.
19720         $input = substr($input, strpos($input, '@'));
19721
19722         $this->lexer->reset();
19723         $this->lexer->setInput(trim($input, '* /'));
19724         $this->lexer->moveNext();
19725
19726         if ($this->lexer->isNextToken(Lexer::T_AT)) {
19727             return $this->Annotations();
19728         }
19729
19730         return array();
19731     }
19732
19733     /**
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.
19736      *
19737      * @param int Token type.
19738      * @return bool True if tokens match; false otherwise.
19739      */
19740     public function match($token)
19741     {
19742         if ( ! ($this->lexer->lookahead['type'] === $token)) {
19743             $this->syntaxError($this->lexer->getLiteral($token));
19744         }
19745         $this->lexer->moveNext();
19746     }
19747
19748     /**
19749      * Generates a new syntax error.
19750      *
19751      * @param string $expected Expected string.
19752      * @param array $token Optional token.
19753      * @throws AnnotationException
19754      */
19755     private function syntaxError($expected, $token = null)
19756     {
19757         if ($token === null) {
19758             $token = $this->lexer->lookahead;
19759         }
19760
19761         $message =  "Expected {$expected}, got ";
19762
19763         if ($this->lexer->lookahead === null) {
19764             $message .= 'end of string';
19765         } else {
19766             $message .= "'{$token['value']}' at position {$token['position']}";
19767         }
19768
19769         if (strlen($this->context)) {
19770             $message .= ' in ' . $this->context;
19771         }
19772
19773         $message .= '.';
19774
19775         throw AnnotationException::syntaxError($message);
19776     }
19777
19778     /**
19779      * Annotations ::= Annotation {[ "*" ]* [Annotation]}*
19780      *
19781      * @return array
19782      */
19783     public function Annotations()
19784     {
19785         $this->isNestedAnnotation = false;
19786
19787         $annotations = array();
19788         $annot = $this->Annotation();
19789
19790         if ($annot !== false) {
19791             $annotations[get_class($annot)] = $annot;
19792             $this->lexer->skipUntil(Lexer::T_AT);
19793         }
19794
19795         while ($this->lexer->lookahead !== null && $this->lexer->isNextToken(Lexer::T_AT)) {
19796             $this->isNestedAnnotation = false;
19797             $annot = $this->Annotation();
19798
19799             if ($annot !== false) {
19800                 $annotations[get_class($annot)] = $annot;
19801                 $this->lexer->skipUntil(Lexer::T_AT);
19802             }
19803         }
19804
19805         return $annotations;
19806     }
19807
19808     /**
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
19816      *
19817      * @return mixed False if it is not a valid annotation.
19818      */
19819     public function Annotation()
19820     {
19821         $values = array();
19822         $nameParts = array();
19823
19824         $this->match(Lexer::T_AT);
19825         $this->match(Lexer::T_IDENTIFIER);
19826         $nameParts[] = $this->lexer->token['value'];
19827
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'];
19832         }
19833
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]);
19837
19838             // If the namespace alias doesnt exist, skip until next annotation
19839             if ( ! isset($this->namespaceAliases[$alias])) {
19840                 $this->lexer->skipUntil(Lexer::T_AT);
19841                 return false;
19842             }
19843
19844             $name = $this->namespaceAliases[$alias] . implode('\\', $nameParts);
19845         } else if (count($nameParts) == 1) {
19846             $name = $this->defaultAnnotationNamespace . $nameParts[0];
19847         } else {
19848             $name = implode('\\', $nameParts);
19849         }
19850
19851         // Does the annotation class exist?
19852         if ( ! class_exists($name, $this->autoloadAnnotations)) {
19853             $this->lexer->skipUntil(Lexer::T_AT);
19854             return false;
19855         }
19856
19857         // Next will be nested
19858         $this->isNestedAnnotation = true;
19859
19860         if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
19861             $this->match(Lexer::T_OPEN_PARENTHESIS);
19862
19863             if ( ! $this->lexer->isNextToken(Lexer::T_CLOSE_PARENTHESIS)) {
19864                 $values = $this->Values();
19865             }
19866
19867             $this->match(Lexer::T_CLOSE_PARENTHESIS);
19868         }
19869
19870         if ($this->annotationCreationFunction !== null) {
19871             $func = $this->annotationCreationFunction;
19872             $annot = $func($name, $values);
19873         }
19874
19875         return isset($annot) ? $annot : $this->newAnnotation($name, $values);
19876     }
19877
19878     /**
19879      * Values ::= Array | Value {"," Value}*
19880      *
19881      * @return array
19882      */
19883     public function Values()
19884     {
19885         $values = array();
19886
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();
19890             return $values;
19891         }
19892
19893         $values[] = $this->Value();
19894
19895         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
19896             $this->match(Lexer::T_COMMA);
19897             $value = $this->Value();
19898
19899             if ( ! is_array($value)) {
19900                 $this->syntaxError('Value', $value);
19901             }
19902
19903             $values[] = $value;
19904         }
19905
19906         foreach ($values as $k => $value) {
19907             if (is_array($value) && is_string(key($value))) {
19908                 $key = key($value);
19909                 $values[$key] = $value[$key];
19910             } else {
19911                 $values['value'] = $value;
19912             }
19913
19914             unset($values[$k]);
19915         }
19916
19917         return $values;
19918     }
19919
19920     /**
19921      * Value ::= PlainValue | FieldAssignment
19922      *
19923      * @return mixed
19924      */
19925     public function Value()
19926     {
19927         $peek = $this->lexer->glimpse();
19928
19929         if ($peek['value'] === '=') {
19930             return $this->FieldAssignment();
19931         }
19932
19933         return $this->PlainValue();
19934     }
19935
19936     /**
19937      * PlainValue ::= integer | string | float | boolean | Array | Annotation
19938      *
19939      * @return mixed
19940      */
19941     public function PlainValue()
19942     {
19943         if ($this->lexer->isNextToken(Lexer::T_OPEN_CURLY_BRACES)) {
19944             return $this->Arrayx();
19945         }
19946
19947         if ($this->lexer->isNextToken(Lexer::T_AT)) {
19948             return $this->Annotation();
19949         }
19950
19951         switch ($this->lexer->lookahead['type']) {
19952             case Lexer::T_STRING:
19953                 $this->match(Lexer::T_STRING);
19954                 return $this->lexer->token['value'];
19955
19956             case Lexer::T_INTEGER:
19957                 $this->match(Lexer::T_INTEGER);
19958                 return $this->lexer->token['value'];
19959
19960             case Lexer::T_FLOAT:
19961                 $this->match(Lexer::T_FLOAT);
19962                 return $this->lexer->token['value'];
19963
19964             case Lexer::T_TRUE:
19965                 $this->match(Lexer::T_TRUE);
19966                 return true;
19967
19968             case Lexer::T_FALSE:
19969                 $this->match(Lexer::T_FALSE);
19970                 return false;
19971
19972             default:
19973                 $this->syntaxError('PlainValue');
19974         }
19975     }
19976
19977     /**
19978      * FieldAssignment ::= FieldName "=" PlainValue
19979      * FieldName ::= identifier
19980      *
19981      * @return array
19982      */
19983     public function FieldAssignment()
19984     {
19985         $this->match(Lexer::T_IDENTIFIER);
19986         $fieldName = $this->lexer->token['value'];
19987         $this->match(Lexer::T_EQUALS);
19988
19989         return array($fieldName => $this->PlainValue());
19990     }
19991
19992     /**
19993      * Array ::= "{" ArrayEntry {"," ArrayEntry}* "}"
19994      *
19995      * @return array
19996      */
19997     public function Arrayx()
19998     {
19999         $array = $values = array();
20000
20001         $this->match(Lexer::T_OPEN_CURLY_BRACES);
20002         $values[] = $this->ArrayEntry();
20003
20004         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
20005             $this->match(Lexer::T_COMMA);
20006             $values[] = $this->ArrayEntry();
20007         }
20008
20009         $this->match(Lexer::T_CLOSE_CURLY_BRACES);
20010
20011         foreach ($values as $value) {
20012             list ($key, $val) = $value;
20013
20014             if ($key !== null) {
20015                 $array[$key] = $val;
20016             } else {
20017                 $array[] = $val;
20018             }
20019         }
20020
20021         return $array;
20022     }
20023
20024     /**
20025      * ArrayEntry ::= Value | KeyValuePair
20026      * KeyValuePair ::= Key "=" PlainValue
20027      * Key ::= string | integer
20028      *
20029      * @return array
20030      */
20031     public function ArrayEntry()
20032     {
20033         $peek = $this->lexer->glimpse();
20034
20035         if ($peek['value'] == '=') {
20036             $this->match(
20037                 $this->lexer->isNextToken(Lexer::T_INTEGER) ? Lexer::T_INTEGER : Lexer::T_STRING
20038             );
20039
20040             $key = $this->lexer->token['value'];
20041             $this->match(Lexer::T_EQUALS);
20042
20043             return array($key, $this->PlainValue());
20044         }
20045
20046         return array(null, $this->Value());
20047     }
20048
20049     /**
20050      * Constructs a new annotation with a given map of values.
20051      *
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.
20055      *
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.
20059      */
20060     protected function newAnnotation($name, array $values)
20061     {
20062         return new $name($values);
20063     }
20064 }<?php
20065 /*
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.
20077  *
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>.
20081  */
20082
20083 namespace Doctrine\Common\Annotations;
20084
20085 /**
20086  * Simple lexer for docblock annotations.
20087  *
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.
20092  *
20093  * @since   2.0
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>
20098  */
20099 class Lexer extends \Doctrine\Common\Lexer
20100 {
20101     const T_NONE                = 1;
20102     const T_IDENTIFIER          = 2;
20103     const T_INTEGER             = 3;
20104     const T_STRING              = 4;
20105     const T_FLOAT               = 5;
20106     
20107     const T_AT                  = 101;
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;
20117     
20118     /**
20119      * @inheritdoc
20120      */
20121     protected function getCatchablePatterns()
20122     {
20123         return array(
20124             '[a-z_][a-z0-9_:]*',
20125             '(?:[0-9]+(?:[\.][0-9]+)*)(?:e[+-]?[0-9]+)?',
20126             '"(?:[^"]|"")*"'
20127         );
20128     }
20129     
20130     /**
20131      * @inheritdoc
20132      */
20133     protected function getNonCatchablePatterns()
20134     {
20135         return array('\s+', '\*+', '(.)');
20136     }
20137
20138     /**
20139      * @inheritdoc
20140      */
20141     protected function getType(&$value)
20142     {
20143         $type = self::T_NONE;
20144         $newVal = $this->getNumeric($value);
20145         
20146         // Checking numeric value
20147         if ($newVal !== false) {
20148             $value = $newVal;
20149             
20150             return (strpos($value, '.') !== false || stripos($value, 'e') !== false)
20151                 ? self::T_FLOAT : self::T_INTEGER;
20152         }
20153         
20154         if ($value[0] === '"') {
20155             $value = str_replace('""', '"', substr($value, 1, strlen($value) - 2));
20156             
20157             return self::T_STRING;
20158         } else {
20159             switch (strtolower($value)) {
20160                 case '@': 
20161                     return self::T_AT;
20162
20163                 case ',': 
20164                     return self::T_COMMA;
20165
20166                 case '(': 
20167                     return self::T_OPEN_PARENTHESIS;
20168
20169                 case ')': 
20170                     return self::T_CLOSE_PARENTHESIS;
20171
20172                 case '{': 
20173                     return self::T_OPEN_CURLY_BRACES;
20174
20175                 case '}': return self::T_CLOSE_CURLY_BRACES;
20176                 case '=': 
20177                     return self::T_EQUALS;
20178
20179                 case '\\': 
20180                     return self::T_NAMESPACE_SEPARATOR;
20181
20182                 case 'true': 
20183                     return self::T_TRUE;
20184
20185                 case 'false': 
20186                     return self::T_FALSE;
20187
20188                 default:
20189                     if (ctype_alpha($value[0]) || $value[0] === '_') {
20190                         return self::T_IDENTIFIER;
20191                     }
20192                     
20193                     break;
20194             }
20195         }
20196
20197         return $type;
20198     }
20199
20200     /**
20201      * Checks if a value is numeric or not
20202      *
20203      * @param mixed $value Value to be inspected
20204      * @return boolean|integer|float Processed value
20205      * @todo Inline
20206      */
20207     private function getNumeric($value)
20208     {
20209         if ( ! is_scalar($value)) {
20210             return false;
20211         }
20212
20213         // Checking for valid numeric numbers: 1.234, -1.234e-2
20214         if (is_numeric($value)) {
20215             return $value;
20216         }
20217
20218         return false;
20219     }
20220 }<?php
20221 /*
20222  *  $Id$
20223  *
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.
20235  *
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>.
20239  */
20240
20241 namespace Doctrine\Common\Annotations;
20242
20243 /**
20244  * Annotations class
20245  *
20246  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
20247  * @link    www.doctrine-project.org
20248  * @since   2.0
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>
20254  */
20255 class Annotation
20256 {
20257     /**
20258      * Value property. Common among all derived classes.
20259      *
20260      * @var string
20261      */
20262     public $value;
20263
20264     /**
20265      * Constructor
20266      *
20267      * @param array $data Key-value for properties to be defined in this class
20268      */
20269     public final function __construct(array $data)
20270     {
20271         foreach ($data as $key => $value) {
20272             $this->$key = $value;
20273         }
20274     }
20275
20276     /**
20277      * Error handler for unknown property accessor in Annotation class.
20278      *
20279      * @param string $name Unknown property name
20280      */
20281     public function __get($name)
20282     {
20283         throw new \BadMethodCallException(
20284             sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
20285         );
20286     }
20287     
20288     /**
20289      * Error handler for unknown property mutator in Annotation class.
20290      *
20291      * @param string $name Unkown property name
20292      * @param mixed $value Property value
20293      */
20294     public function __set($name, $value)
20295     {
20296         throw new \BadMethodCallException(
20297             sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
20298         );
20299     }
20300 }<?php
20301 /*
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.
20313  *
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>.
20317  */
20318
20319 namespace Doctrine\Common;
20320
20321 /**
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.
20326  * 
20327  * If no include path is configured through the constructor or {@link setIncludePath}, a ClassLoader
20328  * relies on the PHP <code>include_path</code>.
20329  * 
20330  * @author Roman Borschel <roman@code-factory.org>
20331  * @since 2.0
20332  */
20333 class ClassLoader
20334 {
20335     private $fileExtension = '.php';
20336     private $namespace;
20337     private $includePath;
20338     private $namespaceSeparator = '\\';
20339
20340     /**
20341      * Creates a new <tt>ClassLoader</tt> that loads classes of the
20342      * specified namespace from the specified include path.
20343      *
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.
20347      * 
20348      * @param string $ns The namespace of the classes to load.
20349      * @param string $includePath The base include path to use.
20350      */
20351     public function __construct($ns = null, $includePath = null)
20352     {
20353         $this->namespace = $ns;
20354         $this->includePath = $includePath;
20355     }
20356
20357     /**
20358      * Sets the namespace separator used by classes in the namespace of this ClassLoader.
20359      * 
20360      * @param string $sep The separator to use.
20361      */
20362     public function setNamespaceSeparator($sep)
20363     {
20364         $this->namespaceSeparator = $sep;
20365     }
20366
20367     /**
20368      * Gets the namespace separator used by classes in the namespace of this ClassLoader.
20369      * 
20370      * @return string
20371      */
20372     public function getNamespaceSeparator()
20373     {
20374         return $this->namespaceSeparator;
20375     }
20376
20377     /**
20378      * Sets the base include path for all class files in the namespace of this ClassLoader.
20379      * 
20380      * @param string $includePath
20381      */
20382     public function setIncludePath($includePath)
20383     {
20384         $this->includePath = $includePath;
20385     }
20386
20387     /**
20388      * Gets the base include path for all class files in the namespace of this ClassLoader.
20389      * 
20390      * @return string
20391      */
20392     public function getIncludePath()
20393     {
20394         return $this->includePath;
20395     }
20396
20397     /**
20398      * Sets the file extension of class files in the namespace of this ClassLoader.
20399      * 
20400      * @param string $fileExtension
20401      */
20402     public function setFileExtension($fileExtension)
20403     {
20404         $this->fileExtension = $fileExtension;
20405     }
20406
20407     /**
20408      * Gets the file extension of class files in the namespace of this ClassLoader.
20409      * 
20410      * @return string
20411      */
20412     public function getFileExtension()
20413     {
20414         return $this->fileExtension;
20415     }
20416
20417     /**
20418      * Registers this ClassLoader on the SPL autoload stack.
20419      */
20420     public function register()
20421     {
20422         spl_autoload_register(array($this, 'loadClass'));
20423     }
20424
20425     /**
20426      * Removes this ClassLoader from the SPL autoload stack.
20427      */
20428     public function unregister()
20429     {
20430         spl_autoload_unregister(array($this, 'loadClass'));
20431     }
20432
20433     /**
20434      * Loads the given class or interface.
20435      *
20436      * @param string $classname The name of the class to load.
20437      * @return boolean TRUE if the class has been successfully loaded, FALSE otherwise.
20438      */
20439     public function loadClass($className)
20440     {
20441         if ($this->namespace !== null && strpos($className, $this->namespace.$this->namespaceSeparator) !== 0) {
20442             return false;
20443         }
20444
20445         require ($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '')
20446                . str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className)
20447                . $this->fileExtension;
20448         
20449         return true;
20450     }
20451
20452     /**
20453      * Asks this ClassLoader whether it can potentially load the class (file) with
20454      * the given name.
20455      *
20456      * @param string $className The fully-qualified name of the class.
20457      * @return boolean TRUE if this ClassLoader can load the class, FALSE otherwise.
20458      */
20459     public function canLoadClass($className)
20460     {
20461         if ($this->namespace !== null && strpos($className, $this->namespace.$this->namespaceSeparator) !== 0) {
20462             return false;
20463         }
20464         return file_exists(($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '')
20465                . str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className)
20466                . $this->fileExtension);
20467     }
20468
20469     /**
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.
20474      *
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.
20481      *
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.
20486      *
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.
20489      */
20490     public static function classExists($className)
20491     {
20492         if (class_exists($className, false)) {
20493             return true;
20494         }
20495
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)) {
20501                             return true;
20502                         }
20503                     } else if ($loader[0]->{$loader[1]}($className)) {
20504                         return true;
20505                     }
20506                 } else if ($loader[0]::$loader[1]($className)) { // array('ClassName', 'methodName')
20507                     return true;
20508                 }
20509             } else if ($loader instanceof \Closure) { // function($className) {..}
20510                 if ($loader($className)) {
20511                     return true;
20512                 }
20513             } else if (is_string($loader) && $loader($className)) { // "MyClass::loadClass"
20514                 return true;
20515             }
20516         }
20517
20518         return false;
20519     }
20520
20521     /**
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.
20524      *
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.
20527      */
20528     public static function getClassLoader($className)
20529     {
20530          foreach (spl_autoload_functions() as $loader) {
20531             if (is_array($loader) && $loader[0] instanceof ClassLoader &&
20532                     $loader[0]->canLoadClass($className)) {
20533                 return $loader[0];
20534             }
20535         }
20536
20537         return null;
20538     }
20539 }<?php
20540 /*
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.
20552  *
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>.
20556  */
20557
20558 namespace Doctrine\Common\Collections;
20559
20560 use Closure, ArrayIterator;
20561
20562 /**
20563  * An ArrayCollection is a Collection implementation that wraps a regular PHP array.
20564  *
20565  * @since   2.0
20566  * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
20567  * @author  Jonathan Wage <jonwage@gmail.com>
20568  * @author  Roman Borschel <roman@code-factory.org>
20569  */
20570 class ArrayCollection implements Collection
20571 {
20572     /**
20573      * An array containing the entries of this collection.
20574      *
20575      * @var array
20576      */
20577     private $_elements;
20578
20579     /**
20580      * Initializes a new ArrayCollection.
20581      *
20582      * @param array $elements
20583      */
20584     public function __construct(array $elements = array())
20585     {
20586         $this->_elements = $elements;
20587     }
20588
20589     /**
20590      * Gets the PHP array representation of this collection.
20591      *
20592      * @return array The PHP array representation of this collection.
20593      */
20594     public function toArray()
20595     {
20596         return $this->_elements;
20597     }
20598
20599     /**
20600      * Sets the internal iterator to the first element in the collection and
20601      * returns this element.
20602      *
20603      * @return mixed
20604      */
20605     public function first()
20606     {
20607         return reset($this->_elements);
20608     }
20609
20610     /**
20611      * Sets the internal iterator to the last element in the collection and
20612      * returns this element.
20613      *
20614      * @return mixed
20615      */
20616     public function last()
20617     {
20618         return end($this->_elements);
20619     }
20620
20621     /**
20622      * Gets the current key/index at the current internal iterator position.
20623      *
20624      * @return mixed
20625      */
20626     public function key()
20627     {
20628         return key($this->_elements);
20629     }
20630     
20631     /**
20632      * Moves the internal iterator position to the next element.
20633      *
20634      * @return mixed
20635      */
20636     public function next()
20637     {
20638         return next($this->_elements);
20639     }
20640     
20641     /**
20642      * Gets the element of the collection at the current internal iterator position.
20643      *
20644      * @return mixed
20645      */
20646     public function current()
20647     {
20648         return current($this->_elements);
20649     }
20650
20651     /**
20652      * Removes an element with a specific key/index from the collection.
20653      *
20654      * @param mixed $key
20655      * @return mixed The removed element or NULL, if no element exists for the given key.
20656      */
20657     public function remove($key)
20658     {
20659         if (isset($this->_elements[$key])) {
20660             $removed = $this->_elements[$key];
20661             unset($this->_elements[$key]);
20662             
20663             return $removed;
20664         }
20665
20666         return null;
20667     }
20668
20669     /**
20670      * Removes the specified element from the collection, if it is found.
20671      *
20672      * @param mixed $element The element to remove.
20673      * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
20674      */
20675     public function removeElement($element)
20676     {
20677         $key = array_search($element, $this->_elements, true);
20678         
20679         if ($key !== false) {
20680             unset($this->_elements[$key]);
20681             
20682             return true;
20683         }
20684         
20685         return false;
20686     }
20687
20688     /**
20689      * ArrayAccess implementation of offsetExists()
20690      *
20691      * @see containsKey()
20692      */
20693     public function offsetExists($offset)
20694     {
20695         return $this->containsKey($offset);
20696     }
20697
20698     /**
20699      * ArrayAccess implementation of offsetGet()
20700      *
20701      * @see get()
20702      */
20703     public function offsetGet($offset)
20704     {
20705         return $this->get($offset);
20706     }
20707
20708     /**
20709      * ArrayAccess implementation of offsetGet()
20710      *
20711      * @see add()
20712      * @see set()
20713      */
20714     public function offsetSet($offset, $value)
20715     {
20716         if ( ! isset($offset)) {
20717             return $this->add($value);
20718         }
20719         return $this->set($offset, $value);
20720     }
20721
20722     /**
20723      * ArrayAccess implementation of offsetUnset()
20724      *
20725      * @see remove()
20726      */
20727     public function offsetUnset($offset)
20728     {
20729         return $this->remove($offset);
20730     }
20731
20732     /**
20733      * Checks whether the collection contains a specific key/index.
20734      *
20735      * @param mixed $key The key to check for.
20736      * @return boolean TRUE if the given key/index exists, FALSE otherwise.
20737      */
20738     public function containsKey($key)
20739     {
20740         return isset($this->_elements[$key]);
20741     }
20742
20743     /**
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.
20748      *
20749      * @param mixed $element
20750      * @return boolean TRUE if the given element is contained in the collection,
20751      *          FALSE otherwise.
20752      */
20753     public function contains($element)
20754     {
20755         return in_array($element, $this->_elements, true);
20756     }
20757
20758     /**
20759      * Tests for the existance of an element that satisfies the given predicate.
20760      *
20761      * @param Closure $p The predicate.
20762      * @return boolean TRUE if the predicate is TRUE for at least one element, FALSE otherwise.
20763      */
20764     public function exists(Closure $p)
20765     {
20766         foreach ($this->_elements as $key => $element)
20767             if ($p($key, $element)) return true;
20768         return false;
20769     }
20770
20771     /**
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.
20776      *
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.
20779      */
20780     public function indexOf($element)
20781     {
20782         return array_search($element, $this->_elements, true);
20783     }
20784
20785     /**
20786      * Gets the element with the given key/index.
20787      *
20788      * @param mixed $key The key.
20789      * @return mixed The element or NULL, if no element exists for the given key.
20790      */
20791     public function get($key)
20792     {
20793         if (isset($this->_elements[$key])) {
20794             return $this->_elements[$key];
20795         }
20796         return null;
20797     }
20798
20799     /**
20800      * Gets all keys/indexes of the collection elements.
20801      *
20802      * @return array
20803      */
20804     public function getKeys()
20805     {
20806         return array_keys($this->_elements);
20807     }
20808
20809     /**
20810      * Gets all elements.
20811      *
20812      * @return array
20813      */
20814     public function getValues()
20815     {
20816         return array_values($this->_elements);
20817     }
20818
20819     /**
20820      * Returns the number of elements in the collection.
20821      *
20822      * Implementation of the Countable interface.
20823      *
20824      * @return integer The number of elements in the collection.
20825      */
20826     public function count()
20827     {
20828         return count($this->_elements);
20829     }
20830
20831     /**
20832      * Adds/sets an element in the collection at the index / with the specified key.
20833      *
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).
20836      *
20837      * @param mixed $key
20838      * @param mixed $value
20839      */
20840     public function set($key, $value)
20841     {
20842         $this->_elements[$key] = $value;
20843     }
20844
20845     /**
20846      * Adds an element to the collection.
20847      *
20848      * @param mixed $value
20849      * @return boolean Always TRUE.
20850      */
20851     public function add($value)
20852     {
20853         $this->_elements[] = $value;
20854         return true;
20855     }
20856
20857     /**
20858      * Checks whether the collection is empty.
20859      * 
20860      * Note: This is preferrable over count() == 0.
20861      *
20862      * @return boolean TRUE if the collection is empty, FALSE otherwise.
20863      */
20864     public function isEmpty()
20865     {
20866         return ! $this->_elements;
20867     }
20868
20869     /**
20870      * Gets an iterator for iterating over the elements in the collection.
20871      *
20872      * @return ArrayIterator
20873      */
20874     public function getIterator()
20875     {
20876         return new ArrayIterator($this->_elements);
20877     }
20878
20879     /**
20880      * Applies the given function to each element in the collection and returns
20881      * a new collection with the elements returned by the function.
20882      *
20883      * @param Closure $func
20884      * @return Collection
20885      */
20886     public function map(Closure $func)
20887     {
20888         return new ArrayCollection(array_map($func, $this->_elements));
20889     }
20890
20891     /**
20892      * Returns all the elements of this collection that satisfy the predicate p.
20893      * The order of the elements is preserved.
20894      *
20895      * @param Closure $p The predicate used for filtering.
20896      * @return Collection A collection with the results of the filter operation.
20897      */
20898     public function filter(Closure $p)
20899     {
20900         return new ArrayCollection(array_filter($this->_elements, $p));
20901     }
20902
20903     /**
20904      * Applies the given predicate p to all elements of this collection,
20905      * returning true, if the predicate yields true for all elements.
20906      *
20907      * @param Closure $p The predicate.
20908      * @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.
20909      */
20910     public function forAll(Closure $p)
20911     {
20912         foreach ($this->_elements as $key => $element) {
20913             if ( ! $p($key, $element)) {
20914                 return false;
20915             }
20916         }
20917         
20918         return true;
20919     }
20920
20921     /**
20922      * Partitions this collection in two collections according to a predicate.
20923      * Keys are preserved in the resulting collections.
20924      *
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.
20929      */
20930     public function partition(Closure $p)
20931     {
20932         $coll1 = $coll2 = array();
20933         foreach ($this->_elements as $key => $element) {
20934             if ($p($key, $element)) {
20935                 $coll1[$key] = $element;
20936             } else {
20937                 $coll2[$key] = $element;
20938             }
20939         }
20940         return array(new ArrayCollection($coll1), new ArrayCollection($coll2));
20941     }
20942
20943     /**
20944      * Returns a string representation of this object.
20945      *
20946      * @return string
20947      */
20948     public function __toString()
20949     {
20950         return __CLASS__ . '@' . spl_object_hash($this);
20951     }
20952
20953     /**
20954      * Clears the collection.
20955      */
20956     public function clear()
20957     {
20958         $this->_elements = array();
20959     }
20960
20961     /**
20962      * Extract a slice of $length elements starting at position $offset from the Collection.
20963      *
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.
20967      *
20968      * @param int $offset
20969      * @param int $length
20970      * @return array
20971      */
20972     public function slice($offset, $length = null)
20973     {
20974         return array_slice($this->_elements, $offset, $length, true);
20975     }
20976 }
20977 <?php
20978 /*
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.
20990  *
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>.
20994  */
20995
20996 namespace Doctrine\Common\Collections;
20997
20998 use Closure, Countable, IteratorAggregate, ArrayAccess;
20999
21000 /**
21001  * The missing (SPL) Collection/Array/OrderedMap interface.
21002  * 
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
21005  * like a list.
21006  * 
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.
21016  * 
21017  * @since   2.0
21018  * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
21019  * @author  Jonathan Wage <jonwage@gmail.com>
21020  * @author  Roman Borschel <roman@code-factory.org>
21021  */
21022 interface Collection extends Countable, IteratorAggregate, ArrayAccess
21023 {
21024     /**
21025      * Adds an element at the end of the collection.
21026      *
21027      * @param mixed $element The element to add.
21028      * @return boolean Always TRUE.
21029      */
21030     function add($element);
21031     
21032     /**
21033      * Clears the collection, removing all elements.
21034      */
21035     function clear();
21036
21037     /**
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.
21040      *
21041      * @param mixed $element The element to search for.
21042      * @return boolean TRUE if the collection contains the element, FALSE otherwise.
21043      */
21044     function contains($element);
21045
21046     /**
21047      * Checks whether the collection is empty (contains no elements).
21048      *
21049      * @return boolean TRUE if the collection is empty, FALSE otherwise.
21050      */
21051     function isEmpty();
21052
21053     /**
21054      * Removes the element at the specified index from the collection.
21055      * 
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.
21058      */
21059     function remove($key);
21060
21061     /**
21062      * Removes the specified element from the collection, if it is found.
21063      *
21064      * @param mixed $element The element to remove.
21065      * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
21066      */
21067     function removeElement($element);
21068
21069     /**
21070      * Checks whether the collection contains an element with the specified key/index.
21071      * 
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,
21074      *          FALSE otherwise.
21075      */
21076     function containsKey($key);
21077
21078     /**
21079      * Gets the element at the specified key/index.
21080      * 
21081      * @param string|integer $key The key/index of the element to retrieve.
21082      * @return mixed
21083      */
21084     function get($key);
21085
21086     /**
21087      * Gets all keys/indices of the collection.
21088      *
21089      * @return array The keys/indices of the collection, in the order of the corresponding
21090      *          elements in the collection.
21091      */
21092     function getKeys();
21093
21094     /**
21095      * Gets all values of the collection. 
21096      * 
21097      * @return array The values of all elements in the collection, in the order they
21098      *          appear in the collection.
21099      */
21100     function getValues();
21101
21102     /**
21103      * Sets an element in the collection at the specified key/index.
21104      * 
21105      * @param string|integer $key The key/index of the element to set.
21106      * @param mixed $value The element to set.
21107      */
21108     function set($key, $value);
21109
21110     /**
21111      * Gets a native PHP array representation of the collection.
21112      * 
21113      * @return array
21114      */
21115     function toArray();
21116
21117     /**
21118      * Sets the internal iterator to the first element in the collection and
21119      * returns this element.
21120      *
21121      * @return mixed
21122      */
21123     function first();
21124
21125     /**
21126      * Sets the internal iterator to the last element in the collection and
21127      * returns this element.
21128      *
21129      * @return mixed
21130      */
21131     function last();
21132
21133     /**
21134      * Gets the key/index of the element at the current iterator position.
21135      *
21136      */
21137     function key();
21138
21139     /**
21140      * Gets the element of the collection at the current iterator position.
21141      *
21142      */
21143     function current();
21144
21145     /**
21146      * Moves the internal iterator position to the next element.
21147      *
21148      */
21149     function next();
21150
21151     /**
21152      * Tests for the existence of an element that satisfies the given predicate.
21153      *
21154      * @param Closure $p The predicate.
21155      * @return boolean TRUE if the predicate is TRUE for at least one element, FALSE otherwise.
21156      */
21157     function exists(Closure $p);
21158
21159     /**
21160      * Returns all the elements of this collection that satisfy the predicate p.
21161      * The order of the elements is preserved.
21162      *
21163      * @param Closure $p The predicate used for filtering.
21164      * @return Collection A collection with the results of the filter operation.
21165      */
21166     function filter(Closure $p);
21167
21168     /**
21169      * Applies the given predicate p to all elements of this collection,
21170      * returning true, if the predicate yields true for all elements.
21171      *
21172      * @param Closure $p The predicate.
21173      * @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.
21174      */
21175     function forAll(Closure $p);
21176
21177     /**
21178      * Applies the given function to each element in the collection and returns
21179      * a new collection with the elements returned by the function.
21180      *
21181      * @param Closure $func
21182      * @return Collection
21183      */
21184     function map(Closure $func);
21185
21186     /**
21187      * Partitions this collection in two collections according to a predicate.
21188      * Keys are preserved in the resulting collections.
21189      *
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.
21194      */
21195     function partition(Closure $p);
21196
21197     /**
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.
21201      *
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.
21204      */
21205     function indexOf($element);
21206
21207     /**
21208      * Extract a slice of $length elements starting at position $offset from the Collection.
21209      *
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.
21213      *
21214      * @param int $offset
21215      * @param int $length
21216      * @return array
21217      */
21218     public function slice($offset, $length = null);
21219 }<?php
21220 /*
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.
21232  *
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>.
21236  */
21237  
21238 namespace Doctrine\Common;
21239
21240 /**
21241  * Class to store and retrieve the version of Doctrine
21242  *
21243  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21244  * @link    www.doctrine-project.org
21245  * @since   2.0
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>
21251  */
21252 class Version
21253 {
21254     /**
21255      * Current Doctrine Version
21256      */
21257     const VERSION = '2.0.0RC2-DEV';
21258
21259     /**
21260      * Compares a Doctrine version with the current one.
21261      *
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.
21265      */
21266     public static function compare($version)
21267     {
21268         $currentVersion = str_replace(' ', '', strtolower(self::VERSION));
21269         $version = str_replace(' ', '', $version);
21270
21271         return version_compare($version, $currentVersion);
21272     }
21273 }<?php
21274 /*
21275  *  $Id$
21276  *
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.
21288  *
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>.
21292  */
21293
21294 namespace Doctrine\Common\Cache;
21295
21296 /**
21297  * Xcache cache driver.
21298  *
21299  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21300  * @link    www.doctrine-project.org
21301  * @since   2.0
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>
21308  */
21309 class XcacheCache extends AbstractCache
21310 {
21311     /**
21312      * {@inheritdoc}
21313      */
21314     public function getIds()
21315     {
21316         $this->_checkAuth();
21317         $keys = array();
21318
21319         for ($i = 0, $count = xcache_count(XC_TYPE_VAR); $i < $count; $i++) {
21320             $entries = xcache_list(XC_TYPE_VAR, $i);
21321
21322             if (is_array($entries['cache_list'])) {
21323                 foreach ($entries['cache_list'] as $entry) {
21324                     $keys[] = $entry['name'];
21325                 }
21326             }
21327         }
21328
21329         return $keys;
21330     }
21331
21332     /**
21333      * {@inheritdoc}
21334      */
21335     protected function _doFetch($id)
21336     {
21337         return $this->_doContains($id) ? unserialize(xcache_get($id)) : false;
21338     }
21339
21340     /**
21341      * {@inheritdoc}
21342      */
21343     protected function _doContains($id)
21344     {
21345         return xcache_isset($id);
21346     }
21347
21348     /**
21349      * {@inheritdoc}
21350      */
21351     protected function _doSave($id, $data, $lifeTime = 0)
21352     {
21353         return xcache_set($id, serialize($data), (int) $lifeTime);
21354     }
21355
21356     /**
21357      * {@inheritdoc}
21358      */
21359     protected function _doDelete($id)
21360     {
21361         return xcache_unset($id);
21362     }
21363
21364
21365     /**
21366      * Checks that xcache.admin.enable_auth is Off
21367      *
21368      * @throws \BadMethodCallException When xcache.admin.enable_auth is On
21369      * @return void
21370      */
21371     protected function _checkAuth()
21372     {
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.');
21375         }
21376     }
21377 }<?php
21378 /*
21379  *  $Id$
21380  *
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.
21392  *
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>.
21396  */
21397
21398 namespace Doctrine\Common\Cache;
21399
21400 /**
21401  * Array cache driver.
21402  *
21403  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21404  * @link    www.doctrine-project.org
21405  * @since   2.0
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>
21412  */
21413 class ArrayCache extends AbstractCache
21414 {
21415     /**
21416      * @var array $data
21417      */
21418     private $data = array();
21419
21420     /**
21421      * {@inheritdoc}
21422      */
21423     public function getIds()
21424     {
21425         return array_keys($this->data);
21426     }
21427
21428     /**
21429      * {@inheritdoc}
21430      */
21431     protected function _doFetch($id)
21432     {
21433         if (isset($this->data[$id])) {
21434             return $this->data[$id];
21435         }
21436
21437         return false;
21438     }
21439
21440     /**
21441      * {@inheritdoc}
21442      */
21443     protected function _doContains($id)
21444     {
21445         return isset($this->data[$id]);
21446     }
21447
21448     /**
21449      * {@inheritdoc}
21450      */
21451     protected function _doSave($id, $data, $lifeTime = 0)
21452     {
21453         $this->data[$id] = $data;
21454
21455         return true;
21456     }
21457
21458     /**
21459      * {@inheritdoc}
21460      */
21461     protected function _doDelete($id)
21462     {
21463         unset($this->data[$id]);
21464         
21465         return true;
21466     }
21467 }<?php
21468 /*
21469  *  $Id$
21470  *
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.
21482  *
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>.
21486  */
21487
21488 namespace Doctrine\Common\Cache;
21489
21490 use \Memcache;
21491
21492 /**
21493  * Memcache cache driver.
21494  *
21495  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21496  * @link    www.doctrine-project.org
21497  * @since   2.0
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>
21504  */
21505 class MemcacheCache extends AbstractCache
21506 {
21507     /**
21508      * @var Memcache
21509      */
21510     private $_memcache;
21511
21512     /**
21513      * Sets the memcache instance to use.
21514      *
21515      * @param Memcache $memcache
21516      */
21517     public function setMemcache(Memcache $memcache)
21518     {
21519         $this->_memcache = $memcache;
21520     }
21521
21522     /**
21523      * Gets the memcache instance used by the cache.
21524      *
21525      * @return Memcache
21526      */
21527     public function getMemcache()
21528     {
21529         return $this->_memcache;
21530     }
21531
21532     /**
21533      * {@inheritdoc}
21534      */
21535     public function getIds()
21536     {
21537         $keys = array();
21538         $allSlabs = $this->_memcache->getExtendedStats('slabs');
21539
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);
21544
21545                     if ($dump) {
21546                         foreach ($dump as $entries) {
21547                             if ($entries) {
21548                                 $keys = array_merge($keys, array_keys($entries));
21549                             }
21550                         }
21551                     }
21552                 }
21553             }
21554         }
21555         return $keys;
21556     }
21557
21558     /**
21559      * {@inheritdoc}
21560      */
21561     protected function _doFetch($id)
21562     {
21563         return $this->_memcache->get($id);
21564     }
21565
21566     /**
21567      * {@inheritdoc}
21568      */
21569     protected function _doContains($id)
21570     {
21571         return (bool) $this->_memcache->get($id);
21572     }
21573
21574     /**
21575      * {@inheritdoc}
21576      */
21577     protected function _doSave($id, $data, $lifeTime = 0)
21578     {
21579         return $this->_memcache->set($id, $data, 0, (int) $lifeTime);
21580     }
21581
21582     /**
21583      * {@inheritdoc}
21584      */
21585     protected function _doDelete($id)
21586     {
21587         return $this->_memcache->delete($id);
21588     }
21589 }<?php
21590 /*
21591  *  $Id$
21592  *
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.
21604  *
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>.
21608  */
21609
21610 namespace Doctrine\Common\Cache;
21611
21612 /**
21613  * Interface for cache drivers.
21614  *
21615  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21616  * @link    www.doctrine-project.org
21617  * @since   2.0
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>
21623  */
21624 interface Cache
21625 {
21626     /**
21627      * Fetches an entry from the cache.
21628      * 
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.
21631      */
21632     function fetch($id);
21633
21634     /**
21635      * Test if an entry exists in the cache.
21636      *
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.
21639      */
21640     function contains($id);
21641
21642     /**
21643      * Puts data into the cache.
21644      *
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.
21649      */
21650     function save($id, $data, $lifeTime = 0);
21651
21652     /**
21653      * Deletes a cache entry.
21654      * 
21655      * @param string $id cache id
21656      * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise.
21657      */
21658     function delete($id);
21659 }<?php
21660 /*
21661  *  $Id$
21662  *
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.
21674  *
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>.
21678  */
21679
21680 namespace Doctrine\Common\Cache;
21681
21682 /**
21683  * APC cache driver.
21684  *
21685  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
21686  * @link    www.doctrine-project.org
21687  * @since   2.0
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
21695  */
21696 class ApcCache extends AbstractCache
21697 {
21698     /**
21699      * {@inheritdoc}
21700      */
21701     public function getIds()
21702     {
21703         $ci = apc_cache_info('user');
21704         $keys = array();
21705
21706         foreach ($ci['cache_list'] as $entry) {
21707             $keys[] = $entry['info'];
21708         }
21709
21710         return $keys;
21711     }
21712
21713     /**
21714      * {@inheritdoc}
21715      */
21716     protected function _doFetch($id)
21717     {
21718         return apc_fetch($id);
21719     }
21720
21721     /**
21722      * {@inheritdoc}
21723      */
21724     protected function _doContains($id)
21725     {
21726         $found = false;
21727
21728         apc_fetch($id, $found);
21729
21730         return $found;
21731     }
21732
21733     /**
21734      * {@inheritdoc}
21735      */
21736     protected function _doSave($id, $data, $lifeTime = 0)
21737     {
21738         return (bool) apc_store($id, $data, (int) $lifeTime);
21739     }
21740
21741     /**
21742      * {@inheritdoc}
21743      */
21744     protected function _doDelete($id)
21745     {
21746         return apc_delete($id);
21747     }
21748 }<?php
21749 /*
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.
21761  *
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>.
21765  */
21766
21767 namespace Doctrine\Common\Cache;
21768
21769 /**
21770  * Base class for cache driver implementations.
21771  *
21772  * @since 2.0
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>
21777  */
21778 abstract class AbstractCache implements Cache
21779 {
21780     /** @var string The cache id to store the index of cache ids under */
21781     private $_cacheIdsIndexId = 'doctrine_cache_ids';
21782
21783     /** @var string The namespace to prefix all cache ids with */
21784     private $_namespace = null;
21785
21786     /**
21787      * Set the namespace to prefix all cache ids with.
21788      *
21789      * @param string $namespace
21790      * @return void
21791      */
21792     public function setNamespace($namespace)
21793     {
21794         $this->_namespace = $namespace;
21795     }
21796
21797     /**
21798      * {@inheritdoc}
21799      */
21800     public function fetch($id)
21801     {
21802         return $this->_doFetch($this->_getNamespacedId($id));
21803     }
21804
21805     /**
21806      * {@inheritdoc}
21807      */
21808     public function contains($id)
21809     {
21810         return $this->_doContains($this->_getNamespacedId($id));
21811     }
21812
21813     /**
21814      * {@inheritdoc}
21815      */
21816     public function save($id, $data, $lifeTime = 0)
21817     {
21818         return $this->_doSave($this->_getNamespacedId($id), $data, $lifeTime);
21819     }
21820
21821     /**
21822      * {@inheritdoc}
21823      */
21824     public function delete($id)
21825     {
21826         $id = $this->_getNamespacedId($id);
21827
21828         if (strpos($id, '*') !== false) {
21829             return $this->deleteByRegex('/' . str_replace('*', '.*', $id) . '/');
21830         }
21831
21832         return $this->_doDelete($id);
21833     }
21834
21835     /**
21836      * Delete all cache entries.
21837      *
21838      * @return array $deleted  Array of the deleted cache ids
21839      */
21840     public function deleteAll()
21841     {
21842         $ids = $this->getIds();
21843
21844         foreach ($ids as $id) {
21845             $this->delete($id);
21846         }
21847
21848         return $ids;
21849     }
21850
21851     /**
21852      * Delete cache entries where the id matches a PHP regular expressions
21853      *
21854      * @param string $regex
21855      * @return array $deleted  Array of the deleted cache ids
21856      */
21857     public function deleteByRegex($regex)
21858     {
21859         $deleted = array();
21860
21861         $ids = $this->getIds();
21862
21863         foreach ($ids as $id) {
21864             if (preg_match($regex, $id)) {
21865                 $this->delete($id);
21866                 $deleted[] = $id;
21867             }
21868         }
21869
21870         return $deleted;
21871     }
21872
21873     /**
21874      * Delete cache entries where the id has the passed prefix
21875      *
21876      * @param string $prefix
21877      * @return array $deleted  Array of the deleted cache ids
21878      */
21879     public function deleteByPrefix($prefix)
21880     {
21881         $deleted = array();
21882
21883         $prefix = $this->_getNamespacedId($prefix);
21884         $ids = $this->getIds();
21885
21886         foreach ($ids as $id) {
21887             if (strpos($id, $prefix) === 0) {
21888                 $this->delete($id);
21889                 $deleted[] = $id;
21890             }
21891         }
21892
21893         return $deleted;
21894     }
21895
21896     /**
21897      * Delete cache entries where the id has the passed suffix
21898      *
21899      * @param string $suffix
21900      * @return array $deleted  Array of the deleted cache ids
21901      */
21902     public function deleteBySuffix($suffix)
21903     {
21904         $deleted = array();
21905
21906         $ids = $this->getIds();
21907
21908         foreach ($ids as $id) {
21909             if (substr($id, -1 * strlen($suffix)) === $suffix) {
21910                 $this->delete($id);
21911                 $deleted[] = $id;
21912             }
21913         }
21914
21915         return $deleted;
21916     }
21917
21918     /**
21919      * Prefix the passed id with the configured namespace value
21920      *
21921      * @param string $id  The id to namespace
21922      * @return string $id The namespaced id
21923      */
21924     private function _getNamespacedId($id)
21925     {
21926         if ( ! $this->_namespace || strpos($id, $this->_namespace) === 0) {
21927             return $id;
21928         } else {
21929             return $this->_namespace . $id;
21930         }
21931     }
21932
21933     /**
21934      * Fetches an entry from the cache.
21935      *
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.
21938      */
21939     abstract protected function _doFetch($id);
21940
21941     /**
21942      * Test if an entry exists in the cache.
21943      *
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.
21946      */
21947     abstract protected function _doContains($id);
21948
21949     /**
21950      * Puts data into the cache.
21951      *
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.
21956      */
21957     abstract protected function _doSave($id, $data, $lifeTime = false);
21958
21959     /**
21960      * Deletes a cache entry.
21961      *
21962      * @param string $id cache id
21963      * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise.
21964      */
21965     abstract protected function _doDelete($id);
21966
21967     /**
21968      * Get an array of all the cache ids stored
21969      *
21970      * @return array $ids
21971      */
21972     abstract public function getIds();
21973 }<?php
21974 /*
21975  *  $Id$
21976  *
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.
21988  *
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>.
21992  */
21993
21994 namespace Doctrine\Common\Util;
21995
21996 /**
21997  * Static class containing most used debug methods.
21998  *
21999  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22000  * @link    www.doctrine-project.org
22001  * @since   2.0
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>
22007  */
22008 final class Debug
22009 {
22010     /**
22011      * Private constructor (prevents from instantiation)
22012      *
22013      */
22014     private function __construct() {}
22015
22016     /**
22017      * Prints a dump of the public, protected and private properties of $var.
22018      *
22019      * @static
22020      * @link http://xdebug.org/
22021      * @param mixed $var
22022      * @param integer $maxDepth Maximum nesting level for object properties
22023      */
22024     public static function dump($var, $maxDepth = 2)
22025     {
22026         ini_set('html_errors', 'On');
22027         
22028         if (extension_loaded('xdebug')) {
22029             ini_set('xdebug.var_display_max_depth', $maxDepth);
22030         }
22031         
22032         $var = self::export($var, $maxDepth++);
22033         
22034         ob_start();
22035         var_dump($var);
22036         $dump = ob_get_contents();
22037         ob_end_clean();
22038         
22039         echo strip_tags(html_entity_decode($dump));
22040         
22041         ini_set('html_errors', 'Off');
22042     }
22043     
22044     public static function export($var, $maxDepth)
22045     {
22046         $return = null;
22047         $isObj = is_object($var);
22048     
22049         if ($isObj && in_array('Doctrine\Common\Collections\Collection', class_implements($var))) {
22050             $var = $var->toArray();
22051         }
22052         
22053         if ($maxDepth) {
22054             if (is_array($var)) {
22055                 $return = array();
22056             
22057                 foreach ($var as $k => $v) {
22058                     $return[$k] = self::export($v, $maxDepth - 1);
22059                 }
22060             } else if ($isObj) {
22061                 if ($var instanceof \DateTime) {
22062                     $return = $var->format('c');
22063                 } else {
22064                     $reflClass = new \ReflectionClass(get_class($var));
22065                     $return = new \stdclass();
22066                     $return->{'__CLASS__'} = get_class($var);
22067
22068                     if ($var instanceof \Doctrine\ORM\Proxy\Proxy && ! $var->__isInitialized__) {
22069                         $reflProperty = $reflClass->getProperty('_identifier');
22070                         $reflProperty->setAccessible(true);
22071
22072                         foreach ($reflProperty->getValue($var) as $name => $value) {
22073                             $return->$name = self::export($value, $maxDepth - 1);
22074                         }
22075                     } else {
22076                         $excludeProperties = array();
22077
22078                         if ($var instanceof \Doctrine\ORM\Proxy\Proxy) {
22079                             $excludeProperties = array('_entityPersister', '__isInitialized__', '_identifier');
22080                         }
22081
22082                         foreach ($reflClass->getProperties() as $reflProperty) {
22083                             $name  = $reflProperty->getName();
22084
22085                             if ( ! in_array($name, $excludeProperties)) {
22086                                 $reflProperty->setAccessible(true);
22087
22088                                 $return->$name = self::export($reflProperty->getValue($var), $maxDepth - 1);
22089                             }
22090                         }
22091                     }
22092                 }
22093             } else {
22094                 $return = $var;
22095             }
22096         } else {
22097             $return = is_object($var) ? get_class($var) 
22098                 : (is_array($var) ? 'Array(' . count($var) . ')' : $var);
22099         }
22100         
22101         return $return;
22102     }
22103
22104     public static function toString($obj)
22105     {
22106         return method_exists('__toString', $obj) ? (string) $obj : get_class($obj) . '@' . spl_object_hash($obj);
22107     }
22108 }
22109 <?php
22110 /*
22111  *  $Id: Inflector.php 3189 2007-11-18 20:37:44Z meus $
22112  *
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.
22124  *
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>.
22128  */
22129
22130 namespace Doctrine\Common\Util;
22131
22132 /**
22133  * Doctrine inflector has static methods for inflecting text
22134  * 
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
22138  *
22139  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
22140  * @link        www.doctrine-project.org
22141  * @since       1.0
22142  * @version     $Revision: 3189 $
22143  * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
22144  * @author      Jonathan H. Wage <jonwage@gmail.com>
22145  */
22146 class Inflector
22147 {
22148     /**
22149      * Convert word in to the format for a Doctrine table name. Converts 'ModelName' to 'model_name'
22150      *
22151      * @param  string $word  Word to tableize
22152      * @return string $word  Tableized word
22153      */
22154     public static function tableize($word)
22155     {
22156         return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $word));
22157     }
22158
22159     /**
22160      * Convert a word in to the format for a Doctrine class name. Converts 'table_name' to 'TableName'
22161      *
22162      * @param string  $word  Word to classify
22163      * @return string $word  Classified word
22164      */
22165     public static function classify($word)
22166     {
22167         return str_replace(" ", "", ucwords(strtr($word, "_-", "  ")));
22168     }
22169
22170     /**
22171      * Camelize a word. This uses the classify() method and turns the first character to lowercase
22172      *
22173      * @param string $word
22174      * @return string $word
22175      */
22176     public static function camelize($word)
22177     {
22178         return lcfirst(self::classify($word));
22179     }
22180 }<?php
22181 /*
22182  *  $Id$
22183  *
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.
22195  *
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>.
22199  */
22200
22201 namespace Doctrine\Common;
22202
22203 /**
22204  * Contract for classes that provide the service of notifying listeners of
22205  * changes to their properties.
22206  *
22207  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22208  * @link    www.doctrine-project.org
22209  * @since   2.0
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>
22214  */
22215 interface NotifyPropertyChanged
22216 {
22217     /**
22218      * Adds a listener that wants to be notified about property changes.
22219      *
22220      * @param PropertyChangedListener $listener
22221      */
22222     function addPropertyChangedListener(PropertyChangedListener $listener);
22223 }
22224
22225 <?php
22226 /*
22227  *  $Id$
22228  *
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.
22240  *
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>.
22244  */
22245
22246 namespace Doctrine\Common;
22247
22248 /**
22249  * Contract for classes that are potential listeners of a <tt>NotifyPropertyChanged</tt>
22250  * implementor.
22251  *
22252  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22253  * @link    www.doctrine-project.org
22254  * @since   2.0
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>
22259  */
22260 interface PropertyChangedListener
22261 {
22262     /**
22263      * Notifies the listener of a property change.
22264      *
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.
22269      */
22270     function propertyChanged($sender, $propertyName, $oldValue, $newValue);
22271 }
22272
22273 <?php
22274 /*
22275  *  $Id$
22276  *
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.
22288  *
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>.
22292  */
22293
22294 namespace Doctrine\Common;
22295
22296 use Doctrine\Common\Events\Event;
22297
22298 /**
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
22301  * manager.
22302  * 
22303  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22304  * @link    www.doctrine-project.org
22305  * @since   2.0
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>
22310  */
22311 class EventManager
22312 {
22313     /**
22314      * Map of registered listeners.
22315      * <event> => <listeners> 
22316      *
22317      * @var array
22318      */
22319     private $_listeners = array();
22320
22321     /**
22322      * Dispatches an event to all registered listeners.
22323      *
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.
22328      * @return boolean
22329      */
22330     public function dispatchEvent($eventName, EventArgs $eventArgs = null)
22331     {
22332         if (isset($this->_listeners[$eventName])) {
22333             $eventArgs = $eventArgs === null ? EventArgs::getEmptyInstance() : $eventArgs;
22334             
22335             foreach ($this->_listeners[$eventName] as $listener) {
22336                 $listener->$eventName($eventArgs);
22337             }
22338         }
22339     }
22340
22341     /**
22342      * Gets the listeners of a specific event or all listeners.
22343      *
22344      * @param string $event The name of the event.
22345      * @return array The event listeners for the specified event, or all event listeners.
22346      */
22347     public function getListeners($event = null)
22348     {
22349         return $event ? $this->_listeners[$event] : $this->_listeners;
22350     }
22351
22352     /**
22353      * Checks whether an event has any registered listeners.
22354      *
22355      * @param string $event
22356      * @return boolean TRUE if the specified event has any listeners, FALSE otherwise.
22357      */
22358     public function hasListeners($event)
22359     {
22360         return isset($this->_listeners[$event]) && $this->_listeners[$event];
22361     }
22362
22363     /**
22364      * Adds an event listener that listens on the specified events.
22365      *
22366      * @param string|array $events The event(s) to listen on.
22367      * @param object $listener The listener object.
22368      */
22369     public function addEventListener($events, $listener)
22370     {
22371         // Picks the hash code related to that listener
22372         $hash = spl_object_hash($listener);
22373         
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;
22378         }
22379     }
22380     
22381     /**
22382      * Removes an event listener from the specified events.
22383      *
22384      * @param string|array $events
22385      * @param object $listener
22386      */
22387     public function removeEventListener($events, $listener)
22388     {
22389         // Picks the hash code related to that listener
22390         $hash = spl_object_hash($listener);
22391         
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]);
22396             }
22397         }
22398     }
22399     
22400     /**
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.
22403      * 
22404      * @param Doctrine\Common\EventSubscriber $subscriber The subscriber.
22405      */
22406     public function addEventSubscriber(EventSubscriber $subscriber)
22407     {
22408         $this->addEventListener($subscriber->getSubscribedEvents(), $subscriber);
22409     }
22410 }<?php
22411 /*
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.
22423  *
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>.
22427  */
22428  
22429 namespace Doctrine\Common;
22430
22431 /**
22432  * Base class for writing simple lexers, i.e. for creating small DSLs.
22433  *
22434  * @since   2.0
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
22439  */
22440 abstract class Lexer
22441 {
22442     /**
22443      * @var array Array of scanned tokens
22444      */
22445     private $tokens = array();
22446
22447     /**
22448      * @var integer Current lexer position in input string
22449      */
22450     private $position = 0;
22451
22452     /**
22453      * @var integer Current peek of current lexer position
22454      */
22455     private $peek = 0;
22456
22457     /**
22458      * @var array The next token in the input.
22459      */
22460     public $lookahead;
22461
22462     /**
22463      * @var array The last matched/seen token.
22464      */
22465     public $token;
22466     
22467     /**
22468      * Sets the input data to be tokenized.
22469      *
22470      * The Lexer is immediately reset and the new input tokenized.
22471      * Any unprocessed tokens from any previous input are lost.
22472      *
22473      * @param string $input The input to be tokenized.
22474      */
22475     public function setInput($input)
22476     {
22477         $this->tokens = array();
22478         $this->reset();
22479         $this->scan($input);
22480     }
22481     
22482     /**
22483      * Resets the lexer.
22484      */
22485     public function reset()
22486     {
22487         $this->lookahead = null;
22488         $this->token = null;
22489         $this->peek = 0;
22490         $this->position = 0;
22491     }
22492
22493     /**
22494      * Resets the peek pointer to 0.
22495      */
22496     public function resetPeek()
22497     {
22498         $this->peek = 0;
22499     }
22500
22501     /**
22502      * Resets the lexer position on the input to the given position.
22503      *
22504      * @param integer $position Position to place the lexical scanner
22505      */
22506     public function resetPosition($position = 0)
22507     {
22508         $this->position = $position;
22509     }
22510     
22511     /**
22512      * Checks whether a given token matches the current lookahead.
22513      *
22514      * @param integer|string $token
22515      * @return boolean
22516      */
22517     public function isNextToken($token)
22518     {
22519         return $this->lookahead['type'] === $token;
22520     }
22521
22522     /**
22523      * Moves to the next token in the input string.
22524      *
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
22528      *                 parameter, none)
22529      *  - 'position' : the position of the token in the input string
22530      *
22531      * @return array|null the next token; null if there is no more tokens left
22532      */
22533     public function moveNext()
22534     {
22535         $this->peek = 0;
22536         $this->token = $this->lookahead;
22537         $this->lookahead = (isset($this->tokens[$this->position]))
22538             ? $this->tokens[$this->position++] : null;
22539         
22540         return $this->lookahead !== null;
22541     }
22542     
22543     /**
22544      * Tells the lexer to skip input tokens until it sees a token with the given value.
22545      * 
22546      * @param $type The token type to skip until.
22547      */
22548     public function skipUntil($type)
22549     {
22550         while ($this->lookahead !== null && $this->lookahead['type'] !== $type) {
22551             $this->moveNext();
22552         }
22553     }
22554     
22555     /**
22556      * Checks if given value is identical to the given token
22557      *
22558      * @param mixed $value
22559      * @param integer $token
22560      * @return boolean
22561      */
22562     public function isA($value, $token)
22563     {
22564         return $this->getType($value) === $token;
22565     }
22566
22567     /**
22568      * Moves the lookahead token forward.
22569      *
22570      * @return array | null The next token or NULL if there are no more tokens ahead.
22571      */
22572     public function peek()
22573     {
22574         if (isset($this->tokens[$this->position + $this->peek])) {
22575             return $this->tokens[$this->position + $this->peek++];
22576         } else {
22577             return null;
22578         }
22579     }
22580
22581     /**
22582      * Peeks at the next token, returns it and immediately resets the peek.
22583      *
22584      * @return array|null The next token or NULL if there are no more tokens ahead.
22585      */
22586     public function glimpse()
22587     {
22588         $peek = $this->peek();
22589         $this->peek = 0;
22590         return $peek;
22591     }
22592     
22593     /**
22594      * Scans the input string for tokens.
22595      *
22596      * @param string $input a query string
22597      */
22598     protected function scan($input)
22599     {
22600         static $regex;
22601
22602         if ( ! isset($regex)) {
22603             $regex = '/(' . implode(')|(', $this->getCatchablePatterns()) . ')|' 
22604                    . implode('|', $this->getNonCatchablePatterns()) . '/i';
22605         }
22606
22607         $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
22608         $matches = preg_split($regex, $input, -1, $flags);
22609
22610         foreach ($matches as $match) {
22611             // Must remain before 'value' assignment since it can change content
22612             $type = $this->getType($match[0]);
22613             
22614             $this->tokens[] = array(
22615                 'value' => $match[0],
22616                 'type'  => $type,
22617                 'position' => $match[1],
22618             );
22619         }
22620     }
22621     
22622     /**
22623      * Gets the literal for a given token.
22624      *
22625      * @param integer $token
22626      * @return string
22627      */
22628     public function getLiteral($token)
22629     {
22630         $className = get_class($this);
22631         $reflClass = new \ReflectionClass($className);
22632         $constants = $reflClass->getConstants();
22633         
22634         foreach ($constants as $name => $value) {
22635             if ($value === $token) {
22636                 return $className . '::' . $name;
22637             }
22638         }
22639         
22640         return $token;
22641     }
22642     
22643     /**
22644      * Lexical catchable patterns.
22645      *
22646      * @return array
22647      */
22648     abstract protected function getCatchablePatterns();
22649     
22650     /**
22651      * Lexical non-catchable patterns.
22652      *
22653      * @return array
22654      */
22655     abstract protected function getNonCatchablePatterns();
22656     
22657     /**
22658      * Retrieve token type. Also processes the token value if necessary.
22659      *
22660      * @param string $value
22661      * @return integer
22662      */
22663     abstract protected function getType(&$value);
22664 }<?php
22665 /*
22666  *  $Id: EventListener.php 4653 2008-07-10 17:17:58Z romanb $
22667  *
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.
22679  *
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>.
22683  */
22684
22685 namespace Doctrine\Common;
22686
22687 /**
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
22691  * returned events.
22692  *
22693  * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
22694  * @link    www.doctrine-project.org
22695  * @since   2.0
22696  * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
22697  * @author  Jonathan Wage <jonwage@gmail.com>
22698  * @author  Roman Borschel <roman@code-factory.org>
22699  */
22700 interface EventSubscriber
22701 {
22702     /**
22703      * Returns an array of events this subscriber wants to listen to.
22704      *
22705      * @return array
22706      */
22707     public function getSubscribedEvents();
22708 }
22709 <?php
22710
22711 namespace Symfony\Component\Yaml;
22712
22713 /*
22714  * This file is part of the symfony package.
22715  * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
22716  *
22717  * For the full copyright and license information, please view the LICENSE
22718  * file that was distributed with this source code.
22719  */
22720
22721 /**
22722  * Yaml offers convenience methods to load and dump YAML.
22723  *
22724  * @package    symfony
22725  * @subpackage yaml
22726  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
22727  */
22728 class Yaml
22729 {
22730   static protected $spec = '1.2';
22731
22732   /**
22733    * Sets the YAML specification version to use.
22734    *
22735    * @param string $version The YAML specification version
22736    */
22737   static public function setSpecVersion($version)
22738   {
22739     if (!in_array($version, array('1.1', '1.2')))
22740     {
22741       throw new \InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version));
22742     }
22743
22744     self::$spec = $version;
22745   }
22746
22747   /**
22748    * Gets the YAML specification version to use.
22749    *
22750    * @return string The YAML specification version
22751    */
22752   static public function getSpecVersion()
22753   {
22754     return self::$spec;
22755   }
22756
22757   /**
22758    * Loads YAML into a PHP array.
22759    *
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.
22762    *
22763    *  Usage:
22764    *  <code>
22765    *   $array = Yaml::load('config.yml');
22766    *   print_r($array);
22767    *  </code>
22768    *
22769    * @param string $input Path of YAML file or string containing YAML
22770    *
22771    * @return array The YAML converted to a PHP array
22772    *
22773    * @throws \InvalidArgumentException If the YAML is not valid
22774    */
22775   public static function load($input)
22776   {
22777     $file = '';
22778
22779     // if input is a file, process it
22780     if (strpos($input, "\n") === false && is_file($input))
22781     {
22782       $file = $input;
22783
22784       ob_start();
22785       $retval = include($input);
22786       $content = ob_get_clean();
22787
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;
22790     }
22791
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))
22794     {
22795       return $input;
22796     }
22797
22798     $yaml = new Parser();
22799
22800     try
22801     {
22802       $ret = $yaml->parse($input);
22803     }
22804     catch (\Exception $e)
22805     {
22806       throw new \InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage()));
22807     }
22808
22809     return $ret;
22810   }
22811
22812   /**
22813    * Dumps a PHP array to a YAML string.
22814    *
22815    * The dump method, when supplied with an array, will do its best
22816    * to convert the array into friendly YAML.
22817    *
22818    * @param array   $array PHP array
22819    * @param integer $inline The level where you switch to inline YAML
22820    *
22821    * @return string A YAML string representing the original PHP array
22822    */
22823   public static function dump($array, $inline = 2)
22824   {
22825     $yaml = new Dumper();
22826
22827     return $yaml->dump($array, $inline);
22828   }
22829 }
22830 <?php
22831
22832 namespace Symfony\Component\Yaml;
22833
22834 /*
22835  * This file is part of the symfony package.
22836  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
22837  *
22838  * For the full copyright and license information, please view the LICENSE
22839  * file that was distributed with this source code.
22840  */
22841
22842 /**
22843  * Dumper dumps PHP variables to YAML strings.
22844  *
22845  * @package    symfony
22846  * @subpackage yaml
22847  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
22848  */
22849 class Dumper
22850 {
22851   /**
22852    * Dumps a PHP value to YAML.
22853    *
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)
22857    *
22858    * @return string  The YAML representation of the PHP value
22859    */
22860   public function dump($input, $inline = 0, $indent = 0)
22861   {
22862     $output = '';
22863     $prefix = $indent ? str_repeat(' ', $indent) : '';
22864
22865     if ($inline <= 0 || !is_array($input) || empty($input))
22866     {
22867       $output .= $prefix.Inline::dump($input);
22868     }
22869     else
22870     {
22871       $isAHash = array_keys($input) !== range(0, count($input) - 1);
22872
22873       foreach ($input as $key => $value)
22874       {
22875         $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
22876
22877         $output .= sprintf('%s%s%s%s',
22878           $prefix,
22879           $isAHash ? Inline::dump($key).':' : '-',
22880           $willBeInlined ? ' ' : "\n",
22881           $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2)
22882         ).($willBeInlined ? "\n" : '');
22883       }
22884     }
22885
22886     return $output;
22887   }
22888 }
22889 <?php
22890
22891 namespace Symfony\Component\Yaml;
22892
22893 /*
22894  * This file is part of the symfony package.
22895  *
22896  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
22897  *
22898  * For the full copyright and license information, please view the LICENSE
22899  * file that was distributed with this source code.
22900  */
22901
22902 /**
22903  * Exception class used by all exceptions thrown by the component.
22904  *
22905  * @package    symfony
22906  * @subpackage yaml
22907  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
22908  */
22909 class ParserException extends Exception
22910 {
22911 }
22912 <?php
22913
22914 namespace Symfony\Component\Yaml;
22915
22916 /*
22917  * This file is part of the symfony package.
22918  *
22919  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
22920  *
22921  * For the full copyright and license information, please view the LICENSE
22922  * file that was distributed with this source code.
22923  */
22924
22925 /**
22926  * Exception class used by all exceptions thrown by the component.
22927  *
22928  * @package    symfony
22929  * @subpackage yaml
22930  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
22931  */
22932 class Exception extends \Exception
22933 {
22934 }
22935 <?php
22936
22937 namespace Symfony\Component\Yaml;
22938
22939 /*
22940  * This file is part of the symfony package.
22941  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
22942  *
22943  * For the full copyright and license information, please view the LICENSE
22944  * file that was distributed with this source code.
22945  */
22946
22947 /**
22948  * Inline implements a YAML parser/dumper for the YAML inline syntax.
22949  *
22950  * @package    symfony
22951  * @subpackage yaml
22952  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
22953  */
22954 class Inline
22955 {
22956   const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
22957
22958   /**
22959    * Convert a YAML string to a PHP array.
22960    *
22961    * @param string $value A YAML string
22962    *
22963    * @return array A PHP array representing the YAML string
22964    */
22965   static public function load($value)
22966   {
22967     $value = trim($value);
22968
22969     if (0 == strlen($value))
22970     {
22971       return '';
22972     }
22973
22974     switch ($value[0])
22975     {
22976       case '[':
22977         return self::parseSequence($value);
22978       case '{':
22979         return self::parseMapping($value);
22980       default:
22981         return self::parseScalar($value);
22982     }
22983   }
22984
22985   /**
22986    * Dumps a given PHP variable to a YAML string.
22987    *
22988    * @param mixed $value The PHP variable to convert
22989    *
22990    * @return string The YAML string representing the PHP array
22991    */
22992   static public function dump($value)
22993   {
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');
22996
22997     switch (true)
22998     {
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:
23006         return 'null';
23007       case true === $value:
23008         return 'true';
23009       case false === $value:
23010         return 'false';
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));
23019       case '' == $value:
23020         return "''";
23021       case preg_match(self::getTimestampRegex(), $value):
23022         return "'$value'";
23023       case in_array(strtolower($value), $trueValues):
23024         return "'$value'";
23025       case in_array(strtolower($value), $falseValues):
23026         return "'$value'";
23027       case in_array(strtolower($value), array('null', '~')):
23028         return "'$value'";
23029       default:
23030         return $value;
23031     }
23032   }
23033
23034   /**
23035    * Dumps a PHP array to a YAML string.
23036    *
23037    * @param array $value The PHP array to dump
23038    *
23039    * @return string The YAML string representing the PHP array
23040    */
23041   static protected function dumpArray($value)
23042   {
23043     // array
23044     $keys = array_keys($value);
23045     if (
23046       (1 == count($keys) && '0' == $keys[0])
23047       ||
23048       (count($keys) > 1 && array_reduce($keys, function ($v, $w) { return (integer) $v + $w; }, 0) == count($keys) * (count($keys) - 1) / 2))
23049     {
23050       $output = array();
23051       foreach ($value as $val)
23052       {
23053         $output[] = self::dump($val);
23054       }
23055
23056       return sprintf('[%s]', implode(', ', $output));
23057     }
23058
23059     // mapping
23060     $output = array();
23061     foreach ($value as $key => $val)
23062     {
23063       $output[] = sprintf('%s: %s', self::dump($key), self::dump($val));
23064     }
23065
23066     return sprintf('{ %s }', implode(', ', $output));
23067   }
23068
23069   /**
23070    * Parses a scalar to a YAML string.
23071    *
23072    * @param scalar  $scalar
23073    * @param string  $delimiters
23074    * @param array   $stringDelimiter
23075    * @param integer $i
23076    * @param boolean $evaluate
23077    *
23078    * @return string A YAML string
23079    */
23080   static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
23081   {
23082     if (in_array($scalar[$i], $stringDelimiters))
23083     {
23084       // quoted scalar
23085       $output = self::parseQuotedScalar($scalar, $i);
23086     }
23087     else
23088     {
23089       // "normal" string
23090       if (!$delimiters)
23091       {
23092         $output = substr($scalar, $i);
23093         $i += strlen($output);
23094
23095         // remove comments
23096         if (false !== $strpos = strpos($output, ' #'))
23097         {
23098           $output = rtrim(substr($output, 0, $strpos));
23099         }
23100       }
23101       else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match))
23102       {
23103         $output = $match[1];
23104         $i += strlen($output);
23105       }
23106       else
23107       {
23108         throw new ParserException(sprintf('Malformed inline YAML string (%s).', $scalar));
23109       }
23110
23111       $output = $evaluate ? self::evaluateScalar($output) : $output;
23112     }
23113
23114     return $output;
23115   }
23116
23117   /**
23118    * Parses a quoted scalar to YAML.
23119    *
23120    * @param string  $scalar
23121    * @param integer $i
23122    *
23123    * @return string A YAML string
23124    */
23125   static protected function parseQuotedScalar($scalar, &$i)
23126   {
23127     if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/A', substr($scalar, $i), $match))
23128     {
23129       throw new ParserException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
23130     }
23131
23132     $output = substr($match[0], 1, strlen($match[0]) - 2);
23133
23134     if ('"' == $scalar[$i])
23135     {
23136       // evaluate the string
23137       $output = str_replace(array('\\"', '\\n', '\\r'), array('"', "\n", "\r"), $output);
23138     }
23139     else
23140     {
23141       // unescape '
23142       $output = str_replace('\'\'', '\'', $output);
23143     }
23144
23145     $i += strlen($match[0]);
23146
23147     return $output;
23148   }
23149
23150   /**
23151    * Parses a sequence to a YAML string.
23152    *
23153    * @param string  $sequence
23154    * @param integer $i
23155    *
23156    * @return string A YAML string
23157    */
23158   static protected function parseSequence($sequence, &$i = 0)
23159   {
23160     $output = array();
23161     $len = strlen($sequence);
23162     $i += 1;
23163
23164     // [foo, bar, ...]
23165     while ($i < $len)
23166     {
23167       switch ($sequence[$i])
23168       {
23169         case '[':
23170           // nested sequence
23171           $output[] = self::parseSequence($sequence, $i);
23172           break;
23173         case '{':
23174           // nested mapping
23175           $output[] = self::parseMapping($sequence, $i);
23176           break;
23177         case ']':
23178           return $output;
23179         case ',':
23180         case ' ':
23181           break;
23182         default:
23183           $isQuoted = in_array($sequence[$i], array('"', "'"));
23184           $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
23185
23186           if (!$isQuoted && false !== strpos($value, ': '))
23187           {
23188             // embedded mapping?
23189             try
23190             {
23191               $value = self::parseMapping('{'.$value.'}');
23192             }
23193             catch (\InvalidArgumentException $e)
23194             {
23195               // no, it's not
23196             }
23197           }
23198
23199           $output[] = $value;
23200
23201           --$i;
23202       }
23203
23204       ++$i;
23205     }
23206
23207     throw new ParserException(sprintf('Malformed inline YAML string %s', $sequence));
23208   }
23209
23210   /**
23211    * Parses a mapping to a YAML string.
23212    *
23213    * @param string  $mapping
23214    * @param integer $i
23215    *
23216    * @return string A YAML string
23217    */
23218   static protected function parseMapping($mapping, &$i = 0)
23219   {
23220     $output = array();
23221     $len = strlen($mapping);
23222     $i += 1;
23223
23224     // {foo: bar, bar:foo, ...}
23225     while ($i < $len)
23226     {
23227       switch ($mapping[$i])
23228       {
23229         case ' ':
23230         case ',':
23231           ++$i;
23232           continue 2;
23233         case '}':
23234           return $output;
23235       }
23236
23237       // key
23238       $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
23239
23240       // value
23241       $done = false;
23242       while ($i < $len)
23243       {
23244         switch ($mapping[$i])
23245         {
23246           case '[':
23247             // nested sequence
23248             $output[$key] = self::parseSequence($mapping, $i);
23249             $done = true;
23250             break;
23251           case '{':
23252             // nested mapping
23253             $output[$key] = self::parseMapping($mapping, $i);
23254             $done = true;
23255             break;
23256           case ':':
23257           case ' ':
23258             break;
23259           default:
23260             $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
23261             $done = true;
23262             --$i;
23263         }
23264
23265         ++$i;
23266
23267         if ($done)
23268         {
23269           continue 2;
23270         }
23271       }
23272     }
23273
23274     throw new ParserException(sprintf('Malformed inline YAML string %s', $mapping));
23275   }
23276
23277   /**
23278    * Evaluates scalars and replaces magic values.
23279    *
23280    * @param string $scalar
23281    *
23282    * @return string A YAML string
23283    */
23284   static protected function evaluateScalar($scalar)
23285   {
23286     $scalar = trim($scalar);
23287
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');
23290
23291     switch (true)
23292     {
23293       case 'null' == strtolower($scalar):
23294       case '' == $scalar:
23295       case '~' == $scalar:
23296         return null;
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):
23304         $raw = $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):
23308         return true;
23309       case in_array(strtolower($scalar), $falseValues):
23310         return false;
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'):
23315         return -log(0);
23316       case 0 == strcasecmp($scalar, '-.inf'):
23317         return log(0);
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);
23322       default:
23323         return (string) $scalar;
23324     }
23325   }
23326
23327   static protected function getTimestampRegex()
23328   {
23329     return <<<EOF
23330     ~^
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]?)
23334     (?:(?:[Tt]|[ \t]+)
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]))?))?)?
23341     $~x
23342 EOF;
23343   }
23344 }
23345 <?php
23346
23347 namespace Symfony\Component\Yaml;
23348
23349 /*
23350  * This file is part of the symfony package.
23351  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
23352  *
23353  * For the full copyright and license information, please view the LICENSE
23354  * file that was distributed with this source code.
23355  */
23356
23357 /**
23358  * Parser parses YAML strings to convert them to PHP arrays.
23359  *
23360  * @package    symfony
23361  * @subpackage yaml
23362  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
23363  */
23364 class Parser
23365 {
23366   protected $offset         = 0;
23367   protected $lines          = array();
23368   protected $currentLineNb  = -1;
23369   protected $currentLine    = '';
23370   protected $refs           = array();
23371
23372   /**
23373    * Constructor
23374    *
23375    * @param integer $offset The offset of YAML document (used for line numbers in error messages)
23376    */
23377   public function __construct($offset = 0)
23378   {
23379     $this->offset = $offset;
23380   }
23381
23382   /**
23383    * Parses a YAML string to a PHP value.
23384    *
23385    * @param  string $value A YAML string
23386    *
23387    * @return mixed  A PHP value
23388    *
23389    * @throws \InvalidArgumentException If the YAML is not valid
23390    */
23391   public function parse($value)
23392   {
23393     $this->currentLineNb = -1;
23394     $this->currentLine = '';
23395     $this->lines = explode("\n", $this->cleanup($value));
23396
23397     $data = array();
23398     while ($this->moveToNextLine())
23399     {
23400       if ($this->isCurrentLineEmpty())
23401       {
23402         continue;
23403       }
23404
23405       // tab?
23406       if (preg_match('#^\t+#', $this->currentLine))
23407       {
23408         throw new ParserException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine));
23409       }
23410
23411       $isRef = $isInPlace = $isProcessed = false;
23412       if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#', $this->currentLine, $values))
23413       {
23414         if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#', $values['value'], $matches))
23415         {
23416           $isRef = $matches['ref'];
23417           $values['value'] = $matches['value'];
23418         }
23419
23420         // array
23421         if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
23422         {
23423           $c = $this->getRealCurrentLineNb() + 1;
23424           $parser = new Parser($c);
23425           $parser->refs =& $this->refs;
23426           $data[] = $parser->parse($this->getNextEmbedBlock());
23427         }
23428         else
23429         {
23430           if (isset($values['leadspaces'])
23431             && ' ' == $values['leadspaces']
23432             && preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{].*?) *\:(\s+(?P<value>.+?))?\s*$#', $values['value'], $matches))
23433           {
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;
23438
23439             $block = $values['value'];
23440             if (!$this->isNextLineIndented())
23441             {
23442               $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + 2);
23443             }
23444
23445             $data[] = $parser->parse($block);
23446           }
23447           else
23448           {
23449             $data[] = $this->parseValue($values['value']);
23450           }
23451         }
23452       }
23453       else if (preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"].*?) *\:(\s+(?P<value>.+?))?\s*$#', $this->currentLine, $values))
23454       {
23455         $key = Inline::parseScalar($values['key']);
23456
23457         if ('<<' === $key)
23458         {
23459           if (isset($values['value']) && '*' === substr($values['value'], 0, 1))
23460           {
23461             $isInPlace = substr($values['value'], 1);
23462             if (!array_key_exists($isInPlace, $this->refs))
23463             {
23464               throw new ParserException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine));
23465             }
23466           }
23467           else
23468           {
23469             if (isset($values['value']) && $values['value'] !== '')
23470             {
23471               $value = $values['value'];
23472             }
23473             else
23474             {
23475               $value = $this->getNextEmbedBlock();
23476             }
23477             $c = $this->getRealCurrentLineNb() + 1;
23478             $parser = new Parser($c);
23479             $parser->refs =& $this->refs;
23480             $parsed = $parser->parse($value);
23481
23482             $merged = array();
23483             if (!is_array($parsed))
23484             {
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));
23486             }
23487             else if (isset($parsed[0]))
23488             {
23489               // Numeric array, merge individual elements
23490               foreach (array_reverse($parsed) as $parsedItem)
23491               {
23492                 if (!is_array($parsedItem))
23493                 {
23494                   throw new ParserException(sprintf("Merge items must be arrays at line %s (%s).", $this->getRealCurrentLineNb() + 1, $parsedItem));
23495                 }
23496                 $merged = array_merge($parsedItem, $merged);
23497               }
23498             }
23499             else
23500             {
23501               // Associative array, merge
23502               $merged = array_merge($merge, $parsed);
23503             }
23504
23505             $isProcessed = $merged;
23506           }
23507         }
23508         else if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#', $values['value'], $matches))
23509         {
23510           $isRef = $matches['ref'];
23511           $values['value'] = $matches['value'];
23512         }
23513
23514         if ($isProcessed)
23515         {
23516           // Merge keys
23517           $data = $isProcessed;
23518         }
23519         // hash
23520         else if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
23521         {
23522           // if next line is less indented or equal, then it means that the current value is null
23523           if ($this->isNextLineIndented())
23524           {
23525             $data[$key] = null;
23526           }
23527           else
23528           {
23529             $c = $this->getRealCurrentLineNb() + 1;
23530             $parser = new Parser($c);
23531             $parser->refs =& $this->refs;
23532             $data[$key] = $parser->parse($this->getNextEmbedBlock());
23533           }
23534         }
23535         else
23536         {
23537           if ($isInPlace)
23538           {
23539             $data = $this->refs[$isInPlace];
23540           }
23541           else
23542           {
23543             $data[$key] = $this->parseValue($values['value']);
23544           }
23545         }
23546       }
23547       else
23548       {
23549         // 1-liner followed by newline
23550         if (2 == count($this->lines) && empty($this->lines[1]))
23551         {
23552           $value = Inline::load($this->lines[0]);
23553           if (is_array($value))
23554           {
23555             $first = reset($value);
23556             if ('*' === substr($first, 0, 1))
23557             {
23558               $data = array();
23559               foreach ($value as $alias)
23560               {
23561                 $data[] = $this->refs[substr($alias, 1)];
23562               }
23563               $value = $data;
23564             }
23565           }
23566
23567           return $value;
23568         }
23569
23570         switch (preg_last_error())
23571         {
23572           case PREG_INTERNAL_ERROR:
23573             $error = 'Internal PCRE error on line';
23574             break;
23575           case PREG_BACKTRACK_LIMIT_ERROR:
23576             $error = 'pcre.backtrack_limit reached on line';
23577             break;
23578           case PREG_RECURSION_LIMIT_ERROR:
23579             $error = 'pcre.recursion_limit reached on line';
23580             break;
23581           case PREG_BAD_UTF8_ERROR:
23582             $error = 'Malformed UTF-8 data on line';
23583             break;
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';
23586             break;
23587           default:
23588             $error = 'Unable to parse line';
23589         }
23590
23591         throw new ParserException(sprintf('%s %d (%s).', $error, $this->getRealCurrentLineNb() + 1, $this->currentLine));
23592       }
23593
23594       if ($isRef)
23595       {
23596         $this->refs[$isRef] = end($data);
23597       }
23598     }
23599
23600     return empty($data) ? null : $data;
23601   }
23602
23603   /**
23604    * Returns the current line number (takes the offset into account).
23605    *
23606    * @return integer The current line number
23607    */
23608   protected function getRealCurrentLineNb()
23609   {
23610     return $this->currentLineNb + $this->offset;
23611   }
23612
23613   /**
23614    * Returns the current line indentation.
23615    *
23616    * @return integer The current line indentation
23617    */
23618   protected function getCurrentLineIndentation()
23619   {
23620     return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' '));
23621   }
23622
23623   /**
23624    * Returns the next embed block of YAML.
23625    *
23626    * @param integer $indentation The indent level at which the block is to be read, or null for default
23627    *
23628    * @return string A YAML string
23629    */
23630   protected function getNextEmbedBlock($indentation = null)
23631   {
23632     $this->moveToNextLine();
23633
23634     if (null === $indentation)
23635     {
23636       $newIndent = $this->getCurrentLineIndentation();
23637
23638       if (!$this->isCurrentLineEmpty() && 0 == $newIndent)
23639       {
23640         throw new ParserException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
23641       }
23642     }
23643     else
23644     {
23645       $newIndent = $indentation;
23646     }
23647
23648     $data = array(substr($this->currentLine, $newIndent));
23649
23650     while ($this->moveToNextLine())
23651     {
23652       if ($this->isCurrentLineEmpty())
23653       {
23654         if ($this->isCurrentLineBlank())
23655         {
23656           $data[] = substr($this->currentLine, $newIndent);
23657         }
23658
23659         continue;
23660       }
23661
23662       $indent = $this->getCurrentLineIndentation();
23663
23664       if (preg_match('#^(?P<text> *)$#', $this->currentLine, $match))
23665       {
23666         // empty line
23667         $data[] = $match['text'];
23668       }
23669       else if ($indent >= $newIndent)
23670       {
23671         $data[] = substr($this->currentLine, $newIndent);
23672       }
23673       else if (0 == $indent)
23674       {
23675         $this->moveToPreviousLine();
23676
23677         break;
23678       }
23679       else
23680       {
23681         throw new ParserException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
23682       }
23683     }
23684
23685     return implode("\n", $data);
23686   }
23687
23688   /**
23689    * Moves the parser to the next line.
23690    */
23691   protected function moveToNextLine()
23692   {
23693     if ($this->currentLineNb >= count($this->lines) - 1)
23694     {
23695       return false;
23696     }
23697
23698     $this->currentLine = $this->lines[++$this->currentLineNb];
23699
23700     return true;
23701   }
23702
23703   /**
23704    * Moves the parser to the previous line.
23705    */
23706   protected function moveToPreviousLine()
23707   {
23708     $this->currentLine = $this->lines[--$this->currentLineNb];
23709   }
23710
23711   /**
23712    * Parses a YAML value.
23713    *
23714    * @param  string $value A YAML value
23715    *
23716    * @return mixed  A PHP value
23717    */
23718   protected function parseValue($value)
23719   {
23720     if ('*' === substr($value, 0, 1))
23721     {
23722       if (false !== $pos = strpos($value, '#'))
23723       {
23724         $value = substr($value, 1, $pos - 2);
23725       }
23726       else
23727       {
23728         $value = substr($value, 1);
23729       }
23730
23731       if (!array_key_exists($value, $this->refs))
23732       {
23733         throw new ParserException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine));
23734       }
23735       return $this->refs[$value];
23736     }
23737
23738     if (preg_match('/^(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?$/', $value, $matches))
23739     {
23740       $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
23741
23742       return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers)));
23743     }
23744     else
23745     {
23746       return Inline::load($value);
23747     }
23748   }
23749
23750   /**
23751    * Parses a folded scalar.
23752    *
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
23756    *
23757    * @return string  The text value
23758    */
23759   protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0)
23760   {
23761     $separator = '|' == $separator ? "\n" : ' ';
23762     $text = '';
23763
23764     $notEOF = $this->moveToNextLine();
23765
23766     while ($notEOF && $this->isCurrentLineBlank())
23767     {
23768       $text .= "\n";
23769
23770       $notEOF = $this->moveToNextLine();
23771     }
23772
23773     if (!$notEOF)
23774     {
23775       return '';
23776     }
23777
23778     if (!preg_match('#^(?P<indent>'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P<text>.*)$#', $this->currentLine, $matches))
23779     {
23780       $this->moveToPreviousLine();
23781
23782       return '';
23783     }
23784
23785     $textIndent = $matches['indent'];
23786     $previousIndent = 0;
23787
23788     $text .= $matches['text'].$separator;
23789     while ($this->currentLineNb + 1 < count($this->lines))
23790     {
23791       $this->moveToNextLine();
23792
23793       if (preg_match('#^(?P<indent> {'.strlen($textIndent).',})(?P<text>.+)$#', $this->currentLine, $matches))
23794       {
23795         if (' ' == $separator && $previousIndent != $matches['indent'])
23796         {
23797           $text = substr($text, 0, -1)."\n";
23798         }
23799         $previousIndent = $matches['indent'];
23800
23801         $text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator);
23802       }
23803       else if (preg_match('#^(?P<text> *)$#', $this->currentLine, $matches))
23804       {
23805         $text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n";
23806       }
23807       else
23808       {
23809         $this->moveToPreviousLine();
23810
23811         break;
23812       }
23813     }
23814
23815     if (' ' == $separator)
23816     {
23817       // replace last separator by a newline
23818       $text = preg_replace('/ (\n*)$/', "\n$1", $text);
23819     }
23820
23821     switch ($indicator)
23822     {
23823       case '':
23824         $text = preg_replace('#\n+$#s', "\n", $text);
23825         break;
23826       case '+':
23827         break;
23828       case '-':
23829         $text = preg_replace('#\n+$#s', '', $text);
23830         break;
23831     }
23832
23833     return $text;
23834   }
23835
23836   /**
23837    * Returns true if the next line is indented.
23838    *
23839    * @return Boolean Returns true if the next line is indented, false otherwise
23840    */
23841   protected function isNextLineIndented()
23842   {
23843     $currentIndentation = $this->getCurrentLineIndentation();
23844     $notEOF = $this->moveToNextLine();
23845
23846     while ($notEOF && $this->isCurrentLineEmpty())
23847     {
23848       $notEOF = $this->moveToNextLine();
23849     }
23850
23851     if (false === $notEOF)
23852     {
23853       return false;
23854     }
23855
23856     $ret = false;
23857     if ($this->getCurrentLineIndentation() <= $currentIndentation)
23858     {
23859       $ret = true;
23860     }
23861
23862     $this->moveToPreviousLine();
23863
23864     return $ret;
23865   }
23866
23867   /**
23868    * Returns true if the current line is blank or if it is a comment line.
23869    *
23870    * @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise
23871    */
23872   protected function isCurrentLineEmpty()
23873   {
23874     return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
23875   }
23876
23877   /**
23878    * Returns true if the current line is blank.
23879    *
23880    * @return Boolean Returns true if the current line is blank, false otherwise
23881    */
23882   protected function isCurrentLineBlank()
23883   {
23884     return '' == trim($this->currentLine, ' ');
23885   }
23886
23887   /**
23888    * Returns true if the current line is a comment line.
23889    *
23890    * @return Boolean Returns true if the current line is a comment line, false otherwise
23891    */
23892   protected function isCurrentLineComment()
23893   {
23894     //checking explicitly the first char of the trim is faster than loops or strpos
23895     $ltrimmedLine = ltrim($this->currentLine, ' ');
23896     return $ltrimmedLine[0] === '#';
23897   }
23898
23899   /**
23900    * Cleanups a YAML string to be parsed.
23901    *
23902    * @param  string $value The input YAML string
23903    *
23904    * @return string A cleaned up YAML string
23905    */
23906   protected function cleanup($value)
23907   {
23908     $value = str_replace(array("\r\n", "\r"), "\n", $value);
23909
23910     if (!preg_match("#\n$#", $value))
23911     {
23912       $value .= "\n";
23913     }
23914
23915     // strip YAML header
23916     $count = 0;
23917     $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#s', '', $value, -1, $count);
23918     $this->offset += $count;
23919
23920     // remove leading comments and/or ---
23921     $trimmedValue = preg_replace('#^((\#.*?\n)|(\-\-\-.*?\n))*#s', '', $value, -1, $count);
23922     if ($count == 1)
23923     {
23924       // items have been removed, update the offset
23925       $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
23926       $value = $trimmedValue;
23927     }
23928
23929     return $value;
23930   }
23931 }
23932 <?php
23933
23934 namespace Symfony\Component\Console\Command;
23935
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;
23942
23943 /*
23944  * This file is part of the Symfony framework.
23945  *
23946  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
23947  *
23948  * This source file is subject to the MIT license that is bundled
23949  * with this source code in the file LICENSE.
23950  */
23951
23952 /**
23953  * ListCommand displays the list of all available commands for the application.
23954  *
23955  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
23956  */
23957 class ListCommand extends Command
23958 {
23959     /**
23960      * @see Command
23961      */
23962     protected function configure()
23963     {
23964         $this
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'),
23968             ))
23969             ->setName('list')
23970             ->setDescription('Lists commands')
23971             ->setHelp(<<<EOF
23972 The <info>list</info> command lists all commands:
23973
23974   <info>./symfony list</info>
23975
23976 You can also display the commands for a specific namespace:
23977
23978   <info>./symfony list test</info>
23979
23980 You can also output the information as XML by using the <comment>--xml</comment> option:
23981
23982   <info>./symfony list --xml</info>
23983 EOF
23984             );
23985     }
23986
23987     /**
23988      * @see Command
23989      */
23990     protected function execute(InputInterface $input, OutputInterface $output)
23991     {
23992         if ($input->getOption('xml')) {
23993             $output->writeln($this->application->asXml($input->getArgument('namespace')), Output::OUTPUT_RAW);
23994         } else {
23995             $output->writeln($this->application->asText($input->getArgument('namespace')));
23996         }
23997     }
23998 }
23999 <?php
24000
24001 namespace Symfony\Component\Console\Command;
24002
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;
24009
24010 /*
24011  * This file is part of the Symfony framework.
24012  *
24013  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24014  *
24015  * This source file is subject to the MIT license that is bundled
24016  * with this source code in the file LICENSE.
24017  */
24018
24019 /**
24020  * HelpCommand displays the help for a given command.
24021  *
24022  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24023  */
24024 class HelpCommand extends Command
24025 {
24026     protected $command;
24027
24028     /**
24029      * @see Command
24030      */
24031     protected function configure()
24032     {
24033         $this->ignoreValidationErrors = true;
24034
24035         $this
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'),
24039             ))
24040             ->setName('help')
24041             ->setAliases(array('?'))
24042             ->setDescription('Displays help for a command')
24043             ->setHelp(<<<EOF
24044 The <info>help</info> command displays help for a given command:
24045
24046   <info>./symfony help list</info>
24047
24048 You can also output the help as XML by using the <comment>--xml</comment> option:
24049
24050   <info>./symfony help --xml list</info>
24051 EOF
24052             );
24053     }
24054
24055     public function setCommand(Command $command)
24056     {
24057         $this->command = $command;
24058     }
24059
24060     /**
24061      * @see Command
24062      */
24063     protected function execute(InputInterface $input, OutputInterface $output)
24064     {
24065         if (null === $this->command) {
24066             $this->command = $this->application->getCommand($input->getArgument('command_name'));
24067         }
24068
24069         if ($input->getOption('xml')) {
24070             $output->writeln($this->command->asXml(), Output::OUTPUT_RAW);
24071         } else {
24072             $output->writeln($this->command->asText());
24073         }
24074     }
24075 }
24076 <?php
24077
24078 namespace Symfony\Component\Console\Command;
24079
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;
24086
24087 /*
24088  * This file is part of the Symfony framework.
24089  *
24090  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24091  *
24092  * This source file is subject to the MIT license that is bundled
24093  * with this source code in the file LICENSE.
24094  */
24095
24096 /**
24097  * Base class for all commands.
24098  *
24099  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24100  */
24101 class Command
24102 {
24103     protected $name;
24104     protected $namespace;
24105     protected $aliases;
24106     protected $definition;
24107     protected $help;
24108     protected $application;
24109     protected $description;
24110     protected $ignoreValidationErrors;
24111     protected $applicationDefinitionMerged;
24112     protected $code;
24113
24114     /**
24115      * Constructor.
24116      *
24117      * @param string $name The name of the command
24118      *
24119      * @throws \LogicException When the command name is empty
24120      */
24121     public function __construct($name = null)
24122     {
24123         $this->definition = new InputDefinition();
24124         $this->ignoreValidationErrors = false;
24125         $this->applicationDefinitionMerged = false;
24126         $this->aliases = array();
24127
24128         if (null !== $name) {
24129             $this->setName($name);
24130         }
24131
24132         $this->configure();
24133
24134         if (!$this->name) {
24135             throw new \LogicException('The command name cannot be empty.');
24136         }
24137     }
24138
24139     /**
24140      * Sets the application instance for this command.
24141      *
24142      * @param Application $application An Application instance
24143      */
24144     public function setApplication(Application $application = null)
24145     {
24146         $this->application = $application;
24147     }
24148
24149     /**
24150      * Configures the current command.
24151      */
24152     protected function configure()
24153     {
24154     }
24155
24156     /**
24157      * Executes the current command.
24158      *
24159      * @param InputInterface  $input  An InputInterface instance
24160      * @param OutputInterface $output An OutputInterface instance
24161      *
24162      * @return integer 0 if everything went fine, or an error code
24163      *
24164      * @throws \LogicException When this abstract class is not implemented
24165      */
24166     protected function execute(InputInterface $input, OutputInterface $output)
24167     {
24168         throw new \LogicException('You must override the execute() method in the concrete command class.');
24169     }
24170
24171     /**
24172      * Interacts with the user.
24173      *
24174      * @param InputInterface  $input  An InputInterface instance
24175      * @param OutputInterface $output An OutputInterface instance
24176      */
24177     protected function interact(InputInterface $input, OutputInterface $output)
24178     {
24179     }
24180
24181     /**
24182      * Initializes the command just after the input has been validated.
24183      *
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.
24186      *
24187      * @param InputInterface  $input  An InputInterface instance
24188      * @param OutputInterface $output An OutputInterface instance
24189      */
24190     protected function initialize(InputInterface $input, OutputInterface $output)
24191     {
24192     }
24193
24194     /**
24195      * Runs the command.
24196      *
24197      * @param InputInterface  $input  An InputInterface instance
24198      * @param OutputInterface $output An OutputInterface instance
24199      */
24200     public function run(InputInterface $input, OutputInterface $output)
24201     {
24202         // add the application arguments and options
24203         $this->mergeApplicationDefinition();
24204
24205         // bind the input against the command specific arguments/options
24206         try {
24207             $input->bind($this->definition);
24208         } catch (\Exception $e) {
24209             if (!$this->ignoreValidationErrors) {
24210                 throw $e;
24211             }
24212         }
24213
24214         $this->initialize($input, $output);
24215
24216         if ($input->isInteractive()) {
24217             $this->interact($input, $output);
24218         }
24219
24220         $input->validate();
24221
24222         if ($this->code) {
24223             return call_user_func($this->code, $input, $output);
24224         } else {
24225             return $this->execute($input, $output);
24226         }
24227     }
24228
24229     /**
24230      * Sets the code to execute when running this command.
24231      *
24232      * @param \Closure $code A \Closure
24233      *
24234      * @return Command The current instance
24235      */
24236     public function setCode(\Closure $code)
24237     {
24238         $this->code = $code;
24239
24240         return $this;
24241     }
24242
24243     /**
24244      * Merges the application definition with the command definition.
24245      */
24246     protected function mergeApplicationDefinition()
24247     {
24248         if (null === $this->application || true === $this->applicationDefinitionMerged) {
24249             return;
24250         }
24251
24252         $this->definition->setArguments(array_merge(
24253             $this->application->getDefinition()->getArguments(),
24254             $this->definition->getArguments()
24255         ));
24256
24257         $this->definition->addOptions($this->application->getDefinition()->getOptions());
24258
24259         $this->applicationDefinitionMerged = true;
24260     }
24261
24262     /**
24263      * Sets an array of argument and option instances.
24264      *
24265      * @param array|Definition $definition An array of argument and option instances or a definition instance
24266      *
24267      * @return Command The current instance
24268      */
24269     public function setDefinition($definition)
24270     {
24271         if ($definition instanceof InputDefinition) {
24272             $this->definition = $definition;
24273         } else {
24274             $this->definition->setDefinition($definition);
24275         }
24276
24277         $this->applicationDefinitionMerged = false;
24278
24279         return $this;
24280     }
24281
24282     /**
24283      * Gets the InputDefinition attached to this Command.
24284      *
24285      * @return InputDefinition An InputDefinition instance
24286      */
24287     public function getDefinition()
24288     {
24289         return $this->definition;
24290     }
24291
24292     /**
24293      * Adds an argument.
24294      *
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)
24299      *
24300      * @return Command The current instance
24301      */
24302     public function addArgument($name, $mode = null, $description = '', $default = null)
24303     {
24304         $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
24305
24306         return $this;
24307     }
24308
24309     /**
24310      * Adds an option.
24311      *
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)
24317      *
24318      * @return Command The current instance
24319      */
24320     public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
24321     {
24322         $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
24323
24324         return $this;
24325     }
24326
24327     /**
24328      * Sets the name of the command.
24329      *
24330      * This method can set both the namespace and the name if
24331      * you separate them by a colon (:)
24332      *
24333      *     $command->setName('foo:bar');
24334      *
24335      * @param string $name The command name
24336      *
24337      * @return Command The current instance
24338      *
24339      * @throws \InvalidArgumentException When command name given is empty
24340      */
24341     public function setName($name)
24342     {
24343         if (false !== $pos = strrpos($name, ':')) {
24344             $namespace = substr($name, 0, $pos);
24345             $name = substr($name, $pos + 1);
24346         } else {
24347             $namespace = $this->namespace;
24348         }
24349
24350         if (!$name) {
24351             throw new \InvalidArgumentException('A command name cannot be empty.');
24352         }
24353
24354         $this->namespace = $namespace;
24355         $this->name = $name;
24356
24357         return $this;
24358     }
24359
24360     /**
24361      * Returns the command namespace.
24362      *
24363      * @return string The command namespace
24364      */
24365     public function getNamespace()
24366     {
24367         return $this->namespace;
24368     }
24369
24370     /**
24371      * Returns the command name
24372      *
24373      * @return string The command name
24374      */
24375     public function getName()
24376     {
24377         return $this->name;
24378     }
24379
24380     /**
24381      * Returns the fully qualified command name.
24382      *
24383      * @return string The fully qualified command name
24384      */
24385     public function getFullName()
24386     {
24387         return $this->getNamespace() ? $this->getNamespace().':'.$this->getName() : $this->getName();
24388     }
24389
24390     /**
24391      * Sets the description for the command.
24392      *
24393      * @param string $description The description for the command
24394      *
24395      * @return Command The current instance
24396      */
24397     public function setDescription($description)
24398     {
24399         $this->description = $description;
24400
24401         return $this;
24402     }
24403
24404     /**
24405      * Returns the description for the command.
24406      *
24407      * @return string The description for the command
24408      */
24409     public function getDescription()
24410     {
24411         return $this->description;
24412     }
24413
24414     /**
24415      * Sets the help for the command.
24416      *
24417      * @param string $help The help for the command
24418      *
24419      * @return Command The current instance
24420      */
24421     public function setHelp($help)
24422     {
24423         $this->help = $help;
24424
24425         return $this;
24426     }
24427
24428     /**
24429      * Returns the help for the command.
24430      *
24431      * @return string The help for the command
24432      */
24433     public function getHelp()
24434     {
24435         return $this->help;
24436     }
24437
24438     /**
24439      * Returns the processed help for the command replacing the %command.name% and
24440      * %command.full_name% patterns with the real values dynamically.
24441      *
24442      * @return string  The processed help for the command
24443      */
24444     public function getProcessedHelp()
24445     {
24446         $name = $this->namespace.':'.$this->name;
24447
24448         $placeholders = array(
24449             '%command.name%',
24450             '%command.full_name%'
24451         );
24452         $replacements = array(
24453             $name,
24454             $_SERVER['PHP_SELF'].' '.$name
24455         );
24456
24457         return str_replace($placeholders, $replacements, $this->getHelp());
24458     }
24459
24460     /**
24461      * Sets the aliases for the command.
24462      *
24463      * @param array $aliases An array of aliases for the command
24464      *
24465      * @return Command The current instance
24466      */
24467     public function setAliases($aliases)
24468     {
24469         $this->aliases = $aliases;
24470
24471         return $this;
24472     }
24473
24474     /**
24475      * Returns the aliases for the command.
24476      *
24477      * @return array An array of aliases for the command
24478      */
24479     public function getAliases()
24480     {
24481         return $this->aliases;
24482     }
24483
24484     /**
24485      * Returns the synopsis for the command.
24486      *
24487      * @return string The synopsis
24488      */
24489     public function getSynopsis()
24490     {
24491         return sprintf('%s %s', $this->getFullName(), $this->definition->getSynopsis());
24492     }
24493
24494     /**
24495      * Gets a helper instance by name.
24496      *
24497      * @param string $name The helper name
24498      *
24499      * @return mixed The helper value
24500      *
24501      * @throws \InvalidArgumentException if the helper is not defined
24502      */
24503     protected function getHelper($name)
24504     {
24505         return $this->application->getHelperSet()->get($name);
24506     }
24507
24508     /**
24509      * Gets a helper instance by name.
24510      *
24511      * @param string $name The helper name
24512      *
24513      * @return mixed The helper value
24514      *
24515      * @throws \InvalidArgumentException if the helper is not defined
24516      */
24517     public function __get($name)
24518     {
24519         return $this->application->getHelperSet()->get($name);
24520     }
24521
24522     /**
24523      * Returns a text representation of the command.
24524      *
24525      * @return string A string representing the command
24526      */
24527     public function asText()
24528     {
24529         $messages = array(
24530             '<comment>Usage:</comment>',
24531             ' '.$this->getSynopsis(),
24532             '',
24533         );
24534
24535         if ($this->getAliases()) {
24536             $messages[] = '<comment>Aliases:</comment> <info>'.implode(', ', $this->getAliases()).'</info>';
24537         }
24538
24539         $messages[] = $this->definition->asText();
24540
24541         if ($help = $this->getProcessedHelp()) {
24542             $messages[] = '<comment>Help:</comment>';
24543             $messages[] = ' '.implode("\n ", explode("\n", $help))."\n";
24544         }
24545
24546         return implode("\n", $messages);
24547     }
24548
24549     /**
24550      * Returns an XML representation of the command.
24551      *
24552      * @param Boolean $asDom Whether to return a DOM or an XML string
24553      *
24554      * @return string|DOMDocument An XML string representing the command
24555      */
24556     public function asXml($asDom = false)
24557     {
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());
24564
24565         $commandXML->appendChild($usageXML = $dom->createElement('usage'));
24566         $usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
24567
24568         $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
24569         $descriptionXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $this->getDescription()))));
24570
24571         $commandXML->appendChild($helpXML = $dom->createElement('help'));
24572         $help = $this->help;
24573         $helpXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $help))));
24574
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));
24579         }
24580
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));
24584
24585         return $asDom ? $dom : $dom->saveXml();
24586     }
24587 }
24588 <?php
24589
24590 namespace Symfony\Component\Console\Output;
24591
24592 /*
24593  * This file is part of the Symfony framework.
24594  *
24595  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24596  *
24597  * This source file is subject to the MIT license that is bundled
24598  * with this source code in the file LICENSE.
24599  */
24600
24601 /**
24602  * ConsoleOutput is the default class for all CLI output. It uses STDOUT.
24603  *
24604  * This class is a convenient wrapper around `StreamOutput`.
24605  *
24606  *     $output = new ConsoleOutput();
24607  *
24608  * This is equivalent to:
24609  *
24610  *     $output = new StreamOutput(fopen('php://stdout', 'w'));
24611  *
24612  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24613  */
24614 class ConsoleOutput extends StreamOutput
24615 {
24616     /**
24617      * Constructor.
24618      *
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)
24621      */
24622     public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null)
24623     {
24624         parent::__construct(fopen('php://stdout', 'w'), $verbosity, $decorated);
24625     }
24626 }
24627 <?php
24628
24629 namespace Symfony\Component\Console\Output;
24630
24631 /*
24632  * This file is part of the Symfony framework.
24633  *
24634  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24635  *
24636  * This source file is subject to the MIT license that is bundled
24637  * with this source code in the file LICENSE.
24638  */
24639
24640 /**
24641  * OutputInterface is the interface implemented by all Output classes.
24642  *
24643  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24644  */
24645 interface OutputInterface
24646 {
24647     /**
24648      * Writes a message to the output.
24649      *
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
24653      *
24654      * @throws \InvalidArgumentException When unknown output type is given
24655      */
24656     function write($messages, $newline = false, $type = 0);
24657
24658     /**
24659      * Sets the verbosity of the output.
24660      *
24661      * @param integer $level The level of verbosity
24662      */
24663     function setVerbosity($level);
24664
24665     /**
24666      * Sets the decorated flag.
24667      *
24668      * @param Boolean $decorated Whether to decorated the messages or not
24669      */
24670     function setDecorated($decorated);
24671 }
24672 <?php
24673
24674 namespace Symfony\Component\Console\Output;
24675
24676 /*
24677  * This file is part of the Symfony framework.
24678  *
24679  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24680  *
24681  * This source file is subject to the MIT license that is bundled
24682  * with this source code in the file LICENSE.
24683  */
24684
24685 /**
24686  * StreamOutput writes the output to a given stream.
24687  *
24688  * Usage:
24689  *
24690  * $output = new StreamOutput(fopen('php://stdout', 'w'));
24691  *
24692  * As `StreamOutput` can use any stream, you can also use a file:
24693  *
24694  * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false));
24695  *
24696  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24697  */
24698 class StreamOutput extends Output
24699 {
24700     protected $stream;
24701
24702     /**
24703      * Constructor.
24704      *
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)
24708      *
24709      * @throws \InvalidArgumentException When first argument is not a real stream
24710      */
24711     public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null)
24712     {
24713         if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
24714             throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
24715         }
24716
24717         $this->stream = $stream;
24718
24719         if (null === $decorated) {
24720             $decorated = $this->hasColorSupport($decorated);
24721         }
24722
24723         parent::__construct($verbosity, $decorated);
24724     }
24725
24726     /**
24727      * Gets the stream attached to this StreamOutput instance.
24728      *
24729      * @return resource A stream resource
24730      */
24731     public function getStream()
24732     {
24733         return $this->stream;
24734     }
24735
24736     /**
24737      * Writes a message to the output.
24738      *
24739      * @param string  $message A message to write to the output
24740      * @param Boolean $newline Whether to add a newline or not
24741      *
24742      * @throws \RuntimeException When unable to write output (should never happen)
24743      */
24744     public function doWrite($message, $newline)
24745     {
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
24751         }
24752
24753         flush();
24754     }
24755
24756     /**
24757      * Returns true if the stream supports colorization.
24758      *
24759      * Colorization is disabled if not supported by the stream:
24760      *
24761      *  -  windows without ansicon
24762      *  -  non tty consoles
24763      *
24764      * @return Boolean true if the stream supports colorization, false otherwise
24765      */
24766     protected function hasColorSupport()
24767     {
24768         // @codeCoverageIgnoreStart
24769         if (DIRECTORY_SEPARATOR == '\\') {
24770             return false !== getenv('ANSICON');
24771         } else {
24772             return function_exists('posix_isatty') && @posix_isatty($this->stream);
24773         }
24774         // @codeCoverageIgnoreEnd
24775     }
24776 }
24777 <?php
24778
24779 namespace Symfony\Component\Console\Output;
24780
24781 /*
24782  * This file is part of the Symfony framework.
24783  *
24784  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
24785  *
24786  * This source file is subject to the MIT license that is bundled
24787  * with this source code in the file LICENSE.
24788  */
24789
24790 /**
24791  * Base class for output classes.
24792  *
24793  * There is three level of verbosity:
24794  *
24795  *  * normal: no option passed (normal output - information)
24796  *  * verbose: -v (more output - debug)
24797  *  * quiet: -q (no output)
24798  *
24799  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
24800  */
24801 abstract class Output implements OutputInterface
24802 {
24803     const VERBOSITY_QUIET   = 0;
24804     const VERBOSITY_NORMAL  = 1;
24805     const VERBOSITY_VERBOSE = 2;
24806
24807     const OUTPUT_NORMAL = 0;
24808     const OUTPUT_RAW = 1;
24809     const OUTPUT_PLAIN = 2;
24810
24811     protected $verbosity;
24812     protected $decorated;
24813
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'),
24819     );
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);
24823
24824     /**
24825      * Constructor.
24826      *
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)
24829      */
24830     public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null)
24831     {
24832         $this->decorated = (Boolean) $decorated;
24833         $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
24834     }
24835
24836     /**
24837      * Sets a new style.
24838      *
24839      * @param string $name    The style name
24840      * @param array  $options An array of options
24841      */
24842     static public function setStyle($name, $options = array())
24843     {
24844         static::$styles[strtolower($name)] = $options;
24845     }
24846
24847     /**
24848      * Sets the decorated flag.
24849      *
24850      * @param Boolean $decorated Whether to decorated the messages or not
24851      */
24852     public function setDecorated($decorated)
24853     {
24854         $this->decorated = (Boolean) $decorated;
24855     }
24856
24857     /**
24858      * Gets the decorated flag.
24859      *
24860      * @return Boolean true if the output will decorate messages, false otherwise
24861      */
24862     public function isDecorated()
24863     {
24864         return $this->decorated;
24865     }
24866
24867     /**
24868      * Sets the verbosity of the output.
24869      *
24870      * @param integer $level The level of verbosity
24871      */
24872     public function setVerbosity($level)
24873     {
24874         $this->verbosity = (int) $level;
24875     }
24876
24877     /**
24878      * Gets the current verbosity of the output.
24879      *
24880      * @return integer The current level of verbosity
24881      */
24882     public function getVerbosity()
24883     {
24884         return $this->verbosity;
24885     }
24886
24887     /**
24888      * Writes a message to the output and adds a newline at the end.
24889      *
24890      * @param string|array $messages The message as an array of lines of a single string
24891      * @param integer      $type     The type of output
24892      */
24893     public function writeln($messages, $type = 0)
24894     {
24895         $this->write($messages, true, $type);
24896     }
24897
24898     /**
24899      * Writes a message to the output.
24900      *
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
24904      *
24905      * @throws \InvalidArgumentException When unknown output type is given
24906      */
24907     public function write($messages, $newline = false, $type = 0)
24908     {
24909         if (self::VERBOSITY_QUIET === $this->verbosity) {
24910             return;
24911         }
24912
24913         if (!is_array($messages)) {
24914             $messages = array($messages);
24915         }
24916
24917         foreach ($messages as $message) {
24918             switch ($type) {
24919                 case Output::OUTPUT_NORMAL:
24920                     $message = $this->format($message);
24921                     break;
24922                 case Output::OUTPUT_RAW:
24923                     break;
24924                 case Output::OUTPUT_PLAIN:
24925                     $message = strip_tags($this->format($message));
24926                     break;
24927                 default:
24928                     throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type));
24929             }
24930
24931             $this->doWrite($message, $newline);
24932         }
24933     }
24934
24935     /**
24936      * Writes a message to the output.
24937      *
24938      * @param string  $message A message to write to the output
24939      * @param Boolean $newline Whether to add a newline or not
24940      */
24941     abstract public function doWrite($message, $newline);
24942
24943     /**
24944      * Formats a message according to the given styles.
24945      *
24946      * @param  string $message The message to style
24947      *
24948      * @return string The styled message
24949      */
24950     protected function format($message)
24951     {
24952         $message = preg_replace_callback('#<([a-z][a-z0-9\-_=;]+)>#i', array($this, 'replaceStartStyle'), $message);
24953
24954         return preg_replace_callback('#</([a-z][a-z0-9\-_]*)?>#i', array($this, 'replaceEndStyle'), $message);
24955     }
24956
24957     /**
24958      * @throws \InvalidArgumentException When style is unknown
24959      */
24960     protected function replaceStartStyle($match)
24961     {
24962         if (!$this->decorated) {
24963             return '';
24964         }
24965
24966         if (isset(static::$styles[strtolower($match[1])])) {
24967             $parameters = static::$styles[strtolower($match[1])];
24968         } else {
24969             // bg=blue;fg=red
24970             if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($match[1]), $matches, PREG_SET_ORDER)) {
24971                 throw new \InvalidArgumentException(sprintf('Unknown style "%s".', $match[1]));
24972             }
24973
24974             $parameters = array();
24975             foreach ($matches as $match) {
24976                 $parameters[$match[1]] = $match[2];
24977             }
24978         }
24979
24980         $codes = array();
24981
24982         if (isset($parameters['fg'])) {
24983             $codes[] = static::$foreground[$parameters['fg']];
24984         }
24985
24986         if (isset($parameters['bg'])) {
24987             $codes[] = static::$background[$parameters['bg']];
24988         }
24989
24990         foreach (static::$options as $option => $value) {
24991             if (isset($parameters[$option]) && $parameters[$option]) {
24992                 $codes[] = $value;
24993             }
24994         }
24995
24996         return "\033[".implode(';', $codes).'m';
24997     }
24998
24999     protected function replaceEndStyle($match)
25000     {
25001         if (!$this->decorated) {
25002             return '';
25003         }
25004
25005         return "\033[0m";
25006     }
25007 }
25008 <?php
25009
25010 namespace Symfony\Component\Console\Output;
25011
25012 /*
25013  * This file is part of the Symfony framework.
25014  *
25015  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25016  *
25017  * This source file is subject to the MIT license that is bundled
25018  * with this source code in the file LICENSE.
25019  */
25020
25021 /**
25022  * NullOutput suppresses all output.
25023  *
25024  *     $output = new NullOutput();
25025  *
25026  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25027  */
25028 class NullOutput extends Output
25029 {
25030     /**
25031      * Writes a message to the output.
25032      *
25033      * @param string $message A message to write to the output
25034      * @param Boolean $newline Whether to add a newline or not
25035      */
25036     public function doWrite($message, $newline)
25037     {
25038     }
25039 }
25040 <?php
25041
25042 namespace Symfony\Component\Console;
25043
25044 use Symfony\Component\Console\Application;
25045 use Symfony\Component\Console\Input\StringInput;
25046 use Symfony\Component\Console\Output\ConsoleOutput;
25047
25048 /*
25049  * This file is part of the Symfony framework.
25050  *
25051  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25052  *
25053  * This source file is subject to the MIT license that is bundled
25054  * with this source code in the file LICENSE.
25055  */
25056
25057 /**
25058  * A Shell wraps an Application to add shell capabilities to it.
25059  *
25060  * This class only works with a PHP compiled with readline support
25061  * (either --with-readline or --with-libedit)
25062  *
25063  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25064  */
25065 class Shell
25066 {
25067     protected $application;
25068     protected $history;
25069     protected $output;
25070
25071     /**
25072      * Constructor.
25073      *
25074      * If there is no readline support for the current PHP executable
25075      * a \RuntimeException exception is thrown.
25076      *
25077      * @param Application $application An application instance
25078      *
25079      * @throws \RuntimeException When Readline extension is not enabled
25080      */
25081     public function __construct(Application $application)
25082     {
25083         if (!function_exists('readline')) {
25084             throw new \RuntimeException('Unable to start the shell as the Readline extension is not enabled.');
25085         }
25086
25087         $this->application = $application;
25088         $this->history = getenv('HOME').'/.history_'.$application->getName();
25089         $this->output = new ConsoleOutput();
25090     }
25091
25092     /**
25093      * Runs the shell.
25094      */
25095     public function run()
25096     {
25097         $this->application->setAutoExit(false);
25098         $this->application->setCatchExceptions(true);
25099
25100         readline_read_history($this->history);
25101         readline_completion_function(array($this, 'autocompleter'));
25102
25103         $this->output->writeln($this->getHeader());
25104         while (true) {
25105             $command = readline($this->application->getName().' > ');
25106
25107             if (false === $command) {
25108                 $this->output->writeln("\n");
25109
25110                 break;
25111             }
25112
25113             readline_add_history($command);
25114             readline_write_history($this->history);
25115
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));
25118             }
25119         }
25120     }
25121
25122     /**
25123      * Tries to return autocompletion for the current entered text.
25124      *
25125      * @param string  $text     The last segment of the entered text
25126      * @param integer $position The current position
25127      */
25128     protected function autocompleter($text, $position)
25129     {
25130         $info = readline_info();
25131         $text = substr($info['line_buffer'], 0, $info['end']);
25132
25133         if ($info['point'] !== $info['end']) {
25134             return true;
25135         }
25136
25137         // task name?
25138         if (false === strpos($text, ' ') || !$text) {
25139             return array_keys($this->application->getCommands());
25140         }
25141
25142         // options and arguments?
25143         try {
25144             $command = $this->application->findCommand(substr($text, 0, strpos($text, ' ')));
25145         } catch (\Exception $e) {
25146             return true;
25147         }
25148
25149         $list = array('--help');
25150         foreach ($command->getDefinition()->getOptions() as $option) {
25151             $list[] = '--'.$option->getName();
25152         }
25153
25154         return $list;
25155     }
25156
25157     /**
25158      * Returns the shell header.
25159      *
25160      * @return string The header string
25161      */
25162     protected function getHeader()
25163     {
25164         return <<<EOF
25165
25166 Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).
25167
25168 At the prompt, type <comment>help</comment> for some help,
25169 or <comment>list</comment> to get a list available commands.
25170
25171 To exit the shell, type <comment>^D</comment>.
25172
25173 EOF;
25174     }
25175 }
25176 <?php
25177
25178 namespace Symfony\Component\Console\Helper;
25179
25180 /*
25181  * This file is part of the Symfony framework.
25182  *
25183  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25184  *
25185  * This source file is subject to the MIT license that is bundled
25186  * with this source code in the file LICENSE.
25187  */
25188
25189 /**
25190  * The Formatter class provides helpers to format messages.
25191  *
25192  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25193  */
25194 class FormatterHelper extends Helper
25195 {
25196     /**
25197      * Formats a message within a section.
25198      *
25199      * @param string  $section The section name
25200      * @param string  $message The message
25201      * @param string  $style   The style to apply to the section
25202      */
25203     public function formatSection($section, $message, $style = 'info')
25204     {
25205         return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
25206     }
25207
25208     /**
25209      * Formats a message as a block of text.
25210      *
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
25214      *
25215      * @return string The formatter message
25216      */
25217     public function formatBlock($messages, $style, $large = false)
25218     {
25219         if (!is_array($messages)) {
25220             $messages = array($messages);
25221         }
25222
25223         $len = 0;
25224         $lines = array();
25225         foreach ($messages as $message) {
25226             $lines[] = sprintf($large ? '  %s  ' : ' %s ', $message);
25227             $len = max($this->strlen($message) + ($large ? 4 : 2), $len);
25228         }
25229
25230         $messages = $large ? array(str_repeat(' ', $len)) : array();
25231         foreach ($lines as $line) {
25232             $messages[] = $line.str_repeat(' ', $len - $this->strlen($line));
25233         }
25234         if ($large) {
25235             $messages[] = str_repeat(' ', $len);
25236         }
25237
25238         foreach ($messages as &$message) {
25239             $message = sprintf('<%s>%s</%s>', $style, $message, $style);
25240         }
25241
25242         return implode("\n", $messages);
25243     }
25244
25245     protected function strlen($string)
25246     {
25247         return function_exists('mb_strlen') ? mb_strlen($string) : strlen($string);
25248     }
25249
25250     /**
25251      * Returns the helper's canonical name
25252      */
25253     public function getName()
25254     {
25255         return 'formatter';
25256     }
25257 }
25258 <?php
25259
25260 namespace Symfony\Component\Console\Helper;
25261
25262 use Symfony\Component\Console\Command\Command;
25263
25264 /*
25265  * This file is part of the Symfony framework.
25266  *
25267  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25268  *
25269  * This source file is subject to the MIT license that is bundled
25270  * with this source code in the file LICENSE.
25271  */
25272
25273 /**
25274  * HelperSet represents a set of helpers to be used with a command.
25275  *
25276  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25277  */
25278 class HelperSet
25279 {
25280     protected $helpers;
25281     protected $command;
25282
25283     /**
25284      * @param Helper[] $helpers An array of helper.
25285      */
25286     public function __construct(array $helpers = array())
25287     {
25288         $this->helpers = array();
25289         foreach ($helpers as $alias => $helper) {
25290             $this->set($helper, is_int($alias) ? null : $alias);
25291         }
25292     }
25293
25294     /**
25295      * Sets a helper.
25296      *
25297      * @param HelperInterface $value The helper instance
25298      * @param string                    $alias An alias
25299      */
25300     public function set(HelperInterface $helper, $alias = null)
25301     {
25302         $this->helpers[$helper->getName()] = $helper;
25303         if (null !== $alias) {
25304             $this->helpers[$alias] = $helper;
25305         }
25306
25307         $helper->setHelperSet($this);
25308     }
25309
25310     /**
25311      * Returns true if the helper if defined.
25312      *
25313      * @param string  $name The helper name
25314      *
25315      * @return Boolean true if the helper is defined, false otherwise
25316      */
25317     public function has($name)
25318     {
25319         return isset($this->helpers[$name]);
25320     }
25321
25322     /**
25323      * Gets a helper value.
25324      *
25325      * @param string $name The helper name
25326      *
25327      * @return HelperInterface The helper instance
25328      *
25329      * @throws \InvalidArgumentException if the helper is not defined
25330      */
25331     public function get($name)
25332     {
25333         if (!$this->has($name)) {
25334             throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
25335         }
25336
25337         return $this->helpers[$name];
25338     }
25339
25340     /**
25341      * Sets the command associated with this helper set.
25342      *
25343      * @param Command $command A Command instance
25344      */
25345     public function setCommand(Command $command = null)
25346     {
25347         $this->command = $command;
25348     }
25349
25350     /**
25351      * Gets the command associated with this helper set.
25352      *
25353      * @return Command A Command instance
25354      */
25355     public function getCommand()
25356     {
25357         return $this->command;
25358     }
25359 }
25360 <?php
25361
25362 namespace Symfony\Component\Console\Helper;
25363
25364 /*
25365  * This file is part of the Symfony framework.
25366  *
25367  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25368  *
25369  * This source file is subject to the MIT license that is bundled
25370  * with this source code in the file LICENSE.
25371  */
25372
25373 /**
25374  * Helper is the base class for all helper classes.
25375  *
25376  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25377  */
25378 abstract class Helper implements HelperInterface
25379 {
25380     protected $helperSet = null;
25381
25382     /**
25383      * Sets the helper set associated with this helper.
25384      *
25385      * @param HelperSet $helperSet A HelperSet instance
25386      */
25387     public function setHelperSet(HelperSet $helperSet = null)
25388     {
25389         $this->helperSet = $helperSet;
25390     }
25391
25392     /**
25393      * Gets the helper set associated with this helper.
25394      *
25395      * @return HelperSet A HelperSet instance
25396      */
25397     public function getHelperSet()
25398     {
25399         return $this->helperSet;
25400     }
25401 }
25402 <?php
25403
25404 namespace Symfony\Component\Console\Helper;
25405
25406 /*
25407  * This file is part of the Symfony framework.
25408  *
25409  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25410  *
25411  * This source file is subject to the MIT license that is bundled
25412  * with this source code in the file LICENSE.
25413  */
25414
25415 /**
25416  * HelperInterface is the interface all helpers must implement.
25417  *
25418  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25419  */
25420 interface HelperInterface
25421 {
25422     /**
25423      * Sets the helper set associated with this helper.
25424      *
25425      * @param HelperSet $helperSet A HelperSet instance
25426      */
25427     function setHelperSet(HelperSet $helperSet = null);
25428
25429     /**
25430      * Gets the helper set associated with this helper.
25431      *
25432      * @return HelperSet A HelperSet instance
25433      */
25434     function getHelperSet();
25435
25436     /**
25437      * Returns the canonical name of this helper.
25438      *
25439      * @return string The canonical name
25440      */
25441     function getName();
25442 }
25443 <?php
25444
25445 namespace Symfony\Component\Console\Helper;
25446
25447 use Symfony\Component\Console\Output\OutputInterface;
25448
25449 /*
25450  * This file is part of the Symfony framework.
25451  *
25452  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25453  *
25454  * This source file is subject to the MIT license that is bundled
25455  * with this source code in the file LICENSE.
25456  */
25457
25458 /**
25459  * The Dialog class provides helpers to interact with the user.
25460  *
25461  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25462  */
25463 class DialogHelper extends Helper
25464 {
25465     /**
25466      * Asks a question to the user.
25467      *
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
25471      *
25472      * @return string The user answer
25473      */
25474     public function ask(OutputInterface $output, $question, $default = null)
25475     {
25476         // @codeCoverageIgnoreStart
25477         $output->writeln($question);
25478
25479         $ret = trim(fgets(STDIN));
25480
25481         return $ret ? $ret : $default;
25482         // @codeCoverageIgnoreEnd
25483     }
25484
25485     /**
25486      * Asks a confirmation to the user.
25487      *
25488      * The question will be asked until the user answer by nothing, yes, or no.
25489      *
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
25493      *
25494      * @return Boolean true if the user has confirmed, false otherwise
25495      */
25496     public function askConfirmation(OutputInterface $output, $question, $default = true)
25497     {
25498         // @codeCoverageIgnoreStart
25499         $answer = 'z';
25500         while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) {
25501             $answer = $this->ask($output, $question);
25502         }
25503
25504         if (false === $default) {
25505             return $answer && 'y' == strtolower($answer[0]);
25506         } else {
25507             return !$answer || 'y' == strtolower($answer[0]);
25508         }
25509         // @codeCoverageIgnoreEnd
25510     }
25511
25512     /**
25513      * Asks for a value and validates the response.
25514      *
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)
25519      *
25520      * @return mixed
25521      *
25522      * @throws \Exception When any of the validator returns an error
25523      */
25524     public function askAndValidate(OutputInterface $output, $question, \Closure $validator, $attempts = false)
25525     {
25526         // @codeCoverageIgnoreStart
25527         $error = null;
25528         while (false === $attempts || $attempts--) {
25529             if (null !== $error) {
25530                 $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'));
25531             }
25532
25533             $value = $this->ask($output, $question, null);
25534
25535             try {
25536                 return $validator($value);
25537             } catch (\Exception $error) {
25538             }
25539         }
25540
25541         throw $error;
25542         // @codeCoverageIgnoreEnd
25543     }
25544
25545     /**
25546      * Returns the helper's canonical name
25547      */
25548     public function getName()
25549     {
25550         return 'dialog';
25551     }
25552 }
25553 <?php
25554
25555 namespace Symfony\Component\Console;
25556
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;
25572
25573 /*
25574  * This file is part of the Symfony framework.
25575  *
25576  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
25577  *
25578  * This source file is subject to the MIT license that is bundled
25579  * with this source code in the file LICENSE.
25580  */
25581
25582 /**
25583  * An Application is the container for a collection of commands.
25584  *
25585  * It is the main entry point of a Console application.
25586  *
25587  * This class is optimized for a standard CLI environment.
25588  *
25589  * Usage:
25590  *
25591  *     $app = new Application('myapp', '1.0 (stable)');
25592  *     $app->addCommand(new SimpleCommand());
25593  *     $app->run();
25594  *
25595  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
25596  */
25597 class Application
25598 {
25599     protected $commands;
25600     protected $aliases;
25601     protected $wantHelps = false;
25602     protected $runningCommand;
25603     protected $name;
25604     protected $version;
25605     protected $catchExceptions;
25606     protected $autoExit;
25607     protected $definition;
25608     protected $helperSet;
25609
25610     /**
25611      * Constructor.
25612      *
25613      * @param string  $name    The name of the application
25614      * @param string  $version The version of the application
25615      */
25616     public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
25617     {
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(),
25627         ));
25628
25629         $this->addCommand(new HelpCommand());
25630         $this->addCommand(new ListCommand());
25631
25632         $this->definition = new InputDefinition(array(
25633             new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
25634
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.'),
25641         ));
25642     }
25643
25644     /**
25645      * Runs the current application.
25646      *
25647      * @param InputInterface  $input  An Input instance
25648      * @param OutputInterface $output An Output instance
25649      *
25650      * @return integer 0 if everything went fine, or an error code
25651      *
25652      * @throws \Exception When doRun returns Exception
25653      */
25654     public function run(InputInterface $input = null, OutputInterface $output = null)
25655     {
25656         if (null === $input) {
25657             $input = new ArgvInput();
25658         }
25659
25660         if (null === $output) {
25661             $output = new ConsoleOutput();
25662         }
25663
25664         try {
25665             $statusCode = $this->doRun($input, $output);
25666         } catch (\Exception $e) {
25667             if (!$this->catchExceptions) {
25668                 throw $e;
25669             }
25670
25671             $this->renderException($e, $output);
25672             $statusCode = $e->getCode();
25673
25674             $statusCode = is_numeric($statusCode) && $statusCode ? $statusCode : 1;
25675         }
25676
25677         if ($this->autoExit) {
25678             if ($statusCode > 255) {
25679                 $statusCode = 255;
25680             }
25681             // @codeCoverageIgnoreStart
25682             exit($statusCode);
25683             // @codeCoverageIgnoreEnd
25684         } else {
25685             return $statusCode;
25686         }
25687     }
25688
25689     /**
25690      * Runs the current application.
25691      *
25692      * @param InputInterface  $input  An Input instance
25693      * @param OutputInterface $output An Output instance
25694      *
25695      * @return integer 0 if everything went fine, or an error code
25696      */
25697     public function doRun(InputInterface $input, OutputInterface $output)
25698     {
25699         $name = $this->getCommandName($input);
25700
25701         if (true === $input->hasParameterOption(array('--ansi', '-a'))) {
25702             $output->setDecorated(true);
25703         }
25704
25705         if (true === $input->hasParameterOption(array('--help', '-h'))) {
25706             if (!$name) {
25707                 $name = 'help';
25708                 $input = new ArrayInput(array('command' => 'help'));
25709             } else {
25710                 $this->wantHelps = true;
25711             }
25712         }
25713
25714         if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) {
25715             $input->setInteractive(false);
25716         }
25717
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);
25722         }
25723
25724         if (true === $input->hasParameterOption(array('--version', '-V'))) {
25725             $output->writeln($this->getLongVersion());
25726
25727             return 0;
25728         }
25729
25730         if (!$name) {
25731             $name = 'list';
25732             $input = new ArrayInput(array('command' => 'list'));
25733         }
25734
25735         // the command name MUST be the first element of the input
25736         $command = $this->findCommand($name);
25737
25738         $this->runningCommand = $command;
25739         $statusCode = $command->run($input, $output);
25740         $this->runningCommand = null;
25741
25742         return is_numeric($statusCode) ? $statusCode : 0;
25743     }
25744
25745     /**
25746      * Set a helper set to be used with the command.
25747      *
25748      * @param HelperSet $helperSet The helper set
25749      */
25750     public function setHelperSet(HelperSet $helperSet)
25751     {
25752         $this->helperSet = $helperSet;
25753     }
25754
25755     /**
25756      * Get the helper set associated with the command
25757      *
25758      * @return HelperSet The HelperSet instance associated with this command
25759      */
25760     public function getHelperSet()
25761     {
25762         return $this->helperSet;
25763     }
25764
25765     /**
25766      * Gets the InputDefinition related to this Application.
25767      *
25768      * @return InputDefinition The InputDefinition instance
25769      */
25770     public function getDefinition()
25771     {
25772         return $this->definition;
25773     }
25774
25775     /**
25776      * Gets the help message.
25777      *
25778      * @return string A help message.
25779      */
25780     public function getHelp()
25781     {
25782         $messages = array(
25783             $this->getLongVersion(),
25784             '',
25785             '<comment>Usage:</comment>',
25786             sprintf("  [options] command [arguments]\n"),
25787             '<comment>Options:</comment>',
25788         );
25789
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()
25795             );
25796         }
25797
25798         return implode("\n", $messages);
25799     }
25800
25801     /**
25802      * Sets whether to catch exceptions or not during commands execution.
25803      *
25804      * @param Boolean $boolean Whether to catch exceptions or not during commands execution
25805      */
25806     public function setCatchExceptions($boolean)
25807     {
25808         $this->catchExceptions = (Boolean) $boolean;
25809     }
25810
25811     /**
25812      * Sets whether to automatically exit after a command execution or not.
25813      *
25814      * @param Boolean $boolean Whether to automatically exit after a command execution or not
25815      */
25816     public function setAutoExit($boolean)
25817     {
25818         $this->autoExit = (Boolean) $boolean;
25819     }
25820
25821     /**
25822      * Gets the name of the application.
25823      *
25824      * @return string The application name
25825      */
25826     public function getName()
25827     {
25828         return $this->name;
25829     }
25830
25831     /**
25832      * Sets the application name.
25833      *
25834      * @param string $name The application name
25835      */
25836     public function setName($name)
25837     {
25838         $this->name = $name;
25839     }
25840
25841     /**
25842      * Gets the application version.
25843      *
25844      * @return string The application version
25845      */
25846     public function getVersion()
25847     {
25848         return $this->version;
25849     }
25850
25851     /**
25852      * Sets the application version.
25853      *
25854      * @param string $version The application version
25855      */
25856     public function setVersion($version)
25857     {
25858         $this->version = $version;
25859     }
25860
25861     /**
25862      * Returns the long version of the application.
25863      *
25864      * @return string The long application version
25865      */
25866     public function getLongVersion()
25867     {
25868         if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
25869             return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
25870         } else {
25871             return '<info>Console Tool</info>';
25872         }
25873     }
25874
25875     /**
25876      * Registers a new command.
25877      *
25878      * @param string $name The command name
25879      *
25880      * @return Command The newly created command
25881      */
25882     public function register($name)
25883     {
25884         return $this->addCommand(new Command($name));
25885     }
25886
25887     /**
25888      * Adds an array of command objects.
25889      *
25890      * @param Command[] $commands An array of commands
25891      */
25892     public function addCommands(array $commands)
25893     {
25894         foreach ($commands as $command) {
25895             $this->addCommand($command);
25896         }
25897     }
25898
25899     /**
25900      * Adds a command object.
25901      *
25902      * If a command with the same name already exists, it will be overridden.
25903      *
25904      * @param Command $command A Command object
25905      *
25906      * @return Command The registered command
25907      */
25908     public function addCommand(Command $command)
25909     {
25910         $command->setApplication($this);
25911
25912         $this->commands[$command->getFullName()] = $command;
25913
25914         foreach ($command->getAliases() as $alias) {
25915             $this->aliases[$alias] = $command;
25916         }
25917
25918         return $command;
25919     }
25920
25921     /**
25922      * Returns a registered command by name or alias.
25923      *
25924      * @param string $name The command name or alias
25925      *
25926      * @return Command A Command object
25927      *
25928      * @throws \InvalidArgumentException When command name given does not exist
25929      */
25930     public function getCommand($name)
25931     {
25932         if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
25933             throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
25934         }
25935
25936         $command = isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name];
25937
25938         if ($this->wantHelps) {
25939             $this->wantHelps = false;
25940
25941             $helpCommand = $this->getCommand('help');
25942             $helpCommand->setCommand($command);
25943
25944             return $helpCommand;
25945         }
25946
25947         return $command;
25948     }
25949
25950     /**
25951      * Returns true if the command exists, false otherwise
25952      *
25953      * @param string $name The command name or alias
25954      *
25955      * @return Boolean true if the command exists, false otherwise
25956      */
25957     public function hasCommand($name)
25958     {
25959         return isset($this->commands[$name]) || isset($this->aliases[$name]);
25960     }
25961
25962     /**
25963      * Returns an array of all unique namespaces used by currently registered commands.
25964      *
25965      * It does not returns the global namespace which always exists.
25966      *
25967      * @return array An array of namespaces
25968      */
25969     public function getNamespaces()
25970     {
25971         $namespaces = array();
25972         foreach ($this->commands as $command) {
25973             if ($command->getNamespace()) {
25974                 $namespaces[$command->getNamespace()] = true;
25975             }
25976         }
25977
25978         return array_keys($namespaces);
25979     }
25980
25981     /**
25982      * Finds a registered namespace by a name or an abbreviation.
25983      *
25984      * @return string A registered namespace
25985      *
25986      * @throws \InvalidArgumentException When namespace is incorrect or ambiguous
25987      */
25988     public function findNamespace($namespace)
25989     {
25990         $abbrevs = static::getAbbreviations($this->getNamespaces());
25991
25992         if (!isset($abbrevs[$namespace])) {
25993             throw new \InvalidArgumentException(sprintf('There are no commands defined in the "%s" namespace.', $namespace));
25994         }
25995
25996         if (count($abbrevs[$namespace]) > 1) {
25997             throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$namespace])));
25998         }
25999
26000         return $abbrevs[$namespace][0];
26001     }
26002
26003     /**
26004      * Finds a command by name or alias.
26005      *
26006      * Contrary to getCommand, this command tries to find the best
26007      * match if you give it an abbreviation of a name or alias.
26008      *
26009      * @param  string $name A command name or a command alias
26010      *
26011      * @return Command A Command instance
26012      *
26013      * @throws \InvalidArgumentException When command name is incorrect or ambiguous
26014      */
26015     public function findCommand($name)
26016     {
26017         // namespace
26018         $namespace = '';
26019         if (false !== $pos = strrpos($name, ':')) {
26020             $namespace = $this->findNamespace(substr($name, 0, $pos));
26021             $name = substr($name, $pos + 1);
26022         }
26023
26024         $fullName = $namespace ? $namespace.':'.$name : $name;
26025
26026         // name
26027         $commands = array();
26028         foreach ($this->commands as $command) {
26029             if ($command->getNamespace() == $namespace) {
26030                 $commands[] = $command->getName();
26031             }
26032         }
26033
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]);
26037         }
26038
26039         if (isset($abbrevs[$name]) && count($abbrevs[$name]) > 1) {
26040             $suggestions = $this->getAbbreviationSuggestions(array_map(function ($command) use ($namespace) { return $namespace.':'.$command; }, $abbrevs[$name]));
26041
26042             throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $fullName, $suggestions));
26043         }
26044
26045         // aliases
26046         $abbrevs = static::getAbbreviations(array_keys($this->aliases));
26047         if (!isset($abbrevs[$fullName])) {
26048             throw new \InvalidArgumentException(sprintf('Command "%s" is not defined.', $fullName));
26049         }
26050
26051         if (count($abbrevs[$fullName]) > 1) {
26052             throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $fullName, $this->getAbbreviationSuggestions($abbrevs[$fullName])));
26053         }
26054
26055         return $this->getCommand($abbrevs[$fullName][0]);
26056     }
26057
26058     /**
26059      * Gets the commands (registered in the given namespace if provided).
26060      *
26061      * The array keys are the full names and the values the command instances.
26062      *
26063      * @param  string  $namespace A namespace name
26064      *
26065      * @return array An array of Command instances
26066      */
26067     public function getCommands($namespace = null)
26068     {
26069         if (null === $namespace) {
26070             return $this->commands;
26071         }
26072
26073         $commands = array();
26074         foreach ($this->commands as $name => $command) {
26075             if ($namespace === $command->getNamespace()) {
26076                 $commands[$name] = $command;
26077             }
26078         }
26079
26080         return $commands;
26081     }
26082
26083     /**
26084      * Returns an array of possible abbreviations given a set of names.
26085      *
26086      * @param array $names An array of names
26087      *
26088      * @return array An array of abbreviations
26089      */
26090     static public function getAbbreviations($names)
26091     {
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);
26098                 } else {
26099                     $abbrevs[$abbrev][] = $name;
26100                 }
26101             }
26102         }
26103
26104         // Non-abbreviations always get entered, even if they aren't unique
26105         foreach ($names as $name) {
26106             $abbrevs[$name] = array($name);
26107         }
26108
26109         return $abbrevs;
26110     }
26111
26112     /**
26113      * Returns a text representation of the Application.
26114      *
26115      * @param string $namespace An optional namespace name
26116      *
26117      * @return string A string representing the Application
26118      */
26119     public function asText($namespace = null)
26120     {
26121         $commands = $namespace ? $this->getCommands($this->findNamespace($namespace)) : $this->commands;
26122
26123         $messages = array($this->getHelp(), '');
26124         if ($namespace) {
26125             $messages[] = sprintf("<comment>Available commands for the \"%s\" namespace:</comment>", $namespace);
26126         } else {
26127             $messages[] = '<comment>Available commands:</comment>';
26128         }
26129
26130         $width = 0;
26131         foreach ($commands as $command) {
26132             $width = strlen($command->getName()) > $width ? strlen($command->getName()) : $width;
26133         }
26134         $width += 2;
26135
26136         // add commands by namespace
26137         foreach ($this->sortCommands($commands) as $space => $commands) {
26138             if (!$namespace && '_global' !== $space) {
26139                 $messages[] = '<comment>'.$space.'</comment>';
26140             }
26141
26142             foreach ($commands as $command) {
26143                 $aliases = $command->getAliases() ? '<comment> ('.implode(', ', $command->getAliases()).')</comment>' : '';
26144
26145                 $messages[] = sprintf("  <info>%-${width}s</info> %s%s", ($command->getNamespace() ? ':' : '').$command->getName(), $command->getDescription(), $aliases);
26146             }
26147         }
26148
26149         return implode("\n", $messages);
26150     }
26151
26152     /**
26153      * Returns an XML representation of the Application.
26154      *
26155      * @param string $namespace An optional namespace name
26156      * @param Boolean $asDom Whether to return a DOM or an XML string
26157      *
26158      * @return string|DOMDocument An XML string representing the Application
26159      */
26160     public function asXml($namespace = null, $asDom = false)
26161     {
26162         $commands = $namespace ? $this->getCommands($this->findNamespace($namespace)) : $this->commands;
26163
26164         $dom = new \DOMDocument('1.0', 'UTF-8');
26165         $dom->formatOutput = true;
26166         $dom->appendChild($xml = $dom->createElement('symfony'));
26167
26168         $xml->appendChild($commandsXML = $dom->createElement('commands'));
26169
26170         if ($namespace) {
26171             $commandsXML->setAttribute('namespace', $namespace);
26172         } else {
26173             $xml->appendChild($namespacesXML = $dom->createElement('namespaces'));
26174         }
26175
26176         // add commands by namespace
26177         foreach ($this->sortCommands($commands) as $space => $commands) {
26178             if (!$namespace) {
26179                 $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
26180                 $namespaceArrayXML->setAttribute('id', $space);
26181             }
26182
26183             foreach ($commands as $command) {
26184                 if (!$namespace) {
26185                     $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
26186                     $commandXML->appendChild($dom->createTextNode($command->getName()));
26187                 }
26188
26189                 $node = $command->asXml(true)->getElementsByTagName('command')->item(0);
26190                 $node = $dom->importNode($node, true);
26191
26192                 $commandsXML->appendChild($node);
26193             }
26194         }
26195
26196         return $asDom ? $dom : $dom->saveXml();
26197     }
26198
26199     /**
26200      * Renders a catched exception.
26201      *
26202      * @param Exception       $e      An exception instance
26203      * @param OutputInterface $output An OutputInterface instance
26204      */
26205     public function renderException($e, $output)
26206     {
26207         $strlen = function ($string)
26208         {
26209             return function_exists('mb_strlen') ? mb_strlen($string) : strlen($string);
26210         };
26211
26212         $title = sprintf('  [%s]  ', get_class($e));
26213         $len = $strlen($title);
26214         $lines = array();
26215         foreach (explode("\n", $e->getMessage()) as $line) {
26216             $lines[] = sprintf('  %s  ', $line);
26217             $len = max($strlen($line) + 4, $len);
26218         }
26219
26220         $messages = array(str_repeat(' ', $len), $title.str_repeat(' ', $len - $strlen($title)));
26221
26222         foreach ($lines as $line) {
26223             $messages[] = $line.str_repeat(' ', $len - $strlen($line));
26224         }
26225
26226         $messages[] = str_repeat(' ', $len);
26227
26228         $output->writeln("\n");
26229         foreach ($messages as $message) {
26230             $output->writeln('<error>'.$message.'</error>');
26231         }
26232         $output->writeln("\n");
26233
26234         if (null !== $this->runningCommand) {
26235             $output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())));
26236             $output->writeln("\n");
26237         }
26238
26239         if (Output::VERBOSITY_VERBOSE === $output->getVerbosity()) {
26240             $output->writeln('</comment>Exception trace:</comment>');
26241
26242             // exception related properties
26243             $trace = $e->getTrace();
26244             array_unshift($trace, array(
26245                 'function' => '',
26246                 'file'     => $e->getFile() != null ? $e->getFile() : 'n/a',
26247                 'line'     => $e->getLine() != null ? $e->getLine() : 'n/a',
26248                 'args'     => array(),
26249             ));
26250
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';
26257
26258                 $output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line));
26259             }
26260
26261             $output->writeln("\n");
26262         }
26263     }
26264
26265     protected function getCommandName(InputInterface $input)
26266     {
26267         return $input->getFirstArgument('command');
26268     }
26269
26270     protected function sortCommands($commands)
26271     {
26272         $namespacedCommands = array();
26273         foreach ($commands as $name => $command) {
26274             $key = $command->getNamespace() ? $command->getNamespace() : '_global';
26275
26276             if (!isset($namespacedCommands[$key])) {
26277                 $namespacedCommands[$key] = array();
26278             }
26279
26280             $namespacedCommands[$key][$name] = $command;
26281         }
26282         ksort($namespacedCommands);
26283
26284         foreach ($namespacedCommands as $name => &$commands) {
26285             ksort($commands);
26286         }
26287
26288         return $namespacedCommands;
26289     }
26290
26291     protected function getAbbreviationSuggestions($abbrevs)
26292     {
26293         return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
26294     }
26295 }
26296 <?php
26297
26298 namespace Symfony\Component\Console\Tester;
26299
26300 use Symfony\Component\Console\Application;
26301 use Symfony\Component\Console\Input\ArrayInput;
26302 use Symfony\Component\Console\Output\StreamOutput;
26303
26304 /*
26305  * This file is part of the Symfony framework.
26306  *
26307  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
26308  *
26309  * This source file is subject to the MIT license that is bundled
26310  * with this source code in the file LICENSE.
26311  */
26312
26313 /**
26314  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
26315  */
26316 class ApplicationTester
26317 {
26318     protected $application;
26319     protected $display;
26320     protected $input;
26321     protected $output;
26322
26323     /**
26324      * Constructor.
26325      *
26326      * @param Application $application A Application instance to test.
26327      */
26328     public function __construct(Application $application)
26329     {
26330         $this->application = $application;
26331     }
26332
26333     /**
26334      * Executes the application.
26335      *
26336      * Available options:
26337      *
26338      *  * interactive: Sets the input interactive flag
26339      *  * decorated:   Sets the output decorated flag
26340      *  * verbosity:   Sets the output verbosity flag
26341      *
26342      * @param array $input   An array of arguments and options
26343      * @param array $options An array of options
26344      */
26345     public function run(array $input, $options = array())
26346     {
26347         $this->input = new ArrayInput($input);
26348         if (isset($options['interactive'])) {
26349             $this->input->setInteractive($options['interactive']);
26350         }
26351
26352         $this->output = new StreamOutput(fopen('php://memory', 'w', false));
26353         if (isset($options['decorated'])) {
26354             $this->output->setDecorated($options['decorated']);
26355         }
26356         if (isset($options['verbosity'])) {
26357             $this->output->setVerbosity($options['verbosity']);
26358         }
26359
26360         $ret = $this->application->run($this->input, $this->output);
26361
26362         rewind($this->output->getStream());
26363
26364         return $this->display = stream_get_contents($this->output->getStream());
26365     }
26366
26367     /**
26368      * Gets the display returned by the last execution of the application.
26369      *
26370      * @return string The display
26371      */
26372     public function getDisplay()
26373     {
26374         return $this->display;
26375     }
26376
26377     /**
26378      * Gets the input instance used by the last execution of the application.
26379      *
26380      * @return InputInterface The current input instance
26381      */
26382     public function getInput()
26383     {
26384         return $this->input;
26385     }
26386
26387     /**
26388      * Gets the output instance used by the last execution of the application.
26389      *
26390      * @return OutputInterface The current output instance
26391      */
26392     public function getOutput()
26393     {
26394         return $this->output;
26395     }
26396 }
26397 <?php
26398
26399 namespace Symfony\Component\Console\Tester;
26400
26401 use Symfony\Component\Console\Command\Command;
26402 use Symfony\Component\Console\Input\ArrayInput;
26403 use Symfony\Component\Console\Output\StreamOutput;
26404
26405 /*
26406  * This file is part of the Symfony framework.
26407  *
26408  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
26409  *
26410  * This source file is subject to the MIT license that is bundled
26411  * with this source code in the file LICENSE.
26412  */
26413
26414 /**
26415  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
26416  */
26417 class CommandTester
26418 {
26419     protected $command;
26420     protected $display;
26421     protected $input;
26422     protected $output;
26423
26424     /**
26425      * Constructor.
26426      *
26427      * @param Command $command A Command instance to test.
26428      */
26429     public function __construct(Command $command)
26430     {
26431         $this->command = $command;
26432     }
26433
26434     /**
26435      * Executes the command.
26436      *
26437      * Available options:
26438      *
26439      *  * interactive: Sets the input interactive flag
26440      *  * decorated:   Sets the output decorated flag
26441      *  * verbosity:   Sets the output verbosity flag
26442      *
26443      * @param array $input   An array of arguments and options
26444      * @param array $options An array of options
26445      */
26446     public function execute(array $input, array $options = array())
26447     {
26448         $this->input = new ArrayInput($input);
26449         if (isset($options['interactive'])) {
26450             $this->input->setInteractive($options['interactive']);
26451         }
26452
26453         $this->output = new StreamOutput(fopen('php://memory', 'w', false));
26454         if (isset($options['decorated'])) {
26455             $this->output->setDecorated($options['decorated']);
26456         }
26457         if (isset($options['verbosity'])) {
26458             $this->output->setVerbosity($options['verbosity']);
26459         }
26460
26461         $ret = $this->command->run($this->input, $this->output);
26462
26463         rewind($this->output->getStream());
26464
26465         return $this->display = stream_get_contents($this->output->getStream());
26466     }
26467
26468     /**
26469      * Gets the display returned by the last execution of the command.
26470      *
26471      * @return string The display
26472      */
26473     public function getDisplay()
26474     {
26475         return $this->display;
26476     }
26477
26478     /**
26479      * Gets the input instance used by the last execution of the command.
26480      *
26481      * @return InputInterface The current input instance
26482      */
26483     public function getInput()
26484     {
26485         return $this->input;
26486     }
26487
26488     /**
26489      * Gets the output instance used by the last execution of the command.
26490      *
26491      * @return OutputInterface The current output instance
26492      */
26493     public function getOutput()
26494     {
26495         return $this->output;
26496     }
26497 }
26498 <?php
26499
26500 namespace Symfony\Component\Console\Input;
26501
26502 /*
26503  * This file is part of the Symfony framework.
26504  *
26505  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
26506  *
26507  * This source file is subject to the MIT license that is bundled
26508  * with this source code in the file LICENSE.
26509  */
26510
26511 /**
26512  * Input is the base class for all concrete Input classes.
26513  *
26514  * Three concrete classes are provided by default:
26515  *
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
26519  *
26520  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
26521  */
26522 abstract class Input implements InputInterface
26523 {
26524     protected $definition;
26525     protected $options;
26526     protected $arguments;
26527     protected $interactive = true;
26528
26529     /**
26530      * Constructor.
26531      *
26532      * @param InputDefinition $definition A InputDefinition instance
26533      */
26534     public function __construct(InputDefinition $definition = null)
26535     {
26536         if (null === $definition) {
26537             $this->definition = new InputDefinition();
26538         } else {
26539             $this->bind($definition);
26540             $this->validate();
26541         }
26542     }
26543
26544     /**
26545      * Binds the current Input instance with the given arguments and options.
26546      *
26547      * @param InputDefinition $definition A InputDefinition instance
26548      */
26549     public function bind(InputDefinition $definition)
26550     {
26551         $this->arguments = array();
26552         $this->options = array();
26553         $this->definition = $definition;
26554
26555         $this->parse();
26556     }
26557
26558     /**
26559      * Processes command line arguments.
26560      */
26561     abstract protected function parse();
26562
26563     /**
26564      * @throws \RuntimeException When not enough arguments are given
26565      */
26566     public function validate()
26567     {
26568         if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) {
26569             throw new \RuntimeException('Not enough arguments.');
26570         }
26571     }
26572
26573     public function isInteractive()
26574     {
26575         return $this->interactive;
26576     }
26577
26578     public function setInteractive($interactive)
26579     {
26580         $this->interactive = (Boolean) $interactive;
26581     }
26582
26583     /**
26584      * Returns the argument values.
26585      *
26586      * @return array An array of argument values
26587      */
26588     public function getArguments()
26589     {
26590         return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
26591     }
26592
26593     /**
26594      * Returns the argument value for a given argument name.
26595      *
26596      * @param string $name The argument name
26597      *
26598      * @return mixed The argument value
26599      *
26600      * @throws \InvalidArgumentException When argument given doesn't exist
26601      */
26602     public function getArgument($name)
26603     {
26604         if (!$this->definition->hasArgument($name)) {
26605             throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
26606         }
26607
26608         return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
26609     }
26610
26611     /**
26612      * Sets an argument value by name.
26613      *
26614      * @param string $name  The argument name
26615      * @param string $value The argument value
26616      *
26617      * @throws \InvalidArgumentException When argument given doesn't exist
26618      */
26619     public function setArgument($name, $value)
26620     {
26621         if (!$this->definition->hasArgument($name)) {
26622             throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
26623         }
26624
26625         $this->arguments[$name] = $value;
26626     }
26627
26628     /**
26629      * Returns true if an InputArgument object exists by name or position.
26630      *
26631      * @param string|integer $name The InputArgument name or position
26632      *
26633      * @return Boolean true if the InputArgument object exists, false otherwise
26634      */
26635     public function hasArgument($name)
26636     {
26637         return $this->definition->hasArgument($name);
26638     }
26639
26640     /**
26641      * Returns the options values.
26642      *
26643      * @return array An array of option values
26644      */
26645     public function getOptions()
26646     {
26647         return array_merge($this->definition->getOptionDefaults(), $this->options);
26648     }
26649
26650     /**
26651      * Returns the option value for a given option name.
26652      *
26653      * @param string $name The option name
26654      *
26655      * @return mixed The option value
26656      *
26657      * @throws \InvalidArgumentException When option given doesn't exist
26658      */
26659     public function getOption($name)
26660     {
26661         if (!$this->definition->hasOption($name)) {
26662             throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
26663         }
26664
26665         return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
26666     }
26667
26668     /**
26669      * Sets an option value by name.
26670      *
26671      * @param string $name  The option name
26672      * @param string $value The option value
26673      *
26674      * @throws \InvalidArgumentException When option given doesn't exist
26675      */
26676     public function setOption($name, $value)
26677     {
26678         if (!$this->definition->hasOption($name)) {
26679             throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
26680         }
26681
26682         $this->options[$name] = $value;
26683     }
26684
26685     /**
26686      * Returns true if an InputOption object exists by name.
26687      *
26688      * @param string $name The InputOption name
26689      *
26690      * @return Boolean true if the InputOption object exists, false otherwise
26691      */
26692     public function hasOption($name)
26693     {
26694         return $this->definition->hasOption($name);
26695     }
26696 }
26697 <?php
26698
26699 namespace Symfony\Component\Console\Input;
26700
26701 /*
26702  * This file is part of the Symfony framework.
26703  *
26704  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
26705  *
26706  * This source file is subject to the MIT license that is bundled
26707  * with this source code in the file LICENSE.
26708  */
26709
26710 /**
26711  * ArrayInput represents an input provided as an array.
26712  *
26713  * Usage:
26714  *
26715  *     $input = new ArrayInput(array('name' => 'foo', '--bar' => 'foobar'));
26716  *
26717  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
26718  */
26719 class ArrayInput extends Input
26720 {
26721     protected $parameters;
26722
26723     /**
26724      * Constructor.
26725      *
26726      * @param array           $param An array of parameters
26727      * @param InputDefinition $definition A InputDefinition instance
26728      */
26729     public function __construct(array $parameters, InputDefinition $definition = null)
26730     {
26731         $this->parameters = $parameters;
26732
26733         parent::__construct($definition);
26734     }
26735
26736     /**
26737      * Returns the first argument from the raw parameters (not parsed).
26738      *
26739      * @return string The value of the first argument or null otherwise
26740      */
26741     public function getFirstArgument()
26742     {
26743         foreach ($this->parameters as $key => $value) {
26744             if ($key && '-' === $key[0]) {
26745                 continue;
26746             }
26747
26748             return $value;
26749         }
26750     }
26751
26752     /**
26753      * Returns true if the raw parameters (not parsed) contains a value.
26754      *
26755      * This method is to be used to introspect the input parameters
26756      * before it has been validated. It must be used carefully.
26757      *
26758      * @param string|array $value The values to look for in the raw parameters (can be an array)
26759      *
26760      * @return Boolean true if the value is contained in the raw parameters
26761      */
26762     public function hasParameterOption($values)
26763     {
26764         if (!is_array($values)) {
26765             $values = array($values);
26766         }
26767
26768         foreach ($this->parameters as $k => $v) {
26769             if (!is_int($k)) {
26770                 $v = $k;
26771             }
26772
26773             if (in_array($v, $values)) {
26774                 return true;
26775             }
26776         }
26777
26778         return false;
26779     }
26780
26781     /**
26782      * Processes command line arguments.
26783      */
26784     protected function parse()
26785     {
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);
26791             } else {
26792                 $this->addArgument($key, $value);
26793             }
26794         }
26795     }
26796
26797     /**
26798      * Adds a short option value.
26799      *
26800      * @param string $shortcut The short option key
26801      * @param mixed  $value    The value for the option
26802      *
26803      * @throws \RuntimeException When option given doesn't exist
26804      */
26805     protected function addShortOption($shortcut, $value)
26806     {
26807         if (!$this->definition->hasShortcut($shortcut)) {
26808             throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
26809         }
26810
26811         $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
26812     }
26813
26814     /**
26815      * Adds a long option value.
26816      *
26817      * @param string $name  The long option key
26818      * @param mixed  $value The value for the option
26819      *
26820      * @throws \InvalidArgumentException When option given doesn't exist
26821      * @throws \InvalidArgumentException When a required value is missing
26822      */
26823     protected function addLongOption($name, $value)
26824     {
26825         if (!$this->definition->hasOption($name)) {
26826             throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
26827         }
26828
26829         $option = $this->definition->getOption($name);
26830
26831         if (null === $value) {
26832             if ($option->isParameterRequired()) {
26833                 throw new \InvalidArgumentException(sprintf('The "--%s" option requires a value.', $name));
26834             }
26835
26836             $value = $option->isParameterOptional() ? $option->getDefault() : true;
26837         }
26838
26839         $this->options[$name] = $value;
26840     }
26841
26842     /**
26843      * Adds an argument value.
26844      *
26845      * @param string $name  The argument name
26846      * @param mixed  $value The value for the argument
26847      *
26848      * @throws \InvalidArgumentException When argument given doesn't exist
26849      */
26850     protected function addArgument($name, $value)
26851     {
26852         if (!$this->definition->hasArgument($name)) {
26853             throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
26854         }
26855
26856         $this->arguments[$name] = $value;
26857     }
26858 }
26859 <?php
26860
26861 namespace Symfony\Component\Console\Input;
26862
26863 /*
26864  * This file is part of the Symfony framework.
26865  *
26866  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
26867  *
26868  * This source file is subject to the MIT license that is bundled
26869  * with this source code in the file LICENSE.
26870  */
26871
26872 /**
26873  * Represents a command line option.
26874  *
26875  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
26876  */
26877 class InputOption
26878 {
26879     const PARAMETER_NONE     = 1;
26880     const PARAMETER_REQUIRED = 2;
26881     const PARAMETER_OPTIONAL = 4;
26882     const PARAMETER_IS_ARRAY = 8;
26883
26884     protected $name;
26885     protected $shortcut;
26886     protected $mode;
26887     protected $default;
26888     protected $description;
26889
26890     /**
26891      * Constructor.
26892      *
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)
26898      *
26899      * @throws \InvalidArgumentException If option mode is invalid or incompatible
26900      */
26901     public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
26902     {
26903         if ('--' === substr($name, 0, 2)) {
26904             $name = substr($name, 2);
26905         }
26906
26907         if (empty($shortcut)) {
26908             $shortcut = null;
26909         }
26910
26911         if (null !== $shortcut) {
26912             if ('-' === $shortcut[0]) {
26913                 $shortcut = substr($shortcut, 1);
26914             }
26915         }
26916
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));
26921         }
26922
26923         $this->name        = $name;
26924         $this->shortcut    = $shortcut;
26925         $this->mode        = $mode;
26926         $this->description = $description;
26927
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.');
26930         }
26931
26932         $this->setDefault($default);
26933     }
26934
26935     /**
26936      * Returns the shortcut.
26937      *
26938      * @return string The shortcut
26939      */
26940     public function getShortcut()
26941     {
26942         return $this->shortcut;
26943     }
26944
26945     /**
26946      * Returns the name.
26947      *
26948      * @return string The name
26949      */
26950     public function getName()
26951     {
26952         return $this->name;
26953     }
26954
26955     /**
26956      * Returns true if the option accept a parameter.
26957      *
26958      * @return Boolean true if parameter mode is not self::PARAMETER_NONE, false otherwise
26959      */
26960     public function acceptParameter()
26961     {
26962         return $this->isParameterRequired() || $this->isParameterOptional();
26963     }
26964
26965     /**
26966      * Returns true if the option requires a parameter.
26967      *
26968      * @return Boolean true if parameter mode is self::PARAMETER_REQUIRED, false otherwise
26969      */
26970     public function isParameterRequired()
26971     {
26972         return self::PARAMETER_REQUIRED === (self::PARAMETER_REQUIRED & $this->mode);
26973     }
26974
26975     /**
26976      * Returns true if the option takes an optional parameter.
26977      *
26978      * @return Boolean true if parameter mode is self::PARAMETER_OPTIONAL, false otherwise
26979      */
26980     public function isParameterOptional()
26981     {
26982         return self::PARAMETER_OPTIONAL === (self::PARAMETER_OPTIONAL & $this->mode);
26983     }
26984
26985     /**
26986      * Returns true if the option can take multiple values.
26987      *
26988      * @return Boolean true if mode is self::PARAMETER_IS_ARRAY, false otherwise
26989      */
26990     public function isArray()
26991     {
26992         return self::PARAMETER_IS_ARRAY === (self::PARAMETER_IS_ARRAY & $this->mode);
26993     }
26994
26995     /**
26996      * Sets the default value.
26997      *
26998      * @param mixed $default The default value
26999      */
27000     public function setDefault($default = null)
27001     {
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.');
27004         }
27005
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.');
27011             }
27012         }
27013
27014         $this->default = $this->acceptParameter() ? $default : false;
27015     }
27016
27017     /**
27018      * Returns the default value.
27019      *
27020      * @return mixed The default value
27021      */
27022     public function getDefault()
27023     {
27024         return $this->default;
27025     }
27026
27027     /**
27028      * Returns the description text.
27029      *
27030      * @return string The description text
27031      */
27032     public function getDescription()
27033     {
27034         return $this->description;
27035     }
27036 }
27037 <?php
27038
27039 namespace Symfony\Component\Console\Input;
27040
27041 /*
27042  * This file is part of the Symfony framework.
27043  *
27044  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
27045  *
27046  * This source file is subject to the MIT license that is bundled
27047  * with this source code in the file LICENSE.
27048  */
27049
27050 /**
27051  * A InputDefinition represents a set of valid command line arguments and options.
27052  *
27053  * Usage:
27054  *
27055  *     $definition = new InputDefinition(array(
27056  *       new InputArgument('name', InputArgument::REQUIRED),
27057  *       new InputOption('foo', 'f', InputOption::PARAMETER_REQUIRED),
27058  *     ));
27059  *
27060  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
27061  */
27062 class InputDefinition
27063 {
27064     protected $arguments;
27065     protected $requiredCount;
27066     protected $hasAnArrayArgument = false;
27067     protected $hasOptional;
27068     protected $options;
27069     protected $shortcuts;
27070
27071     /**
27072      * Constructor.
27073      *
27074      * @param array $definition An array of InputArgument and InputOption instance
27075      */
27076     public function __construct(array $definition = array())
27077     {
27078         $this->setDefinition($definition);
27079     }
27080
27081     public function setDefinition(array $definition)
27082     {
27083         $arguments = array();
27084         $options = array();
27085         foreach ($definition as $item) {
27086             if ($item instanceof InputOption) {
27087                 $options[] = $item;
27088             } else {
27089                 $arguments[] = $item;
27090             }
27091         }
27092
27093         $this->setArguments($arguments);
27094         $this->setOptions($options);
27095     }
27096
27097     /**
27098      * Sets the InputArgument objects.
27099      *
27100      * @param array $arguments An array of InputArgument objects
27101      */
27102     public function setArguments($arguments = array())
27103     {
27104         $this->arguments          = array();
27105         $this->requiredCount      = 0;
27106         $this->hasOptional        = false;
27107         $this->hasAnArrayArgument = false;
27108         $this->addArguments($arguments);
27109     }
27110
27111     /**
27112      * Add an array of InputArgument objects.
27113      *
27114      * @param InputArgument[] $arguments An array of InputArgument objects
27115      */
27116     public function addArguments($arguments = array())
27117     {
27118         if (null !== $arguments) {
27119             foreach ($arguments as $argument) {
27120                 $this->addArgument($argument);
27121             }
27122         }
27123     }
27124
27125     /**
27126      * Add an InputArgument object.
27127      *
27128      * @param InputArgument $argument An InputArgument object
27129      *
27130      * @throws \LogicException When incorrect argument is given
27131      */
27132     public function addArgument(InputArgument $argument)
27133     {
27134         if (isset($this->arguments[$argument->getName()])) {
27135             throw new \LogicException(sprintf('An argument with name "%s" already exist.', $argument->getName()));
27136         }
27137
27138         if ($this->hasAnArrayArgument) {
27139             throw new \LogicException('Cannot add an argument after an array argument.');
27140         }
27141
27142         if ($argument->isRequired() && $this->hasOptional) {
27143             throw new \LogicException('Cannot add a required argument after an optional one.');
27144         }
27145
27146         if ($argument->isArray()) {
27147             $this->hasAnArrayArgument = true;
27148         }
27149
27150         if ($argument->isRequired()) {
27151             ++$this->requiredCount;
27152         } else {
27153             $this->hasOptional = true;
27154         }
27155
27156         $this->arguments[$argument->getName()] = $argument;
27157     }
27158
27159     /**
27160      * Returns an InputArgument by name or by position.
27161      *
27162      * @param string|integer $name The InputArgument name or position
27163      *
27164      * @return InputArgument An InputArgument object
27165      *
27166      * @throws \InvalidArgumentException When argument given doesn't exist
27167      */
27168     public function getArgument($name)
27169     {
27170         $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
27171
27172         if (!$this->hasArgument($name)) {
27173             throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
27174         }
27175
27176         return $arguments[$name];
27177     }
27178
27179     /**
27180      * Returns true if an InputArgument object exists by name or position.
27181      *
27182      * @param string|integer $name The InputArgument name or position
27183      *
27184      * @return Boolean true if the InputArgument object exists, false otherwise
27185      */
27186     public function hasArgument($name)
27187     {
27188         $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
27189
27190         return isset($arguments[$name]);
27191     }
27192
27193     /**
27194      * Gets the array of InputArgument objects.
27195      *
27196      * @return array An array of InputArgument objects
27197      */
27198     public function getArguments()
27199     {
27200         return $this->arguments;
27201     }
27202
27203     /**
27204      * Returns the number of InputArguments.
27205      *
27206      * @return integer The number of InputArguments
27207      */
27208     public function getArgumentCount()
27209     {
27210         return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);
27211     }
27212
27213     /**
27214      * Returns the number of required InputArguments.
27215      *
27216      * @return integer The number of required InputArguments
27217      */
27218     public function getArgumentRequiredCount()
27219     {
27220         return $this->requiredCount;
27221     }
27222
27223     /**
27224      * Gets the default values.
27225      *
27226      * @return array An array of default values
27227      */
27228     public function getArgumentDefaults()
27229     {
27230         $values = array();
27231         foreach ($this->arguments as $argument) {
27232             $values[$argument->getName()] = $argument->getDefault();
27233         }
27234
27235         return $values;
27236     }
27237
27238     /**
27239      * Sets the InputOption objects.
27240      *
27241      * @param array $options An array of InputOption objects
27242      */
27243     public function setOptions($options = array())
27244     {
27245         $this->options = array();
27246         $this->shortcuts = array();
27247         $this->addOptions($options);
27248     }
27249
27250     /**
27251      * Add an array of InputOption objects.
27252      *
27253      * @param InputOption[] $options An array of InputOption objects
27254      */
27255     public function addOptions($options = array())
27256     {
27257         foreach ($options as $option) {
27258             $this->addOption($option);
27259         }
27260     }
27261
27262     /**
27263      * Add an InputOption object.
27264      *
27265      * @param InputOption $option An InputOption object
27266      *
27267      * @throws \LogicException When option given already exist
27268      */
27269     public function addOption(InputOption $option)
27270     {
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()));
27275         }
27276
27277         $this->options[$option->getName()] = $option;
27278         if ($option->getShortcut()) {
27279             $this->shortcuts[$option->getShortcut()] = $option->getName();
27280         }
27281     }
27282
27283     /**
27284      * Returns an InputOption by name.
27285      *
27286      * @param string $name The InputOption name
27287      *
27288      * @return InputOption A InputOption object
27289      */
27290     public function getOption($name)
27291     {
27292         if (!$this->hasOption($name)) {
27293             throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
27294         }
27295
27296         return $this->options[$name];
27297     }
27298
27299     /**
27300      * Returns true if an InputOption object exists by name.
27301      *
27302      * @param string $name The InputOption name
27303      *
27304      * @return Boolean true if the InputOption object exists, false otherwise
27305      */
27306     public function hasOption($name)
27307     {
27308         return isset($this->options[$name]);
27309     }
27310
27311     /**
27312      * Gets the array of InputOption objects.
27313      *
27314      * @return array An array of InputOption objects
27315      */
27316     public function getOptions()
27317     {
27318         return $this->options;
27319     }
27320
27321     /**
27322      * Returns true if an InputOption object exists by shortcut.
27323      *
27324      * @param string $name The InputOption shortcut
27325      *
27326      * @return Boolean true if the InputOption object exists, false otherwise
27327      */
27328     public function hasShortcut($name)
27329     {
27330         return isset($this->shortcuts[$name]);
27331     }
27332
27333     /**
27334      * Gets an InputOption by shortcut.
27335      *
27336      * @return InputOption An InputOption object
27337      */
27338     public function getOptionForShortcut($shortcut)
27339     {
27340         return $this->getOption($this->shortcutToName($shortcut));
27341     }
27342
27343     /**
27344      * Gets an array of default values.
27345      *
27346      * @return array An array of all default values
27347      */
27348     public function getOptionDefaults()
27349     {
27350         $values = array();
27351         foreach ($this->options as $option) {
27352             $values[$option->getName()] = $option->getDefault();
27353         }
27354
27355         return $values;
27356     }
27357
27358     /**
27359      * Returns the InputOption name given a shortcut.
27360      *
27361      * @param string $shortcut The shortcut
27362      *
27363      * @return string The InputOption name
27364      *
27365      * @throws \InvalidArgumentException When option given does not exist
27366      */
27367     protected function shortcutToName($shortcut)
27368     {
27369         if (!isset($this->shortcuts[$shortcut])) {
27370             throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
27371         }
27372
27373         return $this->shortcuts[$shortcut];
27374     }
27375
27376     /**
27377      * Gets the synopsis.
27378      *
27379      * @return string The synopsis
27380      */
27381     public function getSynopsis()
27382     {
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());
27387         }
27388
27389         foreach ($this->getArguments() as $argument) {
27390             $elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : ''));
27391
27392             if ($argument->isArray()) {
27393                 $elements[] = sprintf('... [%sN]', $argument->getName());
27394             }
27395         }
27396
27397         return implode(' ', $elements);
27398     }
27399
27400     /**
27401      * Returns a textual representation of the InputDefinition.
27402      *
27403      * @return string A string representing the InputDefinition
27404      */
27405     public function asText()
27406     {
27407         // find the largest option or argument name
27408         $max = 0;
27409         foreach ($this->getOptions() as $option) {
27410             $max = strlen($option->getName()) + 2 > $max ? strlen($option->getName()) + 2 : $max;
27411         }
27412         foreach ($this->getArguments() as $argument) {
27413             $max = strlen($argument->getName()) > $max ? strlen($argument->getName()) : $max;
27414         }
27415         ++$max;
27416
27417         $text = array();
27418
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());
27424                 } else {
27425                     $default = '';
27426                 }
27427
27428                 $text[] = sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $argument->getDescription(), $default);
27429             }
27430
27431             $text[] = '';
27432         }
27433
27434         if ($this->getOptions()) {
27435             $text[] = '<comment>Options:</comment>';
27436
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());
27440                 } else {
27441                     $default = '';
27442                 }
27443
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);
27446             }
27447
27448             $text[] = '';
27449         }
27450
27451         return implode("\n", $text);
27452     }
27453
27454     /**
27455      * Returns an XML representation of the InputDefinition.
27456      *
27457      * @param Boolean $asDom Whether to return a DOM or an XML string
27458      *
27459      * @return string|DOMDocument An XML string representing the InputDefinition
27460      */
27461     public function asXml($asDom = false)
27462     {
27463         $dom = new \DOMDocument('1.0', 'UTF-8');
27464         $dom->formatOutput = true;
27465         $dom->appendChild($definitionXML = $dom->createElement('definition'));
27466
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()));
27475
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));
27481             }
27482         }
27483
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()));
27494
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));
27501                 }
27502             }
27503         }
27504
27505         return $asDom ? $dom : $dom->saveXml();
27506     }
27507 }
27508 <?php
27509
27510 namespace Symfony\Component\Console\Input;
27511
27512 /*
27513  * This file is part of the Symfony framework.
27514  *
27515  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
27516  *
27517  * This source file is subject to the MIT license that is bundled
27518  * with this source code in the file LICENSE.
27519  */
27520
27521 /**
27522  * InputInterface is the interface implemented by all input classes.
27523  *
27524  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
27525  */
27526 interface InputInterface
27527 {
27528     /**
27529      * Returns the first argument from the raw parameters (not parsed).
27530      *
27531      * @return string The value of the first argument or null otherwise
27532      */
27533     function getFirstArgument();
27534
27535     /**
27536      * Returns true if the raw parameters (not parsed) contains a value.
27537      *
27538      * This method is to be used to introspect the input parameters
27539      * before it has been validated. It must be used carefully.
27540      *
27541      * @param string $value The value to look for in the raw parameters
27542      *
27543      * @return Boolean true if the value is contained in the raw parameters
27544      */
27545     function hasParameterOption($value);
27546
27547     /**
27548      * Binds the current Input instance with the given arguments and options.
27549      *
27550      * @param InputDefinition $definition A InputDefinition instance
27551      */
27552     function bind(InputDefinition $definition);
27553
27554     function validate();
27555
27556     function getArguments();
27557
27558     function getArgument($name);
27559
27560     function getOptions();
27561
27562     function getOption($name);
27563 }
27564 <?php
27565
27566 namespace Symfony\Component\Console\Input;
27567
27568 /*
27569  * This file is part of the Symfony framework.
27570  *
27571  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
27572  *
27573  * This source file is subject to the MIT license that is bundled
27574  * with this source code in the file LICENSE.
27575  */
27576
27577 /**
27578  * ArgvInput represents an input coming from the CLI arguments.
27579  *
27580  * Usage:
27581  *
27582  *     $input = new ArgvInput();
27583  *
27584  * By default, the `$_SERVER['argv']` array is used for the input values.
27585  *
27586  * This can be overridden by explicitly passing the input values in the constructor:
27587  *
27588  *     $input = new ArgvInput($_SERVER['argv']);
27589  *
27590  * If you pass it yourself, don't forget that the first element of the array
27591  * is the name of the running program.
27592  *
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.
27596  *
27597  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
27598  *
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
27601  */
27602 class ArgvInput extends Input
27603 {
27604     protected $tokens;
27605     protected $parsed;
27606
27607     /**
27608      * Constructor.
27609      *
27610      * @param array           $argv An array of parameters from the CLI (in the argv format)
27611      * @param InputDefinition $definition A InputDefinition instance
27612      */
27613     public function __construct(array $argv = null, InputDefinition $definition = null)
27614     {
27615         if (null === $argv) {
27616             $argv = $_SERVER['argv'];
27617         }
27618
27619         // strip the program name
27620         array_shift($argv);
27621
27622         $this->tokens = $argv;
27623
27624         parent::__construct($definition);
27625     }
27626
27627     /**
27628      * Processes command line arguments.
27629      */
27630     protected function parse()
27631     {
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);
27638             } else {
27639                 $this->parseArgument($token);
27640             }
27641         }
27642     }
27643
27644     /**
27645      * Parses a short option.
27646      *
27647      * @param string $token The current token.
27648      */
27649     protected function parseShortOption($token)
27650     {
27651         $name = substr($token, 1);
27652
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));
27657             } else {
27658                 $this->parseShortOptionSet($name);
27659             }
27660         } else {
27661             $this->addShortOption($name, null);
27662         }
27663     }
27664
27665     /**
27666      * Parses a short option set.
27667      *
27668      * @param string $token The current token
27669      *
27670      * @throws \RuntimeException When option given doesn't exist
27671      */
27672     protected function parseShortOptionSet($name)
27673     {
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]));
27678             }
27679
27680             $option = $this->definition->getOptionForShortcut($name[$i]);
27681             if ($option->acceptParameter()) {
27682                 $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
27683
27684                 break;
27685             } else {
27686                 $this->addLongOption($option->getName(), true);
27687             }
27688         }
27689     }
27690
27691     /**
27692      * Parses a long option.
27693      *
27694      * @param string $token The current token
27695      */
27696     protected function parseLongOption($token)
27697     {
27698         $name = substr($token, 2);
27699
27700         if (false !== $pos = strpos($name, '=')) {
27701             $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
27702         } else {
27703             $this->addLongOption($name, null);
27704         }
27705     }
27706
27707     /**
27708      * Parses an argument.
27709      *
27710      * @param string $token The current token
27711      *
27712      * @throws \RuntimeException When too many arguments are given
27713      */
27714     protected function parseArgument($token)
27715     {
27716         if (!$this->definition->hasArgument(count($this->arguments))) {
27717             throw new \RuntimeException('Too many arguments.');
27718         }
27719
27720         $this->arguments[$this->definition->getArgument(count($this->arguments))->getName()] = $token;
27721     }
27722
27723     /**
27724      * Adds a short option value.
27725      *
27726      * @param string $shortcut The short option key
27727      * @param mixed  $value    The value for the option
27728      *
27729      * @throws \RuntimeException When option given doesn't exist
27730      */
27731     protected function addShortOption($shortcut, $value)
27732     {
27733         if (!$this->definition->hasShortcut($shortcut)) {
27734             throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
27735         }
27736
27737         $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
27738     }
27739
27740     /**
27741      * Adds a long option value.
27742      *
27743      * @param string $name  The long option key
27744      * @param mixed  $value The value for the option
27745      *
27746      * @throws \RuntimeException When option given doesn't exist
27747      */
27748     protected function addLongOption($name, $value)
27749     {
27750         if (!$this->definition->hasOption($name)) {
27751             throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
27752         }
27753
27754         $option = $this->definition->getOption($name);
27755
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]) {
27761                 $value = $next;
27762             } else {
27763                 array_unshift($this->parsed, $next);
27764             }
27765         }
27766
27767         if (null === $value) {
27768             if ($option->isParameterRequired()) {
27769                 throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
27770             }
27771
27772             $value = $option->isParameterOptional() ? $option->getDefault() : true;
27773         }
27774
27775         $this->options[$name] = $value;
27776     }
27777
27778     /**
27779      * Returns the first argument from the raw parameters (not parsed).
27780      *
27781      * @return string The value of the first argument or null otherwise
27782      */
27783     public function getFirstArgument()
27784     {
27785         foreach ($this->tokens as $token) {
27786             if ($token && '-' === $token[0]) {
27787                 continue;
27788             }
27789
27790             return $token;
27791         }
27792     }
27793
27794     /**
27795      * Returns true if the raw parameters (not parsed) contains a value.
27796      *
27797      * This method is to be used to introspect the input parameters
27798      * before it has been validated. It must be used carefully.
27799      *
27800      * @param string|array $values The value(s) to look for in the raw parameters (can be an array)
27801      *
27802      * @return Boolean true if the value is contained in the raw parameters
27803      */
27804     public function hasParameterOption($values)
27805     {
27806         if (!is_array($values)) {
27807             $values = array($values);
27808         }
27809
27810         foreach ($this->tokens as $v) {
27811             if (in_array($v, $values)) {
27812                 return true;
27813             }
27814         }
27815
27816         return false;
27817     }
27818 }
27819 <?php
27820
27821 namespace Symfony\Component\Console\Input;
27822
27823 /*
27824  * This file is part of the Symfony framework.
27825  *
27826  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
27827  *
27828  * This source file is subject to the MIT license that is bundled
27829  * with this source code in the file LICENSE.
27830  */
27831
27832 /**
27833  * StringInput represents an input provided as a string.
27834  *
27835  * Usage:
27836  *
27837  *     $input = new StringInput('foo --bar="foobar"');
27838  *
27839  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
27840  */
27841 class StringInput extends ArgvInput
27842 {
27843     const REGEX_STRING = '([^ ]+?)(?: |(?<!\\\\)"|(?<!\\\\)\'|$)';
27844     const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
27845
27846     /**
27847      * Constructor.
27848      *
27849      * @param string     $input An array of parameters from the CLI (in the argv format)
27850      * @param InputDefinition $definition A InputDefinition instance
27851      */
27852     public function __construct($input, InputDefinition $definition = null)
27853     {
27854         parent::__construct(array(), $definition);
27855
27856         $this->tokens = $this->tokenize($input);
27857     }
27858
27859     /**
27860      * @throws \InvalidArgumentException When unable to parse input (should never happen)
27861      */
27862     protected function tokenize($input)
27863     {
27864         $input = preg_replace('/(\r\n|\r|\n|\t)/', ' ', $input);
27865
27866         $tokens = array();
27867         $length = strlen($input);
27868         $cursor = 0;
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]);
27877             } else {
27878                 // should never happen
27879                 // @codeCoverageIgnoreStart
27880                 throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
27881                 // @codeCoverageIgnoreEnd
27882             }
27883
27884             $cursor += strlen($match[0]);
27885         }
27886
27887         return $tokens;
27888     }
27889 }
27890 <?php
27891
27892 namespace Symfony\Component\Console\Input;
27893
27894 /*
27895  * This file is part of the Symfony framework.
27896  *
27897  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
27898  *
27899  * This source file is subject to the MIT license that is bundled
27900  * with this source code in the file LICENSE.
27901  */
27902
27903 /**
27904  * Represents a command line argument.
27905  *
27906  * @author Fabien Potencier <fabien.potencier@symfony-project.com>
27907  */
27908 class InputArgument
27909 {
27910     const REQUIRED = 1;
27911     const OPTIONAL = 2;
27912     const IS_ARRAY = 4;
27913
27914     protected $name;
27915     protected $mode;
27916     protected $default;
27917     protected $description;
27918
27919     /**
27920      * Constructor.
27921      *
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)
27926      *
27927      * @throws \InvalidArgumentException When argument mode is not valid
27928      */
27929     public function __construct($name, $mode = null, $description = '', $default = null)
27930     {
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));
27935         }
27936
27937         $this->name        = $name;
27938         $this->mode        = $mode;
27939         $this->description = $description;
27940
27941         $this->setDefault($default);
27942     }
27943
27944     /**
27945      * Returns the argument name.
27946      *
27947      * @return string The argument name
27948      */
27949     public function getName()
27950     {
27951         return $this->name;
27952     }
27953
27954     /**
27955      * Returns true if the argument is required.
27956      *
27957      * @return Boolean true if parameter mode is self::REQUIRED, false otherwise
27958      */
27959     public function isRequired()
27960     {
27961         return self::REQUIRED === (self::REQUIRED & $this->mode);
27962     }
27963
27964     /**
27965      * Returns true if the argument can take multiple values.
27966      *
27967      * @return Boolean true if mode is self::IS_ARRAY, false otherwise
27968      */
27969     public function isArray()
27970     {
27971         return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
27972     }
27973
27974     /**
27975      * Sets the default value.
27976      *
27977      * @param mixed $default The default value
27978      *
27979      * @throws \LogicException When incorrect default value is given
27980      */
27981     public function setDefault($default = null)
27982     {
27983         if (self::REQUIRED === $this->mode && null !== $default) {
27984             throw new \LogicException('Cannot set a default value except for Parameter::OPTIONAL mode.');
27985         }
27986
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.');
27992             }
27993         }
27994
27995         $this->default = $default;
27996     }
27997
27998     /**
27999      * Returns the default value.
28000      *
28001      * @return mixed The default value
28002      */
28003     public function getDefault()
28004     {
28005         return $this->default;
28006     }
28007
28008     /**
28009      * Returns the description text.
28010      *
28011      * @return string The description text
28012      */
28013     public function getDescription()
28014     {
28015         return $this->description;
28016     }
28017 }
28018 Ûes\85yepâC\f÷p͸Õ\ e<\1e\ 2\0\0\0GBMB