diff --git a/lib/api/ktcmis/ktcmis.inc.php b/lib/api/ktcmis/ktcmis.inc.php index 2d9dfc7..0f564bb 100644 --- a/lib/api/ktcmis/ktcmis.inc.php +++ b/lib/api/ktcmis/ktcmis.inc.php @@ -56,6 +56,7 @@ require_once(CMIS_DIR . '/exceptions/PermissionDeniedException.inc.php'); require_once(CMIS_DIR . '/services/CMISRepositoryService.inc.php'); require_once(CMIS_DIR . '/services/CMISNavigationService.inc.php'); require_once(CMIS_DIR . '/services/CMISObjectService.inc.php'); +require_once(CMIS_DIR . '/services/CMISVersioningService.inc.php'); require_once(CMIS_DIR . '/util/CMISUtil.inc.php'); /** @@ -73,7 +74,6 @@ class KTCMISBase { { // TODO confirm KTAPI instance active??? shouldn't really be responsibility of this code if (is_null($ktapi) && (!is_null($username) && !is_null($password))) { -// echo ":WGHWTWGWGHW"; $this->startSession($username, $password); } else { @@ -87,18 +87,15 @@ class KTCMISBase { // NOTE left in to allow transport protocol to delegate auth to this level, but not actually used in any code at present public function startSession($username, $password) { -// echo $username." :: ".$password."
"; // attempt to recover session if one exists if (!is_null(self::$session) && !PEAR::isError(self::$session)) { -// echo "ATTEMPT TO RECOVER SESSION: ".print_r(self::$session, true)."
\n"; self::$session =& self::$ktapi->get_active_session(self::$session->get_sessionid()); } // start new session if no existing session or problem getting existing session (expired, etc...) if (is_null(self::$session) || PEAR::isError(self::$session)) { -// echo "ATTEMPT TO START NEW SESSION
\n"; self::$ktapi = new KTAPI(); self::$session =& self::$ktapi->start_session($username, $password); } @@ -109,7 +106,6 @@ class KTCMISBase { throw new PermissionDeniedException('You must be authenticated to perform this action'); } -// print_r(self::$ktapi); return self::$session; } @@ -594,6 +590,54 @@ class KTObjectService extends KTCMISBase { 'results' => $objectId ); } + + /** + * Deletes an object from the repository + * + * @param string $repositoryId + * @param string $objectId + * @param string $changeToken [optional] + * @return array + */ + // NOTE Invoking this service method on an object SHALL not delete the entire version series for a Document Object. + // To delete an entire version series, use the deleteAllVersions() service + function deleteObject($repositoryId, $objectId, $changeToken = null) + { + try { + $result = $this->ObjectService->deleteObject($repositoryId, $objectId, $changeToken); + } + catch (Exception $e) + { + return array( + "status_code" => 1, + "message" => $e->getMessage() + ); + } + + return array( + 'status_code' => 0, + 'results' => $objectId + ); + } + + public function deleteTree($repositoryId, $objectId, $changeToken = null, $unfileNonfolderObject = 'delete', $continueOnFailure = false) + { + try { + $result = $this->ObjectService->deleteTree($repositoryId, $objectId, $changeToken, $unfileNonfolderObject, $continueOnFailure); + } + catch (Exception $e) + { + return array( + "status_code" => 1, + "message" => $e->getMessage() + ); + } + + return array( + 'status_code' => 0, + 'results' => $objectId + ); + } /** * Sets the content stream data for an existing document @@ -614,7 +658,7 @@ class KTObjectService extends KTCMISBase { function setContentStream($repositoryId, $documentId, $overwriteFlag, $contentStream, $changeToken = null) { try { - $objectId = $this->ObjectService->setContentStream($repositoryId, $documentId, $overwriteFlag, $contentStream, $changeToken); + $documentId = $this->ObjectService->setContentStream($repositoryId, $documentId, $overwriteFlag, $contentStream, $changeToken); } catch (Exception $e) { @@ -632,4 +676,60 @@ class KTObjectService extends KTCMISBase { } +/** + * Handles requests for and actions on versionable objects + */ +class KTVersioningService extends KTCMISBase { + + protected $VersioningService; + + public function __construct(&$ktapi = null, $username = null, $password = null) + { + parent::__construct($ktapi, $username, $password); + // instantiate underlying CMIS service + $this->VersioningService = new CMISVersioningService(); + $this->setInterface(); + } + + public function startSession($username, $password) + { + parent::startSession($username, $password); + $this->setInterface(); + return self::$session; + } + + public function setInterface(&$ktapi = null) + { + parent::setInterface($ktapi); + $this->VersioningService->setInterface(self::$ktapi); + } + + /** + * Deletes all Document Objects in the specified Version Series, including the Private Working Copy + * + * @param string $repositoryId + * @param string $versionSeriesId + * @return boolean true if successful + */ + public function deleteAllVersions($repositoryId, $versionSeriesId) + { + try { + $result = $this->VersioningService->deleteAllVersions($repositoryId, $versionSeriesId); + } + catch (Exception $e) + { + return array( + "status_code" => 1, + "message" => $e->getMessage() + ); + } + + return array( + 'status_code' => 0, + 'results' => $result + ); + } + +} + ?> diff --git a/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php b/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php index 90aec9e..557afc4 100644 --- a/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php +++ b/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php @@ -144,8 +144,9 @@ class CMISDocumentObject extends CMISBaseObject { // NOTE see ktapi::is_latest_version $this->_setPropertyInternal('IsLatestMajorVersion', true); $this->_setPropertyInternal('VersionLabel', $objectProperties['version']); - // TODO what determines this, do we have anything? - $this->_setPropertyInternal('VersionSeriesId', null); + // VersionSeriesId should be the id of the latest version + // NOTE this may change in the future but is easiest for the current implementation + $this->_setPropertyInternal('VersionSeriesId', $objectProperties['version']); if ($objectProperties['checked_out_by'] != 'n/a') { $checkedOut = true; diff --git a/lib/api/ktcmis/services/CMISNavigationService.inc.php b/lib/api/ktcmis/services/CMISNavigationService.inc.php index eb4393a..c8e692f 100644 --- a/lib/api/ktcmis/services/CMISNavigationService.inc.php +++ b/lib/api/ktcmis/services/CMISNavigationService.inc.php @@ -48,7 +48,7 @@ class CMISNavigationService { protected $ktapi; /** - * Sets the interface to be used to query the repository + * Sets the interface to be used to interact with the repository * * @param object $ktapi The KnowledgeTree API interface */ diff --git a/lib/api/ktcmis/services/CMISObjectService.inc.php b/lib/api/ktcmis/services/CMISObjectService.inc.php index 372a9c9..14a6b60 100644 --- a/lib/api/ktcmis/services/CMISObjectService.inc.php +++ b/lib/api/ktcmis/services/CMISObjectService.inc.php @@ -21,11 +21,11 @@ class CMISObjectService { protected $ktapi; /** - * Sets the interface to be used to query the repository + * Sets the interface to be used to interact with the repository * * @param object $ktapi The KnowledgeTree API interface */ - function setInterface(&$ktapi) + public function setInterface(&$ktapi) { $this->ktapi = $ktapi; } @@ -43,8 +43,8 @@ class CMISObjectService { */ // TODO optional parameter support // TODO FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid - function getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships, - $returnVersion = false, $filter = '') + public function getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships, + $returnVersion = false, $filter = '') { $repository = new CMISRepository($repositoryId); @@ -87,8 +87,8 @@ class CMISObjectService { // TODO throw ConstraintViolationException if: // value of any of the properties violates the min/max/required/length constraints // specified in the property definition in the Object-Type. - function createDocument($repositoryId, $typeId, $properties, $folderId = null, - $contentStream = null, $versioningState = null) + public function createDocument($repositoryId, $typeId, $properties, $folderId = null, + $contentStream = null, $versioningState = null) { $objectId = null; @@ -344,7 +344,7 @@ class CMISObjectService { // TODO throw ConstraintViolationException if: // value of any of the properties violates the min/max/required/length constraints // specified in the property definition in the Object-Type. - function createFolder($repositoryId, $typeId, $properties, $folderId) + public function createFolder($repositoryId, $typeId, $properties, $folderId) { $objectId = null; @@ -399,6 +399,148 @@ class CMISObjectService { return $objectId; } + + /** + * Deletes an object from the repository + * + * @param string $repositoryId + * @param string $objectId + * @param string $changeToken [optional] + * @return boolean true on success (exception should be thrown otherwise) + */ + // NOTE Invoking this service method on an object SHALL not delete the entire version series for a Document Object. + // To delete an entire version series, use the deleteAllVersions() service + public function deleteObject($repositoryId, $objectId, $changeToken = null) + { + // determine object type and internal id + $objectId = CMISUtil::decodeObjectId($objectId, $typeId); + + // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). + $exists = true; + if ($typeId == 'Folder') { + $object = $this->ktapi->get_folder_by_id($objectId); + if (PEAR::isError($object)) { + $exists = false; + } + } + else if ($typeId == 'Document') { + $object = $this->ktapi->get_document_by_id($objectId); + if (PEAR::isError($object)) { + $exists = false; + } + } + else { + $exists = false; + } + + if (!$exists) { + throw new updateConflictException('Unable to delete the object as it cannot be found.'); + } + + // throw ConstraintViolationException if method is invoked on a Folder object that contains one or more objects + if ($typeId == 'Folder') + { + $folderContent = $object->get_listing(); + if (!PEAR::isError($folderContent)) + { + if (count($folderContent) > 0) { + throw new ConstraintViolationException('Unable to delete a folder with content. Use deleteTree instead.'); + } + } + + // now try the delete and throw an exception if there is an error + // TODO add a default reason + // TODO add the electronic signature capability + $result = $this->ktapi->delete_folder($objectId, $reason, $sig_username, $sig_password); + } + else if ($typeId == 'Document') + { + // since we do not allow deleting of only the latest version we must throw an exception when this function is called on any document + // which has more than one version. Okay to delete if there is only the one version. + $versions = $object->get_version_history(); + if (count($versions) > 1) + { + // NOTE possibly may want to just throw a RuntimeException rather than this CMIS specific exception. + throw new ConstraintViolationException('This function may not be used to delete an object which has multiple versions. ' + . 'Since the repository does not allow deleting of only the latest version, nothing can be deleted.'); + } + + // do not allow deletion of a checked out document - this is actually handled by the ktapi code, + // but is possibly slightly more efficient to check before trying to delete + if ($object->is_checked_out()) { + throw new RuntimeException('The object cannot be deleted as it is currently checked out'); + } + + // now try the delete and throw an exception if there is an error + // TODO add a default reason + // TODO add the electronic signature capability + $auth_sig = true; + $result = $this->ktapi->delete_document($objectId, $reason, $auth_sig, $sig_username, $sig_password); + } + + // if there was an error performing the delete, throw exception + if ($result['status_code'] == 1) { + throw new RuntimeException('There was an error deleting the object: ' . $result['message']); + } + + return true; + } + + /** + * Deletes an entire tree including all subfolders and other filed objects + * + * @param string $repositoryId + * @param string $objectId + * @param string $changeToken [optional] + * @param boolean $unfileNonfolderObject [optional] - note that since KnowledgeTree does not allow unfiling this will be ignored + * @param boolean $continueOnFailure [optional] - note that since KnowledgeTree does not allow continue on failure this will be ignored + * @return array $failedToDelete A list of identifiers of objects in the folder tree that were not deleted. + */ + // NOTE • A Repository MAY attempt to delete child- and descendant-objects of the specified folder in any order. + // • Any child- or descendant-object that the Repository cannot delete SHALL persist in a valid state in the CMIS domain model. + // • This is not transactional. + // • However, if DeleteSingleFiled is chosen and some objects fail to delete, then single-filed objects are either deleted or kept, + // never just unfiled. This is so that a user can call this command again to recover from the error by using the same tree. + public function deleteTree($repositoryId, $objectId, $changeToken = null, $unfileNonfolderObject = 'delete', $continueOnFailure = false) + { + // NOTE since we do not currently allow partial deletes this will always be empty + // (unless there is a failure at the requested folder level - what do we do then? exception or array of all objects?) + $failedToDelete = array(); + + // determine object type and internal id + $objectId = CMISUtil::decodeObjectId($objectId, $typeId); + + // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). + $exists = true; + if ($typeId == 'Folder') { + $object = $this->ktapi->get_folder_by_id($objectId); + if (PEAR::isError($object)) { + $exists = false; + } + } + // if not of type folder then we have a general problem, throw exception + else { + throw new RuntimeException('Cannot call deleteTree on a non-folder object.'); + } + + if (!$exists) { + throw new updateConflictException('Unable to delete the object as it cannot be found.'); + } + + // attempt to delete tree, throw RuntimeException if failed + // TODO add a default reason + // TODO add the electronic signature capability + $result = $this->ktapi->delete_folder($objectId, $reason, $sig_username, $sig_password); + // if there was an error performing the delete, throw exception + // TODO list of objects which failed in $failedToDelete array; + // since we do not delete the folder or any contents if anything cannot be deleted, this will contain the entire tree listing + // NOTE once we do this we will need to deal with it externally as well, since we can no longer just catch an exception. + if ($result['status_code'] == 1) { + throw new RuntimeException('There was an error deleting the object: ' . $result['message']); + } + + return $failedToDelete; + } // NOTE this function is presently incomplete and untested. Completion deferred to implementation of Checkout/Checkin // functionality @@ -428,7 +570,7 @@ class CMISObjectService { // updateConflictException: The operation is attempting to update an object that is no longer current // (as determined by the repository). // versioningException: The repository MAY throw this exception if the object is a non-current Document Version. - function setContentStream($repositoryId, $documentId, $overwriteFlag, $contentStream, $changeToken = null) + public function setContentStream($repositoryId, $documentId, $overwriteFlag, $contentStream, $changeToken = null) { // if no document id was supplied, we are going to create the underlying physical document // NOTE while it might have been nice to keep this out of here, KTAPI has no method for creating a document without diff --git a/lib/api/ktcmis/services/CMISVersioningService.inc.php b/lib/api/ktcmis/services/CMISVersioningService.inc.php new file mode 100644 index 0000000..6ced85b --- /dev/null +++ b/lib/api/ktcmis/services/CMISVersioningService.inc.php @@ -0,0 +1,74 @@ +ktapi = $ktapi; + } + + /** + * Deletes all Document Objects in the specified Version Series, including the Private Working Copy + * + * @param string $repositoryId + * @param string $versionSeriesId + * @return boolean true if successful + */ + // NOTE For KnowledgeTree the $versionSeriesId should be the latest version, if not it will be taken as implied. + // Should we decide to implement the ability to delete individual versions, + // then an exception may be thrown under certain circumstances (to be determined) + // NOTE I am not really sure how this is going to be handled by CMIS clients. + // Testing with CMISSpaces we have it sending the actual document id, not a version series id. + // This may be due to the data sent back from our code, or it may just be how CMISSpaces does it. + // There is a note in their source code about this. + // Meantime we will try based on document id and adjust as needed later + public function deleteAllVersions($repositoryId, $versionSeriesId) + { + // attempt to delete based on versionSeriesId as document/object id + // determine object type and internal id + $objectId = CMISUtil::decodeObjectId($versionSeriesId, $typeId); + + // if not a versionable object, throw exception + // NOTE that we are assuming only documents are versionable at the moment + if ($typeId != 'Document') { + throw new RuntimeException('The object type is not versionable and cannot be deleted using deleteAllVersions.'); + } + + // try to delete + // TODO add a default reason + // TODO add the electronic signature capability + $auth_sig = true; + $result = $this->ktapi->delete_document($objectId, $reason, $auth_sig, $sig_username, $sig_password); + + // if there was an error performing the delete, throw exception + if ($result['status_code'] == 1) { + throw new RuntimeException('There was an error deleting the object: ' . $result['message']); + } + + return true; + } + +} + +?> diff --git a/webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php b/webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php index 5c6a965..c1d325b 100644 --- a/webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php +++ b/webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php @@ -33,18 +33,20 @@ When POSTing an Atom Document, the atom fields take precedence over the CMIS pro include_once CMIS_ATOM_LIB_FOLDER . 'RepositoryService.inc.php'; include_once CMIS_ATOM_LIB_FOLDER . 'NavigationService.inc.php'; include_once CMIS_ATOM_LIB_FOLDER . 'ObjectService.inc.php'; +include_once CMIS_ATOM_LIB_FOLDER . 'VersioningService.inc.php'; include_once 'KT_cmis_atom_service_helper.inc.php'; // TODO auth failed response requires WWW-Authenticate: Basic realm="KnowledgeTree DMS" header /** * AtomPub Service: folder - * - * Returns children, descendants (up to arbitrary depth) or detail for a particular folder - * */ class KT_cmis_atom_service_folder extends KT_atom_service { + /** + * Deals with GET actions for folders. + * This includes children and tree/descendant listings as well as individual folder retrieval + */ public function GET_action() { $RepositoryService = new RepositoryService(); @@ -88,6 +90,10 @@ class KT_cmis_atom_service_folder extends KT_atom_service { $this->responseFeed = $feed; } + /** + * Deals with folder service POST actions. + * This includes creation of both folders and documents. + */ public function POST_action() { $RepositoryService = new RepositoryService(); @@ -131,23 +137,50 @@ class KT_cmis_atom_service_folder extends KT_atom_service { if ($typeId != 'Unknown') { - /*$f = fopen('c:\kt-stuff\here.txt', 'w'); - fwrite($f, 'fgfgfgfg'); - fclose($f);*/ $this->setStatus(self::STATUS_CREATED); $feed = KT_cmis_atom_service_helper::getObjectFeed($ObjectService, $repositoryId, $newObjectId, 'POST'); } - else - { - /*$f = fopen('c:\kt-stuff\failed.txt', 'w'); - fwrite($f, 'fgfgfgfg'); - fclose($f);*/ + else { $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $newObjectId['message']); } //Expose the responseFeed $this->responseFeed = $feed; } + + /** + * Deals with DELETE actions for folders. + * This includes deleting a single folder (with no content) and deleting an entire folder tree + * + * @return 204 on success, 500 on error + */ + public function DELETE_action() + { + // NOTE due to the way KnowledgeTree works with folders this is always going to call deleteTree. + // we COULD call deleteObject but when we delete a folder we expect to be trying to delete + // the folder and all content. + + $RepositoryService = new RepositoryService(); + $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt()); + + $repositories = $RepositoryService->getRepositories(); + $repositoryId = $repositories[0]['repositoryId']; + + // attempt delete + $result = $ObjectService->deleteTree($repositoryId, $this->params[0]); + + // error? + if (PEAR::isError($result)) + { + $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $result->getMessage()); + //Expose the responseFeed + $this->responseFeed = $feed; + return null; + } + + // success + $this->setStatus(self::STATUS_NO_CONTENT); + } /** * Retrieves children/descendants of the specified folder @@ -217,9 +250,6 @@ class KT_cmis_atom_service_folder extends KT_atom_service { /** * AtomPub Service: types - * - * Returns a list of supported object types - * */ class KT_cmis_atom_service_types extends KT_atom_service { @@ -241,9 +271,6 @@ class KT_cmis_atom_service_types extends KT_atom_service { /** * AtomPub Service: type - * - * Returns the type defintion for the selected type - * */ class KT_cmis_atom_service_type extends KT_atom_service { @@ -318,13 +345,13 @@ class KT_cmis_atom_service_type extends KT_atom_service { /** * AtomPub Service: checkedout - * - * Returns a list of checked out documents for the logged in user - * */ // NOTE this is always an empty document, underlying API code still to be implemented class KT_cmis_atom_service_checkedout extends KT_atom_service { - + + /** + * Deals with GET actions for checkedout documents. + */ public function GET_action() { $RepositoryService = new RepositoryService(); @@ -350,7 +377,6 @@ class KT_cmis_atom_service_checkedout extends KT_atom_service { // TODO get actual most recent update time, only use current if no other available $feed->appendChild($feed->newElement('updated', KT_cmis_atom_service_helper::formatDatestamp())); -//'urn:uuid:checkedout' foreach($checkedout as $document) { $entry = $feed->newEntry(); @@ -380,12 +406,13 @@ class KT_cmis_atom_service_checkedout extends KT_atom_service { /** * AtomPub Service: document - * - * Returns detail on a particular document - * */ class KT_cmis_atom_service_document extends KT_atom_service { + /** + * Deals with GET actions for documents. + * This includes individual document retrieval + */ public function GET_action() { $RepositoryService = new RepositoryService(); @@ -400,16 +427,48 @@ class KT_cmis_atom_service_document extends KT_atom_service { $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI); $feed->newField('title', $cmisEntry['properties']['ObjectTypeId']['value'], $feed); - $feed->newField('id', 'urn:uuid:' . $cmisEntry['properties']['ObjectId']['value'], $feed); ; + $feed->newField('id', 'urn:uuid:' . $cmisEntry['properties']['ObjectId']['value'], $feed); KT_cmis_atom_service_helper::createObjectEntry($feed, $cmisEntry, $cmisEntry['properties']['ParentId']['value']); - // false - //Expose the responseFeed $this->responseFeed=$feed; } + /** + * Deals with DELETE actions for documents. + * This includes deletion of a specific version of a document (latest version) via deleteObject + * as well as deleteAllVersions + * + * @return 204 on success, 500 on error + */ + public function DELETE_action() + { + // NOTE due to the way KnowledgeTree works with documents this is always going to call deleteAllVersions. + // we do not have support for deleting only specific versions (this may be added in the future.) + + $RepositoryService = new RepositoryService(); + $VersioningService = new VersioningService(KT_cmis_atom_service_helper::getKt()); + + $repositories = $RepositoryService->getRepositories(); + $repositoryId = $repositories[0]['repositoryId']; + + // attempt delete + $result = $VersioningService->deleteAllVersions($repositoryId, $this->params[0]); + + // error? + if (PEAR::isError($result)) + { + $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $result->getMessage()); + //Expose the responseFeed + $this->responseFeed = $feed; + return null; + } + + // success + $this->setStatus(self::STATUS_NO_CONTENT); + } + } ?> \ No newline at end of file diff --git a/webservice/classes/atompub/KT_atom_service.inc.php b/webservice/classes/atompub/KT_atom_service.inc.php index 4a3c410..832a1b2 100644 --- a/webservice/classes/atompub/KT_atom_service.inc.php +++ b/webservice/classes/atompub/KT_atom_service.inc.php @@ -2,6 +2,7 @@ class KT_atom_service{ const STATUS_OK = '200 OK'; const STATUS_NOT_FOUND = '204 No Content'; + const STATUS_NO_CONTENT = '204 No Content'; const STATUS_NOT_ALLOWED = '204 Not Allowed'; const STATUS_CREATED = '201 Created'; const STATUS_UPDATED = '200 Updated'; diff --git a/webservice/classes/atompub/cmis/ObjectService.inc.php b/webservice/classes/atompub/cmis/ObjectService.inc.php index 90171e6..897736a 100644 --- a/webservice/classes/atompub/cmis/ObjectService.inc.php +++ b/webservice/classes/atompub/cmis/ObjectService.inc.php @@ -26,8 +26,7 @@ class ObjectService extends KTObjectService { $result = parent::getProperties($repositoryId, $objectId, $includeAllowableActions, $returnVersion, $filter); - if ($result['status_code'] == 0) - { + if ($result['status_code'] == 0) { return $result['results']; } } @@ -45,12 +44,10 @@ class ObjectService extends KTObjectService { { $result = parent::createFolder($repositoryId, $typeId, $properties, $folderId); - if ($result['status_code'] == 0) - { + if ($result['status_code'] == 0) { return $result['results']; } - else - { + else { return $result; } } @@ -75,15 +72,57 @@ class ObjectService extends KTObjectService { { $result = parent::createDocument($repositoryId, $typeId, $properties, $folderId, $contentStream, $versioningState); - if ($result['status_code'] == 0) - { + if ($result['status_code'] == 0) { return $result['results']; } - else - { + else { return $result; } } + + /** + * Deletes an object from the repository + * + * @param string $repositoryId + * @param string $objectId + * @param string $changeToken [optional] + * @return boolean true on success, false on failure + */ + // NOTE Invoking this service method on an object SHALL not delete the entire version series for a Document Object. + // To delete an entire version series, use the deleteAllVersions() service + function deleteObject($repositoryId, $objectId, $changeToken = null) + { + $result = parent::deleteObject($repositoryId, $objectId, $changeToken); + + if ($result['status_code'] == 0) { + return $result['results']; + } + else { + return new PEAR_Error($result['message']); + } + } + + /** + * Deletes an entire tree including all subfolders and other filed objects + * + * @param string $repositoryId + * @param string $objectId + * @param string $changeToken [optional] + * @param boolean $unfileNonfolderObject [optional] - note that since KnowledgeTree does not allow unfiling this will be ignored + * @param boolean $continueOnFailure [optional] - note that since KnowledgeTree does not allow continue on failure this will be ignored + * @return array $failedToDelete A list of identifiers of objects in the folder tree that were not deleted. + */ + public function deleteTree($repositoryId, $objectId, $changeToken = null, $unfileNonfolderObject = 'delete', $continueOnFailure = false) + { + $result = parent::deleteTree($repositoryId, $objectId, $changeToken, $unfileNonfolderObject, $continueOnFailure); + + if ($result['status_code'] == 0) { + return $result['results']; + } + else { + return new PEAR_Error($result['message']); + } + } } diff --git a/webservice/classes/atompub/cmis/VersioningService.inc.php b/webservice/classes/atompub/cmis/VersioningService.inc.php new file mode 100644 index 0000000..6a2c3aa --- /dev/null +++ b/webservice/classes/atompub/cmis/VersioningService.inc.php @@ -0,0 +1,33 @@ +