Commit 834f8d17e9eafc10fa964bc693b4aa584961a1c6

Authored by Paul Barrett
1 parent 6a1d367a

Added some CMIS exception classes. Used these exceptions in the createFolder fu…

…nction and a few other places according to the specification.  Modified ktcmis interface to check for exceptions in appropriate cases.

Extended Unit Tests for CMIS to double check folder creation instead of relying on initial output of createFolder function.

Cleaned up some comments and unnecessary code in CMIS classes.

Additional framework code for CMIS checkedout functionality

Committed by: Paul Barrett
ktatompub/services/cmis/NavigationService.inc.php
@@ -99,6 +99,26 @@ class NavigationService extends KTNavigationService { @@ -99,6 +99,26 @@ class NavigationService extends KTNavigationService {
99 } 99 }
100 } 100 }
101 101
  102 + /**
  103 + * Returns a list of checked out documents from the selected repository
  104 + *
  105 + * @param string $repositoryId
  106 + * @param string $folderId The folder for which checked out docs are requested
  107 + * @param string $filter
  108 + * @param int $maxItems
  109 + * @param int $skipCount
  110 + * @return array $checkedout The collection of checked out documents
  111 + */
  112 + function getCheckedoutDocs($repositoryId, $folderId = null, $filter = '', $maxItems = 0, $skipCount = 0)
  113 + {
  114 + $checkedout = parent::getObjectParents($repositoryId, $folderId, $filter, $maxItems, $skipCount);
  115 +
  116 + if ($result['status_code'] == 0)
  117 + {
  118 + return $result['results'];
  119 + }
  120 + }
  121 +
102 } 122 }
103 123
104 ?> 124 ?>
ktatompub/services/cmis/checkedout.inc.php
@@ -20,8 +20,28 @@ $NavigationService->startSession($username, $password); @@ -20,8 +20,28 @@ $NavigationService->startSession($username, $password);
20 $repositories = $RepositoryService->getRepositories(); 20 $repositories = $RepositoryService->getRepositories();
21 $repositoryId = $repositories[0]['repositoryId']; 21 $repositoryId = $repositories[0]['repositoryId'];
22 22
  23 +$checkedout = $NavigationService->getCheckedoutDocs($repositoryId);
  24 +
23 $feed = new KTCMISAPPFeed(KT_APP_BASE_URI, 'Checked out Documents', null, null, null, 'urn:uuid:checkedout'); 25 $feed = new KTCMISAPPFeed(KT_APP_BASE_URI, 'Checked out Documents', null, null, null, 'urn:uuid:checkedout');
24 26
  27 +foreach($checkedout as $document)
  28 +{
  29 + $entry = $feed->newEntry();
  30 + $objectElement = $feed->newElement('cmis:object');
  31 + $propertiesElement = $feed->newElement('cmis:properties');
  32 +
  33 + foreach($cmisEntry['properties'] as $propertyName => $property)
  34 + {
  35 + $propElement = $feed->newElement('cmis:' . $property['type']);
  36 + $propElement->appendChild($feed->newAttr('cmis:name', $propertyName));
  37 + $feed->newField('value', CMISUtil::boolToString($property['value']), $propElement);
  38 + $propertiesElement->appendChild($propElement);
  39 + }
  40 +
  41 + $objectElement->appendChild($propertiesElement);
  42 + $entry->appendChild($objectElement);
  43 +}
  44 +
25 $entry = null; 45 $entry = null;
26 $feed->newField('hasMoreItems', 'false', $entry, true); 46 $feed->newField('hasMoreItems', 'false', $entry, true);
27 47
ktatompub/services/cmis/folder.inc.php
@@ -444,6 +444,7 @@ class CMISFolderFeed extends CMISObjectFeed { @@ -444,6 +444,7 @@ class CMISFolderFeed extends CMISObjectFeed {
444 // <cmis:hasMoreItems>false</cmis:hasMoreItems> 444 // <cmis:hasMoreItems>false</cmis:hasMoreItems>
445 445
446 $output = $feed->getAPPdoc(); 446 $output = $feed->getAPPdoc();
  447 +
447 $outputs = '<?xml version="1.0" encoding="UTF-8"?> 448 $outputs = '<?xml version="1.0" encoding="UTF-8"?>
448 <feed xmlns="http://www.w3.org/2005/Atom" xmlns:cmis="http://www.cmis.org/2008/05"> 449 <feed xmlns="http://www.w3.org/2005/Atom" xmlns:cmis="http://www.cmis.org/2008/05">
449 <entry> 450 <entry>
lib/api/ktcmis/classes/CMISPropertyCollection.inc.php
@@ -54,8 +54,6 @@ abstract class CMISPropertyCollection { @@ -54,8 +54,6 @@ abstract class CMISPropertyCollection {
54 static $LastModifiedBy; 54 static $LastModifiedBy;
55 static $LastModificationDate; 55 static $LastModificationDate;
56 static $ChangeToken; 56 static $ChangeToken;
57 - static $ContentStreamLength;  
58 - static $ContentStreamMimeType;  
59 // TODO these definitions probably belong elsewhere, but here will do for now 57 // TODO these definitions probably belong elsewhere, but here will do for now
60 static $propertyTypes; 58 static $propertyTypes;
61 59
lib/api/ktcmis/classes/CMISRepository.inc.php
@@ -167,44 +167,6 @@ class CMISRepository { @@ -167,44 +167,6 @@ class CMISRepository {
167 return $this->objectTypes; 167 return $this->objectTypes;
168 } 168 }
169 169
170 -// // TODO this function MUST accept the same arguments as the calling functions and respond accordingly  
171 -// // TODO consider moving this into the RepositoryService class:  
172 -// // anything which requires a repository id seems like it does not belong in the repository class  
173 -// function getTypes()  
174 -// {  
175 -// $objectTypes = $this->objectTypes->getObjectTypes();  
176 -//  
177 -// // fetch the attributes for each type  
178 -// foreach ($objectTypes as $key => $objectType)  
179 -// {  
180 -// $objectTypes[$key] = $this->getTypeDefinition($this->repositoryId, $objectType);  
181 -// }  
182 -//  
183 -// return $objectTypes;  
184 -// }  
185 -  
186 -// // TODO consider moving this into the RepositoryService class:  
187 -// // anything which requires a repository id seems like it does not belong in the repository class  
188 -// function getTypeDefinition($repositoryId, $typeId)  
189 -// {  
190 -// // TODO is this the best way of doing this?  
191 -// switch ($typeId)  
192 -// {  
193 -// case 'Document':  
194 -// require_once(CMIS_DIR . '/objecttypes/CMISDocumentObject.inc.php');  
195 -// $tmpObject = new DocumentObject();  
196 -// $objectAttributes = $tmpObject->getProperties();  
197 -// break;  
198 -// case 'Folder':  
199 -// require_once(CMIS_DIR . '/objecttypes/CMISFolderObject.inc.php');  
200 -// $tmpObject = new FolderObject();  
201 -// $objectAttributes = $tmpObject->getProperties();  
202 -// break;  
203 -// }  
204 -//  
205 -// return $objectAttributes;  
206 -// }  
207 -  
208 } 170 }
209 171
210 ?> 172 ?>
lib/api/ktcmis/exceptions/ConstraintViolationException.inc.php 0 → 100644
  1 +<?php
  2 +
  3 +class ConstraintViolationException extends Exception {
  4 +
  5 +}
  6 +
  7 +?>
lib/api/ktcmis/exceptions/InvalidArgumentException.inc.php 0 → 100644
  1 +<?php
  2 +
  3 +class IllegalArgumentException extends Exception {
  4 +
  5 +}
  6 +
  7 +?>
lib/api/ktcmis/exceptions/ObjectNotFoundException.inc.php 0 → 100644
  1 +<?php
  2 +
  3 +class ObjectNotFoundException extends Exception {
  4 +
  5 +}
  6 +
  7 +?>
lib/api/ktcmis/exceptions/StorageException.inc.php 0 → 100644
  1 +<?php
  2 +
  3 +class StorageException extends Exception {
  4 +
  5 +}
  6 +
  7 +?>
lib/api/ktcmis/ktcmis.inc.php
@@ -85,7 +85,7 @@ class KTCMISBase { @@ -85,7 +85,7 @@ class KTCMISBase {
85 return $this->session; 85 return $this->session;
86 } 86 }
87 87
88 - // TODO what about destroying sessions? 88 + // TODO what about destroying sessions? only on logout (which is not offered by the CMIS clients tested so far)
89 } 89 }
90 90
91 /** 91 /**
@@ -152,8 +152,8 @@ class KTRepositoryService extends KTCMISBase { @@ -152,8 +152,8 @@ class KTRepositoryService extends KTCMISBase {
152 ); 152 );
153 } 153 }
154 154
155 - // TODO output this manually, the function works but only for some objects so rather avoid it completely  
156 - // NOTE the fact that it works for this instance is irrelevant... 155 + // TODO output this manually, the function works but only for some objects so rather avoid it completely?
  156 + // NOTE the problems appear to be due to recursive objects
157 return array ( 157 return array (
158 "status_code" => 0, 158 "status_code" => 0,
159 "results" => CMISUtil::objectToArray($repositoryInfo) 159 "results" => CMISUtil::objectToArray($repositoryInfo)
@@ -168,13 +168,15 @@ class KTRepositoryService extends KTCMISBase { @@ -168,13 +168,15 @@ class KTRepositoryService extends KTCMISBase {
168 public function getTypes($repositoryId, $typeId = '', $returnPropertyDefinitions = false, 168 public function getTypes($repositoryId, $typeId = '', $returnPropertyDefinitions = false,
169 $maxItems = 0, $skipCount = 0, &$hasMoreItems = false) 169 $maxItems = 0, $skipCount = 0, &$hasMoreItems = false)
170 { 170 {
171 - $repositoryObjectTypeResult = $this->RepositoryService->getTypes($repositoryId, $typeId, $returnPropertyDefinitions,  
172 - $maxItems, $skipCount, $hasMoreItems);  
173 - if (PEAR::isError($repositoryObjectTypeResult)) 171 + try {
  172 + $repositoryObjectTypeResult = $this->RepositoryService->getTypes($repositoryId, $typeId, $returnPropertyDefinitions,
  173 + $maxItems, $skipCount, $hasMoreItems);
  174 + }
  175 + catch (Exception $e)
174 { 176 {
175 return array( 177 return array(
176 "status_code" => 1, 178 "status_code" => 1,
177 - "message" => "Failed getting supported object types" 179 + "message" => $e->getMessage()
178 ); 180 );
179 } 181 }
180 182
@@ -202,13 +204,14 @@ class KTRepositoryService extends KTCMISBase { @@ -202,13 +204,14 @@ class KTRepositoryService extends KTCMISBase {
202 */ 204 */
203 public function getTypeDefinition($repositoryId, $typeId) 205 public function getTypeDefinition($repositoryId, $typeId)
204 { 206 {
205 - $typeDefinitionResult = $this->RepositoryService->getTypeDefinition($repositoryId, $typeId);  
206 -  
207 - if (PEAR::isError($typeDefinitionResult)) 207 + try {
  208 + $typeDefinitionResult = $this->RepositoryService->getTypeDefinition($repositoryId, $typeId);
  209 + }
  210 + catch (Exception $e)
208 { 211 {
209 return array( 212 return array(
210 "status_code" => 1, 213 "status_code" => 1,
211 - "message" => "Failed getting object type definition for $typeId" 214 + "message" => $e->getMessage()
212 ); 215 );
213 } 216 }
214 217
@@ -380,6 +383,35 @@ class KTNavigationService extends KTCMISBase { @@ -380,6 +383,35 @@ class KTNavigationService extends KTCMISBase {
380 ); 383 );
381 } 384 }
382 385
  386 + /**
  387 + * Returns a list of checked out documents from the selected repository
  388 + *
  389 + * @param string $repositoryId
  390 + * @param string $folderId The folder for which checked out docs are requested
  391 + * @param string $filter
  392 + * @param int $maxItems
  393 + * @param int $skipCount
  394 + * @return array $checkedout The collection of checked out documents
  395 + */
  396 + function getCheckedoutDocs($repositoryId, $folderId = null, $filter = '', $maxItems = 0, $skipCount = 0)
  397 + {
  398 + $checkedout = $this->NavigationService->getObjectParents($repositoryId, $objectId, $includeAllowableActions,
  399 + $includeRelationships);
  400 +
  401 + if (PEAR::isError($ancestryResult))
  402 + {
  403 + return array(
  404 + "status_code" => 1,
  405 + "message" => "Failed getting list of checked out documents"
  406 + );
  407 + }
  408 +
  409 + return array(
  410 + "status_code" => 0,
  411 + "results" => $checkedout
  412 + );
  413 + }
  414 +
383 } 415 }
384 416
385 /** 417 /**
@@ -415,13 +447,15 @@ class KTObjectService extends KTCMISBase { @@ -415,13 +447,15 @@ class KTObjectService extends KTCMISBase {
415 public function getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships, 447 public function getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships,
416 $returnVersion = false, $filter = '') 448 $returnVersion = false, $filter = '')
417 { 449 {
418 - $propertyCollection = $this->ObjectService->getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships);  
419 -  
420 - if (PEAR::isError($propertiesResult)) 450 + try {
  451 + $propertyCollection = $this->ObjectService->getProperties($repositoryId, $objectId, $includeAllowableActions,
  452 + $includeRelationships);
  453 + }
  454 + catch (Exception $e)
421 { 455 {
422 return array( 456 return array(
423 "status_code" => 1, 457 "status_code" => 1,
424 - "message" => "Failed getting properties for object" 458 + "message" => $e->getMessage()
425 ); 459 );
426 } 460 }
427 461
@@ -446,13 +480,14 @@ class KTObjectService extends KTCMISBase { @@ -446,13 +480,14 @@ class KTObjectService extends KTCMISBase {
446 { 480 {
447 $objectId = null; 481 $objectId = null;
448 482
449 - $objectId = $this->ObjectService->createFolder($repositoryId, $typeId, $properties, $folderId);  
450 -  
451 - if (PEAR::isError($propertiesResult)) 483 + try {
  484 + $objectId = $this->ObjectService->createFolder($repositoryId, $typeId, $properties, $folderId);
  485 + }
  486 + catch (Exception $e)
452 { 487 {
453 return array( 488 return array(
454 "status_code" => 1, 489 "status_code" => 1,
455 - "message" => "Failed getting properties for object" 490 + "message" => $e->getMessage()
456 ); 491 );
457 } 492 }
458 493
lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php
@@ -54,7 +54,7 @@ class CMISDocumentObject extends CMISBaseObject { @@ -54,7 +54,7 @@ class CMISDocumentObject extends CMISBaseObject {
54 private $uri; 54 private $uri;
55 55
56 // TODO some of this should probably come from configuration files as it is repository specific 56 // TODO some of this should probably come from configuration files as it is repository specific
57 - function CMISDocumentObject(&$ktapi = null, $uri = null) 57 + function __construct($documentId = null, &$ktapi = null, $uri = null)
58 { 58 {
59 $this->ktapi = $ktapi; 59 $this->ktapi = $ktapi;
60 // uri to use for document links 60 // uri to use for document links
@@ -92,12 +92,16 @@ class CMISDocumentObject extends CMISBaseObject { @@ -92,12 +92,16 @@ class CMISDocumentObject extends CMISBaseObject {
92 // parent::__construct(); 92 // parent::__construct();
93 93
94 // set document specific property definitions 94 // set document specific property definitions
95 - 95 +
  96 + if (!is_null($documentId))
  97 + {
  98 + $this->_get($documentId);
  99 + }
96 } 100 }
97 101
98 - function get($objectId) 102 + private function _get($documentId)
99 { 103 {
100 - $object = $this->ktapi->get_document_by_id($objectId); 104 + $object = $this->ktapi->get_document_by_id($documentId);
101 105
102 // error? 106 // error?
103 if (PEAR::isError($object)) 107 if (PEAR::isError($object))
lib/api/ktcmis/objecttypes/CMISFolderObject.inc.php
@@ -49,7 +49,7 @@ class CMISFolderObject extends CMISBaseObject { @@ -49,7 +49,7 @@ class CMISFolderObject extends CMISBaseObject {
49 var $ktapi; 49 var $ktapi;
50 var $uri; 50 var $uri;
51 51
52 - function CMISFolderObject(&$ktapi = null, $uri = null) 52 + function __construct($folderId = null, &$ktapi = null, $uri = null)
53 { 53 {
54 $this->ktapi = $ktapi; 54 $this->ktapi = $ktapi;
55 $this->uri = $uri; 55 $this->uri = $uri;
@@ -69,11 +69,16 @@ class CMISFolderObject extends CMISBaseObject { @@ -69,11 +69,16 @@ class CMISFolderObject extends CMISBaseObject {
69 69
70 // properties 70 // properties
71 $this->properties = new CMISFolderPropertyCollection(); 71 $this->properties = new CMISFolderPropertyCollection();
  72 +
  73 + if (!is_null($folderId))
  74 + {
  75 + $this->_get($folderId);
  76 + }
72 } 77 }
73 78
74 - function get($objectId) 79 + private function _get($folderId)
75 { 80 {
76 - $object = $this->ktapi->get_folder_by_id($objectId); 81 + $object = $this->ktapi->get_folder_by_id($folderId);
77 82
78 // error? 83 // error?
79 if (PEAR::isError($object)) 84 if (PEAR::isError($object))
lib/api/ktcmis/services/CMISNavigationService.inc.php
@@ -40,7 +40,6 @@ @@ -40,7 +40,6 @@
40 * @version Version 0.1 40 * @version Version 0.1
41 */ 41 */
42 42
43 -// really wanted to keep KT code out of here but I don't see how  
44 require_once(KT_DIR . '/ktapi/ktapi.inc.php'); 43 require_once(KT_DIR . '/ktapi/ktapi.inc.php');
45 require_once(CMIS_DIR . '/util/CMISUtil.inc.php'); 44 require_once(CMIS_DIR . '/util/CMISUtil.inc.php');
46 45
@@ -75,7 +74,6 @@ class CMISNavigationService { @@ -75,7 +74,6 @@ class CMISNavigationService {
75 // NOTE If the Repository supports the optional “VersionSpecificFiling” capability, 74 // NOTE If the Repository supports the optional “VersionSpecificFiling” capability,
76 // then the repository SHALL return the document versions filed in the specified folder or its descendant folders. 75 // then the repository SHALL return the document versions filed in the specified folder or its descendant folders.
77 // Otherwise, the latest version of the documents SHALL be returned. 76 // Otherwise, the latest version of the documents SHALL be returned.
78 -  
79 // TODO FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid 77 // TODO FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid
80 function getDescendants($repositoryId, $folderId, $includeAllowableActions, $includeRelationships, 78 function getDescendants($repositoryId, $folderId, $includeAllowableActions, $includeRelationships,
81 $depth = 1, $typeId = 'Any', $filter = '') 79 $depth = 1, $typeId = 'Any', $filter = '')
@@ -156,8 +154,8 @@ class CMISNavigationService { @@ -156,8 +154,8 @@ class CMISNavigationService {
156 * @return array $ancestry 154 * @return array $ancestry
157 */ 155 */
158 // TODO FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid 156 // TODO FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid
  157 + // TODO If this service method is invoked on the root folder of the Repository, then the Repository SHALL return an empty result set.
159 // NOTE SHOULD always include the “ObjectId” and “ParentId” properties for all objects returned 158 // NOTE SHOULD always include the “ObjectId” and “ParentId” properties for all objects returned
160 - // NOTE If this service method is invoked on the root folder of the Repository, then the Repository shall return an empty result set.  
161 function getFolderParent($repositoryId, $folderId, $includeAllowableActions, $includeRelationships, $returnToRoot, $filter = '') 159 function getFolderParent($repositoryId, $folderId, $includeAllowableActions, $includeRelationships, $returnToRoot, $filter = '')
162 { 160 {
163 $ancestry = array(); 161 $ancestry = array();
@@ -217,7 +215,7 @@ class CMISNavigationService { @@ -217,7 +215,7 @@ class CMISNavigationService {
217 * @return array $parents 215 * @return array $parents
218 */ 216 */
219 // TODO ConstraintViolationException: The Repository SHALL throw this exception if this method is invoked 217 // TODO ConstraintViolationException: The Repository SHALL throw this exception if this method is invoked
220 - // on an object who Object-Type Defintion specifies that it is not fileable. 218 + // on an object who Object-Type Definition specifies that it is not fileable.
221 // FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid. 219 // FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid.
222 function getObjectParents($repositoryId, $objectId, $includeAllowableActions, $includeRelationships, $filter = '') 220 function getObjectParents($repositoryId, $objectId, $includeAllowableActions, $includeRelationships, $filter = '')
223 { 221 {
@@ -245,6 +243,26 @@ class CMISNavigationService { @@ -245,6 +243,26 @@ class CMISNavigationService {
245 return $ancestry; 243 return $ancestry;
246 } 244 }
247 245
  246 + /**
  247 + * Returns a list of checked out documents from the selected repository
  248 + *
  249 + * @param string $repositoryId
  250 + * @param string $folderId The folder for which checked out docs are requested
  251 + * @param string $filter
  252 + * @param int $maxItems
  253 + * @param int $skipCount
  254 + * @return array $checkedout The collection of checked out documents
  255 + */
  256 + // NOTE NOT YET IMPLEMENTED (this function is just a place holder at the moment :))
  257 + function getCheckedoutDocs($repositoryId, $folderId = null, $filter = '', $maxItems = 0, $skipCount = 0)
  258 + {
  259 + $checkedout = array();
  260 +
  261 +
  262 +
  263 + return $checkedout();
  264 + }
  265 +
248 } 266 }
249 267
250 ?> 268 ?>
lib/api/ktcmis/services/CMISObjectService.inc.php
1 <?php 1 <?php
2 2
3 -// really wanted to keep KT code out of here but I don't see how  
4 require_once(KT_DIR . '/ktapi/ktapi.inc.php'); 3 require_once(KT_DIR . '/ktapi/ktapi.inc.php');
  4 +require_once(CMIS_DIR . '/exceptions/ConstraintViolationException.inc.php');
  5 +require_once(CMIS_DIR . '/exceptions/ObjectNotFoundException.inc.php');
  6 +require_once(CMIS_DIR . '/exceptions/StorageException.inc.php');
  7 +require_once(CMIS_DIR . '/services/CMISRepositoryService.inc.php');
5 require_once(CMIS_DIR . '/objecttypes/CMISDocumentObject.inc.php'); 8 require_once(CMIS_DIR . '/objecttypes/CMISDocumentObject.inc.php');
6 require_once(CMIS_DIR . '/objecttypes/CMISFolderObject.inc.php'); 9 require_once(CMIS_DIR . '/objecttypes/CMISFolderObject.inc.php');
7 require_once(CMIS_DIR . '/classes/CMISRepository.inc.php'); 10 require_once(CMIS_DIR . '/classes/CMISRepository.inc.php');
@@ -44,17 +47,21 @@ class CMISObjectService { @@ -44,17 +47,21 @@ class CMISObjectService {
44 47
45 $typeId = CMISUtil::decodeObjectId($objectId); 48 $typeId = CMISUtil::decodeObjectId($objectId);
46 49
  50 + if ($typeId == 'Unknown')
  51 + {
  52 + throw new ObjectNotFoundException('The type of the requested object could not be determined');
  53 + }
  54 +
47 switch($typeId) 55 switch($typeId)
48 { 56 {
49 case 'Document': 57 case 'Document':
50 - $CMISObject = new CMISDocumentObject($this->ktapi, $repository->getRepositoryURI()); 58 + $CMISObject = new CMISDocumentObject($objectId, $this->ktapi, $repository->getRepositoryURI());
51 break; 59 break;
52 case 'Folder': 60 case 'Folder':
53 - $CMISObject = new CMISFolderObject($this->ktapi, $repository->getRepositoryURI()); 61 + $CMISObject = new CMISFolderObject($objectId, $this->ktapi, $repository->getRepositoryURI());
54 break; 62 break;
55 } 63 }
56 64
57 - $CMISObject->get($objectId);  
58 $properties = $CMISObject->getProperties(); 65 $properties = $CMISObject->getProperties();
59 66
60 return $properties; 67 return $properties;
@@ -70,14 +77,24 @@ class CMISObjectService { @@ -70,14 +77,24 @@ class CMISObjectService {
70 * @return string $objectId The id of the created folder object 77 * @return string $objectId The id of the created folder object
71 */ 78 */
72 // TODO throw ConstraintViolationException if: 79 // TODO throw ConstraintViolationException if:
73 - // typeID is not an Object-Type whose baseType is “Folder”.  
74 // value of any of the properties violates the min/max/required/length constraints 80 // value of any of the properties violates the min/max/required/length constraints
75 // specified in the property definition in the Object-Type. 81 // specified in the property definition in the Object-Type.
76 - // typeID is NOT in the list of AllowedChildObjectTypeIds of the parent-folder specified by folderId  
77 - // TODO throw storageException under conditions specified in "specific exceptions" section  
78 function createFolder($repositoryId, $typeId, $properties, $folderId) 82 function createFolder($repositoryId, $typeId, $properties, $folderId)
79 { 83 {
80 - $objectId = null; 84 + // fetch type definition of supplied type and check for base type "folder", if not true throw exception
  85 + $RepositoryService = new CMISRepositoryService();
  86 + try {
  87 + $typeDefinition = $RepositoryService->getTypeDefinition($repositoryId, $typeId);
  88 + }
  89 + catch (Exception $e)
  90 + {
  91 + throw new ConstraintViolationException('Object is not of base type folder.');
  92 + }
  93 +
  94 + if ($typeDefinition['attributes']['baseType'] != 'folder')
  95 + {
  96 + throw new ConstraintViolationException('Object is not of base type folder');
  97 + }
81 98
82 // TODO determine whether this is in fact necessary or if we should require decoding in the calling code 99 // TODO determine whether this is in fact necessary or if we should require decoding in the calling code
83 // Attempt to decode $folderId, use as is if not detected as encoded 100 // Attempt to decode $folderId, use as is if not detected as encoded
@@ -85,11 +102,21 @@ class CMISObjectService { @@ -85,11 +102,21 @@ class CMISObjectService {
85 $tmpTypeId = CMISUtil::decodeObjectId($objectId); 102 $tmpTypeId = CMISUtil::decodeObjectId($objectId);
86 if ($tmpTypeId != 'Unknown') 103 if ($tmpTypeId != 'Unknown')
87 $folderId = $objectId; 104 $folderId = $objectId;
  105 +
  106 + // if parent folder is not allowed to hold this type, throw exception
  107 + $CMISFolder = new CMISFolderObject($folderId, $this->ktapi);
  108 + $folderProperties = $CMISFolder->getProperties();
  109 + $allowed = $folderProperties->getValue('AllowedChildObjectTypeIds');
  110 + if (!is_array($allowed) || !in_array($typeId, $allowed))
  111 + {
  112 + throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')');
  113 + }
88 114
89 $response = $this->ktapi->create_folder($folderId, $properties['name'], $sig_username = '', $sig_password = '', $reason = ''); 115 $response = $this->ktapi->create_folder($folderId, $properties['name'], $sig_username = '', $sig_password = '', $reason = '');
90 if ($response['status_code'] != 0) 116 if ($response['status_code'] != 0)
91 { 117 {
92 - // TODO add some error handling here 118 + // throw storageException
  119 + throw new StorageException('The repository was unable to create the folder - ' . $response['message']);
93 } 120 }
94 else 121 else
95 { 122 {
lib/api/ktcmis/services/CMISRepositoryService.inc.php
@@ -43,6 +43,7 @@ @@ -43,6 +43,7 @@
43 43
44 require_once(CMIS_DIR . '/classes/CMISRepository.inc.php'); 44 require_once(CMIS_DIR . '/classes/CMISRepository.inc.php');
45 require_once(CMIS_DIR . '/classes/CMISObjectTypes.inc.php'); 45 require_once(CMIS_DIR . '/classes/CMISObjectTypes.inc.php');
  46 +require_once(CMIS_DIR . '/exceptions/InvalidArgumentException.inc.php');
46 47
47 /** 48 /**
48 * CMIS Repository Service. 49 * CMIS Repository Service.
@@ -98,10 +99,21 @@ class CMISRepositoryService { @@ -98,10 +99,21 @@ class CMISRepositoryService {
98 * @return array $objectTypes 99 * @return array $objectTypes
99 */ 100 */
100 // NOTE this code may fit better within the Repository Class 101 // NOTE this code may fit better within the Repository Class
  102 + // TODO return for specific type when $typeId is specified
  103 + // TODO other optional parameters
101 function getTypes($repositoryId, $typeId = '', $returnPropertyDefinitions = false, 104 function getTypes($repositoryId, $typeId = '', $returnPropertyDefinitions = false,
102 $maxItems = 0, $skipCount = 0, &$hasMoreItems = false) 105 $maxItems = 0, $skipCount = 0, &$hasMoreItems = false)
103 { 106 {
104 - // TODO throw invalidArgumentException if invalid typeId submitted 107 + if ($typeId != '')
  108 + {
  109 + try {
  110 + $typeDefinition = $this->getTypeDefinition($repositoryId, $typeId);
  111 + }
  112 + catch (Exception $e)
  113 + {
  114 + throw new InvalidArgumentException('Type ' . $typeId . ' is not supported');
  115 + }
  116 + }
105 117
106 $repository = new CMISRepository($repositoryId); 118 $repository = new CMISRepository($repositoryId);
107 $supportedTypes = $repository->getTypes(); 119 $supportedTypes = $repository->getTypes();
@@ -140,15 +152,24 @@ class CMISRepositoryService { @@ -140,15 +152,24 @@ class CMISRepositoryService {
140 * @param string $typeId The ID of the object type requested 152 * @param string $typeId The ID of the object type requested
141 * @return $array $typeDefinition 153 * @return $array $typeDefinition
142 */ 154 */
  155 + // NOTE this code may fit better in the Repository Class
143 function getTypeDefinition($repositoryId, $typeId) 156 function getTypeDefinition($repositoryId, $typeId)
144 { 157 {
  158 + $object = 'CMIS' . $typeId . 'Object';
  159 +
  160 + // check whether the object type exists, return error if not
  161 + // consider throwing an exception instead (see General Exceptions)
  162 + if (!file_exists(CMIS_DIR . '/objecttypes/' . $object . '.inc.php'))
  163 + {
  164 + throw new InvalidArgumentException('Type ' . $typeId . ' is not supported');
  165 + }
  166 +
145 $typeDefinition = array(); 167 $typeDefinition = array();
146 168
147 - require_once(CMIS_DIR . '/objecttypes/CMIS' . $typeId . 'Object.inc.php');  
148 - $object = 'CMIS' . $typeId . 'Object';  
149 - $tmpObject = new $object;  
150 - $typeDefinition['attributes'] = $tmpObject->getAttributes();  
151 - $typeDefinition['properties'] = $tmpObject->getProperties(); 169 + require_once(CMIS_DIR . '/objecttypes/' . $object . '.inc.php');
  170 + $cmisObject = new $object;
  171 + $typeDefinition['attributes'] = $cmisObject->getAttributes();
  172 + $typeDefinition['properties'] = $cmisObject->getProperties();
152 173
153 return $typeDefinition; 174 return $typeDefinition;
154 } 175 }
lib/api/ktcmis/util/CMISUtil.inc.php
@@ -133,14 +133,13 @@ class CMISUtil { @@ -133,14 +133,13 @@ class CMISUtil {
133 switch($object['item_type']) 133 switch($object['item_type'])
134 { 134 {
135 case 'D': 135 case 'D':
136 - $CMISObject = new CMISDocumentObject($ktapi, $repositoryURI); 136 + $CMISObject = new CMISDocumentObject($object['id'], $ktapi, $repositoryURI);
137 break; 137 break;
138 case 'F': 138 case 'F':
139 - $CMISObject = new CMISFolderObject($ktapi, $repositoryURI); 139 + $CMISObject = new CMISFolderObject($object['id'], $ktapi, $repositoryURI);
140 break; 140 break;
141 } 141 }
142 142
143 - $CMISObject->get($object['id']);  
144 $CMISArray[$count]['object'] = $CMISObject; 143 $CMISArray[$count]['object'] = $CMISObject;
145 144
146 // if sub-array 145 // if sub-array
@@ -184,8 +183,7 @@ class CMISUtil { @@ -184,8 +183,7 @@ class CMISUtil {
184 183
185 if (isset($detail['id'])) 184 if (isset($detail['id']))
186 { 185 {
187 - $CMISObject = new CMISFolderObject($ktapi, $repositoryURI);  
188 - $CMISObject->get($detail['id']); 186 + $CMISObject = new CMISFolderObject($detail['id'], $ktapi, $repositoryURI);
189 $CMISElement['object'] = $CMISObject; 187 $CMISElement['object'] = $CMISObject;
190 188
191 // if more parent elements 189 // if more parent elements
tests/ktcmis/testCmisApi.php
@@ -7,6 +7,7 @@ require_once (KT_LIB_DIR . &#39;/api/ktcmis/ktcmis.inc.php&#39;); @@ -7,6 +7,7 @@ require_once (KT_LIB_DIR . &#39;/api/ktcmis/ktcmis.inc.php&#39;);
7 define (KT_TEST_USER, 'admin'); 7 define (KT_TEST_USER, 'admin');
8 define (KT_TEST_PASS, 'admin'); 8 define (KT_TEST_PASS, 'admin');
9 9
  10 +// set to true to print out results
10 define (DEBUG_CMIS, false); 11 define (DEBUG_CMIS, false);
11 12
12 /** 13 /**
@@ -339,15 +340,23 @@ class CMISTestCase extends KTUnitTestCase { @@ -339,15 +340,23 @@ class CMISTestCase extends KTUnitTestCase {
339 // TODO test invalid type 340 // TODO test invalid type
340 // TODO test invalid parent folder 341 // TODO test invalid parent folder
341 // TODO other invalid parameters 342 // TODO other invalid parameters
342 - $created = $ObjectService->createFolder($repositoryId, 'Folder', array('name' => 'My Test Folder ' . mt_rand()), 1); 343 + $created = $ObjectService->createFolder($repositoryId, 'Folder', array('name' => 'My Test Folder ' . mt_rand()), 'F1');
343 $this->assertNotNull($created['results']); 344 $this->assertNotNull($created['results']);
344 345
345 - // delete created folder  
346 if (!is_null($created['results'])) 346 if (!is_null($created['results']))
347 { 347 {
348 - $folder_id = $created['results'];  
349 - CMISUtil::decodeObjectId($folder_id);  
350 - $this->ktapi->delete_folder($folder_id, 'Testing API', KT_TEST_USER, KT_TEST_PASS); 348 + $folderId = $created['results'];
  349 +
  350 + // check that folder object actually exists
  351 + $properties = $ObjectService->getProperties($repositoryId, $folderId, false, false);
  352 + $this->assertNotNull($properties['results']);
  353 +
  354 + // test printout
  355 + $this->printTable($properties['results'][0], 'Properties for CMIS Created Folder Object ' . $folderId . ' (getProperties())');
  356 +
  357 + // delete
  358 + CMISUtil::decodeObjectId($folderId);
  359 + $this->ktapi->delete_folder($folderId, 'Testing API', KT_TEST_USER, KT_TEST_PASS);
351 } 360 }
352 361
353 // tear down the folder/doc tree structure with which we were testing 362 // tear down the folder/doc tree structure with which we were testing