vendor/doctrine-migrations/lib/Doctrine/DBAL/Migrations/Configuration/Configuration.php
changeset 39 03b14b0fe101
equal deleted inserted replaced
38:bbdc7f9aa25e 39:03b14b0fe101
       
     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 namespace Doctrine\DBAL\Migrations\Configuration;
       
    21 
       
    22 use Doctrine\DBAL\Connection,
       
    23     Doctrine\DBAL\Migrations\MigrationException,
       
    24     Doctrine\DBAL\Migrations\Version,
       
    25     Doctrine\DBAL\Migrations\OutputWriter,
       
    26     Doctrine\DBAL\Schema\Table,
       
    27     Doctrine\DBAL\Schema\Column,
       
    28     Doctrine\DBAL\Types\Type;
       
    29 
       
    30 /**
       
    31  * Default Migration Configurtion object used for configuring an instance of
       
    32  * the Migration class. Set the connection, version table name, register migration
       
    33  * classes/versions, etc.
       
    34  *
       
    35  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
       
    36  * @link        www.doctrine-project.org
       
    37  * @since       2.0
       
    38  * @author      Jonathan H. Wage <jonwage@gmail.com>
       
    39  */
       
    40 class Configuration
       
    41 {
       
    42     /**
       
    43      * Name of this set of migrations
       
    44      *
       
    45      * @var string
       
    46      */
       
    47     private $name;
       
    48 
       
    49     /**
       
    50      * Flag for whether or not the migration table has been created
       
    51      *
       
    52      * @var bool
       
    53      */
       
    54     private $migrationTableCreated = false;
       
    55 
       
    56     /**
       
    57      * Connection instance to use for migrations
       
    58      *
       
    59      * @var Connection
       
    60      */
       
    61     private $connection;
       
    62 
       
    63     /**
       
    64      * OutputWriter instance for writing output during migrations
       
    65      * 
       
    66      * @var OutputWriter
       
    67      */
       
    68     private $outputWriter;
       
    69 
       
    70     /**
       
    71      * The migration table name to track versions in
       
    72      *
       
    73      * @var string
       
    74      */
       
    75     private $migrationsTableName = 'doctrine_migration_versions';
       
    76 
       
    77     /**
       
    78      * The path to a directory where new migration classes will be written
       
    79      * 
       
    80      * @var string
       
    81      */
       
    82     private $migrationsDirectory;
       
    83 
       
    84     /**
       
    85      * Namespace the migration classes live in
       
    86      *
       
    87      * @var string
       
    88      */
       
    89     private $migrationsNamespace;
       
    90 
       
    91     /**
       
    92      * Array of the registered migrations
       
    93      *
       
    94      * @var array
       
    95      */
       
    96     private $migrations = array();
       
    97 
       
    98     /**
       
    99      * Construct a migration configuration object.
       
   100      *
       
   101      * @param Connection $connection      A Connection instance
       
   102      * @param OutputWriter $outputWriter  A OutputWriter instance
       
   103      */
       
   104     public function __construct(Connection $connection, OutputWriter $outputWriter = null)
       
   105     {
       
   106         $this->connection = $connection;
       
   107         if ($outputWriter === null) {
       
   108             $outputWriter = new OutputWriter();
       
   109         }
       
   110         $this->outputWriter = $outputWriter;
       
   111     }
       
   112 
       
   113     /**
       
   114      * Validation that this instance has all the required properties configured
       
   115      *
       
   116      * @return void
       
   117      * @throws MigrationException
       
   118      */
       
   119     public function validate()
       
   120     {
       
   121         if ( ! $this->migrationsNamespace) {
       
   122             throw MigrationException::migrationsNamespaceRequired();
       
   123         }
       
   124         if ( ! $this->migrationsDirectory) {
       
   125             throw MigrationException::migrationsDirectoryRequired();
       
   126         }
       
   127     }
       
   128 
       
   129     /**
       
   130      * Set the name of this set of migrations
       
   131      *
       
   132      * @param string $name The name of this set of migrations
       
   133      */
       
   134     public function setName($name)
       
   135     {
       
   136         $this->name = $name;
       
   137     }
       
   138 
       
   139     /**
       
   140      * Returns the name of this set of migrations
       
   141      *
       
   142      * @return string $name The name of this set of migrations
       
   143      */
       
   144     public function getName()
       
   145     {
       
   146         return $this->name;
       
   147     }
       
   148 
       
   149     /**
       
   150      * Returns the OutputWriter instance
       
   151      *
       
   152      * @return OutputWriter $outputWriter  The OutputWriter instance
       
   153      */
       
   154     public function getOutputWriter()
       
   155     {
       
   156         return $this->outputWriter;
       
   157     }
       
   158 
       
   159     /**
       
   160      * Returns a timestamp version as a formatted date
       
   161      *
       
   162      * @param string $version 
       
   163      * @return string $formattedVersion The formatted version
       
   164      */
       
   165     public function formatVersion($version)
       
   166     {
       
   167         return sprintf('%s-%s-%s %s:%s:%s',
       
   168             substr($version, 0, 4),
       
   169             substr($version, 4, 2),
       
   170             substr($version, 6, 2),
       
   171             substr($version, 8, 2),
       
   172             substr($version, 10, 2),
       
   173             substr($version, 12, 2)
       
   174         );
       
   175     }
       
   176 
       
   177     /**
       
   178      * Returns the Connection instance
       
   179      *
       
   180      * @return Connection $connection  The Connection instance
       
   181      */
       
   182     public function getConnection()
       
   183     {
       
   184         return $this->connection;
       
   185     }
       
   186 
       
   187     /**
       
   188      * Set the migration table name
       
   189      *
       
   190      * @param string $tableName The migration table name
       
   191      */
       
   192     public function setMigrationsTableName($tableName)
       
   193     {
       
   194         $this->migrationsTableName = $tableName;
       
   195     }
       
   196 
       
   197     /**
       
   198      * Returns the migration table name
       
   199      *
       
   200      * @return string $migrationsTableName The migration table name
       
   201      */
       
   202     public function getMigrationsTableName()
       
   203     {
       
   204         return $this->migrationsTableName;
       
   205     }
       
   206 
       
   207     /**
       
   208      * Set the new migrations directory where new migration classes are generated
       
   209      *
       
   210      * @param string $migrationsDirectory The new migrations directory 
       
   211      */
       
   212     public function setMigrationsDirectory($migrationsDirectory)
       
   213     {
       
   214         $this->migrationsDirectory = $migrationsDirectory;
       
   215     }
       
   216 
       
   217     /**
       
   218      * Returns the new migrations directory where new migration classes are generated
       
   219      *
       
   220      * @return string $migrationsDirectory The new migrations directory
       
   221      */
       
   222     public function getMigrationsDirectory()
       
   223     {
       
   224         return $this->migrationsDirectory;
       
   225     }
       
   226 
       
   227     /**
       
   228      * Set the migrations namespace
       
   229      *
       
   230      * @param string $migrationsNamespace The migrations namespace
       
   231      */
       
   232     public function setMigrationsNamespace($migrationsNamespace)
       
   233     {
       
   234         $this->migrationsNamespace = $migrationsNamespace;
       
   235     }
       
   236 
       
   237     /**
       
   238      * Returns the migrations namespace
       
   239      *
       
   240      * @return string $migrationsNamespace The migrations namespace
       
   241      */
       
   242     public function getMigrationsNamespace()
       
   243     {
       
   244         return $this->migrationsNamespace;
       
   245     }
       
   246 
       
   247     /**
       
   248      * Register migrations from a given directory. Recursively finds all files
       
   249      * with the pattern VersionYYYYMMDDHHMMSS.php as the filename and registers
       
   250      * them as migrations.
       
   251      *
       
   252      * @param string $path  The root directory to where some migration classes live.
       
   253      * @return $migrations  The array of migrations registered.
       
   254      */
       
   255     public function registerMigrationsFromDirectory($path)
       
   256     {
       
   257         $path = realpath($path);
       
   258         $path = rtrim($path, '/');
       
   259         $files = glob($path . '/Version*.php');
       
   260         $versions = array();
       
   261         if ($files) {
       
   262             foreach ($files as $file) {
       
   263                 require_once($file);
       
   264                 $info = pathinfo($file);
       
   265                 $version = substr($info['filename'], 7);
       
   266                 $class = $this->migrationsNamespace . '\\' . $info['filename'];
       
   267                 $versions[] = $this->registerMigration($version, $class);
       
   268             }
       
   269         }
       
   270         return $versions;
       
   271     }
       
   272 
       
   273     /**
       
   274      * Register a single migration version to be executed by a AbstractMigration
       
   275      * class.
       
   276      *
       
   277      * @param string $version  The version of the migration in the format YYYYMMDDHHMMSS.
       
   278      * @param string $class    The migration class to execute for the version.
       
   279      */
       
   280     public function registerMigration($version, $class)
       
   281     {
       
   282         $version = (string) $version;
       
   283         $class = (string) $class;
       
   284         if (isset($this->migrations[$version])) {
       
   285             throw MigrationException::duplicateMigrationVersion($version, get_class($this->migrations[$version]));
       
   286         }
       
   287         $version = new Version($this, $version, $class);
       
   288         $this->migrations[$version->getVersion()] = $version;
       
   289         ksort($this->migrations);
       
   290         return $version;
       
   291     }
       
   292 
       
   293     /**
       
   294      * Register an array of migrations. Each key of the array is the version and
       
   295      * the value is the migration class name.
       
   296      *
       
   297      *
       
   298      * @param array $migrations
       
   299      * @return void
       
   300      */
       
   301     public function registerMigrations(array $migrations)
       
   302     {
       
   303         $versions = array();
       
   304         foreach ($migrations as $version => $class) {
       
   305             $versions[] = $this->registerMigration($version, $class);
       
   306         }
       
   307         return $versions;
       
   308     }
       
   309 
       
   310     /**
       
   311      * Get the array of registered migration versions.
       
   312      *
       
   313      * @return array $migrations
       
   314      */
       
   315     public function getMigrations()
       
   316     {
       
   317         return $this->migrations;
       
   318     }
       
   319 
       
   320     /**
       
   321      * Returns the Version instance for a given version in the format YYYYMMDDHHMMSS.
       
   322      *
       
   323      * @param string $version   The version string in the format YYYYMMDDHHMMSS.
       
   324      * @return Version $version
       
   325      * @throws MigrationException $exception Throws exception if migration version does not exist.
       
   326      */
       
   327     public function getVersion($version)
       
   328     {
       
   329         if ( ! isset($this->migrations[$version])) {
       
   330             throw MigrationException::unknownMigrationVersion($version);
       
   331         }
       
   332         return $this->migrations[$version];
       
   333     }
       
   334 
       
   335     /**
       
   336      * Check if a version exists.
       
   337      *
       
   338      * @param string $version
       
   339      * @return bool $exists
       
   340      */
       
   341     public function hasVersion($version)
       
   342     {
       
   343         return isset($this->migrations[$version]) ? true : false;
       
   344     }
       
   345 
       
   346     /**
       
   347      * Check if a version has been migrated or not yet
       
   348      *
       
   349      * @param Version $version
       
   350      * @return bool $migrated
       
   351      */
       
   352     public function hasVersionMigrated(Version $version)
       
   353     {
       
   354         $this->createMigrationTable();
       
   355 
       
   356         $version = $this->connection->fetchColumn("SELECT version FROM " . $this->migrationsTableName . " WHERE version = ?", array($version->getVersion()));
       
   357         return $version !== false ? true : false;
       
   358     }
       
   359 
       
   360     /**
       
   361      * Returns all migrated versions from the versions table, in an array.
       
   362      *
       
   363      * @return array $migrated
       
   364      */
       
   365     public function getMigratedVersions()
       
   366     {
       
   367         $this->createMigrationTable();
       
   368 
       
   369         $ret = $this->connection->fetchAll("SELECT version FROM " . $this->migrationsTableName);
       
   370         $versions = array();
       
   371         foreach ($ret as $version) {
       
   372             $versions[] = current($version);
       
   373         }
       
   374 
       
   375         return $versions;
       
   376     }
       
   377 
       
   378     /**
       
   379      * Returns the current migrated version from the versions table.
       
   380      *
       
   381      * @return bool $currentVersion
       
   382      */
       
   383     public function getCurrentVersion()
       
   384     {
       
   385         $this->createMigrationTable();
       
   386 
       
   387         $sql = "SELECT version FROM " . $this->migrationsTableName . " ORDER BY version DESC";
       
   388         $sql = $this->connection->getDatabasePlatform()->modifyLimitQuery($sql, 1);
       
   389         $result = $this->connection->fetchColumn($sql);
       
   390         return $result !== false ? (string) $result : '0';
       
   391     }
       
   392 
       
   393     /**
       
   394      * Returns the total number of executed migration versions
       
   395      *
       
   396      * @return integer $count
       
   397      */
       
   398     public function getNumberOfExecutedMigrations()
       
   399     {
       
   400         $this->createMigrationTable();
       
   401 
       
   402         $result = $this->connection->fetchColumn("SELECT COUNT(version) FROM " . $this->migrationsTableName);
       
   403         return $result !== false ? $result : 0;
       
   404     }
       
   405 
       
   406     /**
       
   407      * Returns the total number of available migration versions
       
   408      *
       
   409      * @return integer $count
       
   410      */
       
   411     public function getNumberOfAvailableMigrations()
       
   412     {
       
   413         return count($this->migrations);
       
   414     }
       
   415 
       
   416     /**
       
   417      * Returns the latest available migration version.
       
   418      *
       
   419      * @return string $version  The version string in the format YYYYMMDDHHMMSS.
       
   420      */
       
   421     public function getLatestVersion()
       
   422     {
       
   423         $versions = array_keys($this->migrations);
       
   424         $latest = end($versions);
       
   425         return $latest !== false ? (string) $latest : '0';
       
   426     }
       
   427 
       
   428     /**
       
   429      * Create the migration table to track migrations with.
       
   430      *
       
   431      * @return bool $created  Whether or not the table was created.
       
   432      */
       
   433     public function createMigrationTable()
       
   434     {
       
   435         $this->validate();
       
   436 
       
   437         if ($this->migrationTableCreated) {
       
   438             return false;
       
   439         }
       
   440 
       
   441         $schema = $this->connection->getSchemaManager()->createSchema();
       
   442         if ( ! $schema->hasTable($this->migrationsTableName)) {
       
   443             $columns = array(
       
   444                 'version' => new Column('version', Type::getType('string'), array('length' => 255)),
       
   445             );
       
   446             $table = new Table($this->migrationsTableName, $columns);
       
   447             $table->setPrimaryKey(array('version'));
       
   448             $this->connection->getSchemaManager()->createTable($table);
       
   449 
       
   450             $this->migrationTableCreated = true;
       
   451 
       
   452             return true;
       
   453         }
       
   454         return false;
       
   455     }
       
   456 
       
   457     /**
       
   458      * Returns the array of migrations to executed based on the given direction
       
   459      * and target version number.
       
   460      *
       
   461      * @param string $direction    The direction we are migrating.
       
   462      * @param string $to           The version to migrate to.
       
   463      * @return array $migrations   The array of migrations we can execute.
       
   464      */
       
   465     public function getMigrationsToExecute($direction, $to)
       
   466     {
       
   467         if ($direction === 'down') {
       
   468             if (count($this->migrations)) {
       
   469                 $allVersions = array_reverse(array_keys($this->migrations));
       
   470                 $classes = array_reverse(array_values($this->migrations));
       
   471                 $allVersions = array_combine($allVersions, $classes);
       
   472             } else {
       
   473                 $allVersions = array();
       
   474             }
       
   475         } else {
       
   476             $allVersions = $this->migrations;
       
   477         }
       
   478         $versions = array();
       
   479         $migrated = $this->getMigratedVersions();
       
   480         foreach ($allVersions as $version) {
       
   481             if ($this->shouldExecuteMigration($direction, $version, $to, $migrated)) {
       
   482                 $versions[$version->getVersion()] = $version;
       
   483             }
       
   484         }
       
   485         return $versions;
       
   486     }
       
   487 
       
   488     /**
       
   489      * Check if we should execute a migration for a given direction and target
       
   490      * migration version.
       
   491      *
       
   492      * @param string $direction   The direction we are migrating.
       
   493      * @param Version $version    The Version instance to check.
       
   494      * @param string $to          The version we are migrating to.
       
   495      * @param array $migrated     Migrated versions array.
       
   496      * @return void
       
   497      */
       
   498     private function shouldExecuteMigration($direction, Version $version, $to, $migrated)
       
   499     {
       
   500         if ($direction === 'down') {
       
   501             if ( ! in_array($version->getVersion(), $migrated)) {
       
   502                 return false;
       
   503             }
       
   504             return $version->getVersion() > $to ? true : false;
       
   505         } else if ($direction === 'up') {
       
   506             if (in_array($version->getVersion(), $migrated)) {
       
   507                 return false;
       
   508             }
       
   509             return $version->getVersion() <= $to ? true : false;
       
   510         }
       
   511     }
       
   512 }