diff --git a/lib/api/ktcmis/ktNavigationService.inc.php b/lib/api/ktcmis/ktNavigationService.inc.php index fb9bfde..5ddb97c 100644 --- a/lib/api/ktcmis/ktNavigationService.inc.php +++ b/lib/api/ktcmis/ktNavigationService.inc.php @@ -80,19 +80,20 @@ class KTNavigationService extends KTCMISBase { * * @param string $repositoryId * @param string $folderId - * @param boolean $includeAllowableActions - * @param boolean $includeRelationships - * @param string $typeID * @param int $depth * @param string $filter + * @param boolean $includeRelationships + * @param string $renditionFilter + * @param boolean $includeAllowableAc * @return array $descendants */ - public function getDescendants($repositoryId, $folderId, $includeAllowableActions, $includeRelationships, - $depth = 1, $typeID = 'Any', $filter = '') + public function getDescendants($repositoryId, $folderId, $depth = 2, $filter = '', $includeRelationships = false, $renditionFilter = '', + $includeAllowableActions = false, $includePathSegment = false) { // TODO optional parameters - $descendantsResult = $this->NavigationService->getDescendants($repositoryId, $folderId, $includeAllowableActions, - $includeRelationships, $depth); + $descendantsResult = $this->NavigationService->getDescendants($repositoryId, $folderId, $depth, $filter, + $includeRelationships = false, $renditionFilter = '', + $includeAllowableActions = false, $includePathSegment = false); if (PEAR::isError($descendantsResult)) { @@ -101,11 +102,11 @@ class KTNavigationService extends KTCMISBase { "message" => "Failed getting descendants for folder" ); } - + // format for webservices consumption // NOTE this will almost definitely be changing in the future, this is just to get something working - $descendants = CMISUtil::decodeObjectHierarchy($descendantsResult, 'child'); - + $descendants = CMISUtil::decodeObjectHierarchy($descendantsResult, 'children'); + return array ( "status_code" => 0, "results" => $descendants @@ -126,7 +127,7 @@ class KTNavigationService extends KTCMISBase { * @return array $descendants */ public function getChildren($repositoryId, $folderId, $includeAllowableActions, $includeRelationships, - $typeID = 'Any', $filter = '', $maxItems = 0, $skipCount = 0) + $typeID = 'Any', $filter = '', $maxItems = 0, $skipCount = 0) { // TODO paging // TODO optional parameters @@ -140,7 +141,7 @@ class KTNavigationService extends KTCMISBase { ); } - $children = CMISUtil::decodeObjectHierarchy($childrenResult, 'child'); + $children = CMISUtil::decodeObjectHierarchy($childrenResult, 'children'); return array( "status_code" => 0, @@ -180,7 +181,7 @@ class KTNavigationService extends KTCMISBase { ); } - $ancestry = CMISUtil::decodeObjectHierarchy($ancestryResult, 'child'); + $ancestry = CMISUtil::decodeObjectHierarchy($ancestryResult, 'children'); return array( "status_code" => 0, @@ -211,7 +212,7 @@ class KTNavigationService extends KTCMISBase { ); } - $ancestry = CMISUtil::decodeObjectHierarchy($ancestryResult, 'child'); + $ancestry = CMISUtil::decodeObjectHierarchy($ancestryResult, 'children'); return array( "status_code" => 0, diff --git a/lib/api/ktcmis/ktObjectService.inc.php b/lib/api/ktcmis/ktObjectService.inc.php index 4b4abd9..e3e293b 100644 --- a/lib/api/ktcmis/ktObjectService.inc.php +++ b/lib/api/ktcmis/ktObjectService.inc.php @@ -80,17 +80,13 @@ class KTObjectService extends KTCMISBase { * * @param string $repositoryId * @param string $objectId - * @param boolean $includeAllowableActions - * @param boolean $includeRelationships - * @param string $returnVersion * @param string $filter * @return properties[] */ - public function getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships, - $returnVersion = false, $filter = '') + public function getProperties($repositoryId, $objectId, $filter = '') { try { - $propertyCollection = $this->ObjectService->getProperties($repositoryId, $objectId, $includeAllowableActions, + $properties = $this->ObjectService->getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships); } catch (Exception $e) @@ -101,8 +97,6 @@ class KTObjectService extends KTCMISBase { ); } - $properties = CMISUtil::createObjectPropertiesEntry($propertyCollection); - return array( "status_code" => 0, "results" => $properties @@ -236,15 +230,13 @@ class KTObjectService extends KTCMISBase { * * @param string $repositoryId * @param string $objectId - * @param string $changeToken [optional] + * @param string $allVersions [optional] If true, delete all versions * @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 - public function deleteObject($repositoryId, $objectId, $changeToken = null) + public function deleteObject($repositoryId, $objectId, $allVersions = true) { try { - $this->ObjectService->deleteObject($repositoryId, $objectId, $changeToken); + $this->ObjectService->deleteObject($repositoryId, $objectId, $allVersions); } catch (Exception $e) { diff --git a/lib/api/ktcmis/ktVersioningService.inc.php b/lib/api/ktcmis/ktVersioningService.inc.php index 0349f77..0d940a3 100644 --- a/lib/api/ktcmis/ktVersioningService.inc.php +++ b/lib/api/ktcmis/ktVersioningService.inc.php @@ -81,32 +81,6 @@ class KTVersioningService extends KTCMISBase { } /** - * 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 - ); - } - - /** * Checks out a document and creates the PWC (Private Working Copy) which will represent the checked out document * * @param string $repositoryId diff --git a/lib/api/ktcmis/services/CMISNavigationService.inc.php b/lib/api/ktcmis/services/CMISNavigationService.inc.php index 959bc63..5a85f21 100644 --- a/lib/api/ktcmis/services/CMISNavigationService.inc.php +++ b/lib/api/ktcmis/services/CMISNavigationService.inc.php @@ -62,85 +62,108 @@ class CMISNavigationService { } /** - * Get descendents of the specified folder, up to the depth indicated + * Get direct children of the specified folder * * @param string $repositoryId * @param string $folderId * @param boolean $includeAllowableActions * @param boolean $includeRelationships * @param string $typeId - * @param int $depth * @param string $filter + * @param int $maxItems + * @param int $skipCount * @return array $descendants + * MUST include (unless not requested) for each object: + * array $properties + * array $relationships + * array $renditions + * $allowableActions + * string $pathSegment + * boolean $hasMoreItems + * int $numItems [optional] */ - - // NOTE This method does NOT support paging as defined in the paging section // NOTE If the Repository supports the optional “VersionSpecificFiling��? capability, // then the repository SHALL return the document versions filed in the specified folder or its descendant folders. // Otherwise, the latest version of the documents SHALL be returned. // TODO FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid - function getDescendants($repositoryId, $folderId, $includeAllowableActions, $includeRelationships, - $depth = 1, $typeId = 'Any', $filter = '') + function getChildren($repositoryId, $folderId, $includeAllowableActions = null, $includeRelationships = null, + $typeId = 'Any', $filter = '', $maxItems = 0, $skipCount = 0, $orderBy = '', $renditionFilter = null, + $includePathSegment = false) { + // TODO paging // TODO optional parameters - $descendants = array(); + $children = array(); $repository = new CMISRepository($repositoryId); - // if this is not a folder, cannot get descendants + // if this is not a folder, cannot get children $folderId = CMISUtil::decodeObjectId($folderId, $type); - - if ($type != 'Folder') - { - return $descendants; + + if ($type != 'Folder') { + throw new invalidArgumentException('The specified object is not a folder'); } $folder = $this->ktapi->get_folder_by_id($folderId); - $descendants = $folder->get_listing($depth); + $children = $folder->get_listing(); - // parse ktapi descendants result into a list of CMIS objects - $descendants = CMISUtil::createChildObjectHierarchy($descendants, $repository->getRepositoryURI, $this->ktapi); + $children = CMISUtil::createChildObjectHierarchy($children, $repository->getRepositoryURI, $this->ktapi); - return $descendants; + return $children; } /** - * Get direct children of the specified folder + * Get descendents of the specified folder, up to the depth indicated * * @param string $repositoryId * @param string $folderId - * @param boolean $includeAllowableActions - * @param boolean $includeRelationships - * @param string $typeId + * @param int $depth * @param string $filter - * @param int $maxItems - * @param int $skipCount + * @param boolean $includeRelationships + * @param string $renditionFilter + * @param boolean $includeAllowableActions + * @param boolean $includePathSegment * @return array $descendants + * MUST include (unless not requested) for each object: + * array $properties + * array $relationships + * array $renditions + * $allowableActions + * string $pathSegment */ + + // NOTE This method does NOT support paging as defined in the paging section // NOTE If the Repository supports the optional “VersionSpecificFiling��? capability, // then the repository SHALL return the document versions filed in the specified folder or its descendant folders. // Otherwise, the latest version of the documents SHALL be returned. + // NOTE If the Repository supports the optional capability capabilityMutlifiling and the same document is encountered + // multiple times in the hierarchy, then the repository MUST return that document each time is encountered. + // NOTE The default value for the $depth parameter is repository specific and SHOULD be at least 2 or -1 + // Chosen 2 as the underlying code currently has no concept of digging all the way down // TODO FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid - function getChildren($repositoryId, $folderId, $includeAllowableActions = null, $includeRelationships = null, - $typeId = 'Any', $filter = '', $maxItems = 0, $skipCount = 0, $orderBy = '', $renditionFilter = null, $includePathSegment = false) + function getDescendants($repositoryId, $folderId, $depth = 2, $filter = '', $includeRelationships = false, $renditionFilter = '', + $includeAllowableActions = false, $includePathSegment = false) { - // TODO paging - // TODO optional parameters - $children = array(); - $repository = new CMISRepository($repositoryId); + if ($depth == 0) { + throw new InvalidArgumentException('Invalid depth argument supplied'); + } - // if this is not a folder, cannot get children + // if this is not a folder, cannot get descendants $folderId = CMISUtil::decodeObjectId($folderId, $type); - + if ($type != 'Folder') { - throw new invalidArgumentException('The specified object is not a folder'); + throw new InvalidArgumentException('The supplied object is not a folder, unable to return descendants'); } + + // TODO optional parameters + $descendants = array(); + $repository = new CMISRepository($repositoryId); $folder = $this->ktapi->get_folder_by_id($folderId); - $children = $folder->get_listing(); + $descendants = $folder->get_listing($depth); - $children = CMISUtil::createChildObjectHierarchy($children, $repository->getRepositoryURI, $this->ktapi); + // parse ktapi descendants result into a list of CMIS objects + $descendants = CMISUtil::createChildObjectHierarchy($descendants, $repository->getRepositoryURI, $this->ktapi); - return $children; + return $descendants; } /** diff --git a/lib/api/ktcmis/services/CMISObjectService.inc.php b/lib/api/ktcmis/services/CMISObjectService.inc.php index 4c54fe6..34eab81 100644 --- a/lib/api/ktcmis/services/CMISObjectService.inc.php +++ b/lib/api/ktcmis/services/CMISObjectService.inc.php @@ -357,22 +357,15 @@ class CMISObjectService { * * @param string $repositoryId * @param string $objectId - * @param boolean $includeAllowableActions - * @param boolean $includeRelationships - * @param boolean $returnVersion * @param string $filter * @return object CMIS object properties */ // TODO optional parameter support // TODO FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid - public function getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships, - $returnVersion = false, $filter = '') + public function getProperties($repositoryId, $objectId, $filter = '') { $repository = new CMISRepository($repositoryId); - - // TODO a better default value? $properties = array(); - $objectId = CMISUtil::decodeObjectId($objectId, $typeId); if ($typeId == 'Unknown') { @@ -395,7 +388,8 @@ class CMISObjectService { throw new ObjectNotFoundException('The requested object could not be found'); } - $properties = $CMISObject->getProperties(); + $propertyCollection = $CMISObject->getProperties(); + $properties = CMISUtil::createObjectPropertiesEntry($propertyCollection); return $properties; } @@ -518,12 +512,11 @@ class CMISObjectService { * * @param string $repositoryId * @param string $objectId - * @param string $changeToken [optional] - * @return boolean true on success (exception should be thrown otherwise) + * @param string $allVersions [optional] If true, delete all versions */ - // 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) + // NOTE Invoking this service method on an object SHALL not delete the entire version series for a Document Object + // if $allVersions is false. + public function deleteObject($repositoryId, $objectId, $allVersions = true) { // determine object type and internal id $objectId = CMISUtil::decodeObjectId($objectId, $typeId); @@ -553,7 +546,7 @@ class CMISObjectService { if (!$exists) { throw new updateConflictException('Unable to delete the object as it cannot be found.'); } - + global $default; // throw ConstraintViolationException if method is invoked on a Folder object that contains one or more objects if ($typeId == 'Folder') { @@ -572,14 +565,17 @@ class CMISObjectService { } else if ($typeId == 'Document') { + // NOTE KnowledgeTree does not support deleting of individual versions and will always delete all versions + // Throw an exception instead if individual version requested for delete // 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.'); + if (!$allVersions) { + $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 repository does not allow deleting of only the latest version.'); + } } // do not allow deletion of a checked out document - this is actually handled by the ktapi code, @@ -605,9 +601,9 @@ class CMISObjectService { * 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 string $folderId + * @param boolean $unfileObjects [optional] unfile/deletesinglefiles/delete - 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. */ @@ -616,57 +612,52 @@ class CMISObjectService { // • 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 when $continueOnFailure is false, the repository SHOULD abort this method when it fails to delete a single child- or + // descendant-object + public function deleteTree($repositoryId, $folderId, $unfileObjects = '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); + $folderId = CMISUtil::decodeObjectId($folderId, $typeId); - // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). - $exists = true; + // throw updateConflictException if the operation is attempting to update an object that is no longer current + // (as determined by the repository) if ($typeId == 'Folder') { - $object = $this->ktapi->get_folder_by_id($objectId); + $object = $this->ktapi->get_folder_by_id($folderId); if (PEAR::isError($object)) { - $exists = false; + throw new updateConflictException('Unable to delete the object as it cannot be found.'); } } // 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) + // TODO support of $continueOnFailure == false - this is not supported by the underlying code and so is left out for now + $result = $this->ktapi->delete_folder($folderId, $reason, $sig_username, $sig_password); + // if there was an error performing the delete, list objects not deleted + if ($result['status_code'] == 1) { // TODO consider sending back full properties on each object? // Not sure yet what this output may be used for by a client, and the current specification (0.61c) says: // "A list of identifiers of objects in the folder tree that were not deleted", so let's leave it returning just ids for now. - $failedToDelete[] = CMISUtil::encodeObjectId(FOLDER, $objectId); + $failedToDelete[] = CMISUtil::encodeObjectId(FOLDER, $folderId); $folderContents = $object->get_full_listing(); foreach($folderContents as $folderObject) { - if ($folderObject['item_type'] == 'F') $type = 'Folder'; - else if ($folderObject['item_type'] == 'D') $type = 'Document'; - // TODO deal with non-folder and non-document content - else continue; + if ($folderObject['item_type'] == 'F') { + $type = 'Folder'; + } + else if ($folderObject['item_type'] == 'D') { + $type = 'Document'; + } - // TODO find out whether this is meant to be a hierarchical list or simply a list. - // for now we are just returning the list in non-hierarchical form - // (seeing as we don't really know how CMIS AtomPub is planning to deal with hierarchies at this time.) $failedToDelete[] = CMISUtil::encodeObjectId($type, $folderObject['id']); } } @@ -674,14 +665,8 @@ class CMISObjectService { return $failedToDelete; } - // NOTE this function is presently incomplete and untested. Completion deferred to implementation of Checkout/Checkin - // functionality - // NOTE I am not sure yet when this function would ever be called - checkin would be able to update the content stream - // already and the only easy method we have (via KTAPI as it stands) to update the content is on checkin anyway. - // Additionally this function doesn't take a value for the versioning status (major/minor) and so cannot pass it - // on to the ktapi checkin function. - // I imagine this function may be called if we ever allow updating document content independent of checkin, - // or if we change some of the underlying code and call direct to the document functions and not via KTAPI. + // NOTE this function is presently incomplete and untested. Completion deferred until Knowledgetree supports setting + // content streams independent of checkin (which may be necessary for proper client interaction with some clients) /** * Sets the content stream data for an existing document * diff --git a/lib/api/ktcmis/services/CMISVersioningService.inc.php b/lib/api/ktcmis/services/CMISVersioningService.inc.php index 3f21168..04130aa 100644 --- a/lib/api/ktcmis/services/CMISVersioningService.inc.php +++ b/lib/api/ktcmis/services/CMISVersioningService.inc.php @@ -25,49 +25,6 @@ class CMISVersioningService { } /** - * Deletes all Document Objects in the specified Version Series, including the Private Working Copy if it exists - * - * @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); - - // TODO delete any PWC which may exist (NOTE added 24 August 2009 - we did not have any PWC functionality when this function was originally created) - - // 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; - } - - /** * Checks out a document and creates the PWC (Private Working Copy) which will represent the checked out document * * @param string $repositoryId diff --git a/lib/api/ktcmis/util/CMISUtil.inc.php b/lib/api/ktcmis/util/CMISUtil.inc.php index 821f903..7ac5e5a 100644 --- a/lib/api/ktcmis/util/CMISUtil.inc.php +++ b/lib/api/ktcmis/util/CMISUtil.inc.php @@ -182,16 +182,15 @@ class CMISUtil { $CMISArray[$count]['object'] = $CMISObject; // if sub-array - if (count($object['items']) > 0) - { - $CMISArray[$count]['items'] = self::createChildObjectHierarchy($object['items'], $repositoryURI, $ktapi); + if (count($object['items']) > 0) { + $CMISArray[$count]['children'] = self::createChildObjectHierarchy($object['items'], $repositoryURI, $ktapi); } } else { // NOTE why is this necessary? That's what you get for not commenting it at the time // TODO comment this properly, once we know why it is happening - $CMISArray[$count] = self::createChildObjectHierarchy($object, $repositoryURI, $ktapi); +// $CMISArray[$count] = self::createChildObjectHierarchy($object, $repositoryURI, $ktapi); } } } @@ -226,9 +225,8 @@ class CMISUtil { $CMISElement['object'] = $CMISObject; // if more parent elements - if (count($input) > 0) - { - $CMISElement['items'] = self::createParentObjectHierarchy($input, $repositoryURI, $ktapi); + if (count($input) > 0) { + $CMISElement['parents'] = self::createParentObjectHierarchy($input, $repositoryURI, $ktapi); } $CMISArray[] = $CMISElement; @@ -245,10 +243,10 @@ class CMISUtil { * though the output may well be different to what went into that function * * @param array $input // input hierarchy to decode - * @param string $linkText // 'child' or 'parent' - indicates direction of hierarchy => descending or ascending + * @param string $linkText // 'children' or 'parents' - indicates direction of hierarchy => descending or ascending * @return array $hierarchy */ - static public function decodeObjectHierarchy($input, $linkText) + static public function decodeObjectHierarchy($input, $linkText = 'children') { $hierarchy = array(); @@ -257,8 +255,11 @@ class CMISUtil { { $object = $entry['object']; $properties = $object->getProperties(); - $hierarchy[$key] = self::createObjectPropertiesEntry($properties); + + if (isset($entry[$linkText]) && count($entry[$linkText])) { + $hierarchy[$key][$linkText] = self::decodeObjectHierarchy($entry[$linkText], $linkText); + } } return $hierarchy; @@ -288,19 +289,6 @@ class CMISUtil { } } - /* what was this for and is it still needed? */ - /* - // if we have found a child/parent with one or more children/parents, recurse into the child/parent object - if (count($entry['items']) > 0) { - $object[$linkText] = self::decodeObjectHierarchy($entry['items'], $linkText); - } - // NOTE may need to set a null value here in case webservices don't like it unset - // so we'll set it just in case... - else { - $object[$linkText] = null; - } - */ - return $object; } 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 d9c7087..f0c6545 100644 --- a/webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php +++ b/webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php @@ -84,7 +84,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { $response = $response['results']; } - $folderName = $response['properties']['Name']['value']; + $folderName = $response['properties']['name']['value']; } // NOTE parent changes to parents in later specification // TODO update when updating to later specification @@ -262,13 +262,14 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { // 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. + // TODO determine whether client is requesting deleteObject or deleteTree $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService); $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt()); - // attempt delete - $response = $ObjectService->deleteTree($repositoryId, $this->params[0]); + // attempt delete - last parameter sets $deleteAllVersions true + $response = $ObjectService->deleteTree($repositoryId, $this->params[0], 'delete', true); // error? if ($response['status_code'] == 1) { @@ -300,7 +301,6 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { $propertiesElement->appendChild($propElement); $objectElement->appendChild($propertiesElement); $entry->appendChild($objectElement); -// $entry->appendChild($feed->newElement('cmis:terminator')); } $this->responseFeed = $feed; @@ -326,7 +326,8 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { $entries = $NavigationService->getChildren($repositoryId, $folderId, false, false); } else if ($feedType == 'descendants') { - $entries = $NavigationService->getDescendants($repositoryId, $folderId, false, false); + // TODO how will client request depth? + $entries = $NavigationService->getDescendants($repositoryId, $folderId); } else { // error, we shouldn't be here, if we are then the wrong service/function was called @@ -362,9 +363,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/folder/' . $folderId)); $feed->appendChild($link); - foreach($entries as $cmisEntry) { - KT_cmis_atom_service_helper::createObjectEntry($feed, $cmisEntry, $folderName); - } + KT_cmis_atom_service_helper::createObjectFeed($feed, $entries, $folderName); $feed->newField('cmis:hasMoreItems', 'false', $feed); @@ -435,16 +434,14 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service { * @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.) - + { $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService); $VersioningService = new KTVersioningService(KT_cmis_atom_service_helper::getKt()); - + $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt()); + // attempt delete - $response = $VersioningService->deleteAllVersions($repositoryId, $this->params[0]); + $response = $ObjectService->deleteObject($repositoryId, $this->params[0]); if ($response['status_code'] == 1) { $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response['message']); diff --git a/webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php b/webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php index 0ce0805..8c2b27c 100644 --- a/webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php +++ b/webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php @@ -90,13 +90,20 @@ class KT_cmis_atom_service_helper { return $response; } + + static public function createObjectFeed(&$feed, $entries, $folderName) + { + foreach($entries as $cmisEntry) { + self::createObjectEntry($feed, $cmisEntry, $folderName); + } + } /** * Creates an AtomPub entry for a CMIS entry and adds it to the supplied feed * * @param object $feed The feed to which we add the entry * @param array $cmisEntry The entry data - * @param string $parent The parent folder + * @param string $parent The parent folder - this appears to be unused, not sure what it was meant for * @param boolean $pwc Whether this is a PWC object * @param $method The request method used (POST/GET/...) */ @@ -118,6 +125,54 @@ class KT_cmis_atom_service_helper { $entry->appendChild($response->newAttr('xmlns:cmisra', 'http://docs.oasis-open.org/ns/cmis/restatom/200908/')); } + self::createObjectEntryContent($entry, $response, $cmisEntry, $parent, $pwc, $method); + } + + /** + * Creates an AtomPub child feed for a CMIS entry and adds it to the supplied entry + * + * @param $feed The child feed element + * @param $entries Entried contained within the child feed element + * @param $folderName The parent folder name (currently unused) + */ + static public function createObjectChildrenFeed(&$childrenFeed, $entries, $workspace, $feed, $folderName) + { + foreach($entries as $cmisEntry) { + self::createChildObjectEntry($childrenFeed, $cmisEntry, $workspace, $feed, $folderName); + } + } + + /** + * Creates an AtomPub child feed for a CMIS entry and adds it to the supplied entry + * + * @param object $entry The entry to which we add the child feed + * @param array $cmisEntry The object entry data + */ + // NOTE this approach appears to be necessary due to the structure of the underlying atompub code and specification, + // which does not directly support nesting - attempting to create a new feed and append it within the outer + // feed resulted in an empty cmisra:children node, so this approach was substituted + static public function createChildObjectEntry(&$childrenFeed, $cmisEntry, $workspace, $response, $folderNam) + { + $type = strtolower($cmisEntry['properties']['objectTypeId']['value']); + + // create entry + $entry = $response->newElement('entry'); + self::createObjectEntryContent($entry, $response, $cmisEntry);//, $parent, $pwc, $method); + $childrenFeed->appendChild($entry); + } + + /** + * Creates the actual object entry: this is shared between other functions which require this content + * + * @param object $entry The entry object + * @param object $response The response feed + * @param array $cmisEntry The CMIS object content + * @param string $parent The parent folder name + * @param boolean $pwc Whether this is a PWC object (will be returned slightly differently) + * @param string $method The calling method (slightly affects the output) + */ + static public function createObjectEntryContent($entry, &$response, $cmisEntry, $parent = '', $pwc = false, $method = 'GET') + { // TODO dynamic actual creator name $responseElement = $response->newField('author'); $element = $response->newField('name', 'admin', $responseElement); @@ -303,13 +358,23 @@ class KT_cmis_atom_service_helper { $objectElement->appendChild($propertiesElement); $entry->appendChild($objectElement); - // after every entry, append a cmis:terminator tag -// $entry->appendChild($response->newElement('cmis:terminator')); - // TODO check determination of when to add app:edited tag // if ($method == 'POST') { $entry->appendChild($response->newElement('app:edited', self::formatDatestamp())); // } + + // TODO pathSegment entry + + // deal with child objects + if (isset($cmisEntry['children'])) { + // add children node and fill with child entries + $childrenFeed = $response->newElement('feed'); + self::createObjectChildrenFeed($childrenFeed, $cmisEntry['children'], $workspace, $response, '' /*folderName not passed through*/); + + $childrenElement = $response->newElement('cmisra:children'); + $childrenElement->appendChild($childrenFeed); + $entry->appendChild($childrenElement); + } } /** diff --git a/webservice/classes/atompub/cmis/KT_cmis_atom_responseFeed.inc.php b/webservice/classes/atompub/cmis/KT_cmis_atom_responseFeed.inc.php index 6af5a3a..5a580ac 100644 --- a/webservice/classes/atompub/cmis/KT_cmis_atom_responseFeed.inc.php +++ b/webservice/classes/atompub/cmis/KT_cmis_atom_responseFeed.inc.php @@ -38,55 +38,6 @@ class KT_cmis_atom_responseFeed extends KT_atom_responseFeed { $this->feed->appendChild($element); } - // this is ALL going away...adjust all calling code... - /* - protected function constructHeader() - { - if (!is_null($this->id)) - { - $this->newId($this->id, $this->feed); - } - - $link = $this->newElement('link'); - $link->appendChild($this->newAttr('rel','self')); - $link->appendChild($this->newAttr('href', $this->baseURI . trim($_SERVER['QUERY_STRING'], '/'))); - $feed->appendChild($link); - - if (!is_null($this->title)) - { - $this->feed->appendChild($this->newElement('title', $this->title)); - } - - $this->DOM->appendChild($this->feed); - } - - public function &newId($id, $entry = null) - { - $id = $this->newElement('id', $id); - if(isset($entry))$entry->appendChild($id); - return $id; - } - - public function &newField($name = NULL, $value = NULL, &$entry = NULL) - { - $append = false; - - if(func_num_args() > 3) - { - $append = ((func_get_arg(3) === true) ? true : false); - } - - $field = $this->newElement($name, $value); - - if (isset($entry)) $entry->appendChild($field); - else if ($append) $this->feed->appendChild($field); - - return $field; - } -\ - * - */ - } class KT_cmis_atom_ResponseFeed_GET extends KT_cmis_atom_responseFeed{} diff --git a/webservice/classes/atompub/cmis/KT_cmis_atom_server.inc.php b/webservice/classes/atompub/cmis/KT_cmis_atom_server.inc.php index 94035b6..417121d 100644 --- a/webservice/classes/atompub/cmis/KT_cmis_atom_server.inc.php +++ b/webservice/classes/atompub/cmis/KT_cmis_atom_server.inc.php @@ -160,26 +160,15 @@ class KT_cmis_atom_server extends KT_atom_server { public function render() { - ob_end_clean(); - if (!$this->headersSet) header('Content-type: text/xml'); - - //include('/var/www/atompub_response.xml'); - -// if (false && preg_match('/F1\-children/', $this->output)) { -// readfile('C:\Users\Paul\Documents\Downloads\alfresco folder tree atompub response.xml'); -// } -// else if (false && preg_match('/urn:uuid:checkedout/', $this->output)) { -// readfile('C:\Users\Paul\Documents\Downloads\alfresco checkedout atompub response.xml'); -// } -// else if (false && preg_match('/urn:uuid:types\-all/', $this->output)) { -// readfile('C:\Users\Paul\Documents\Downloads\alfresco types atompub response.xml'); -// } -// else if (false && preg_match('/\/', $this->output)) { -// readfile('C:\Users\Paul\Documents\Downloads\cmis_mod_kt.xml'); -// } -// else { - if ($this->renderBody) echo $this->output; -// } + ob_end_clean(); + + if (!$this->headersSet) { + header('Content-type: text/xml'); + } + + if ($this->renderBody) { + echo $this->output; + } } }