This repository has been archived on 2024-11-28. You can view files and clone it, but cannot push or open issues or pull requests.
Incam_SGD/lib/documentmanagement/documentutil.inc.php

1653 lines
61 KiB
PHP
Raw Normal View History

<?php
/**
* $Id$
*
* Document-handling utility functions
*
* Simplifies and canonicalises operations such as adding, updating, and
* deleting documents from the repository.
*
* KnowledgeTree Community Edition
* Document Management Made Simple
* Copyright (C) 2008, 2009 KnowledgeTree Inc.
*
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 3 as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
* California 94120-7775, or email info@knowledgetree.com.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "Powered by
* KnowledgeTree" logo and retain the original copyright notice. If the display of the
* logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
* must display the words "Powered by KnowledgeTree" and retain the original
* copyright notice.
* Contributor( s): ______________________________________
*/
// LEGACY PATHS
require_once(KT_LIB_DIR . '/documentmanagement/DocumentFieldLink.inc');
require_once(KT_LIB_DIR . '/documentmanagement/DocumentTransaction.inc');
require_once(KT_LIB_DIR . '/documentmanagement/Document.inc');
// NEW PATHS
require_once(KT_LIB_DIR . '/storage/storagemanager.inc.php');
require_once(KT_LIB_DIR . '/filelike/filelikeutil.inc.php');
require_once(KT_LIB_DIR . '/metadata/metadatautil.inc.php');
require_once(KT_LIB_DIR . '/metadata/fieldset.inc.php');
require_once(KT_LIB_DIR . '/subscriptions/subscriptions.inc.php');
require_once(KT_LIB_DIR . '/triggers/triggerregistry.inc.php');
require_once(KT_LIB_DIR . '/foldermanagement/Folder.inc');
require_once(KT_LIB_DIR . '/alert/EmailTemplate.inc.php');
require_once(KT_LIB_DIR . '/browse/browseutil.inc.php');
// WORKFLOW
require_once(KT_LIB_DIR . '/workflow/workflowutil.inc.php');
class KTDocumentUtil {
function checkin($oDocument, $sFilename, $sCheckInComment, $oUser, $aOptions = false, $bulk_action = false) {
$oStorage =& KTStorageManagerUtil::getSingleton();
$iFileSize = filesize($sFilename);
$iPreviousMetadataVersion = $oDocument->getMetadataVersionId();
$bSuccess = $oDocument->startNewContentVersion($oUser);
if (PEAR::isError($bSuccess)) {
return $bSuccess;
}
KTDocumentUtil::copyMetadata($oDocument, $iPreviousMetadataVersion);
$aOptions['temp_file'] = $sFilename;
$res = KTDocumentUtil::storeContents($oDocument, '', $aOptions);
if (PEAR::isError($res)) {
return $res;
}
$oDocument->setLastModifiedDate(getCurrentDateTime());
$oDocument->setModifiedUserId($oUser->getId());
$oDocument->setIsCheckedOut(false);
$oDocument->setCheckedOutUserID(-1);
if ($aOptions['major_update']) {
$oDocument->setMajorVersionNumber($oDocument->getMajorVersionNumber()+1);
$oDocument->setMinorVersionNumber('0');
} else {
$oDocument->setMinorVersionNumber($oDocument->getMinorVersionNumber()+1);
}
$oDocument->setFileSize($iFileSize);
if(is_array($aOptions)) {
$sFilename = KTUtil::arrayGet($aOptions, 'newfilename', '');
if(!empty($sFilename)) {
global $default;
$oDocument->setFileName($sFilename);
$default->log->info('renamed document ' . $oDocument->getId() . ' to ' . $sFilename);
// detection of mime types needs to be refactored. this stuff is damn messy!
// If the filename has changed then update the mime type
$iMimeTypeId = KTMime::getMimeTypeID('', $sFilename);
$oDocument->setMimeTypeId($iMimeTypeId);
}
}
$bSuccess = $oDocument->update();
if ($bSuccess !== true) {
if (PEAR::isError($bSuccess)) {
return $bSuccess;
}
return PEAR::raiseError(_kt('An error occurred while storing this document in the database'));
}
// create the document transaction record
$oDocumentTransaction = new DocumentTransaction($oDocument, $sCheckInComment, 'ktcore.transactions.check_in');
$oDocumentTransaction->create();
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('content', 'scan');
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$oTrigger->setDocument($oDocument);
$ret = $oTrigger->scan();
if (PEAR::isError($ret)) {
$oDocument->delete();
return $ret;
}
}
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('checkin', 'postValidate');
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$aInfo = array(
'document' => $oDocument,
'aOptions' => $aOrigOptions,
);
$oTrigger->setInfo($aInfo);
$ret = $oTrigger->postValidate();
}
Indexer::index($oDocument);
if(!$bulk_action) {
// fire subscription alerts for the checked in document
$oSubscriptionEvent = new SubscriptionEvent();
$oFolder = Folder::get($oDocument->getFolderID());
$oSubscriptionEvent->CheckinDocument($oDocument, $oFolder);
}
return true;
}
function checkout($oDocument, $sCheckoutComment, $oUser, $bulk_action = false) {
//automatically check out the linked document if this is a shortcut
if($oDocument->isSymbolicLink()){
$oDocument->switchToLinkedCore();
}
if ($oDocument->getIsCheckedOut()) {
return PEAR::raiseError(_kt('Already checked out.'));
}
if($oDocument->getImmutable()){
return PEAR::raiseError(_kt('Document cannot be checked out as it is immutable'));
}
// Check if the action is restricted by workflow on the document
if(!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.checkout')){
return PEAR::raiseError(_kt('Checkout is restricted by the workflow state.'));
}
// FIXME at the moment errors this _does not_ rollback.
$oDocument->setIsCheckedOut(true);
$oDocument->setCheckedOutUserID($oUser->getId());
if (!$oDocument->update()) { return PEAR::raiseError(_kt('There was a problem checking out the document.')); }
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('checkout', 'postValidate');
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$aInfo = array(
'document' => $oDocument,
);
$oTrigger->setInfo($aInfo);
$ret = $oTrigger->postValidate(true);
if (PEAR::isError($ret)) {
return $ret;
}
}
$oDocumentTransaction = new DocumentTransaction($oDocument, $sCheckoutComment, 'ktcore.transactions.check_out');
$oDocumentTransaction->create();
if(!$bulk_action) {
// fire subscription alerts for the downloaded document
$oSubscriptionEvent = new SubscriptionEvent();
$oFolder = Folder::get($oDocument->getFolderID());
$oSubscriptionEvent->CheckOutDocument($oDocument, $oFolder);
}
return true;
}
function archive($oDocument, $sReason, $bulk_action = false) {
if($oDocument->isSymbolicLink()){
return PEAR::raiseError(_kt("It is not possible to archive a shortcut. Please archive the target document."));
}
// Ensure the action is not blocked
if(!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.archive')){
return PEAR::raiseError(_kt('Document cannot be archived as it is restricted by the workflow.'));
}
$oDocument->setStatusID(ARCHIVED);
$res = $oDocument->update();
if (PEAR::isError($res) || ($res === false)) {
return PEAR::raiseError(_kt('There was a database error while trying to archive this file'));
}
//delete all shortcuts linking to this document
$aSymlinks = $oDocument->getSymbolicLinks();
foreach($aSymlinks as $aSymlink){
$oShortcutDocument = Document::get($aSymlink['id']);
$oOwnerUser = User::get($oShortcutDocument->getOwnerID());
KTDocumentUtil::deleteSymbolicLink($aSymlink['id']);
//send an email to the owner of the shortcut
if($oOwnerUser->getEmail()!=null && $oOwnerUser->getEmailNotification() == true){
$emailTemplate = new EmailTemplate("kt3/notifications/notification.SymbolicLinkArchived",array('user_name'=>$this->oUser->getName(),
'url'=>KTUtil::ktLink(KTBrowseUtil::getUrlForDocument($oShortcutDocument)),
'title' =>$oShortcutDocument->getName()));
$email = new EmailAlert($oOwnerUser->getEmail(),_kt("KnowledgeTree Notification"),$emailTemplate->getBody());
$email->send();
}
}
$oDocumentTransaction = & new DocumentTransaction($oDocument, sprintf(_kt('Document archived: %s'), $sReason), 'ktcore.transactions.update');
$oDocumentTransaction->create();
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('archive', 'postValidate');
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$aInfo = array(
'document' => $oDocument,
);
$oTrigger->setInfo($aInfo);
$ret = $oTrigger->postValidate(true);
if (PEAR::isError($ret)) {
$oDocument->delete();
return $ret;
}
}
if(!$bulk_action) {
// fire subscription alerts for the archived document
$oSubscriptionEvent = new SubscriptionEvent();
$oFolder = Folder::get($oDocument->getFolderID());
$oSubscriptionEvent->ArchivedDocument($oDocument, $oFolder);
}
return true;
}
function &_add($oFolder, $sFilename, $oUser, $aOptions) {
global $default;
//$oContents = KTUtil::arrayGet($aOptions, 'contents');
$aMetadata = KTUtil::arrayGet($aOptions, 'metadata', null, false);
$oDocumentType = KTUtil::arrayGet($aOptions, 'documenttype');
$sDescription = KTUtil::arrayGet($aOptions, 'description', '');
if(empty($sDescription)){
// If no document name is provided use the filename minus the extension
$aFile = pathinfo($sFilename);
$sDescription = (isset($aFile['filename']) && !empty($aFile['filename'])) ? $aFile['filename'] : $sFilename;
}
$oUploadChannel =& KTUploadChannel::getSingleton();
if ($oDocumentType) {
$iDocumentTypeId = KTUtil::getId($oDocumentType);
} else {
$iDocumentTypeId = 1;
}
$oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Creating database entry')));
$oDocument =& Document::createFromArray(array(
'name' => $sDescription,
'description' => $sDescription,
'filename' => $sFilename,
'folderid' => $oFolder->getID(),
'creatorid' => $oUser->getID(),
'documenttypeid' => $iDocumentTypeId,
));
$oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Storing contents')));
$res = KTDocumentUtil::storeContents($oDocument, '', $aOptions);
if (PEAR::isError($res)) {
if (!PEAR::isError($oDocument)) {
$oDocument->delete();
}
return $res;
}
if (is_null($aMetadata)) {
$res = KTDocumentUtil::setIncomplete($oDocument, 'metadata');
if (PEAR::isError($res)) {
$oDocument->delete();
return $res;
}
} else {
$oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Saving metadata')));
$res = KTDocumentUtil::saveMetadata($oDocument, $aMetadata, $aOptions);
if (PEAR::isError($res)) {
$oDocument->delete();
return $res;
}
}
// setIncomplete and storeContents may change the document's status or
// storage_path, so now is the time to update
$oDocument->update();
return $oDocument;
}
/**
* Create a symbolic link in the target folder
*
* @param Document $sourceDocument the document to create a link to
* @param Folder $targetFolder the folder to place the link in
* @param User $user current user
*/
static function createSymbolicLink($sourceDocument, $targetFolder, $user = null) // added/
{
//validate input
if (is_numeric($sourceDocument))
{
$sourceDocument = Document::get($sourceDocument);
}
if (!$sourceDocument instanceof Document)
{
return PEAR::raiseError(_kt('Source document not specified'));
}
if (is_numeric($targetFolder))
{
$targetFolder = Folder::get($targetFolder);
}
if (!$targetFolder instanceof Folder)
{
return PEAR::raiseError(_kt('Target folder not specified'));
}
if (is_null($user))
{
$user = $_SESSION['userID'];
}
if (is_numeric($user))
{
$user = User::get($user);
}
//check for permissions
$oPermission =& KTPermission::getByName("ktcore.permissions.write");
$oReadPermission =& KTPermission::getByName("ktcore.permissions.read");
if (KTBrowseUtil::inAdminMode($user, $targetFolder)) {
if(!KTPermissionUtil::userHasPermissionOnItem($user, $oPermission, $targetFolder)){
return PEAR::raiseError(_kt('You\'re not authorized to create shortcuts'));
}
}
if (!KTBrowseUtil::inAdminMode($user, $sourceDocument->getParentID())) {
if(!KTPermissionUtil::userHasPermissionOnItem($user, $oReadPermission, $sourceDocument)){
return PEAR::raiseError(_kt('You\'re not authorized to create a shortcut to this document'));
}
}
//check if the shortcut doesn't already exists in the target folder
$aSymlinks = $sourceDocument->getSymbolicLinks();
foreach($aSymlinks as $iSymlink){
$oSymlink = Document::get($iSymlink['id']);
$oSymlink->switchToRealCore();
if($oSymlink->getFolderID() == $targetFolder->getID()){
return PEAR::raiseError(_kt('There already is a shortcut to this document in the target folder.'));
}
}
//create the actual shortcut
$oCore = KTDocumentCore::createFromArray(array(
'iCreatorId'=>$user->getId(),
'iFolderId'=>$targetFolder->getId(),
'iLinkedDocumentId'=>$sourceDocument->getId(),
'sFullPath'=> $targetFolder->getFullPath() . '/' .
$sourceDocument->getName(),
'iPermissionObjectId'=>$targetFolder->getPermissionObjectID(),
'iPermissionLookupId'=>$targetFolder->getPermissionLookupID(),
'iStatusId'=>1,
'iMetadataVersionId'=>$sourceDocument->getMetadataVersionId(),
));
$document = Document::get($oCore->getId());
return $document;
}
/**
* Deletes a document symbolic link
*
* @param Document $document the symbolic link document
* @param User $user the user deleting the link
* @return unknown
*/
static function deleteSymbolicLink($document, $user = null) // added/
{
//validate input
if (is_numeric($document))
{
$document = Document::get($document);
}
if (!$document instanceof Document)
{
return PEAR::raiseError(_kt('Document not specified'));
}
if (!$document->isSymbolicLink())
{
return PEAR::raiseError(_kt('Document must be a symbolic link entity'));
}
if (is_null($user))
{
$user = $_SESSION['userID'];
}
if (is_numeric($user))
{
$user = User::get($user);
}
//check permissions
$oPerm = KTPermission::getByName('ktcore.permissions.delete');
if (!KTBrowseUtil::inAdminMode($user, $document->getParentID())) {
if(!KTPermissionUtil::userHasPermissionOnItem($user, $oPerm, $document)){
return PEAR::raiseError(_kt('You\'re not authorized to delete this shortcut'));
}
}
// we only need to delete the document entry for the link
$sql = "DELETE FROM documents WHERE id=?";
DBUtil::runQuery(array($sql, array($document->getId())));
}
// Overwrite the document
function overwrite($oDocument, $sFilename, $sTempFileName, $oUser, $aOptions) {
//$oDocument, $sFilename, $sCheckInComment, $oUser, $aOptions = false
$oStorage =& KTStorageManagerUtil::getSingleton();
$iFileSize = filesize($sTempFileName);
// Check that document is not checked out
if($oDocument->getIsCheckedOut()) {
return PEAR::raiseError(_kt('Document is checkout and cannot be overwritten'));
}
if (!$oStorage->upload($oDocument, $sTempFileName)) {
return PEAR::raiseError(_kt('An error occurred while storing the new file'));
}
$oDocument->setLastModifiedDate(getCurrentDateTime());
$oDocument->setModifiedUserId($oUser->getId());
$oDocument->setFileSize($iFileSize);
$sOriginalFilename = $oDocument->getFileName();
if($sOriginalFilename != $sFilename){
if(strlen($sFilename)) {
global $default;
$oDocument->setFileName($sFilename);
$default->log->info('renamed document ' . $oDocument->getId() . ' to ' . $sFilename);
}
$oDocument->setMinorVersionNumber($oDocument->getMinorVersionNumber()+1);
}
$sType = KTMime::getMimeTypeFromFile($sFilename);
$iMimeTypeId = KTMime::getMimeTypeID($sType, $oDocument->getFileName());
$oDocument->setMimeTypeId($iMimeTypeId);
$bSuccess = $oDocument->update();
if ($bSuccess !== true) {
if (PEAR::isError($bSuccess)) {
return $bSuccess;
}
return PEAR::raiseError(_kt('An error occurred while storing this document in the database'));
}
/*
// create the document transaction record
$oDocumentTransaction = new DocumentTransaction($oDocument, $sCheckInComment, 'ktcore.transactions.check_in');
$oDocumentTransaction->create();
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('content', 'scan');
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$oTrigger->setDocument($oDocument);
$ret = $oTrigger->scan();
if (PEAR::isError($ret)) {
$oDocument->delete();
return $ret;
}
}
// NEW SEARCH
Indexer::index($oDocument);
// fire subscription alerts for the checked in document
$oSubscriptionEvent = new SubscriptionEvent();
$oFolder = Folder::get($oDocument->getFolderID());
$oSubscriptionEvent->CheckinDocument($oDocument, $oFolder);
*/
return true;
}
// {{{ validateMetadata
function validateMetadata(&$oDocument, $aMetadata) {
$aFieldsets =& KTFieldset::getGenericFieldsets();
$aFieldsets =& kt_array_merge($aFieldsets,
KTFieldset::getForDocumentType($oDocument->getDocumentTypeId()));
$aSimpleMetadata = array();
foreach ($aMetadata as $aSingleMetadatum) {
list($oField, $sValue) = $aSingleMetadatum;
if (is_null($oField)) {
continue;
}
$aSimpleMetadata[$oField->getId()] = $sValue;
}
$aFailed = array();
foreach ($aFieldsets as $oFieldset) {
$aFields =& $oFieldset->getFields();
$aFieldValues = array();
$isRealConditional = ($oFieldset->getIsConditional() && KTMetadataUtil::validateCompleteness($oFieldset));
foreach ($aFields as $oField) {
$v = KTUtil::arrayGet($aSimpleMetadata, $oField->getId());
if ($oField->getIsMandatory() && !$isRealConditional) {
if (empty($v)) {
// XXX: What I'd do for a setdefault...
$aFailed['field'][$oField->getId()] = 1;
}
}
if (!empty($v)) {
$aFieldValues[$oField->getId()] = $v;
}
}
if ($isRealConditional) {
$res = KTMetadataUtil::getNext($oFieldset, $aFieldValues);
if ($res) {
foreach ($res as $aMDSet) {
if ($aMDSet['field']->getIsMandatory()) {
$aFailed['fieldset'][$oFieldset->getId()] = 1;
}
}
}
}
}
if (!empty($aFailed)) {
return new KTMetadataValidationError($aFailed);
}
return $aMetadata;
}
// }}}
// {{{ saveMetadata
function saveMetadata(&$oDocument, $aMetadata, $aOptions = null) {
$table = 'document_fields_link';
$bNoValidate = KTUtil::arrayGet($aOptions, 'novalidate', false);
if ($bNoValidate !== true)
{
$res = KTDocumentUtil::validateMetadata($oDocument, $aMetadata);
if (PEAR::isError($res))
{
return $res;
}
$aMetadata = empty($res)?array():$res;
}
$iMetadataVersionId = $oDocument->getMetadataVersionId();
$res = DBUtil::runQuery(array("DELETE FROM $table WHERE metadata_version_id = ?", array($iMetadataVersionId)));
if (PEAR::isError($res)) {
return $res;
}
// XXX: Metadata refactor
foreach ($aMetadata as $aInfo) {
list($oMetadata, $sValue) = $aInfo;
if (is_null($oMetadata)) {
continue;
}
$res = DBUtil::autoInsert($table, array(
'metadata_version_id' => $iMetadataVersionId,
'document_field_id' => $oMetadata->getID(),
'value' => $sValue,
));
if (PEAR::isError($res)) {
return $res;
}
}
KTDocumentUtil::setComplete($oDocument, 'metadata');
DocumentFieldLink::clearAllCaches();
return true;
}
// }}}
function copyMetadata($oDocument, $iPreviousMetadataVersionId) {
$iNewMetadataVersion = $oDocument->getMetadataVersionId();
$sTable = KTUtil::getTableName('document_fields_link');
$aFields = DBUtil::getResultArray(array("SELECT * FROM $sTable WHERE metadata_version_id = ?", array($iPreviousMetadataVersionId)));
foreach ($aFields as $aRow) {
unset($aRow['id']);
$aRow['metadata_version_id'] = $iNewMetadataVersion;
DBUtil::autoInsert($sTable, $aRow);
}
}
// {{{ setIncomplete
function setIncomplete(&$oDocument, $reason) {
$oDocument->setStatusID(STATUS_INCOMPLETE);
$table = 'document_incomplete';
$iId = $oDocument->getId();
$aIncomplete = DBUtil::getOneResult(array("SELECT * FROM $table WHERE id = ?", array($iId)));
if (PEAR::isError($aIncomplete)) {
return $aIncomplete;
}
if (is_null($aIncomplete)) {
$aIncomplete = array('id' => $iId);
}
$aIncomplete[$reason] = true;
$res = DBUtil::autoDelete($table, $iId);
if (PEAR::isError($res)) {
return $res;
}
$res = DBUtil::autoInsert($table, $aIncomplete);
if (PEAR::isError($res)) {
return $res;
}
return true;
}
// }}}
// {{{ setComplete
function setComplete(&$oDocument, $reason) {
$table = 'document_incomplete';
$iId = $oDocument->getID();
$aIncomplete = DBUtil::getOneResult(array("SELECT * FROM $table WHERE id = ?", array($iId)));
if (PEAR::isError($aIncomplete)) {
return $aIncomplete;
}
if (is_null($aIncomplete)) {
$oDocument->setStatusID(LIVE);
return true;
}
$aIncomplete[$reason] = false;
$bIncomplete = false;
foreach ($aIncomplete as $k => $v) {
if ($k === 'id') { continue; }
if ($v) {
$bIncomplete = true;
}
}
if ($bIncomplete === false) {
DBUtil::autoDelete($table, $iId);
$oDocument->setStatusID(LIVE);
return true;
}
$res = DBUtil::autoDelete($table, $iId);
if (PEAR::isError($res)) {
return $res;
}
$res = DBUtil::autoInsert($table, $aIncomplete);
if (PEAR::isError($res)) {
return $res;
}
}
// }}}
/*
* Document Add
* Author : Jarrett Jordaan
* Modified : 28/04/09
*
* @params : KTFolderUtil $oFolder
* string $sFilename
* KTUser $oUser
* array $aOptions
* boolean $bulk_action
*/
// {{{ add
function &add($oFolder, $sFilename, $oUser, $aOptions, $bulk_action = false) {
$GLOBALS['_IN_ADD'] = true;
$ret = KTDocumentUtil::_in_add($oFolder, $sFilename, $oUser, $aOptions, $bulk_action);
unset($GLOBALS['_IN_ADD']);
return $ret;
}
// }}}
function getUniqueFilename($oFolder, $sFilename) {
// this is just a quick refactoring. We should look at a more optimal way of doing this as there are
// quite a lot of queries.
$iFolderId = $oFolder->getId();
while (KTDocumentUtil::fileExists($oFolder, $sFilename)) {
$oDoc = Document::getByFilenameAndFolder($sFilename, $iFolderId);
$sFilename = KTDocumentUtil::generateNewDocumentFilename($oDoc->getFileName());
}
return $sFilename;
}
function getUniqueDocumentName($oFolder, $sFilename)
{
// this is just a quick refactoring. We should look at a more optimal way of doing this as there are
// quite a lot of queries.
$iFolderId = $oFolder->getId();
while(KTDocumentUtil::nameExists($oFolder, $sFilename)) {
$oDoc = Document::getByNameAndFolder($sFilename, $iFolderId);
$sFilename = KTDocumentUtil::generateNewDocumentName($oDoc->getName());
}
return $sFilename;
}
/*
* Document Add
* Author : Jarrett Jordaan
* Modified : 28/04/09
*
* @params : KTFolderUtil $oFolder
* string $sFilename
* KTUser $oUser
* array $aOptions
* boolean $bulk_action
*/
// {{{ _in_add
function &_in_add($oFolder, $sFilename, $oUser, $aOptions, $bulk_action = false) {
$aOrigOptions = $aOptions;
$sFilename = KTDocumentUtil::getUniqueFilename($oFolder, $sFilename);
$sName = KTUtil::arrayGet($aOptions, 'description', $sFilename);
$sName = KTDocumentUtil::getUniqueDocumentName($oFolder, $sName);
$aOptions['description'] = $sName;
$oUploadChannel =& KTUploadChannel::getSingleton();
$oUploadChannel->sendMessage(new KTUploadNewFile($sFilename));
DBUtil::startTransaction();
$oDocument =& KTDocumentUtil::_add($oFolder, $sFilename, $oUser, $aOptions);
$oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Document created')));
if (PEAR::isError($oDocument)) {
return $oDocument;
}
$oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Scanning file')));
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('content', 'scan');
$iTrigger = 0;
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$oTrigger->setDocument($oDocument);
// $oUploadChannel->sendMessage(new KTUploadGenericMessage(sprintf(_kt(" (trigger %s)"), $sTrigger)));
$ret = $oTrigger->scan();
if (PEAR::isError($ret)) {
$oDocument->delete();
return $ret;
}
}
// refresh the document object
DBUtil::commit();
$oDocument->clearAllCaches();
// NEW SEARCH
Indexer::index($oDocument);
$oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Creating transaction')));
$aOptions = array('user' => $oUser);
//create the document transaction record
$oDocumentTransaction = new DocumentTransaction($oDocument, _kt('Document created'), 'ktcore.transactions.create', $aOptions);
$res = $oDocumentTransaction->create();
if (PEAR::isError($res)) {
$oDocument->delete();
return $res;
}
$oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Sending subscriptions')));
// TODO : better way of checking if its a bulk upload
if(!$bulk_action) {
// fire subscription alerts for the checked in document
$oSubscriptionEvent = new SubscriptionEvent();
$oFolder = Folder::get($oDocument->getFolderID());
$oSubscriptionEvent->AddDocument($oDocument, $oFolder);
}
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('add', 'postValidate');
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$aInfo = array(
'document' => $oDocument,
'aOptions' => $aOrigOptions,
);
$oTrigger->setInfo($aInfo);
$ret = $oTrigger->postValidate();
}
// update document object with additional fields / data from the triggers
$oDocument = Document::get($oDocument->iId);
$oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Checking permissions...')));
// Check if there are any dynamic conditions / permissions that need to be updated on the document
// If there are dynamic conditions then update the permissions on the document
// The dynamic condition test fails unless the document exists in the DB therefore update permissions after committing the transaction.
include_once(KT_LIB_DIR.'/permissions/permissiondynamiccondition.inc.php');
$iPermissionObjectId = $oFolder->getPermissionObjectID();
$dynamicCondition = KTPermissionDynamicCondition::getByPermissionObjectId($iPermissionObjectId);
if(!PEAR::isError($dynamicCondition) && !empty($dynamicCondition)){
$res = KTPermissionUtil::updatePermissionLookup($oDocument);
}
$oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('All done...')));
return $oDocument;
}
// }}}
function incrementNameCollissionNumbering($sDocFilename, $skipExtension = false){
$iDot = strpos($sDocFilename, '.');
if ($skipExtension || $iDot === false)
{
if(preg_match("/\(([0-9]+)\)$/", $sDocFilename, $matches, PREG_OFFSET_CAPTURE)) {
$iCount = $matches[1][0];
$iPos = $matches[1][1];
$iNewCount = $iCount + 1;
$sDocFilename = substr($sDocFilename, 0, $iPos) . $iNewCount . substr($sDocFilename, $iPos + strlen($iCount));
}
else {
$sDocFilename = $sDocFilename . '(1)';
}
}
else
{
if(preg_match("/\(([0-9]+)\)(\.[^\.]+)+$/", $sDocFilename, $matches, PREG_OFFSET_CAPTURE)) {
$iCount = $matches[1][0];
$iPos = $matches[1][1];
$iNewCount = $iCount + 1;
$sDocFilename = substr($sDocFilename, 0, $iPos) . $iNewCount . substr($sDocFilename, $iPos + strlen($iCount));
}
else {
$sDocFilename = substr($sDocFilename, 0, $iDot) . '(1)' . substr($sDocFilename, $iDot);
}
}
return $sDocFilename;
}
function generateNewDocumentFilename($sDocFilename) {
return self::incrementNameCollissionNumbering($sDocFilename, false);
}
function generateNewDocumentName($sDocName){
return self::incrementNameCollissionNumbering($sDocName, true);
}
// {{{ fileExists
function fileExists($oFolder, $sFilename) {
return Document::fileExists($sFilename, $oFolder->getID());
}
// }}}
// {{{ nameExists
function nameExists($oFolder, $sName) {
return Document::nameExists($sName, $oFolder->getID());
}
// }}}
// {{{ storeContents
/**
* Stores contents (filelike) from source into the document storage
*/
function storeContents(&$oDocument, $oContents = null, $aOptions = null) {
if (is_null($aOptions)) {
$aOptions = array();
}
if (PEAR::isError($oDocument)) {
return PEAR::raiseError(sprintf(_kt("Couldn't store contents: %s"), $oDocument->getMessage()));
}
$bCanMove = KTUtil::arrayGet($aOptions, 'move');
$oStorage =& KTStorageManagerUtil::getSingleton();
$oKTConfig =& KTConfig::getSingleton();
$sBasedir = $oKTConfig->get('urls/tmpDirectory');
$sFilename = (isset($aOptions['temp_file'])) ? $aOptions['temp_file'] : '';
if(empty($sFilename)){
return PEAR::raiseError(sprintf(_kt("Couldn't store contents: %s"), _kt('The uploaded file does not exist.')));
}
$md5hash = md5_file($sFilename);
$content = $oDocument->_oDocumentContentVersion;
$content->setStorageHash($md5hash);
$content->update();
if (empty($aOptions)) $aOptions = array();
$aOptions['md5hash'] = $md5hash;
// detection of mime types needs to be refactored. this stuff is damn messy!
$sType = KTMime::getMimeTypeFromFile($sFilename);
$iMimeTypeId = KTMime::getMimeTypeID($sType, $oDocument->getFileName(), $sFilename);
$oDocument->setMimeTypeId($iMimeTypeId);
$res = $oStorage->upload($oDocument, $sFilename, $aOptions);
if ($res === false) {
return PEAR::raiseError(sprintf(_kt("Couldn't store contents: %s"), _kt('No reason given')));
}
if (PEAR::isError($res)) {
return PEAR::raiseError(sprintf(_kt("Couldn't store contents: %s"), $res->getMessage()));
}
KTDocumentUtil::setComplete($oDocument, 'contents');
if ($aOptions['cleanup_initial_file'] && file_exists($sFilename)) {
@unlink($sFilename);
}
return true;
}
// }}}
/*
* Document Delete
* Author : Jarrett Jordaan
* Modified : 28/04/09
*
* @params : KTDocumentUtil $oDocument
* string $sReason
* int $iDestFolderId
* boolean $bulk_action
*/
// {{{ delete
function delete($oDocument, $sReason, $iDestFolderId = null, $bulk_action = false) {
// use the deleteSymbolicLink function is this is a symlink
if ($oDocument->isSymbolicLink())
{
return KTDocumentUtil::deleteSymbolicLink($oDocument);
}
$oDocument =& KTUtil::getObject('Document', $oDocument);
if (is_null($iDestFolderId)) {
$iDestFolderId = $oDocument->getFolderID();
}
$oStorageManager =& KTStorageManagerUtil::getSingleton();
global $default;
if (count(trim($sReason)) == 0) {
return PEAR::raiseError(_kt('Deletion requires a reason'));
}
if (PEAR::isError($oDocument) || ($oDocument == false)) {
return PEAR::raiseError(_kt('Invalid document object.'));
}
if ($oDocument->getIsCheckedOut() == true) {
return PEAR::raiseError(sprintf(_kt('The document is checked out and cannot be deleted: %s'), $oDocument->getName()));
}
if(!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.delete')){
return PEAR::raiseError(_kt('Document cannot be deleted as it is restricted by the workflow.'));
}
// IF we're deleted ...
if ($oDocument->getStatusID() == DELETED) {
return true;
}
$oOrigFolder = Folder::get($oDocument->getFolderId());
DBUtil::startTransaction();
// flip the status id
$oDocument->setStatusID(DELETED);
// $iDestFolderId is DEPRECATED.
$oDocument->setFolderID(null);
$oDocument->setRestoreFolderId($oOrigFolder->getId());
$oDocument->setRestoreFolderPath(Folder::generateFolderIDs($oOrigFolder->getId()));
$res = $oDocument->update();
if (PEAR::isError($res) || ($res == false)) {
DBUtil::rollback();
return PEAR::raiseError(_kt('There was a problem deleting the document from the database.'));
}
// now move the document to the delete folder
$res = $oStorageManager->delete($oDocument);
if (PEAR::isError($res) || ($res == false)) {
//could not delete the document from the file system
$default->log->error('Deletion: Filesystem error deleting document ' .
$oDocument->getFileName() . ' from folder ' .
Folder::getFolderPath($oDocument->getFolderID()) .
' id=' . $oDocument->getFolderID());
// we use a _real_ transaction here ...
DBUtil::rollback();
/*
//reverse the document deletion
$oDocument->setStatusID(LIVE);
$oDocument->update();
*/
return PEAR::raiseError(_kt('There was a problem deleting the document from storage.'));
}
// get the user object
$oUser = User::get($_SESSION['userID']);
//delete all shortcuts linking to this document
$aSymlinks = $oDocument->getSymbolicLinks();
foreach($aSymlinks as $aSymlink){
$oShortcutDocument = Document::get($aSymlink['id']);
$oOwnerUser = User::get($oShortcutDocument->getOwnerID());
KTDocumentUtil::deleteSymbolicLink($aSymlink['id']);
//send an email to the owner of the shortcut
if($oOwnerUser->getEmail()!=null && $oOwnerUser->getEmailNotification() == true){
$emailTemplate = new EmailTemplate("kt3/notifications/notification.SymbolicLinkDeleted",array('user_name'=>$oUser->getName(),
'url'=>KTUtil::ktLink(KTBrowseUtil::getUrlForDocument($oShortcutDocument)),
'title' =>$oShortcutDocument->getName()));
$email = new EmailAlert($oOwnerUser->getEmail(),_kt("KnowledgeTree Notification"),$emailTemplate->getBody());
$email->send();
}
}
$oDocumentTransaction = new DocumentTransaction($oDocument, _kt('Document deleted: ') . $sReason, 'ktcore.transactions.delete');
$oDocumentTransaction->create();
$oDocument->setFolderID(1);
DBUtil::commit();
// TODO : better way of checking if its a bulk delete
if(!$bulk_action) {
// we weren't doing notifications on this one
$oSubscriptionEvent = new SubscriptionEvent();
$oSubscriptionEvent->RemoveDocument($oDocument, $oOrigFolder);
}
// document is now deleted: triggers are best-effort.
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('delete', 'postValidate');
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$aInfo = array(
'document' => $oDocument,
);
$oTrigger->setInfo($aInfo);
$ret = $oTrigger->postValidate(true);
if (PEAR::isError($ret)) {
$oDocument->delete(); // FIXME nbm: review that on-fail => delete is correct ?!
return $ret;
}
}
}
// }}}
function reindexDocument($oDocument) {
Indexer::index($oDocument);
}
function canBeCopied($oDocument, &$sError) {
if ($oDocument->getIsCheckedOut()) {
$sError = PEAR::raiseError(_kt('Document cannot be copied as it is checked out.'));
return false;
}
if (!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.copy')) {
$sError = PEAR::raiseError(_kt('Document cannot be copied as it is restricted by the workflow.'));
return false;
}
return true;
}
function canBeMoved($oDocument, &$sError) {
if ($oDocument->getImmutable()) {
$sError = PEAR::raiseError(_kt('Document cannot be moved as it is immutable.'));
return false;
}
if ($oDocument->getIsCheckedOut()) {
$sError = PEAR::raiseError(_kt('Document cannot be moved as it is checked out.'));
return false;
}
if (!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.move')) {
$sError = PEAR::raiseError(_kt('Document cannot be moved as it is restricted by the workflow.'));
return false;
}
return true;
}
function canBeDeleted($oDocument, &$sError) {
if($oDocument->getImmutable())
{
$sError = PEAR::raiseError(_kt('Document cannot be deleted as it is immutable.'));
return false;
}
if ($oDocument->getIsCheckedOut()) {
$sError = PEAR::raiseError(_kt('Document cannot be deleted as it is checked out.'));
return false;
}
if(!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.delete')){
$sError = PEAR::raiseError(_kt('Document cannot be deleted as it is restricted by the workflow.'));
return false;
}
return true;
}
function canBeArchived($oDocument, &$sError) {
if ($oDocument->getIsCheckedOut()) {
$sError = PEAR::raiseError(_kt('Document cannot be archived as it is checked out.'));
return false;
}
if(!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.archive')){
$sError = PEAR::raiseError(_kt('Document cannot be archived as it is restricted by the workflow.'));
return false;
}
return true;
}
function copy($oDocument, $oDestinationFolder, $sReason = null, $sDestinationDocName = null, $bulk_action = false) {
// 1. generate a new triad of content, metadata and core objects.
// 2. update the storage path.
//print '--------------------------------- BEFORE';
//print_r($oDocument);
// TODO: this is not optimal. we have get() functions that will do SELECT when we already have the data in arrays
// get the core record to be copied
$sDocumentTable = KTUtil::getTableName('documents');
$sQuery = 'SELECT * FROM ' . $sDocumentTable . ' WHERE id = ?';
$aParams = array($oDocument->getId());
$aCoreRow = DBUtil::getOneResult(array($sQuery, $aParams));
// we unset the id as a new one will be created on insert
unset($aCoreRow['id']);
// we unset immutable since a new document will be created on insert
unset($aCoreRow['immutable']);
// get a copy of the latest metadata version for the copied document
$iOldMetadataId = $aCoreRow['metadata_version_id'];
$sMetadataTable = KTUtil::getTableName('document_metadata_version');
$sQuery = 'SELECT * FROM ' . $sMetadataTable . ' WHERE id = ?';
$aParams = array($iOldMetadataId);
$aMDRow = DBUtil::getOneResult(array($sQuery, $aParams));
// we unset the id as a new one will be created on insert
unset($aMDRow['id']);
// set the name for the document, possibly using name collission
if (empty($sDestinationDocName)){
$aMDRow['name'] = KTDocumentUtil::getUniqueDocumentName($oDestinationFolder, $aMDRow['name']);
}
else {
$aMDRow['name'] = $sDestinationDocName;
}
// get a copy of the latest content version for the copied document
$iOldContentId = $aMDRow['content_version_id'];
$sContentTable = KTUtil::getTableName('document_content_version');
$sQuery = 'SELECT * FROM ' . $sContentTable . ' WHERE id = ?';
$aParams = array($iOldContentId);
$aContentRow = DBUtil::getOneResult(array($sQuery, $aParams));
// we unset the id as a new one will be created on insert
unset($aContentRow['id']);
// set the filename for the document, possibly using name collission
if(empty($sDestinationDocName)) {
$aContentRow['filename'] = KTDocumentUtil::getUniqueFilename($oDestinationFolder, $aContentRow['filename']);
}
else {
$aContentRow['filename'] = $sDestinationDocName;
}
// create the new document record
$aCoreRow['modified'] = date('Y-m-d H:i:s');
$aCoreRow['folder_id'] = $oDestinationFolder->getId(); // new location.
$id = DBUtil::autoInsert($sDocumentTable, $aCoreRow);
if (PEAR::isError($id)) { return $id; }
$iNewDocumentId = $id;
// create the new metadata record
$aMDRow['document_id'] = $iNewDocumentId;
$aMDRow['description'] = $aMDRow['name'];
$id = DBUtil::autoInsert($sMetadataTable, $aMDRow);
if (PEAR::isError($id)) { return $id; }
$iNewMetadataId = $id;
// the document metadata version is still pointing to the original
$aCoreUpdate = array();
$aCoreUpdate['metadata_version_id'] = $iNewMetadataId;
$aCoreUpdate['metadata_version'] = 0;
// create the new content version
$aContentRow['document_id'] = $iNewDocumentId;
$id = DBUtil::autoInsert($sContentTable, $aContentRow);
if (PEAR::isError($id)) { return $id; }
$iNewContentId = $id;
// the metadata content version is still pointing to the original
$aMetadataUpdate = array();
$aMetadataUpdate['content_version_id'] = $iNewContentId;
$aMetadataUpdate['metadata_version'] = 0;
// apply the updates to the document and metadata records
$res = DBUtil::autoUpdate($sDocumentTable, $aCoreUpdate, $iNewDocumentId);
if (PEAR::isError($res)) { return $res; }
$res = DBUtil::autoUpdate($sMetadataTable, $aMetadataUpdate, $iNewMetadataId);
if (PEAR::isError($res)) { return $res; }
// now, we have a semi-sane document object. get it.
$oNewDocument = Document::get($iNewDocumentId);
//print '--------------------------------- AFTER';
//print_r($oDocument);
//print '======';
//print_r($oNewDocument);
// copy the metadata from old to new.
$res = KTDocumentUtil::copyMetadata($oNewDocument, $iOldMetadataId);
if (PEAR::isError($res)) { return $res; }
// Ensure the copied document is not checked out
$oNewDocument->setIsCheckedOut(false);
$oNewDocument->setCheckedOutUserID(-1);
// finally, copy the actual file.
$oStorage =& KTStorageManagerUtil::getSingleton();
$res = $oStorage->copy($oDocument, $oNewDocument);
$oOriginalFolder = Folder::get($oDocument->getFolderId());
$iOriginalFolderPermissionObjectId = $oOriginalFolder->getPermissionObjectId();
$iDocumentPermissionObjectId = $oDocument->getPermissionObjectId();
if ($iDocumentPermissionObjectId === $iOriginalFolderPermissionObjectId) {
$oNewDocument->setPermissionObjectId($oDestinationFolder->getPermissionObjectId());
}
$res = $oNewDocument->update();
if (PEAR::isError($res)) { return $res; }
KTPermissionUtil::updatePermissionLookup($oNewDocument);
if (is_null($sReason)) {
$sReason = '';
}
$oDocumentTransaction = new DocumentTransaction($oDocument, sprintf(_kt("Copied to folder \"%s\". %s"), $oDestinationFolder->getName(), $sReason), 'ktcore.transactions.copy');
$oDocumentTransaction->create();
$oSrcFolder = Folder::get($oDocument->getFolderID());
$oDocumentTransaction = new DocumentTransaction($oNewDocument, sprintf(_kt("Copied from original in folder \"%s\". %s"), $oSrcFolder->getName(), $sReason), 'ktcore.transactions.copy');
$oDocumentTransaction->create();
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('copyDocument', 'postValidate');
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$aInfo = array(
'document' => $oNewDocument,
'old_folder' => $oSrcFolder,
'new_folder' => $oDestinationFolder,
);
$oTrigger->setInfo($aInfo);
$ret = $oTrigger->postValidate();
if (PEAR::isError($ret)) {
return $ret;
}
}
if(!$bulk_action) {
// fire subscription alerts for the copied document
$oSubscriptionEvent = new SubscriptionEvent();
$oFolder = Folder::get($oDocument->getFolderID());
$oSubscriptionEvent->MoveDocument($oDocument, $oDestinationFolder, $oSrcFolder, 'CopiedDocument');
}
return $oNewDocument;
}
function rename($oDocument, $sNewFilename, $oUser) {
$oStorage =& KTStorageManagerUtil::getSingleton();
$oKTConfig = KTConfig::getSingleton();
$updateVersion = $oKTConfig->get('tweaks/incrementVersionOnRename', true);
$iPreviousMetadataVersion = $oDocument->getMetadataVersionId();
$oOldContentVersion = $oDocument->_oDocumentContentVersion;
if($updateVersion) // We only need to start a new content version if the version is in fact changing.
{
$bSuccess = $oDocument->startNewContentVersion($oUser);
if (PEAR::isError($bSuccess)) {
return $bSuccess;
}
KTDocumentUtil::copyMetadata($oDocument, $iPreviousMetadataVersion);
}
$res = $oStorage->renameDocument($oDocument, $oOldContentVersion, $sNewFilename);
if (!$res) {
return PEAR::raiseError(_kt('An error occurred while storing the new file'));
}
$oDocument->setLastModifiedDate(getCurrentDateTime());
$oDocument->setModifiedUserId($oUser->getId());
if($updateVersion) { // Update version number
$oDocument->setMinorVersionNumber($oDocument->getMinorVersionNumber()+1);
}
$oDocument->_oDocumentContentVersion->setFilename($sNewFilename);
$sType = KTMime::getMimeTypeFromFile($sNewFilename);
$iMimeTypeId = KTMime::getMimeTypeID($sType, $sNewFilename);
$oDocument->setMimeTypeId($iMimeTypeId);
$bSuccess = $oDocument->update();
if ($bSuccess !== true) {
if (PEAR::isError($bSuccess)) {
return $bSuccess;
}
return PEAR::raiseError(_kt('An error occurred while storing this document in the database'));
}
// create the document transaction record
$oDocumentTransaction = new DocumentTransaction($oDocument, _kt('Document renamed'), 'ktcore.transactions.update');
$oDocumentTransaction->create();
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('renameDocument', 'postValidate');
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$aInfo = array(
'document' => $oDocument
);
$oTrigger->setInfo($aInfo);
$ret = $oTrigger->postValidate();
if (PEAR::isError($ret)) {
return $ret;
}
}
// fire subscription alerts for the checked in document
$oSubscriptionEvent = new SubscriptionEvent();
$oFolder = Folder::get($oDocument->getFolderID());
$oSubscriptionEvent->ModifyDocument($oDocument, $oFolder);
return true;
}
/*
* Document Move
* Author : Jarrett Jordaan
* Modified : 28/04/09
*
* @params : KTDocumentUtil $oDocument
* KTFolderUtil $oToFolder
* KTUser $oUser
* string $sReason
* boolean $bulk_action
*/
function move($oDocument, $oToFolder, $oUser = null, $sReason = null, $bulk_action = false) {
//make sure we move the symlink, and the document it's linking to
if($oDocument->isSymbolicLink()){
$oDocument->switchToRealCore();
}else{
$oDocument->switchToLinkedCore();
}
$oFolder = $oToFolder; // alias.
$oOriginalFolder = Folder::get($oDocument->getFolderId());
$iOriginalFolderPermissionObjectId = $oOriginalFolder->getPermissionObjectId();
$iDocumentPermissionObjectId = $oDocument->getPermissionObjectId();
if ($iDocumentPermissionObjectId === $iOriginalFolderPermissionObjectId) {
$oDocument->setPermissionObjectId($oFolder->getPermissionObjectId());
}
//put the document in the new folder
$oDocument->setFolderID($oFolder->getId());
$sName = $oDocument->getName();
$sFilename = $oDocument->getFileName();
$oDocument->setFileName(KTDocumentUtil::getUniqueFilename($oToFolder, $sFilename));
$oDocument->setName(KTDocumentUtil::getUniqueDocumentName($oToFolder, $sName));
$res = $oDocument->update();
if (PEAR::isError($res)) {
return $res;
}
//move the document on the file system(not if it's a symlink)
if(!$oDocument->isSymbolicLink()){
$oStorage =& KTStorageManagerUtil::getSingleton();
$res = $oStorage->moveDocument($oDocument, $oFolder, $oOriginalFolder);
if (PEAR::isError($res) || ($res === false)) {
$oDocument->setFolderID($oOriginalFolder->getId());
$res = $oDocument->update();
if (PEAR::isError($res)) {
return $res;
}
return $res; // we failed, bail.
}
}
$sMoveMessage = sprintf(_kt("Moved from %s/%s to %s/%s. %s"),
$oOriginalFolder->getFullPath(),
$oOriginalFolder->getName(),
$oFolder->getFullPath(),
$oFolder->getName(),
$sReason);
// create the document transaction record
$oDocumentTransaction = new DocumentTransaction($oDocument, $sMoveMessage, 'ktcore.transactions.move');
$oDocumentTransaction->create();
$oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
$aTriggers = $oKTTriggerRegistry->getTriggers('moveDocument', 'postValidate');
foreach ($aTriggers as $aTrigger) {
$sTrigger = $aTrigger[0];
$oTrigger = new $sTrigger;
$aInfo = array(
'document' => $oDocument,
'old_folder' => $oOriginalFolder,
'new_folder' => $oFolder,
);
$oTrigger->setInfo($aInfo);
$ret = $oTrigger->postValidate(true);
if (PEAR::isError($ret)) {
return $ret;
}
}
if(!$bulk_action) {
// fire subscription alerts for the moved document
$oSubscriptionEvent = new SubscriptionEvent();
$oSubscriptionEvent->MoveDocument($oDocument, $oFolder, $oOriginalFolder);
}
return KTPermissionUtil::updatePermissionLookup($oDocument);
}
/**
* Delete a selected version of the document.
*/
function deleteVersion($oDocument, $iVersionID, $sReason){
$oDocument =& KTUtil::getObject('Document', $oDocument);
$oVersion =& KTDocumentMetadataVersion::get($iVersionID);
$oStorageManager =& KTStorageManagerUtil::getSingleton();
global $default;
if (empty($sReason)) {
return PEAR::raiseError(_kt('Deletion requires a reason'));
}
if (PEAR::isError($oDocument) || ($oDocument == false)) {
return PEAR::raiseError(_kt('Invalid document object.'));
}
if (PEAR::isError($oVersion) || ($oVersion == false)) {
return PEAR::raiseError(_kt('Invalid document version object.'));
}
$iContentId = $oVersion->getContentVersionId();
$oContentVersion = KTDocumentContentVersion::get($iContentId);
if (PEAR::isError($oContentVersion) || ($oContentVersion == false)) {
return PEAR::raiseError(_kt('Invalid document content version object.'));
}
// Check that the document content is not the same as the current content version
$sDocStoragePath = $oDocument->getStoragePath();
$sVersionStoragePath = $oContentVersion->getStoragePath();
if($sDocStoragePath == $sVersionStoragePath){
return PEAR::raiseError(_kt("Can't delete version: content is the same as the current document content."));
}
DBUtil::startTransaction();
// now delete the document version
$res = $oStorageManager->deleteVersion($oVersion);
if (PEAR::isError($res) || ($res == false)) {
//could not delete the document version from the file system
$default->log->error('Deletion: Filesystem error deleting the metadata version ' .
$oVersion->getMetadataVersion() . ' of the document ' .
$oDocument->getFileName() . ' from folder ' .
Folder::getFolderPath($oDocument->getFolderID()) .
' id=' . $oDocument->getFolderID());
// we use a _real_ transaction here ...
DBUtil::rollback();
return PEAR::raiseError(_kt('There was a problem deleting the document from storage.'));
}
// change status for the metadata version
$oVersion->setStatusId(VERSION_DELETED);
$oVersion->update();
// set the storage path to empty
// $oContentVersion->setStoragePath('');
DBUtil::commit();
}
public static function getDocumentContent($oDocument)
{
global $default;
//get the path to the document on the server
//$docRoot = $default->documentRoot;
$oConfig =& KTConfig::getSingleton();
$docRoot = $oConfig->get('urls/documentRoot');
$path = $docRoot .'/'. $oDocument->getStoragePath();
// Ensure the file exists
if (file_exists($path))
{
// Get the mime type - this is not relevant at the moment...
$mimeId = $oDocument->getMimeTypeID();
$mimetype = KTMime::getMimeTypeName($mimeId);
if ($bIsCheckout && $default->fakeMimetype) {
// note this does not work for "image" types in some browsers
$mimetype = 'application/x-download';
}
$sFileName = $oDocument->getFileName( );
$iFileSize = $oDocument->getFileSize();
} else {
return null;
}
$content = file_get_contents($path);
return $content;
}
}
class KTMetadataValidationError extends PEAR_Error {
function KTMetadataValidationError ($aFailed) {
$this->aFailed = $aFailed;
$message = _kt('Please be sure to enter information for all the Required fields below');
parent::PEAR_Error($message);
}
}
class KTUploadChannel {
var $observers = array();
function &getSingleton() {
if (!KTUtil::arrayGet($GLOBALS, 'KT_UploadChannel')) {
$GLOBALS['KT_UploadChannel'] = new KTUploadChannel;
}
return $GLOBALS['KT_UploadChannel'];
}
function sendMessage(&$msg) {
foreach ($this->observers as $oObserver) {
$oObserver->receiveMessage($msg);
}
}
function addObserver(&$obs) {
array_push($this->observers, $obs);
}
}
class KTUploadGenericMessage {
function KTUploadGenericMessage($sMessage) {
$this->sMessage = $sMessage;
}
function getString() {
return $this->sMessage;
}
}
class KTUploadNewFile {
function KTUploadNewFile($sFilename) {
$this->sFilename = $sFilename;
}
function getString() {
return $this->sFilename;
}
}
?>