예제 #1
0
 function display_viewlet()
 {
     $oKTTemplating =& KTTemplating::getSingleton();
     $oTemplate =& $oKTTemplating->loadTemplate("ktcore/document/viewlets/workflow");
     if (is_null($oTemplate)) {
         return "";
     }
     $oWorkflowState = KTWorkflowState::get($this->oDocument->getWorkflowStateId());
     if (PEAR::isError($oWorkflowState)) {
         return "";
     }
     $aDisplayTransitions = array();
     $aTransitions = KTWorkflowUtil::getTransitionsForDocumentUser($this->oDocument, $this->oUser);
     if (empty($aTransitions)) {
         return "";
     }
     // Check if the document has been checked out
     $bIsCheckedOut = $this->oDocument->getIsCheckedOut();
     $iId = $this->oDocument->getId();
     if ($bIsCheckedOut) {
         // If document is checked out, don't link into the workflow.
         $aDisplayTransitions = array();
     } else {
         foreach ($aTransitions as $oTransition) {
             if (is_null($oTransition) || PEAR::isError($oTransition)) {
                 continue;
             }
             $aDisplayTransitions[] = array('url' => KTUtil::ktLink('action.php', 'ktcore.actions.document.workflow', array("fDocumentId" => $iId, "action" => "quicktransition", "fTransitionId" => $oTransition->getId())), 'name' => $oTransition->getName());
         }
     }
     //Retreive the comment for the previous transition
     $aCommentQuery = array("SELECT comment FROM document_transactions\n            where transaction_namespace='ktcore.transactions.workflow_state_transition'\n            AND document_id = ?\n            ORDER BY id DESC LIMIT 1;");
     $aCommentQuery[] = array($iId);
     $aTransitionComments = DBUtil::getResultArray($aCommentQuery);
     $oLatestTransitionComment = null;
     if (!empty($aTransitionComments)) {
         $aRow = $aTransitionComments[0];
         $oLatestTransitionComment = $aRow['comment'];
         $iCommentPosition = strpos($oLatestTransitionComment, ':');
         //comment found after first colon in string
         if ($iCommentPosition > 0) {
             $oLatestTransitionComment = substr($oLatestTransitionComment, $iCommentPosition + 2, strlen($oLatestTransitionComment) - $iCommentPosition);
         } else {
             $oLatestTransitionComment = null;
         }
     }
     $oTemplate->setData(array('context' => $this, 'bIsCheckedOut' => $bIsCheckedOut, 'transitions' => $aDisplayTransitions, 'state_name' => $oWorkflowState->getName(), 'comment' => $oLatestTransitionComment));
     return $oTemplate->render();
 }
예제 #2
0
 function finalise()
 {
     $fWizardKey = KTUtil::arrayGet($_REQUEST, 'fWizardKey');
     if (!empty($fWizardKey)) {
         $this->errorRedirectToMain(_kt("Could not create workflow."));
         exit;
     }
     $wiz_data = $_SESSION['_wiz_data'][$fWizardKey];
     // gather all our data.  we're sure this is all good and healthy.
     $states = $wiz_data['states'];
     $transitions = $wiz_data['transitions'];
     $from = $wiz_data['from'];
     $to = $wiz_data['to'];
     $initial_state = $wiz_data['initial_state'];
     $workflow_name = $wiz_data['workflow_name'];
     $this->startTransaction();
     // create the initial workflow
     $oWorkflow = KTWorkflow::createFromArray(array('name' => $workflow_name, 'humanname' => $workflow_name, 'enabled' => true));
     if (PEAR::isError($oWorkflow)) {
         $this->errorRedirectToMain(sprintf(_kt("Failed to create workflow: %s"), $oWorkflow->getMessage()));
     }
     $iWorkflowId = $oWorkflow->getId();
     // create the states.
     $aStates = array();
     foreach ($states as $state_name) {
         $oState = KTWorkflowState::createFromArray(array('workflowid' => $iWorkflowId, 'name' => $state_name, 'humanname' => $state_name));
         if (PEAR::isError($oState)) {
             $this->errorRedirectToMain(sprintf(_kt("Failed to create state: %s"), $oState->getMessage()));
         }
         $aStates[$state_name] = $oState;
     }
     // update the initial state on workflow
     $oInitialState = $aStates[$initial_state];
     $oWorkflow->setStartStateId($oInitialState->getId());
     $res = $oWorkflow->update();
     if (PEAR::isError($res)) {
         $this->errorRedirectToMain(sprintf(_kt("Failed to update workflow: %s"), $res->getMessage()));
     }
     // next, we create and hook up the transitions.
     $aTransitions = array();
     foreach ($transitions as $transition) {
         $dest_name = $to[$transition];
         $oDestState = $aStates[$dest_name];
         $oTransition = KTWorkflowTransition::createFromArray(array("WorkflowId" => $iWorkflowId, "Name" => $transition, "HumanName" => $transition, "TargetStateId" => $oDestState->getId(), "GuardPermissionId" => null, "GuardGroupId" => null, "GuardRoleId" => null, "GuardConditionId" => null));
         if (PEAR::isError($oTransition)) {
             $this->errorRedirectToMain(sprintf(_kt("Failed to create transition: %s"), $oTransition->getMessage()));
         }
         // hook up source states.
         $state_ids = array();
         $sources = (array) $from[$transition];
         foreach ($sources as $state_name) {
             // must exist.
             $oState = $aStates[$state_name];
             $state_ids[] = $oState->getId();
         }
         $res = KTWorkflowAdminUtil::saveTransitionSources($oTransition, $state_ids);
         if (PEAR::isError($res)) {
             $this->errorRedirectToMain(sprintf(_kt("Failed to set transition origins: %s"), $res->getMessage()));
         }
     }
     $this->commitTransaction();
     // finally, we want to redirect the user to the parent dispatcher somehow.
     // FIXME nbm:  how do you recommend we do this?
     $base = $_SERVER['PHP_SELF'];
     $qs = sprintf("action=view&fWorkflowId=%d", $oWorkflow->getId());
     $url = KTUtil::addQueryString($base, $qs);
     $this->addInfoMessage(_kt("Your new workflow has been created.  You may want to configure security and notifications from the menu on the left."));
     redirect($url);
 }
예제 #3
0
 /**
  * This returns detailed information on the document.
  *
  * @author KnowledgeTree Team
  * @access public
  * @return array The document information
  */
 function get_detail()
 {
     global $default;
     // make sure we ge tthe latest
     $this->clearCache();
     $config = KTConfig::getSingleton();
     $wsversion = $config->get('webservice/version', LATEST_WEBSERVICE_VERSION);
     $detail = array();
     $document = $this->document;
     // get the document id
     $detail['document_id'] = (int) $document->getId();
     $oem_document_no = null;
     if ($wsversion >= 2) {
         $oem_document_no = $document->getOemNo();
     }
     if (empty($oem_document_no)) {
         $oem_document_no = 'n/a';
     }
     $detail['custom_document_no'] = 'n/a';
     $detail['oem_document_no'] = $oem_document_no;
     // get the title
     $detail['title'] = $document->getName();
     // get the document type
     $documenttypeid = $document->getDocumentTypeID();
     $documenttype = '* unknown *';
     if (is_numeric($documenttypeid)) {
         $dt = DocumentType::get($documenttypeid);
         if (!is_null($dt) && !PEAR::isError($dt)) {
             $documenttype = $dt->getName();
         }
     }
     $detail['document_type'] = $documenttype;
     // get the filename
     $detail['filename'] = $document->getFilename();
     // get the filesize
     $detail['filesize'] = (int) $document->getFileSize();
     // get the folder id
     $detail['folder_id'] = (int) $document->getFolderID();
     // get the creator
     $userid = $document->getCreatorID();
     $username = '******';
     if (is_numeric($userid)) {
         $username = '******';
         $user = User::get($userid);
         if (!is_null($user) && !PEAR::isError($user)) {
             $username = $user->getName();
         }
     }
     $detail['created_by'] = $username;
     // get the creation date
     $detail['created_date'] = $document->getCreatedDateTime();
     // get the checked out user
     $userid = $document->getCheckedOutUserID();
     $username = '******';
     if (is_numeric($userid)) {
         $username = '******';
         $user = User::get($userid);
         if (!is_null($user) && !PEAR::isError($user)) {
             $username = $user->getName();
         }
     }
     $detail['checked_out_by'] = $username;
     // get the checked out date
     list($major, $minor, $fix) = explode('.', $default->systemVersion);
     if ($major == 3 && $minor >= 5) {
         $detail['checked_out_date'] = $document->getCheckedOutDate();
     } else {
         $detail['checked_out_date'] = $detail['modified_date'];
     }
     if (is_null($detail['checked_out_date'])) {
         $detail['checked_out_date'] = 'n/a';
     }
     // get the modified user
     $userid = $document->getModifiedUserId();
     $username = '******';
     if (is_numeric($userid)) {
         $username = '******';
         $user = User::get($userid);
         if (!is_null($user) && !PEAR::isError($user)) {
             $username = $user->getName();
         }
     }
     $detail['modified_by'] = $detail['updated_by'] = $username;
     // get the modified date
     $detail['updated_date'] = $detail['modified_date'] = $document->getLastModifiedDate();
     // get the owner
     $userid = $document->getOwnerID();
     $username = '******';
     if (is_numeric($userid)) {
         $username = '******';
         $user = User::get($userid);
         if (!is_null($user) && !PEAR::isError($user)) {
             $username = $user->getName();
         }
     }
     $detail['owned_by'] = $username;
     // get the version
     $detail['version'] = $document->getVersion();
     if ($wsversion >= 2) {
         $detail['version'] = (double) $detail['version'];
     }
     //might be unset at the bottom in case of old webservice version
     //make sure we're using the real document for this one
     $this->document->switchToRealCore();
     $detail['linked_document_id'] = $document->getLinkedDocumentId();
     $this->document->switchToLinkedCore();
     // check immutability
     $detail['is_immutable'] = (bool) $document->getImmutable();
     // check permissions
     $detail['permissions'] = KTAPI_Document::get_permission_string($document);
     // get workflow name
     $workflowid = $document->getWorkflowId();
     $workflowname = 'n/a';
     if (is_numeric($workflowid)) {
         $workflow = KTWorkflow::get($workflowid);
         if (!is_null($workflow) && !PEAR::isError($workflow)) {
             $workflowname = $workflow->getName();
         }
     }
     $detail['workflow'] = $workflowname;
     // get the workflow state
     $stateid = $document->getWorkflowStateId();
     $workflowstate = 'n/a';
     if (is_numeric($stateid)) {
         $state = KTWorkflowState::get($stateid);
         if (!is_null($state) && !PEAR::isError($state)) {
             $workflowstate = $state->getName();
         }
     }
     $detail['workflow_state'] = $workflowstate;
     // get the full path
     $detail['full_path'] = '/' . $this->document->getFullPath();
     // get mime info
     $mimetypeid = $document->getMimeTypeID();
     $detail['mime_type'] = KTMime::getMimeTypeName($mimetypeid);
     $detail['mime_icon_path'] = KTMime::getIconPath($mimetypeid);
     $detail['mime_display'] = KTMime::getFriendlyNameForString($detail['mime_type']);
     // get the storage path
     $detail['storage_path'] = $document->getStoragePath();
     if ($wsversion >= 2) {
         unset($detail['updated_by']);
         unset($detail['updated_date']);
     }
     if ($wsversion < 3) {
         unset($detail['linked_document_id']);
     }
     return $detail;
 }
예제 #4
0
 /**
  * Performs a workflow transition on a document, changing it from
  * one workflow state to another, with potential side effects (user
  * scripts, and so forth).
  *
  * This function currently assumes that the user in question is
  * allowed to perform the transition and that all the guard
  * functionality on the transition has passed.
  */
 function performTransitionOnDocument($oTransition, $oDocument, $oUser, $sComments)
 {
     $oWorkflow =& KTWorkflow::getByDocument($oDocument);
     if (empty($oWorkflow)) {
         return PEAR::raiseError(_kt("Document has no workflow"));
     }
     if (PEAR::isError($oWorkflow)) {
         return $oWorkflow;
     }
     $oSourceState =& KTWorkflowUtil::getWorkflowStateForDocument($oDocument);
     // walk the action triggers.
     $aActionTriggers = KTWorkflowUtil::getActionTriggersForTransition($oTransition);
     if (PEAR::isError($aActionTriggers)) {
         return $aActionTriggers;
         // error out?
     }
     foreach ($aActionTriggers as $oTrigger) {
         $res = $oTrigger->precheckTransition($oDocument, $oUser);
         if (PEAR::isError($res)) {
             return $res;
         }
     }
     $iPreviousMetadataVersion = $oDocument->getMetadataVersionId();
     $oDocument->startNewMetadataVersion($oUser);
     KTDocumentUtil::copyMetadata($oDocument, $iPreviousMetadataVersion);
     $iStateId = $oTransition->getTargetStateId();
     $oDocument->setWorkflowStateId($iStateId);
     $res = $oDocument->update();
     if (PEAR::isError($res)) {
         return $res;
     }
     $oTargetState =& KTWorkflowState::get($iStateId);
     $sSourceState = $oSourceState->getName();
     $sTargetState = $oTargetState->getName();
     // create the document transaction record
     $sTransactionComments = sprintf(_kt("Workflow state changed from %s to %s"), $sSourceState, $sTargetState);
     if ($sComments) {
         $sTransactionComments .= _kt("; Reason given was: ") . $sComments;
     }
     $oDocumentTransaction = new DocumentTransaction($oDocument, $sTransactionComments, 'ktcore.transactions.workflow_state_transition');
     $oDocumentTransaction->create();
     // walk the action triggers.
     foreach ($aActionTriggers as $oTrigger) {
         $res = $oTrigger->performTransition($oDocument, $oUser);
         if (PEAR::isError($res)) {
             return $res;
         }
     }
     KTPermissionUtil::updatePermissionLookup($oDocument);
     KTWorkflowUtil::informUsersForState($oTargetState, KTWorkflowUtil::getInformedForState($oTargetState), $oDocument, $oUser, $sComments);
     return true;
 }
예제 #5
0
 function &getByDocument($oDocument)
 {
     $oDocument =& KTUtil::getObject('Document', $oDocument);
     $iStateId = $oDocument->getWorkflowStateId();
     if (PEAR::isError($iStateId)) {
         return $iStateId;
     }
     if (is_null($iStateId)) {
         return $iStateId;
     }
     return KTWorkflowState::get($iStateId);
 }
 function getSourceStates($oTransition, $aOptions = null)
 {
     $bIds = KTUtil::arrayGet($aOptions, 'ids');
     $sTable = KTUtil::getTableName('workflow_state_transitions');
     $aQuery = array("SELECT state_id FROM {$sTable} WHERE transition_id = ?", array($oTransition->getId()));
     $aStateIds = DBUtil::getResultArrayKey($aQuery, 'state_id');
     if (PEAR::isError($aStateIds)) {
         return $aStateIds;
     }
     if ($bIds) {
         return $aStateIds;
     }
     $aRet = array();
     foreach ($aStateIds as $iId) {
         $aRet[] =& KTWorkflowState::get($iId);
     }
     return $aRet;
 }
예제 #7
0
 function get_graph($oWorkflow)
 {
     $fontsize = 11.0;
     $fontname = "Times-Roman";
     $opts = array('fontsize' => $fontsize, 'fontname' => $fontname);
     $graph = new Image_GraphViz(true, $opts);
     $graph->dotCommand = $this->dotCommand;
     // we need all states & transitions
     // FIXME do we want guards?
     // we want to enable link-editing, and indicate that transitions "converge"
     // so we use a temporary "node" for transitions
     // we also use a "fake" URL which we catch later
     // so we can give good "alt" tags.
     $states = KTWorkflowState::getByWorkflow($oWorkflow);
     $transitions = KTWorkflowTransition::getByWorkflow($oWorkflow);
     $this->state_names = array();
     $this->transition_names = array();
     $state_opts = array('shape' => 'box', 'fontsize' => $fontsize, 'fontname' => $fontname);
     $transition_opts = array('shape' => 'box', 'color' => '#ffffff', 'fontsize' => $fontsize, 'fontname' => $fontname);
     $finaltransition_opts = array('color' => '#333333');
     $sourcetransition_opts = array('color' => '#999999');
     // to make this a little more useful, we want to cascade our output from
     // start to end states - this will tend to give a better output.
     //
     // to do this, we need to order our nodes in terms of "nearness" to the
     // initial node.
     $processing_nodes = array();
     $sorted_ids = array();
     $availability = array();
     $sources = array();
     $destinations = array();
     $states = KTUtil::keyArray($states);
     $transitions = KTUtil::keyArray($transitions);
     foreach ($transitions as $tid => $oTransition) {
         $sources[$tid] = KTWorkflowAdminUtil::getSourceStates($oTransition, array('ids' => true));
         $destinations[$tid] = $oTransition->getTargetStateId();
         foreach ($sources[$tid] as $sourcestateid) {
             $av = (array) KTUtil::arrayGet($availability, $sourcestateid, array());
             $av[] = $tid;
             $availability[$sourcestateid] = $av;
         }
     }
     //var_dump($sources); exit(0);
     //var_dump($availability); exit(0);
     $processing = array($oWorkflow->getStartStateId());
     while (!empty($processing)) {
         $active = array_shift($processing);
         if (!$processing_nodes[$active]) {
             // mark that we've seen this node
             $processing_nodes[$active] = true;
             $sorted[] = $active;
             // now add all reachable nodes to the *end* of the queue.
             foreach ((array) $availability[$active] as $tid) {
                 $next = $destinations[$tid];
                 if (!$processing_nodes[$next]) {
                     $processing[] = $next;
                 }
             }
         }
         //var_dump($processing);
     }
     //var_dump($sorted); exit(0);
     foreach ($sorted as $sid) {
         $oState = $states[$sid];
         $this->state_names[$oState->getId()] = $oState->getHumanName();
         $local_opts = array('URL' => sprintf("s%d", $oState->getId()), 'label' => $oState->getHumanName(), 'color' => '#666666');
         if ($oState->getId() == $oWorkflow->getStartStateId()) {
             $local_opts['color'] = '#000000';
             $local_opts['style'] = 'filled';
             $local_opts['fillcolor'] = '#cccccc';
         }
         $graph->addNode(sprintf('state%d', $oState->getId()), KTUtil::meldOptions($state_opts, $local_opts));
     }
     foreach ($transitions as $tid => $oTransition) {
         $name = sprintf('transition%d', $tid);
         $this->transition_names[$oTransition->getId()] = $oTransition->getHumanName();
         // we "cheat" and use
         $graph->addNode($name, KTUtil::meldOptions($transition_opts, array('URL' => sprintf("t%d", $tid), 'label' => $oTransition->getHumanName())));
         $dest = sprintf("state%d", $oTransition->getTargetStateId());
         $graph->addEdge(array($name => $dest), $finaltransition_opts);
         foreach ($sources[$tid] as $source_id) {
             $source_name = sprintf("state%d", $source_id);
             $graph->addEdge(array($source_name => $name), $sourcetransition_opts);
         }
     }
     // some simple analysis
     $errors = array();
     $info = array();
     $sourceless_transitions = array();
     foreach ($transitions as $tid => $oTransition) {
         if (empty($sources[$tid])) {
             $sourceless_transitions[] = $oTransition->getHumanName();
         }
     }
     if (!empty($sourceless_transitions)) {
         $errors[] = sprintf(_kt("Some transitions have no source states: %s"), implode(', ', $sourceless_transitions));
     }
     $unlinked_states = array();
     foreach ($states as $sid => $oState) {
         if (!$processing_nodes[$sid]) {
             // quick sanity check
             $unlinked_states[] = $oState->getHumanName();
         }
     }
     if (!empty($unlinked_states)) {
         $errors[] = sprintf(_kt("Some states cannot be reached from the initial state (<strong>%s</strong>): %s"), $states[$oWorkflow->getStartStateId()]->getHumanName(), implode(', ', $unlinked_states));
     }
     $data = array('graph' => $graph, 'errors' => $errors, 'info' => $info);
     return $data;
 }
예제 #8
0
 /**
  * Create a table of the document metadata.
  * Hard coded for the moment
  *
  * @return unknown
  */
 function getMetadata()
 {
     /* Get document info */
     // Filename
     $sFilenameLb = _kt('Document Filename: ');
     $sFilename = $this->_oDocument->getFileName();
     // Mime type
     $sMimeTypeLb = _kt('File is a: ');
     $iMimeId = $this->_oDocument->getMimeTypeID();
     $sMimeType = KTMime::getMimeTypeName($iMimeId);
     $sMimeType = KTMime::getFriendlyNameForString($sMimeType);
     // Version
     $sVersionLb = _kt('Document Version: ');
     $iVersion = $this->_oDocument->getVersion();
     // Created by
     $sCreatedByLb = _kt('Created by: ');
     $iCreatorId = $this->_oDocument->getCreatorID();
     $sCreated = $this->_oDocument->getCreatedDateTime();
     $oCreator = User::get($iCreatorId);
     $sCreatedBy = $oCreator->getName() . ' (' . $sCreated . ')';
     // Owned by
     $sOwnedByLb = _kt('Owned by: ');
     $iOwnedId = $this->_oDocument->getOwnerID();
     $oOwner = User::get($iOwnedId);
     $sOwnedBy = $oOwner->getName();
     // Last update by
     $iModifiedId = $this->_oDocument->getModifiedUserId();
     $sLastUpdatedByLb = '';
     $sLastUpdatedBy = '';
     if (!empty($iModifiedId)) {
         $sLastUpdatedByLb = _kt('Last updated by: ');
         $sModified = $this->_oDocument->getLastModifiedDate();
         $oModifier = User::get($iModifiedId);
         $sLastUpdatedBy = $oModifier->getName() . ' (' . $sModified . ')';
     }
     // Document type
     $sDocTypeLb = _kt('Document Type: ');
     $iDocTypeId = $this->_oDocument->getDocumentTypeID();
     $oDocType = DocumentType::get($iDocTypeId);
     $sDocType = $oDocType->getName();
     // Workflow
     $iWFId = $this->_oDocument->getWorkflowId();
     $sWF = '';
     $sWFLb = '';
     if (!empty($iWFId)) {
         $sWFLb = _kt('Workflow: ');
         $iWFStateId = $this->_oDocument->getWorkflowStateId();
         $oWF = KTWorkflow::get($iWFId);
         $sWF = $oWF->getHumanName();
         $oWFState = KTWorkflowState::get($iWFStateId);
         $sWF .= ' (' . $oWFState->getHumanName() . ')';
     }
     // Checked out by
     $sCheckedLb = '';
     $sCheckedOutBy = '';
     if ($this->_oDocument->getIsCheckedOut()) {
         $sCheckedLb = _kt('Checked out by: ');
         $iCheckedID = $this->_oDocument->getCheckedOutUserID();
         $oCheckedUser = User::get($iCheckedID);
         $sCheckedOutBy = $oCheckedUser->getName();
     }
     // Id
     $sIdLb = _kt('Document ID: ');
     $sId = $this->_IDocId;
     /* Create table */
     $sInfo = "<div style='float:left; width:405px;'>\n            <table cellspacing='3px' cellpadding='3px' width='405px'>\n            <tr><td>{$sFilenameLb}</td><td><b>{$sFilename}</b></td></tr>\n            <tr><td>{$sMimeTypeLb}</td><td><b>{$sMimeType}</b></td></tr>\n            <tr><td>{$sVersionLb}</td><td><b>{$iVersion}</b></td></tr>\n            <tr><td>{$sCreatedByLb}</td><td><b>{$sCreatedBy}</b></td></tr>\n            <tr><td>{$sOwnedByLb}</td><td><b>{$sOwnedBy}</b></td></tr>";
     if (!empty($sLastUpdatedBy)) {
         $sInfo .= "<tr><td>{$sLastUpdatedByLb}</td><td><b>{$sLastUpdatedBy}</b></td></tr>";
     }
     $sInfo .= "<tr><td>{$sDocTypeLb}</td><td><b>{$sDocType}</b></td></tr>";
     if (!empty($sWF)) {
         $sInfo .= "<tr><td>{$sWFLb}</td><td><b>{$sWF}</b></td></tr>";
     }
     if (!empty($sCheckedOutBy)) {
         $sInfo .= "<tr><td>{$sCheckedLb}</td><td><b>{$sCheckedOutBy}</b></td></tr>";
     }
     $sInfo .= "<tr><td>{$sIdLb}</td><td><b>{$sId}</b></td></tr>";
     $sInfo .= " </table></div>";
     return $sInfo;
 }
 function showDescription()
 {
     $oWorkflowState =& KTWorkflowState::get($this->getTargetStateId());
     return sprintf(_kt("%s (to state %s)"), $this->getName(), $oWorkflowState->getName());
 }