Commit 2b68ca023d074734c213a81885a23ac5378efc9d
1 parent
bf8f7fb7
Story ID: 966930. Added support for move via AtomPub and CMIS
In order to be able to move content using a CMIS client, as a user, I would like KnowledgeTree's CMIS interface to support move Committed by: Paul Barrett Reviewed by: Jarrett Jordaan
Showing
5 changed files
with
279 additions
and
70 deletions
lib/api/ktcmis/ktcmis.inc.php
| ... | ... | @@ -538,7 +538,7 @@ class KTObjectService extends KTCMISBase { |
| 538 | 538 | * @param string $versioningState optional version state value: checkedout/major/minor |
| 539 | 539 | * @return string $objectId The id of the created folder object |
| 540 | 540 | */ |
| 541 | - function createDocument($repositoryId, $typeId, $properties, $folderId = null, | |
| 541 | + public function createDocument($repositoryId, $typeId, $properties, $folderId = null, | |
| 542 | 542 | $contentStream = null, $versioningState = null) |
| 543 | 543 | { |
| 544 | 544 | $objectId = null; |
| ... | ... | @@ -570,7 +570,7 @@ class KTObjectService extends KTCMISBase { |
| 570 | 570 | * @param string $folderId The id of the folder which will be the parent of the created folder object |
| 571 | 571 | * @return string $objectId The id of the created folder object |
| 572 | 572 | */ |
| 573 | - function createFolder($repositoryId, $typeId, $properties, $folderId) | |
| 573 | + public function createFolder($repositoryId, $typeId, $properties, $folderId) | |
| 574 | 574 | { |
| 575 | 575 | $objectId = null; |
| 576 | 576 | |
| ... | ... | @@ -592,6 +592,34 @@ class KTObjectService extends KTCMISBase { |
| 592 | 592 | } |
| 593 | 593 | |
| 594 | 594 | /** |
| 595 | + * Moves a fileable object from one folder to another. | |
| 596 | + * | |
| 597 | + * @param object $repositoryId | |
| 598 | + * @param object $objectId | |
| 599 | + * @param object $changeToken [optional] | |
| 600 | + * @param object $targetFolderId | |
| 601 | + * @param object $sourceFolderId [optional] | |
| 602 | + */ | |
| 603 | + public function moveObject($repositoryId, $objectId, $changeToken = '', $targetFolderId, $sourceFolderId = null) | |
| 604 | + { | |
| 605 | + try { | |
| 606 | + $this->ObjectService->moveObject($repositoryId, $objectId, $changeToken, $targetFolderId, $sourceFolderId); | |
| 607 | + } | |
| 608 | + catch (Exception $e) | |
| 609 | + { | |
| 610 | + return array( | |
| 611 | + "status_code" => 1, | |
| 612 | + "message" => $e->getMessage() | |
| 613 | + ); | |
| 614 | + } | |
| 615 | + | |
| 616 | + return array( | |
| 617 | + 'status_code' => 0, | |
| 618 | + 'results' => $objectId | |
| 619 | + ); | |
| 620 | + } | |
| 621 | + | |
| 622 | + /** | |
| 595 | 623 | * Deletes an object from the repository |
| 596 | 624 | * |
| 597 | 625 | * @param string $repositoryId |
| ... | ... | @@ -601,10 +629,10 @@ class KTObjectService extends KTCMISBase { |
| 601 | 629 | */ |
| 602 | 630 | // NOTE Invoking this service method on an object SHALL not delete the entire version series for a Document Object. |
| 603 | 631 | // To delete an entire version series, use the deleteAllVersions() service |
| 604 | - function deleteObject($repositoryId, $objectId, $changeToken = null) | |
| 632 | + public function deleteObject($repositoryId, $objectId, $changeToken = null) | |
| 605 | 633 | { |
| 606 | 634 | try { |
| 607 | - $result = $this->ObjectService->deleteObject($repositoryId, $objectId, $changeToken); | |
| 635 | + $this->ObjectService->deleteObject($repositoryId, $objectId, $changeToken); | |
| 608 | 636 | } |
| 609 | 637 | catch (Exception $e) |
| 610 | 638 | { | ... | ... |
lib/api/ktcmis/services/CMISObjectService.inc.php
| ... | ... | @@ -198,7 +198,7 @@ class CMISObjectService { |
| 198 | 198 | { |
| 199 | 199 | // TODO consider checking whether content is encoded (currently we expect encoded) |
| 200 | 200 | // TODO choose between this and the alternative decode function (see CMISUtil class) |
| 201 | - // The current one appears to be miles better (1/0/3 vs 14/4/57 on respective test files) | |
| 201 | + // this will require some basic benchmarking | |
| 202 | 202 | $contentStream = CMISUtil::decodeChunkedContentStream($contentStream); |
| 203 | 203 | |
| 204 | 204 | // NOTE There is a function in CMISUtil to do this, written for the unit tests but since KTUploadManager exists |
| ... | ... | @@ -390,7 +390,7 @@ class CMISObjectService { |
| 390 | 390 | $response = $this->ktapi->create_folder((int)$folderId, $properties['name'], $sig_username = '', $sig_password = '', $reason = ''); |
| 391 | 391 | if ($response['status_code'] != 0) |
| 392 | 392 | { |
| 393 | - throw new StorageException('The repository was unable to create the folder - ' . $response['message']); | |
| 393 | + throw new StorageException('The repository was unable to create the folder: ' . $response['message']); | |
| 394 | 394 | } |
| 395 | 395 | else |
| 396 | 396 | { |
| ... | ... | @@ -401,6 +401,74 @@ class CMISObjectService { |
| 401 | 401 | } |
| 402 | 402 | |
| 403 | 403 | /** |
| 404 | + * Moves a fileable object from one folder to another. | |
| 405 | + * | |
| 406 | + * @param object $repositoryId | |
| 407 | + * @param object $objectId | |
| 408 | + * @param object $changeToken [optional] | |
| 409 | + * @param object $targetFolderId | |
| 410 | + * @param object $sourceFolderId [optional] | |
| 411 | + */ | |
| 412 | + // TODO versioningException: The repository MAY throw this exception if the object is a non-current Document Version. | |
| 413 | + // TODO check whether object is in fact fileable? not strictly needed, but possibly should be here. | |
| 414 | + public function moveObject($repositoryId, $objectId, $changeToken = '', $targetFolderId, $sourceFolderId = null) | |
| 415 | + { | |
| 416 | + // The $sourceFolderId parameter SHALL be specified if the Repository supports the optional 'unfiling' capability | |
| 417 | + if (is_null($sourceFolderId)) | |
| 418 | + { | |
| 419 | + $RepositoryService = new CMISRepositoryService(); | |
| 420 | + $info = $RepositoryService->getRepositoryInfo($repositoryId); | |
| 421 | + $capabilities = $info->getCapabilities(); | |
| 422 | + // check for unfiling capability | |
| 423 | + // NOTE this is only required once/if KnowledgeTree allows the source folder id to be optional, | |
| 424 | + // but it is required for CMIS specification compliance. | |
| 425 | + if ($capabilities->hasCapabilityUnfiling() === 'true') { | |
| 426 | + throw new RuntimeException('The source folder id MUST be supplied when unfiling is supported.'); | |
| 427 | + } | |
| 428 | + } | |
| 429 | + | |
| 430 | + // Attempt to decode $objectId, use as is if not detected as encoded | |
| 431 | + $tmpObjectId = $objectId; | |
| 432 | + $tmpObjectId = CMISUtil::decodeObjectId($tmpObjectId, $typeId); | |
| 433 | + if ($tmpTypeId != 'Unknown') $objectId = $tmpObjectId; | |
| 434 | + | |
| 435 | + $targetFolderId = CMISUtil::decodeObjectId($targetFolderId); | |
| 436 | + | |
| 437 | + // check type id of object against allowed child types for destination folder | |
| 438 | + $CMISFolder = new CMISFolderObject($targetFolderId, $this->ktapi); | |
| 439 | + $allowed = $CMISFolder->getProperty('AllowedChildObjectTypeIds'); | |
| 440 | + if (!is_array($allowed) || !in_array($typeId, $allowed)) | |
| 441 | + { | |
| 442 | + throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')'); | |
| 443 | + } | |
| 444 | + | |
| 445 | + // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). | |
| 446 | + $exists = CMISUtil::contentExists($typeId, $objectId, $this->ktapi); | |
| 447 | + if (!$exists) { | |
| 448 | + throw new updateConflictException('Unable to move the object as it cannot be found.'); | |
| 449 | + } | |
| 450 | + | |
| 451 | + // TODO add reasons and sig data | |
| 452 | + // attempt to move object | |
| 453 | + if ($typeId == 'Folder') { | |
| 454 | + $response = $this->ktapi->move_folder($objectId, $targetFolderId, $reason, $sig_username, $sig_password); | |
| 455 | + } | |
| 456 | + else if ($typeId == 'Document') { | |
| 457 | + $response = $this->ktapi->move_document($objectId, $targetFolderId, $reason, null, null, $sig_username, $sig_password); | |
| 458 | + } | |
| 459 | + else { | |
| 460 | + $response['status_code'] = 1; | |
| 461 | + $response['message'] = 'The object type could not be determined.'; | |
| 462 | + } | |
| 463 | + | |
| 464 | + // if failed, throw StorageException | |
| 465 | + if ($response['status_code'] != 0) | |
| 466 | + { | |
| 467 | + throw new StorageException('The repository was unable to move the object: ' . $response['message']); | |
| 468 | + } | |
| 469 | + } | |
| 470 | + | |
| 471 | + /** | |
| 404 | 472 | * Deletes an object from the repository |
| 405 | 473 | * |
| 406 | 474 | * @param string $repositoryId |
| ... | ... | @@ -415,6 +483,7 @@ class CMISObjectService { |
| 415 | 483 | // determine object type and internal id |
| 416 | 484 | $objectId = CMISUtil::decodeObjectId($objectId, $typeId); |
| 417 | 485 | |
| 486 | + // TODO this should probably be a function, it is now used in two places... | |
| 418 | 487 | // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). |
| 419 | 488 | $exists = true; |
| 420 | 489 | if ($typeId == 'Folder') { |
| ... | ... | @@ -428,6 +497,7 @@ class CMISObjectService { |
| 428 | 497 | if (PEAR::isError($object)) { |
| 429 | 498 | $exists = false; |
| 430 | 499 | } |
| 500 | + // TODO check deleted status? | |
| 431 | 501 | } |
| 432 | 502 | else { |
| 433 | 503 | $exists = false; |
| ... | ... | @@ -482,8 +552,6 @@ class CMISObjectService { |
| 482 | 552 | if ($result['status_code'] == 1) { |
| 483 | 553 | throw new RuntimeException('There was an error deleting the object: ' . $result['message']); |
| 484 | 554 | } |
| 485 | - | |
| 486 | - return true; | |
| 487 | 555 | } |
| 488 | 556 | |
| 489 | 557 | /** | ... | ... |
lib/api/ktcmis/util/CMISUtil.inc.php
| ... | ... | @@ -397,30 +397,33 @@ class CMISUtil { |
| 397 | 397 | return $temp; |
| 398 | 398 | } |
| 399 | 399 | |
| 400 | - // TODO run evaluations on each of the following two functions and determine which | |
| 401 | - // is generally more efficienct | |
| 402 | - | |
| 403 | 400 | /** |
| 404 | - * Alternative function for decoding chunked streams, this will decode in blocks of 4. | |
| 405 | - * Not sure which method is more efficient, this or the function below (this does not | |
| 406 | - * re-encode but I am working on removing that step for the other function.) | |
| 401 | + * Checks the contentStream and ensures that it is a correct base64 string; | |
| 402 | + * This is purely for clients such as CMISSpaces breaking the content into | |
| 403 | + * chunks before base64 encoding. | |
| 404 | + * | |
| 405 | + * If the stream is chunked, it is decoded in chunks and sent back as a single stream. | |
| 406 | + * If it is not chunked it is decoded as is and sent back as a single stream. | |
| 407 | + * | |
| 408 | + * NOTE there is an alternative version of this function called decodeChunkedContentStreamLong. | |
| 409 | + * that version checks line lengths, which should not be necessary. | |
| 410 | + * this version merely splits on one or two "=" which is less complex and possibly faster (test this assumption) | |
| 411 | + * (one or two "=" signs is the specified padding used for base64 encoding at the end of an encoded string, when needed) | |
| 407 | 412 | * |
| 408 | - * NOTE The current one appears to be much slower (14/4/57 vs 1/0/3 on respective test files) | |
| 409 | - * | |
| 410 | - * @param string $contentStream the base64 encoded content stream | |
| 411 | - * @return string $decoded the decoded content stream | |
| 413 | + * @param object $contentStream | |
| 414 | + * @return string decoded | |
| 412 | 415 | */ |
| 413 | - static public function decodeContentStream($contentStream) | |
| 416 | + static public function decodeChunkedContentStream($contentStream) | |
| 414 | 417 | { |
| 415 | 418 | $decoded = ''; |
| 416 | 419 | |
| 417 | - $contentStream = preg_replace('/\r?\n+/', '', $contentStream); | |
| 418 | - | |
| 419 | - // decode in chunks or 4 chars at a time | |
| 420 | - for($i = 0, $len = strlen($contentStream); $i < $len; $i += 4) { | |
| 421 | - $decoded .= base64_decode(substr($contentStream, $i, 4)); | |
| 420 | + // split the content stream on ={1,2} | |
| 421 | + $parts = preg_split('/={1,2}/', $contentStream, null, PREG_SPLIT_NO_EMPTY); | |
| 422 | + foreach($parts as $part) { | |
| 423 | + // decode, append to output to be re-encoded | |
| 424 | + $decoded .= base64_decode($part); | |
| 422 | 425 | } |
| 423 | - | |
| 426 | + | |
| 424 | 427 | return $decoded; |
| 425 | 428 | } |
| 426 | 429 | |
| ... | ... | @@ -438,7 +441,7 @@ class CMISUtil { |
| 438 | 441 | * @param object $contentStream |
| 439 | 442 | * @return string decoded |
| 440 | 443 | */ |
| 441 | - static public function decodeChunkedContentStream($contentStream) | |
| 444 | + static public function decodeChunkedContentStreamLong($contentStream) | |
| 442 | 445 | { |
| 443 | 446 | // check the content stream for any lines of unusual length (except the last line, which can be any length) |
| 444 | 447 | $count = -1; |
| ... | ... | @@ -464,7 +467,7 @@ class CMISUtil { |
| 464 | 467 | { |
| 465 | 468 | // check for a new chunk |
| 466 | 469 | // either we have an equals sign (or two) |
| 467 | - if (preg_match('/([^=]*={0,2})(.*)/', $line, $matches)) | |
| 470 | + if (preg_match('/([^=]*={1,2})(.*)/', $line, $matches)) | |
| 468 | 471 | { |
| 469 | 472 | $lastChunk = $matches[1]; |
| 470 | 473 | $nextChunk = $matches[2]; |
| ... | ... | @@ -507,6 +510,39 @@ class CMISUtil { |
| 507 | 510 | |
| 508 | 511 | return $decoded; |
| 509 | 512 | } |
| 513 | + | |
| 514 | + /** | |
| 515 | + * Function to check whether a specified object exists within the KnowledgeTree system | |
| 516 | + * | |
| 517 | + * @param string $typeId | |
| 518 | + * @param string $objectId | |
| 519 | + * @param object $ktapi | |
| 520 | + * @return boolean | |
| 521 | + */ | |
| 522 | + public function contentExists($typeId, $objectId, &$ktapi) | |
| 523 | + { | |
| 524 | + $exists = true; | |
| 525 | + if ($typeId == 'Folder') | |
| 526 | + { | |
| 527 | + $object = $ktapi->get_folder_by_id($objectId); | |
| 528 | + if (PEAR::isError($object)) { | |
| 529 | + $exists = false; | |
| 530 | + } | |
| 531 | + } | |
| 532 | + else if ($typeId == 'Document') | |
| 533 | + { | |
| 534 | + $object = $ktapi->get_document_by_id($objectId); | |
| 535 | + if (PEAR::isError($object)) { | |
| 536 | + $exists = false; | |
| 537 | + } | |
| 538 | + // TODO check deleted status? | |
| 539 | + } | |
| 540 | + else { | |
| 541 | + $exists = false; | |
| 542 | + } | |
| 543 | + | |
| 544 | + return $exists; | |
| 545 | + } | |
| 510 | 546 | |
| 511 | 547 | } |
| 512 | 548 | ... | ... |
webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php
| ... | ... | @@ -36,11 +36,14 @@ include_once CMIS_ATOM_LIB_FOLDER . 'ObjectService.inc.php'; |
| 36 | 36 | include_once CMIS_ATOM_LIB_FOLDER . 'VersioningService.inc.php'; |
| 37 | 37 | include_once 'KT_cmis_atom_service_helper.inc.php'; |
| 38 | 38 | |
| 39 | -// TODO auth failed response requires WWW-Authenticate: Basic realm="KnowledgeTree DMS" header | |
| 39 | +// TODO consider changing all responses from the webservice layer to return PEAR errors or success results instead of the half/half we have at the moment. | |
| 40 | +// the half/half occurred because on initial services PEAR Error seemed unnecessary, but it has proven useful for some of the newer functions :) | |
| 40 | 41 | |
| 41 | 42 | /** |
| 42 | 43 | * AtomPub Service: folder |
| 43 | 44 | */ |
| 45 | +// TODO implement failure responses for documents and folders not found. (KTS-4364: http://issues.knowledgetree.com/browse/KTS-4364) | |
| 46 | +// NOTE what about documents which are deleted, need to respond that those are also not found. | |
| 44 | 47 | class KT_cmis_atom_service_folder extends KT_atom_service { |
| 45 | 48 | |
| 46 | 49 | /** |
| ... | ... | @@ -92,7 +95,7 @@ class KT_cmis_atom_service_folder extends KT_atom_service { |
| 92 | 95 | |
| 93 | 96 | /** |
| 94 | 97 | * Deals with folder service POST actions. |
| 95 | - * This includes creation of both folders and documents. | |
| 98 | + * This includes creation/moving of both folders and documents. | |
| 96 | 99 | */ |
| 97 | 100 | public function POST_action() |
| 98 | 101 | { |
| ... | ... | @@ -100,48 +103,101 @@ class KT_cmis_atom_service_folder extends KT_atom_service { |
| 100 | 103 | $repositories = $RepositoryService->getRepositories(); |
| 101 | 104 | $repositoryId = $repositories[0]['repositoryId']; |
| 102 | 105 | |
| 106 | + // set default action, objectId and typeId | |
| 107 | + $action = 'create'; | |
| 108 | + $objectId = null; | |
| 109 | + $typeId = null; | |
| 110 | + | |
| 103 | 111 | $folderId = $this->params[0]; |
| 104 | 112 | $title = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'title'); |
| 105 | 113 | $summary = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'summary'); |
| 106 | 114 | |
| 107 | 115 | $properties = array('name' => $title, 'summary' => $summary); |
| 108 | 116 | |
| 109 | - // determine whether this is a folder or a document create | |
| 110 | - // document create will have a content tag <atom:content> or <content> containing base64 encoding of the document | |
| 111 | - $content = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'content'); | |
| 117 | + // determine whether this is a folder or a document action | |
| 118 | + // document action create will have a content tag <atom:content> or <content> containing base64 encoding of the document | |
| 119 | + // move action will have an existing id supplied as a parameter - not sure how this works yet as the CMIS clients we are | |
| 120 | + // testing don't support move functionality at this time (2009/07/23) and so we are presuming the following format: | |
| 121 | + // /folder/<folderId>/children/<objectId> | |
| 122 | + // also possible that there will be an existing ObjectId property, try to cater for both until we know how it really works | |
| 123 | + | |
| 124 | + // check for existing object id as parameter in url | |
| 125 | + if (isset($this->params[2])) | |
| 126 | + { | |
| 127 | + $action = 'move'; | |
| 128 | + $objectId = $this->params[2]; | |
| 129 | + } | |
| 130 | + | |
| 131 | + $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->parsedXMLContent['@children']['cmis:object'] | |
| 132 | + [0]['@children']['cmis:properties'] | |
| 133 | + [0]['@children']); | |
| 134 | + | |
| 135 | + // check for existing object id as property of submitted object data | |
| 136 | + if (!empty($cmisObjectProperties['ObjectId'])) | |
| 137 | + { | |
| 138 | + $action = 'move'; | |
| 139 | + $objectId = $cmisObjectProperties['ObjectId']; | |
| 140 | + } | |
| 141 | + | |
| 142 | + // TODO there may be more to do for the checking of an existing object. | |
| 143 | + // e.g. verifying that it does indeed exist, and throwing an exception if it does not: | |
| 144 | + // "If the objected property is present but not valid an exception will be thrown" (from CMIS specification) | |
| 145 | + // NOTE this exception should be thrown in the service API code and not here. | |
| 146 | + | |
| 147 | + // determine type if object is being moved | |
| 148 | + if (!is_null($objectId)) { | |
| 149 | + CMISUtil::decodeObjectId($objectId, $typeId); | |
| 150 | + } | |
| 112 | 151 | |
| 113 | - // check content for weird chars | |
| 114 | - $matches = array(); | |
| 115 | - preg_match('/[^\w\d\/\+\n]*/', $content, $matches); | |
| 152 | + // now check for content stream | |
| 153 | + $content = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'content'); | |
| 116 | 154 | |
| 117 | - if (is_null($content)) { | |
| 155 | + // check content for weird chars - don't think this serves a purpose any longer, should probably be removed. | |
| 156 | + // was meant to check for any non-base64 characters in the content string. | |
| 157 | + // preg_match('/[^\w\d\/\+=\n]*/', $content); | |
| 158 | + // TODO this will possibly need to change somewhat once Relationship Objects come into play. | |
| 159 | + if ((($action == 'create') && (is_null($content))) || ($typeId == 'Folder')) { | |
| 118 | 160 | $type = 'folder'; |
| 119 | 161 | } |
| 120 | 162 | else { |
| 121 | 163 | $type = 'document'; |
| 122 | 164 | } |
| 123 | 165 | |
| 124 | - $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->parsedXMLContent['@children']['cmis:object'] | |
| 125 | - [0]['@children']['cmis:properties'] | |
| 126 | - [0]['@children']); | |
| 127 | - | |
| 128 | 166 | $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt()); |
| 129 | 167 | |
| 130 | - if ($type == 'folder') | |
| 131 | - $newObjectId = $ObjectService->createFolder($repositoryId, ucwords($cmisObjectProperties['ObjectTypeId']), $properties, $folderId); | |
| 132 | - else | |
| 133 | - $newObjectId = $ObjectService->createDocument($repositoryId, ucwords($cmisObjectProperties['ObjectTypeId']), $properties, $folderId, $content); | |
| 134 | - | |
| 135 | - // check if returned Object Id is a valid CMIS Object Id | |
| 136 | - CMISUtil::decodeObjectId($newObjectId, $typeId); | |
| 168 | + $success = false; | |
| 169 | + $error = null; | |
| 170 | + if ($action == 'create') | |
| 171 | + { | |
| 172 | + if ($type == 'folder') | |
| 173 | + $newObjectId = $ObjectService->createFolder($repositoryId, ucwords($cmisObjectProperties['ObjectTypeId']), $properties, $folderId); | |
| 174 | + else | |
| 175 | + $newObjectId = $ObjectService->createDocument($repositoryId, ucwords($cmisObjectProperties['ObjectTypeId']), $properties, $folderId, $content); | |
| 176 | + | |
| 177 | + // check if returned Object Id is a valid CMIS Object Id | |
| 178 | + CMISUtil::decodeObjectId($newObjectId, $typeId); | |
| 179 | + if ($typeId != 'Unknown') $success = true; | |
| 180 | + else $error = $newObjectId['message']; | |
| 181 | + } | |
| 182 | + else if ($action == 'move') | |
| 183 | + { | |
| 184 | + $result = $ObjectService->moveObject($repositoryId, $objectId, '', $folderId); | |
| 185 | + | |
| 186 | + if (!PEAR::isError($result)) $success = true; | |
| 187 | + else $error = $result->getMessage(); | |
| 188 | + | |
| 189 | + // same object as before | |
| 190 | + $newObjectId = $objectId; | |
| 191 | + $typeId = ucwords($type); | |
| 192 | + } | |
| 137 | 193 | |
| 138 | - if ($typeId != 'Unknown') | |
| 194 | + if ($success) | |
| 139 | 195 | { |
| 140 | - $this->setStatus(self::STATUS_CREATED); | |
| 196 | + $this->setStatus(($action == 'create') ? self::STATUS_CREATED : self::STATUS_UPDATED); | |
| 141 | 197 | $feed = KT_cmis_atom_service_helper::getObjectFeed($ObjectService, $repositoryId, $newObjectId, 'POST'); |
| 142 | 198 | } |
| 143 | 199 | else { |
| 144 | - $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $newObjectId['message']); | |
| 200 | + $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $error); | |
| 145 | 201 | } |
| 146 | 202 | |
| 147 | 203 | //Expose the responseFeed | ... | ... |
webservice/classes/atompub/cmis/ObjectService.inc.php
| ... | ... | @@ -32,6 +32,34 @@ class ObjectService extends KTObjectService { |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | 34 | /** |
| 35 | + * Creates a new document within the repository | |
| 36 | + * | |
| 37 | + * @param string $repositoryId The repository to which the document must be added | |
| 38 | + * @param string $typeId Object Type id for the document object being created | |
| 39 | + * @param array $properties Array of properties which must be applied to the created document object | |
| 40 | + * @param string $folderId The id of the folder which will be the parent of the created document object | |
| 41 | + * This parameter is optional IF unfilingCapability is supported | |
| 42 | + * @param contentStream $contentStream optional content stream data | |
| 43 | + * @param string $versioningState optional version state value: checkedout/major/minor | |
| 44 | + * @return string $objectId The id of the created folder object | |
| 45 | + */ | |
| 46 | + // TODO throw ConstraintViolationException if: | |
| 47 | + // value of any of the properties violates the min/max/required/length constraints | |
| 48 | + // specified in the property definition in the Object-Type. | |
| 49 | + public function createDocument($repositoryId, $typeId, $properties, $folderId = null, | |
| 50 | + $contentStream = null, $versioningState = null) | |
| 51 | + { | |
| 52 | + $result = parent::createDocument($repositoryId, $typeId, $properties, $folderId, $contentStream, $versioningState); | |
| 53 | + | |
| 54 | + if ($result['status_code'] == 0) { | |
| 55 | + return $result['results']; | |
| 56 | + } | |
| 57 | + else { | |
| 58 | + return $result; | |
| 59 | + } | |
| 60 | + } | |
| 61 | + | |
| 62 | + /** | |
| 35 | 63 | * Creates a new folder within the repository |
| 36 | 64 | * |
| 37 | 65 | * @param string $repositoryId The repository to which the folder must be added |
| ... | ... | @@ -40,7 +68,7 @@ class ObjectService extends KTObjectService { |
| 40 | 68 | * @param string $folderId The id of the folder which will be the parent of the created folder object |
| 41 | 69 | * @return string $objectId The id of the created folder object |
| 42 | 70 | */ |
| 43 | - function createFolder($repositoryId, $typeId, $properties, $folderId) | |
| 71 | + public function createFolder($repositoryId, $typeId, $properties, $folderId) | |
| 44 | 72 | { |
| 45 | 73 | $result = parent::createFolder($repositoryId, $typeId, $properties, $folderId); |
| 46 | 74 | |
| ... | ... | @@ -51,32 +79,25 @@ class ObjectService extends KTObjectService { |
| 51 | 79 | return $result; |
| 52 | 80 | } |
| 53 | 81 | } |
| 54 | - | |
| 82 | + | |
| 55 | 83 | /** |
| 56 | - * Creates a new document within the repository | |
| 57 | - * | |
| 58 | - * @param string $repositoryId The repository to which the document must be added | |
| 59 | - * @param string $typeId Object Type id for the document object being created | |
| 60 | - * @param array $properties Array of properties which must be applied to the created document object | |
| 61 | - * @param string $folderId The id of the folder which will be the parent of the created document object | |
| 62 | - * This parameter is optional IF unfilingCapability is supported | |
| 63 | - * @param contentStream $contentStream optional content stream data | |
| 64 | - * @param string $versioningState optional version state value: checkedout/major/minor | |
| 65 | - * @return string $objectId The id of the created folder object | |
| 84 | + * Moves a fileable object from one folder to another. | |
| 85 | + * | |
| 86 | + * @param object $repositoryId | |
| 87 | + * @param object $objectId | |
| 88 | + * @param object $changeToken [optional] | |
| 89 | + * @param object $targetFolderId | |
| 90 | + * @param object $sourceFolderId [optional] | |
| 66 | 91 | */ |
| 67 | - // TODO throw ConstraintViolationException if: | |
| 68 | - // value of any of the properties violates the min/max/required/length constraints | |
| 69 | - // specified in the property definition in the Object-Type. | |
| 70 | - function createDocument($repositoryId, $typeId, $properties, $folderId = null, | |
| 71 | - $contentStream = null, $versioningState = null) | |
| 92 | + public function moveObject($repositoryId, $objectId, $changeToken = '', $targetFolderId, $sourceFolderId = null) | |
| 72 | 93 | { |
| 73 | - $result = parent::createDocument($repositoryId, $typeId, $properties, $folderId, $contentStream, $versioningState); | |
| 94 | + $result = parent::moveObject($repositoryId, $objectId, $changeToken, $targetFolderId, $sourceFolderId); | |
| 74 | 95 | |
| 75 | 96 | if ($result['status_code'] == 0) { |
| 76 | 97 | return $result['results']; |
| 77 | 98 | } |
| 78 | 99 | else { |
| 79 | - return $result; | |
| 100 | + return new PEAR_Error($result['message']); | |
| 80 | 101 | } |
| 81 | 102 | } |
| 82 | 103 | |
| ... | ... | @@ -90,7 +111,7 @@ class ObjectService extends KTObjectService { |
| 90 | 111 | */ |
| 91 | 112 | // NOTE Invoking this service method on an object SHALL not delete the entire version series for a Document Object. |
| 92 | 113 | // To delete an entire version series, use the deleteAllVersions() service |
| 93 | - function deleteObject($repositoryId, $objectId, $changeToken = null) | |
| 114 | + public function deleteObject($repositoryId, $objectId, $changeToken = null) | |
| 94 | 115 | { |
| 95 | 116 | $result = parent::deleteObject($repositoryId, $objectId, $changeToken); |
| 96 | 117 | ... | ... |