public function endMigration(APIMigration $migration, $force = false)
    {
        if ($migration->status == APIMigration::STATUS_STARTED) {
            throw new \Exception($this->getEntityName($migration)." '{$migration->name}' can not be ended as its status is 'started'...");
        }

        $this->createTableIfNeeded();

        // select for update

        // annoyingly enough, neither Doctrine nor EZP provide built in support for 'FOR UPDATE' in their query builders...
        // at least the doctrine one allows us to still use parameter binding when we add our sql particle
        $conn = $this->getConnection();

        $qb = $conn->createQueryBuilder();
        $qb->select('*')
            ->from($this->tableName, 'm')
            ->where('migration = ?');
        $sql = $qb->getSQL() . ' FOR UPDATE';

        $conn->beginTransaction();

        $stmt = $conn->executeQuery($sql, array($migration->name));
        $existingMigrationData = $stmt->fetch(\PDO::FETCH_ASSOC);

        // fail if it was not executing

        if (!is_array($existingMigrationData)) {
            // commit to release the lock
            $conn->commit();
            throw new \Exception($this->getEntityName($migration)." '{$migration->name}' can not be ended as it is not found");
        }

        if (($existingMigrationData['status'] != APIMigration::STATUS_STARTED) && !$force) {
            // commit to release the lock
            $conn->commit();
            throw new \Exception($this->getEntityName($migration)." '{$migration->name}' can not be ended as it is not executing");
        }

        $conn->update(
            $this->tableName,
            array(
                'status' => $migration->status,
                /// @todo use mb_substr (if all dbs we support count col length not in bytes but in chars...)
                'execution_error' => substr($migration->executionError, 0, 4000),
                'execution_date' => $migration->executionDate
            ),
            array('migration' => $migration->name)
        );

        $conn->commit();
    }
public function endMigration(APIMigration $migration, $force = false)
    {
        if ($migration->status == APIMigration::STATUS_STARTED) {
            throw new \Exception($this->getEntityName($migration)." '{$migration->name}' can not be ended as its status is 'started'...");
        }

        $this->createTableIfNeeded();

        // select for update

        // annoyingly enough, neither Doctrine nor EZP provide built in support for 'FOR UPDATE' in their query builders...
        // at least the doctrine one allows us to still use parameter binding when we add our sql particle
        $conn = $this->getConnection();

        $qb = $conn->createQueryBuilder();
        $qb->select('*')
            ->from($this->tableName, 'm')
            ->where('migration = ?');
        $sql = $qb->getSQL() . ' FOR UPDATE';

        $conn->beginTransaction();

        $stmt = $conn->executeQuery($sql, array($migration->name));
        $existingMigrationData = $stmt->fetch(\PDO::FETCH_ASSOC);

        // fail if it was not executing

        if (!is_array($existingMigrationData)) {
            // commit to release the lock
            $conn->commit();
            throw new \Exception($this->getEntityName($migration)." '{$migration->name}' can not be ended as it is not found");
        }

        if (($existingMigrationData['status'] != APIMigration::STATUS_STARTED) && !$force) {
            // commit to release the lock
            $conn->commit();
            throw new \Exception($this->getEntityName($migration)." '{$migration->name}' can not be ended as it is not executing");
        }

        $conn->update(
            $this->tableName,
            array(
                'status' => $migration->status,
                /// @todo use mb_substr (if all dbs we support count col length not in bytes but in chars...)
                'execution_error' => substr($migration->executionError, 0, 4000),
                'execution_date' => $migration->executionDate
            ),
            array('migration' => $migration->name)
        );

        $conn->commit();
    }
public function endMigration ( APIMigration $ migration , $ force = false ) { if ( $ migration -> status == APIMigration :: STATUS_STARTED ) { throw new \ Exception ( $ this -> getEntityName ( $ migration ) . " '{$migration->name}' can not be ended as its status is 'started'..." ) ; } $ this -> createTableIfNeeded ( ) ; // select for update // annoyingly enough, neither Doctrine nor EZP provide built in support for 'FOR UPDATE' in their query builders... // at least the doctrine one allows us to still use parameter binding when we add our sql particle $ conn = $ this -> getConnection ( ) ; $ qb = $ conn -> createQueryBuilder ( ) ; $ qb -> select ( '*' ) -> from ( $ this -> tableName , 'm' ) -> where ( 'migration = ?' ) ; $ sql = $ qb -> getSQL ( ) . ' FOR UPDATE' ; $ conn -> beginTransaction ( ) ; $ stmt = $ conn -> executeQuery ( $ sql , array ( $ migration -> name ) ) ; $ existingMigrationData = $ stmt -> fetch ( \ PDO :: FETCH_ASSOC ) ; // fail if it was not executing if ( ! is_array ( $ existingMigrationData ) ) { // commit to release the lock $ conn -> commit ( ) ; throw new \ Exception ( $ this -> getEntityName ( $ migration ) . " '{$migration->name}' can not be ended as it is not found" ) ; } if ( ( $ existingMigrationData [ 'status' ] != APIMigration :: STATUS_STARTED ) && ! $ force ) { // commit to release the lock $ conn -> commit ( ) ; throw new \ Exception ( $ this -> getEntityName ( $ migration ) . " '{$migration->name}' can not be ended as it is not executing" ) ; } $ conn -> update ( $ this -> tableName , array ( 'status' => $ migration -> status , /// @todo use mb_substr (if all dbs we support count col length not in bytes but in chars...) 'execution_error' => substr ( $ migration -> executionError , 0 , 4000 ) , 'execution_date' => $ migration -> executionDate ) , array ( 'migration' => $ migration -> name ) ) ; $ conn -> commit ( ) ; }
Stops a migration by storing it in the db. Migration status can not be 'started'

NB: if this call happens within another DB transaction which has already been flagged for rollback, the result
will be that a RuntimeException is thrown, as Doctrine does not allow to call commit() after rollback().
One way to fix the problem would be not to use a transaction and select-for-update here, but since that is the
best way to insure atomic updates, I am loath to remove it.
A known workaround is to call the Doctrine Connection method setNestTransactionsWithSavepoints(true); this can
be achieved as simply as setting the parameter 'use_savepoints' in the doctrine connection configuration.

@param APIMigration $migration
@param bool $force When true, the migration will be updated even if it was not in 'started' status
@throws \Exception If the migration was not started (unless $force=true)
Stops a migration by storing it in the db . Migration status can not be started