/**
  * Deals with GET actions for folders.
  * This includes children and tree/descendant listings as well as individual folder retrieval 
  */
 public function GET_action()
 {
     $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
     // TODO implement full path/node separation as with Alfresco - i.e. path requests come in on path/ and node requests come in on node/
     //      path request e.g.: path/Root Folder/DroppedDocuments
     //      node request e.g.: node/F1/children
     //      node request e.g.: node/F2/parent
     //      node request e.g.: node/F2
     if (urldecode($this->params[0]) == 'Root Folder') {
         $folderId = CMISUtil::encodeObjectId(FOLDER, 1);
         $folderName = urldecode($this->params[0]);
     } else {
         if ($this->params[0] == 'path') {
             $ktapi =& KT_cmis_atom_service_helper::getKt();
             $folderId = KT_cmis_atom_service_helper::getFolderId($this->params, $ktapi);
         } else {
             if ($this->params[1] == 'children' || $this->params[1] == 'descendants') {
                 $folderId = $this->params[0];
                 $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt());
                 $response = $ObjectService->getProperties($repositoryId, $folderId, false, false);
                 if (PEAR::isError($response)) {
                     $feed = KT_cmis_atom_service_helper::getErrorFeed($this, KT_cmis_atom_service::STATUS_SERVER_ERROR, $response->getMessage());
                     $this->responseFeed = $feed;
                     return null;
                 }
                 $folderName = $response['properties']['Name']['value'];
             } else {
                 if ($this->params[1] == 'parent') {
                     // abstract this to be used also by the document service (and the PWC service?) ???
                     // alternatively use getFolderParent here makes sense and use getObjectParents when document service?
                     $folderId = $this->params[0];
                     $NavigationService = new NavigationService(KT_cmis_atom_service_helper::getKt());
                     $response = $NavigationService->getFolderParent($repositoryId, $folderId, false, false, false);
                     if (PEAR::isError($response)) {
                         $feed = KT_cmis_atom_service_helper::getErrorFeed($this, KT_cmis_atom_service::STATUS_SERVER_ERROR, $response->getMessage());
                         $this->responseFeed = $feed;
                         return null;
                     }
                     // we know that a folder will only have one parent, so we can assume element 0
                     $folderId = $response[0]['properties']['ObjectId']['value'];
                     $folderName = $response[0]['properties']['Name']['value'];
                 } else {
                     $folderId = $this->params[0];
                 }
             }
         }
     }
     if (!empty($this->params[1]) && ($this->params[1] == 'children' || $this->params[1] == 'descendants')) {
         $NavigationService = new NavigationService(KT_cmis_atom_service_helper::getKt());
         $feed = $this->getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $this->params[1]);
     } else {
         $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt());
         $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $folderId);
     }
     // Expose the responseFeed
     $this->responseFeed = $feed;
 }
 /**
  * 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();
     $repositories = $RepositoryService->getRepositories();
     $repositoryId = $repositories[0]['repositoryId'];
     // TODO implement full path/node separation as with Alfresco - i.e. path requests come in on path/ and node requests come in on node/
     //      path request e.g.: Root Folder/DroppedDocuments
     //      node request e.g.: F1/children
     //      node request e.g.: F2
     if (urldecode($this->params[0]) == 'Root Folder') {
         $folderId = CMISUtil::encodeObjectId('Folder', 1);
         $folderName = urldecode($this->params[0]);
     } else {
         if ($this->params[0] == 'path') {
             $ktapi =& KT_cmis_atom_service_helper::getKt();
             $folderId = KT_cmis_atom_service_helper::getFolderId($this->params, $ktapi);
         } else {
             if ($this->params[1] == 'children' || $this->params[1] == 'descendants') {
                 $folderId = $this->params[0];
                 $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt());
                 $response = $ObjectService->getProperties($repositoryId, $folderId, false, false);
                 if (PEAR::isError($response)) {
                     $feed = KT_cmis_atom_service_helper::getErrorFeed($this, KT_cmis_atom_service::STATUS_SERVER_ERROR, $response->getMessage());
                     $this->responseFeed = $feed;
                     return null;
                 }
                 $folderName = $response['properties']['Name']['value'];
             } else {
                 $folderId = $this->params[0];
             }
         }
     }
     if (!empty($this->params[1]) && ($this->params[1] == 'children' || $this->params[1] == 'descendants')) {
         $NavigationService = new NavigationService(KT_cmis_atom_service_helper::getKt());
         $feed = $this->getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $this->params[1]);
     } else {
         $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt());
         $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $folderId);
     }
     //Expose the responseFeed
     $this->responseFeed = $feed;
 }
 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;
         }
     } 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 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);
         $folderContents = $object->get_full_listing();
         foreach ($folderContents as $folderObject) {
             if ($folderObject['item_type'] == 'F') {
                 $type = 'Folder';
             } else {
                 if ($folderObject['item_type'] == 'D') {
                     $type = 'Document';
                 } else {
                     continue;
                 }
             }
             // 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']);
         }
     }
     return $failedToDelete;
 }
 private function get($folderId)
 {
     $object = $this->ktapi->get_folder_by_id((int) $folderId);
     // error?
     if (PEAR::isError($object)) {
         // throw an exception?
         return $object;
     }
     //          static $allowedChildObjectTypeIds;
     $objectProperties = $object->get_detail();
     $this->_setPropertyInternal('ObjectId', CMISUtil::encodeObjectId($this->typeId, $objectProperties['id']));
     // prevent doubled '/' chars
     $uri = preg_replace_callback('/([^:]\\/)\\//', create_function('$matches', 'return $matches[1];'), $this->uri . '/browse.php?fFolderId=' . $objectProperties['id']);
     // TODO this url is probably incorrect...needs to be checked
     //        $this->_setPropertyInternal('Uri', $uri);
     $this->_setPropertyInternal('Uri', '');
     // TODO what is this?  Assuming it is the object type id, and not OUR document type?
     $this->_setPropertyInternal('ObjectTypeId', $this->getAttribute('typeId'));
     // Needed to distinguish type
     $this->_setPropertyInternal('BaseType', strtolower($this->getAttribute('typeId')));
     $this->_setPropertyInternal('CreatedBy', $objectProperties['created_by']);
     // TODO cannot currently retrieve via ktapi or regular folder code - add as with created by
     $this->_setPropertyInternal('CreationDate', $objectProperties['created_date']);
     // TODO cannot currently retrieve via ktapi or regular folder code - add as with created by
     $this->_setPropertyInternal('LastModifiedBy', $objectProperties['modified_by']);
     // TODO cannot currently retrieve via ktapi or regular folder code - add as with created by
     $this->_setPropertyInternal('LastModificationDate', $objectProperties['modified_date']);
     $this->_setPropertyInternal('ChangeToken', null);
     $this->_setPropertyInternal('Name', $objectProperties['folder_name']);
     $this->_setPropertyInternal('ParentId', $objectProperties['parent_id']);
     $this->_setPropertyInternal('AllowedChildObjectTypeIds', array('Document', 'Folder'));
     $this->_setPropertyInternal('Author', $objectProperties['created_by']);
 }
Exemplo n.º 5
0
 function testVersioningService()
 {
     $VersioningService = new KTVersioningService($this->ktapi);
     $NavigationService = new KTNavigationService($this->ktapi);
     // set up the folder/doc tree structure with which we will be testing
     $this->createFolderDocStructure();
     $RepositoryService = new KTRepositoryService();
     $response = $RepositoryService->getRepositories();
     $this->assertEqual($response['status_code'], 0);
     $this->assertNotNull($response['results'][0]);
     //
     // we only expect one repository
     $repository = $response['results'][0];
     $repositoryId = $repository['repositoryId'];
     // test deletion of document via deleteAllVersions
     $versionSeriesId = 'D' . $this->docs[0]->get_documentid();
     $response = $VersioningService->deleteAllVersions($repositoryId, $versionSeriesId);
     $this->assertEqual($response['status_code'], 0);
     $this->assertNotNull($response['results']);
     // TODO test checkout of document
     $documentId = CMISUtil::encodeObjectId('Document', $this->docs[1]->get_documentid());
     $response = $VersioningService->checkOut($repositoryId, $documentId);
     $this->assertEqual($response['status_code'], 0);
     $this->assertNotNull($response['results']);
     ////        // use this id for cancel checkout and checkin, not the original document id
     ////        $pwcId = $response['results'];
     $pwcId = CMISUtil::encodeObjectId(DOCUMENT, $this->docs[1]->get_documentid());
     // try again, this time it should fail - not working at the moment as ktapi registers the same user for download
     // even if already checked out, so no error is generated unless a different user attempts to do a checkout
     /*
     $response = $VersioningService->checkOut($repositoryId, $documentId);
     $this->assertEqual($response['status_code'], 1);
     $this->assertNotNull($response['message']);
     */
     // test cancel checkout
     //        echo "WITH: $pwcId<BR>";
     $response = $VersioningService->cancelCheckOut($repositoryId, $pwcId);
     $this->assertEqual($response['status_code'], 0);
     $this->assertNotNull($response['results']);
     // test cancel checkout of document no longer checked out
     $response = $VersioningService->cancelCheckOut($repositoryId, $pwcId);
     $this->assertEqual($response['status_code'], 1);
     $this->assertNotNull($response['message']);
     // test listing of checked out documents
     // first check out the document again :)
     $response = $VersioningService->checkOut($repositoryId, $documentId);
     // now check that it appears in the listing
     $response = $NavigationService->getCheckedOutDocs($repositoryId, false, false);
     $this->assertEqual($response['status_code'], 0);
     $this->assertNotNull($response['results']);
     $this->assertTrue($this->findInPropertiesArray('ObjectId', $documentId, $response['results']));
     // now let's cancel the checkout so that we can delete later during cleanup :)
     $response = $VersioningService->cancelCheckOut($repositoryId, $pwcId);
     // TODO test checkin
     // TODO add testing of failure conditions - e.g. checked out/immutable document (for all appropriate functions)
     // tear down the folder/doc tree structure with which we were testing
     $this->cleanupFolderDocStructure();
 }
 private function get($documentId)
 {
     $object = $this->ktapi->get_document_by_id((int) $documentId);
     // document does not exist?
     if (PEAR::isError($object)) {
         throw new ObjectNotFoundException('The document you are trying to access does not exist or is inaccessible');
     }
     $objectProperties = $object->get_detail();
     $this->_setPropertyInternal('ObjectId', CMISUtil::encodeObjectId($this->typeId, $objectProperties['document_id']));
     // prevent doubled '/' chars
     $uri = preg_replace_callback('/([^:]\\/)\\//', create_function('$matches', 'return $matches[1];'), $this->uri . 'action.php?kt_path_info=ktnetwork.inlineview.actions.view&fDocumentId=' . $objectProperties['document_id']);
     // NOTE what about instead creating a downloadable version with appropriate link?  see ktapi::download_document
     //      also ktapidocument::get_download_url
     //        $this->_setPropertyInternal('Uri', $uri);
     $this->_setPropertyInternal('Uri', '');
     // TODO what is this?  Assuming it is the object type id, and not OUR document type?
     $this->_setPropertyInternal('ObjectTypeId', $this->getAttribute('typeId'));
     // Needed to distinguish type
     $this->_setPropertyInternal('BaseType', strtolower($this->getAttribute('typeId')));
     $this->_setPropertyInternal('CreatedBy', $objectProperties['created_by']);
     $this->_setPropertyInternal('CreationDate', $objectProperties['created_date']);
     $this->_setPropertyInternal('LastModifiedBy', $objectProperties['modified_by']);
     $this->_setPropertyInternal('LastModificationDate', $objectProperties['modified_date']);
     $this->_setPropertyInternal('ChangeToken', null);
     $this->_setPropertyInternal('Name', $objectProperties['title']);
     $this->_setPropertyInternal('ParentId', $objectProperties['folder_id']);
     $this->_setPropertyInternal('IsImmutable', $objectProperties['is_immutable']);
     // NOTE if access to older versions is allowed, this will need to be checked, else just set to yes
     //      see ktapi::get_document_version_history
     // NOTE see ktapi::is_latest_version
     $this->_setPropertyInternal('IsLatestVersion', true);
     $this->_setPropertyInternal('IsMajorVersion', strstr($objectProperties['version'], '.') ? false : true);
     // NOTE if access to older versions is allowed, this will need to be checked, else just set to yes
     //      see ktapi::get_document_version_history
     // NOTE see ktapi::is_latest_version
     $this->_setPropertyInternal('IsLatestMajorVersion', true);
     $this->_setPropertyInternal('VersionLabel', $objectProperties['version']);
     // 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;
         $checkedOutBy = $objectProperties['checked_out_by'];
         // TODO this is not what it will actually be, just a convenient placeholder
         $checkedOutId = $objectProperties['version'];
     } else {
         $checkedOut = false;
         $checkedOutBy = null;
         $checkedOutId = null;
     }
     $this->_setPropertyInternal('IsVersionSeriesCheckedOut', $checkedOut);
     $this->_setPropertyInternal('VersionSeriesCheckedOutBy', $checkedOutBy);
     // TODO presumably this is the ID of the Private Working Copy created on checkout?
     //      will find out more when we do checkout/checkin
     $this->_setPropertyInternal('VersionSeriesCheckedOutId', $checkedOutId);
     // TODO currently not returned by KnowledgeTree?
     $this->_setPropertyInternal('CheckinComment', null);
     $this->_setPropertyInternal('ContentStreamLength', $objectProperties['filesize']);
     $this->_setPropertyInternal('ContentStreamMimeType', $objectProperties['mime_type']);
     $this->_setPropertyInternal('ContentStreamFilename', $objectProperties['filename']);
     $this->_setPropertyInternal('ContentStreamUri', $this->getProperty('ObjectId') . '/' . $objectProperties['filename']);
     $this->_setPropertyInternal('Author', $objectProperties['created_by']);
 }
 public function checkIn($repositoryId, $documentId, $major, $contentStream = null, $changeToken = '', $properties = array(), $checkinComment = '')
 {
     $documentId = CMISUtil::decodeObjectId($documentId, $typeId);
     // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository).
     try {
         $pwc = new CMISDocumentObject($documentId, $this->ktapi);
     } catch (exception $e) {
         throw new UpdateConflictException($e->getMessage());
     }
     // throw exception if the object is not versionable
     if (!$pwc->getAttribute('versionable')) {
         throw new ConstraintViolationException('This document is not versionable and may not be checked in');
     }
     $RepositoryService = new CMISRepositoryService();
     try {
         $typeDefinition = $RepositoryService->getTypeDefinition($repositoryId, $typeId);
     } catch (exception $e) {
         // if we can't get the type definition, then we can't store the content
         throw new StorageException($e->getMessage());
     }
     if ($typeDefinition['attributes']['contentStreamAllowed'] == 'notAllowed' && !empty($contentStream)) {
         throw new StreamNotSupportedException('Content Streams are not supported');
     }
     // check that this is the latest version
     if ($pwc->getProperty('IsLatestVersion') != true) {
         throw new VersioningException('The document is not the latest version and cannot be checked in');
     }
     // now do the checkin
     $tempfilename = CMISUtil::createTemporaryFile($contentStream);
     $response = $this->ktapi->checkin_document($documentId, $pwc->getProperty('ContentStreamFilename'), $reason, $tempfilename, $major, $sig_username, $sig_password);
     // if there was any error in cancelling the checkout
     if ($response['status_code'] == 1) {
         throw new RuntimeException('There was an error checking in the document: ' . $response['message']);
     }
     return CMISUtil::encodeObjectId(DOCUMENT, $documentId);
 }
 public static function getFolderId($path, &$ktapi)
 {
     // lose first item
     array_shift($path);
     $numQ = count($path);
     $numFolders = $numQ;
     $folderId = 1;
     $start = 0;
     while ($start < $numFolders) {
         $name = $path[$numQ - $numFolders + $start];
         // fix for possible url encoding issue
         $name = str_replace('%2520', '%20', $name);
         $folderName = urldecode($name);
         $folder = $ktapi->get_folder_by_name($folderName, $folderId);
         $folderId = $folder->get_folderid();
         ++$start;
     }
     return CMISUtil::encodeObjectId('Folder', $folderId);
 }
 public function checkOut($repositoryId, &$documentId, $changeToken = '')
 {
     $contentCopied = false;
     $documentId = CMISUtil::decodeObjectId($documentId, $typeId);
     // NOTE We are not planning on persisting the PWC beyond the current session, it will be re-created on access of the checked out document
     // TODO consider persisting in the database?  How will this relate to JSR if we are switching to that?
     // NOTE within the current system it is assumed if a new document metadata version is created that this is the latest version of the document
     // TODO see if there is an easy way to modify this, else we may not have an easy way to persist PWC objects
     // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository).
     try {
         $pwc = new CMISDocumentObject($documentId, $this->ktapi);
     } catch (exception $e) {
         throw new UpdateConflictException($e->getMessage());
     }
     // throw exception if the object is not versionable
     if (!$pwc->getAttribute('versionable')) {
         throw new ConstraintViolationException('This document is not versionable and may not be checked out');
     }
     // NOTE KTAPI as currently implemented does not give a direct response which indicates if the document is already checked out,
     //      as long as the same use is calling the checkout again, so should we add a check here specifically?
     // run checkout process - set $download = false (third function argument) as we want to return the document content via the contentStream
     $response = $this->ktapi->checkout_document($documentId, 'CMIS Checkout Action', false, $sig_username, $sig_password);
     // if there was an error, throw an exception
     if ($response['status_code'] == 1) {
         throw new StorageException($response['message']);
     }
     // if successful, set $contentCopied = true; unless contentStream is not set
     if ($pwc->getProperty('ContentStreamFilename') != '') {
         $contentCopied = true;
     }
     $documentId = CMISUtil::encodeObjectId('Document', $documentId);
     // mark document object as checked out
     $pwc->setProperty('IsVersionSeriesCheckedOut', true);
     $userName = '';
     $user = $this->ktapi->get_user();
     if (!PEAR::isError($user)) {
         $userName = $user->getName();
     }
     $pwc->setProperty('VersionSeriesCheckedOutBy', $userName);
     $pwc->setProperty('VersionSeriesCheckedOutId', $documentId);
     return $contentCopied;
 }