| <?php |
| /** |
| * File containing the ezcWorkflowDatabaseExecution class. |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * @package WorkflowDatabaseTiein |
| * @version //autogen// |
| * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved. |
| * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
| */ |
| |
| /** |
| * Workflow executer that suspends and resumes workflow |
| * execution states to and from a database. |
| * |
| * @package WorkflowDatabaseTiein |
| * @version //autogen// |
| */ |
| class ezcWorkflowDatabaseExecution extends ezcWorkflowExecution |
| { |
| /** |
| * ezcDbHandler instance to be used. |
| * |
| * @var ezcDbHandler |
| */ |
| protected $db; |
| |
| /** |
| * Flag that indicates whether the execution has been loaded. |
| * |
| * @var boolean |
| */ |
| protected $loaded = false; |
| |
| /** |
| * Container to hold the properties |
| * |
| * @var array(string=>mixed) |
| */ |
| protected $properties = array( |
| 'definitionStorage' => null, |
| 'workflow' => null, |
| 'options' => null |
| ); |
| |
| /** |
| * Construct a new database execution. |
| * |
| * This constructor is a tie-in. |
| * |
| * @param ezcDbHandler $db |
| * @param int $executionId |
| * @throws ezcWorkflowExecutionException |
| */ |
| public function __construct ( ezcDbHandler $db, $executionId = null ) |
| { |
| if ( $executionId !== null && !is_int( $executionId ) ) |
| { |
| throw new ezcWorkflowExecutionException( '$executionId must be an integer.' ); |
| } |
| |
| $this->db = $db; |
| $this->properties['definitionStorage'] = new ezcWorkflowDatabaseDefinitionStorage( $db ); |
| $this->properties['options'] = new ezcWorkflowDatabaseOptions; |
| |
| if ( is_int( $executionId ) ) |
| { |
| $this->loadExecution( $executionId ); |
| } |
| } |
| |
| /** |
| * Property get access. |
| * |
| * @param string $propertyName |
| * @return mixed |
| * @throws ezcBasePropertyNotFoundException |
| * If the given property could not be found. |
| * @ignore |
| */ |
| public function __get( $propertyName ) |
| { |
| switch ( $propertyName ) |
| { |
| case 'definitionStorage': |
| case 'workflow': |
| case 'options': |
| return $this->properties[$propertyName]; |
| } |
| |
| throw new ezcBasePropertyNotFoundException( $propertyName ); |
| } |
| |
| /** |
| * Property set access. |
| * |
| * @param string $propertyName |
| * @param string $propertyValue |
| * @throws ezcBasePropertyNotFoundException |
| * If the given property could not be found. |
| * @throws ezcBaseValueException |
| * If the value for the property options is not an ezcWorkflowDatabaseOptions object. |
| * @ignore |
| */ |
| public function __set( $propertyName, $propertyValue ) |
| { |
| switch ( $propertyName ) |
| { |
| case 'definitionStorage': |
| case 'workflow': |
| return parent::__set( $propertyName, $propertyValue ); |
| case 'options': |
| if ( !( $propertyValue instanceof ezcWorkflowDatabaseOptions ) ) |
| { |
| throw new ezcBaseValueException( |
| $propertyName, |
| $propertyValue, |
| 'ezcWorkflowDatabaseOptions' |
| ); |
| } |
| break; |
| default: |
| throw new ezcBasePropertyNotFoundException( $propertyName ); |
| } |
| $this->properties[$propertyName] = $propertyValue; |
| } |
| |
| /** |
| * Property isset access. |
| * |
| * @param string $propertyName |
| * @return bool |
| * @ignore |
| */ |
| public function __isset( $propertyName ) |
| { |
| switch ( $propertyName ) |
| { |
| case 'definitionStorage': |
| case 'workflow': |
| case 'options': |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Start workflow execution. |
| * |
| * @param int $parentId |
| * @throws ezcDbException |
| */ |
| protected function doStart( $parentId ) |
| { |
| $this->db->beginTransaction(); |
| |
| $query = $this->db->createInsertQuery(); |
| |
| $query->insertInto( $this->db->quoteIdentifier( $this->options['prefix'] . 'execution' ) ) |
| ->set( $this->db->quoteIdentifier( 'workflow_id' ), $query->bindValue( (int)$this->workflow->id ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_parent' ), $query->bindValue( (int)$parentId ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_started' ), $query->bindValue( time() ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_variables' ), $query->bindValue( ezcWorkflowDatabaseUtil::serialize( $this->variables ) ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_waiting_for' ), $query->bindValue( ezcWorkflowDatabaseUtil::serialize( $this->waitingFor ) ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_threads' ), $query->bindValue( ezcWorkflowDatabaseUtil::serialize( $this->threads ) ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_next_thread_id' ), $query->bindValue( (int)$this->nextThreadId ) ); |
| |
| $statement = $query->prepare(); |
| $statement->execute(); |
| |
| $this->id = (int)$this->db->lastInsertId( 'execution_execution_id_seq' ); |
| } |
| |
| /** |
| * Suspend workflow execution. |
| * |
| * @throws ezcDbException |
| */ |
| protected function doSuspend() |
| { |
| $this->cleanupTable( 'execution_state' ); |
| |
| $query = $this->db->createUpdateQuery(); |
| |
| $query->update( $this->db->quoteIdentifier( $this->options['prefix'] . 'execution' ) ) |
| ->where( $query->expr->eq( $this->db->quoteIdentifier( 'execution_id' ), $query->bindValue( (int)$this->id ) ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_suspended' ), $query->bindValue( time() ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_variables' ), $query->bindValue( ezcWorkflowDatabaseUtil::serialize( $this->variables ) ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_waiting_for' ), $query->bindValue( ezcWorkflowDatabaseUtil::serialize( $this->waitingFor ) ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_threads' ), $query->bindValue( ezcWorkflowDatabaseUtil::serialize( $this->threads ) ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_next_thread_id' ), $query->bindValue( (int)$this->nextThreadId ) ); |
| |
| $statement = $query->prepare(); |
| $statement->execute(); |
| |
| foreach ( $this->activatedNodes as $node ) |
| { |
| $query = $this->db->createInsertQuery(); |
| |
| $query->insertInto( $this->db->quoteIdentifier( $this->options['prefix'] . 'execution_state' ) ) |
| ->set( $this->db->quoteIdentifier( 'execution_id' ), $query->bindValue( (int)$this->id ) ) |
| ->set( $this->db->quoteIdentifier( 'node_id' ), $query->bindValue( (int)$node->getId() ) ) |
| ->set( $this->db->quoteIdentifier( 'node_state' ), $query->bindValue( ezcWorkflowDatabaseUtil::serialize( $node->getState() ) ) ) |
| ->set( $this->db->quoteIdentifier( 'node_activated_from' ), $query->bindValue( ezcWorkflowDatabaseUtil::serialize( $node->getActivatedFrom() ) ) ) |
| ->set( $this->db->quoteIdentifier( 'node_thread_id' ), $query->bindValue( (int)$node->getThreadId() ) ); |
| |
| $statement = $query->prepare(); |
| $statement->execute(); |
| } |
| |
| $this->db->commit(); |
| } |
| |
| /** |
| * Resume workflow execution. |
| * |
| * @throws ezcDbException |
| */ |
| protected function doResume() |
| { |
| $this->db->beginTransaction(); |
| } |
| |
| /** |
| * End workflow execution. |
| * |
| * @throws ezcDbException |
| */ |
| protected function doEnd() |
| { |
| $this->cleanupTable( 'execution' ); |
| $this->cleanupTable( 'execution_state' ); |
| |
| if ( !$this->isCancelled() ) |
| { |
| $this->db->commit(); |
| } |
| } |
| |
| /** |
| * Returns a new execution object for a sub workflow. |
| * |
| * @param int $id |
| * @return ezcWorkflowExecution |
| */ |
| protected function doGetSubExecution( $id = null ) |
| { |
| return new ezcWorkflowDatabaseExecution( $this->db, $id ); |
| } |
| |
| /** |
| * Cleanup execution / execution_state tables. |
| * |
| * @param string $tableName |
| * @throws ezcDbException |
| */ |
| protected function cleanupTable( $tableName ) |
| { |
| $query = $this->db->createDeleteQuery(); |
| $query->deleteFrom( $this->db->quoteIdentifier( $this->options['prefix'] . $tableName ) ); |
| |
| $id = $query->expr->eq( $this->db->quoteIdentifier( 'execution_id' ), $query->bindValue( (int)$this->id ) ); |
| |
| if ( $tableName == 'execution' ) |
| { |
| $parent = $query->expr->eq( $this->db->quoteIdentifier( 'execution_parent' ), $query->bindValue( (int)$this->id ) ); |
| $query->where( $query->expr->lOr( $id, $parent ) ); |
| } |
| else |
| { |
| $query->where( $id ); |
| } |
| |
| $statement = $query->prepare(); |
| $statement->execute(); |
| } |
| |
| /** |
| * Load execution state. |
| * |
| * @param int $executionId ID of the execution to load. |
| * @throws ezcWorkflowExecutionException |
| */ |
| protected function loadExecution( $executionId ) |
| { |
| $query = $this->db->createSelectQuery(); |
| |
| $query->select( $this->db->quoteIdentifier( 'workflow_id' ) ) |
| ->select( $this->db->quoteIdentifier( 'execution_variables' ) ) |
| ->select( $this->db->quoteIdentifier( 'execution_threads' ) ) |
| ->select( $this->db->quoteIdentifier( 'execution_next_thread_id' ) ) |
| ->select( $this->db->quoteIdentifier( 'execution_waiting_for' ) ) |
| ->from( $this->db->quoteIdentifier( $this->options['prefix'] . 'execution' ) ) |
| ->where( $query->expr->eq( $this->db->quoteIdentifier( 'execution_id' ), |
| $query->bindValue( (int)$executionId ) ) ); |
| |
| $stmt = $query->prepare(); |
| $stmt->execute(); |
| |
| $result = $stmt->fetchAll( PDO::FETCH_ASSOC ); |
| |
| if ( $result === false || empty( $result ) ) |
| { |
| throw new ezcWorkflowExecutionException( |
| 'Could not load execution state.' |
| ); |
| } |
| |
| $this->id = $executionId; |
| $this->nextThreadId = $result[0]['execution_next_thread_id']; |
| |
| $this->threads = ezcWorkflowDatabaseUtil::unserialize( $result[0]['execution_threads'] ); |
| $this->variables = ezcWorkflowDatabaseUtil::unserialize( $result[0]['execution_variables'] ); |
| $this->waitingFor = ezcWorkflowDatabaseUtil::unserialize( $result[0]['execution_waiting_for'] ); |
| |
| $workflowId = $result[0]['workflow_id']; |
| $this->workflow = $this->properties['definitionStorage']->loadById( $workflowId ); |
| |
| $query = $this->db->createSelectQuery(); |
| |
| $query->select( $this->db->quoteIdentifier( 'node_id' ) ) |
| ->select( $this->db->quoteIdentifier( 'node_state' ) ) |
| ->select( $this->db->quoteIdentifier( 'node_activated_from' ) ) |
| ->select( $this->db->quoteIdentifier( 'node_thread_id' ) ) |
| ->from( $this->db->quoteIdentifier( $this->options['prefix'] . 'execution_state' ) ) |
| ->where( $query->expr->eq( $this->db->quoteIdentifier( 'execution_id' ), |
| $query->bindValue( (int)$executionId ) ) ); |
| |
| $stmt = $query->prepare(); |
| $stmt->execute(); |
| |
| $result = $stmt->fetchAll( PDO::FETCH_ASSOC ); |
| $active = array(); |
| |
| foreach ( $result as $row ) |
| { |
| $active[$row['node_id']] = array( |
| 'activated_from' => ezcWorkflowDatabaseUtil::unserialize( |
| $row['node_activated_from'] |
| ), |
| 'state' => ezcWorkflowDatabaseUtil::unserialize( |
| $row['node_state'], null |
| ), |
| 'thread_id' => $row['node_thread_id'] |
| ); |
| } |
| |
| foreach ( $this->workflow->nodes as $node ) |
| { |
| $nodeId = $node->getId(); |
| |
| if ( isset( $active[$nodeId] ) ) |
| { |
| $node->setActivationState( ezcWorkflowNode::WAITING_FOR_EXECUTION ); |
| $node->setThreadId( $active[$nodeId]['thread_id'] ); |
| $node->setState( $active[$nodeId]['state'], null ); |
| $node->setActivatedFrom( $active[$nodeId]['activated_from'] ); |
| |
| $this->activate( $node, false ); |
| } |
| } |
| |
| $this->cancelled = false; |
| $this->ended = false; |
| $this->loaded = true; |
| $this->resumed = false; |
| $this->suspended = true; |
| } |
| } |
| ?> |