Commit 712f1028b28666565c909c426d6930604b7cb512

Authored by Paul Barrett
1 parent 515bed4a

Add basic URI templates and service support

Story ID:2713417. CMIS working with PHP client

Committed by: Paul Barrett
webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php
... ... @@ -42,6 +42,45 @@ include_once 'KT_cmis_atom_service_helper.inc.php';
42 42 // FIXME ContentStreamAllowed tag is empty (at least sometimes)
43 43  
44 44 /**
  45 + * AtomPub Service: object by id
  46 + */
  47 +class KT_cmis_atom_service_objectbyid extends KT_cmis_atom_service {
  48 +
  49 + public function GET_action()
  50 + {
  51 + $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
  52 + $objectId = $this->params[0];
  53 + $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
  54 +
  55 + $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $objectId);
  56 +
  57 + // Expose the responseFeed
  58 + $this->responseFeed = $feed;
  59 + }
  60 +
  61 +}
  62 +
  63 +/**
  64 + * AtomPub Service: object by path
  65 + * Fetches an object using the path to the object instead of the object id
  66 + */
  67 +class KT_cmis_atom_service_objectbypath extends KT_cmis_atom_service {
  68 +
  69 + public function GET_action()
  70 + {
  71 + $ktapi =& KT_cmis_atom_service_helper::getKt();
  72 + $objectId = KT_cmis_atom_service_helper::getObjectId(explode('/', urldecode($this->params[0])), $ktapi, false);
  73 + $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
  74 +
  75 + $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $objectId);
  76 +
  77 + // Expose the responseFeed
  78 + $this->responseFeed = $feed;
  79 + }
  80 +
  81 +}
  82 +
  83 +/**
45 84 * AtomPub Service: folder
46 85 */
47 86 class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
... ... @@ -53,7 +92,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
53 92 public function GET_action()
54 93 {
55 94 $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
56   -
  95 +
57 96 // TODO implement full path/node separation as with Alfresco - i.e. path requests come in on path/ and node requests come in on node/
58 97 // path request e.g.: path/Root Folder/DroppedDocuments
59 98 // node request e.g.: node/F1/children
... ... @@ -67,14 +106,14 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
67 106 else if ($this->params[0] == 'path')
68 107 {
69 108 $ktapi =& KT_cmis_atom_service_helper::getKt();
70   - $folderId = KT_cmis_atom_service_helper::getFolderId($this->params, $ktapi);
  109 + $folderId = KT_cmis_atom_service_helper::getObjectId($this->params, $ktapi);
71 110 }
72 111 else if (($this->params[1] == 'children') || ($this->params[1] == 'descendants'))
73 112 {
74 113 $folderId = $this->params[0];
75 114 $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
76 115 $response = $ObjectService->getProperties($repositoryId, $folderId, false, false);
77   -
  116 +
78 117 if ($response['status_code'] == 1) {
79 118 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, KT_cmis_atom_service::STATUS_SERVER_ERROR, $response['message']);
80 119 $this->responseFeed = $feed;
... ... @@ -83,7 +122,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
83 122 else {
84 123 $response = $response['results'];
85 124 }
86   -
  125 +
87 126 $folderName = $response['properties']['name']['value'];
88 127 }
89 128 // NOTE parent changes to parents in later specification
... ... @@ -103,7 +142,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
103 142 else {
104 143 $response = $response['results'];
105 144 }
106   -
  145 +
107 146 // we know that a folder will only have one parent, so we can assume element 0
108 147 $folderId = $response['properties']['objectId']['value'];
109 148 $folderName = $response['properties']['name']['value'];
... ... @@ -132,14 +171,14 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
132 171 * This includes creation/moving of both folders and documents.
133 172 */
134 173 public function POST_action()
135   - {
  174 + {
136 175 $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
137 176  
138 177 // set default action, objectId and typeId
139   - $action = 'create';
  178 + $action = 'create';
140 179 $objectId = null;
141 180 $typeId = null;
142   -
  181 +
143 182 $folderId = $this->params[0];
144 183 $title = KT_cmis_atom_service_helper::getAtomValues($this->rawContent, 'title');
145 184 $summary = KT_cmis_atom_service_helper::getAtomValues($this->rawContent, 'summary');
... ... @@ -151,41 +190,41 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
151 190 // /folder/<folderId>/<sourceFolderId>/<objectId>
152 191 // also possible that there will be an existing ObjectId property, try to cater for both until we know how it really works
153 192 // NOTE this also applies to the source folder id, see above
154   -
  193 +
155 194 // check for existing object id as parameter in url
156 195 // if sourceFolderId parameter is submitted (expected as parameter 3, or params[2]) then this is a move
157 196 if (isset($this->params[2])) {
158 197 $action = 'move';
159 198 $sourceFolderId = $this->params[2];
160 199 }
161   -
  200 +
162 201 // get object properties - todo send through original properties array and not modified version
163 202 $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisObjectProperties($this->rawContent);
164 203 $properties = array('name' => $title, 'summary' => $summary, 'objectTypeId' => $cmisObjectProperties['cmis:objectTypeId']);
165   -
  204 +
166 205 // check for existing object id as property of submitted object data
167 206 if (!empty($cmisObjectProperties['cmis:objectId'])) {
168 207 $objectId = $cmisObjectProperties['cmis:objectId'];
169 208 }
170   -
  209 +
171 210 // TODO there may be more to do for the checking of an existing object.
172 211 // e.g. verifying that it does indeed exist, and throwing an exception if it does not:
173 212 // "If the objected property is present but not valid an exception will be thrown" (from CMIS specification)
174 213 // NOTE this exception should be thrown in the service API code and not here.
175   -
  214 +
176 215 // determine type if object is being moved
177 216 if (!is_null($objectId)) {
178 217 CMISUtil::decodeObjectId($objectId, $typeId);
179 218 }
180   -
  219 +
181 220 // check for content stream
182 221 $content = KT_cmis_atom_service_helper::getCmisContent($this->rawContent);
183 222 // NOTE not sure about the text type, will need testing, most content will be base64
184   - $cmisContent = (isset($content['cmisra:base64'])
185   - ? $content['cmisra:base64']
186   - : ((isset($content['cmisra:text']))
187   - ? $content['cmisra:text']
188   - : null));
  223 + $cmisContent = (isset($content['cmisra:base64'])
  224 + ? $content['cmisra:base64']
  225 + : ((isset($content['cmisra:text']))
  226 + ? $content['cmisra:text']
  227 + : null));
189 228  
190 229 $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
191 230  
... ... @@ -220,20 +259,20 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
220 259 else if ($action == 'move')
221 260 {
222 261 $response = $ObjectService->moveObject($repositoryId, $objectId, $folderId, $sourceFolderId);
223   -
  262 +
224 263 if ($response['status_code'] == 0) {
225 264 $success = true;
226 265 }
227 266 else {
228 267 $error = $response['message'];
229 268 }
230   -
  269 +
231 270 // same object as before
232 271 $newObjectId = $objectId;
233 272 // FIXME why set this? it does not appear to get used
234 273 $typeId = ucwords($cmisObjectProperties['cmis:objectTypeId']);
235 274 }
236   -
  275 +
237 276 if ($success)
238 277 {
239 278 $this->setStatus(($action == 'create') ? self::STATUS_CREATED : self::STATUS_UPDATED);
... ... @@ -246,7 +285,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
246 285 // Expose the responseFeed
247 286 $this->responseFeed = $feed;
248 287 }
249   -
  288 +
250 289 /**
251 290 * Deals with DELETE actions for folders.
252 291 * This includes deleting a single folder (with no content) and deleting an entire folder tree
... ... @@ -259,9 +298,9 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
259 298 // we COULD call deleteObject but when we delete a folder we expect to be trying to delete
260 299 // the folder and all content.
261 300 // TODO determine whether client is requesting deleteObject or deleteTree
262   -
  301 +
263 302 $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
264   -
  303 +
265 304 $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
266 305  
267 306 // attempt delete - last parameter sets $deleteAllVersions true
... ... @@ -277,17 +316,17 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
277 316 else {
278 317 $response = $response['results'];
279 318 }
280   -
  319 +
281 320 // list of failed objects?
282 321 if (is_array($response))
283 322 {
284 323 $this->setStatus(self::STATUS_SERVER_ERROR);
285   -
  324 +
286 325 $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI);
287 326 $feed->newField('title', 'Error: Failed to delete all objects in tree: ' . self::STATUS_SERVER_ERROR, $feed);
288   -
  327 +
289 328 foreach($response as $failed)
290   - {
  329 + {
291 330 $entry = $feed->newEntry();
292 331 $objectElement = $feed->newElement('cmisra:object');
293 332 $propertiesElement = $feed->newElement('cmis:properties');
... ... @@ -298,11 +337,11 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
298 337 $objectElement->appendChild($propertiesElement);
299 338 $entry->appendChild($objectElement);
300 339 }
301   -
  340 +
302 341 $this->responseFeed = $feed;
303 342 return null;
304 343 }
305   -
  344 +
306 345 // success
307 346 $this->setStatus(self::STATUS_NO_CONTENT);
308 347 }
... ... @@ -325,7 +364,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
325 364 // TODO how will client request depth? for now we assume as part of the url - will probably be covered by URI templates
326 365 if (isset($this->params[2])) {
327 366 $entries = $NavigationService->getDescendants($repositoryId, $folderId, $this->params[2]);
328   -
  367 +
329 368 }
330 369 else {
331 370 $entries = $NavigationService->getDescendants($repositoryId, $folderId);
... ... @@ -334,22 +373,22 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
334 373 else {
335 374 // error, we shouldn't be here, if we are then the wrong service/function was called
336 375 }
337   -
  376 +
338 377 // hack, for removing one level of access
339 378 $entries = $entries['results'];
340 379  
341 380 // $baseURI=NULL,$title=NULL,$link=NULL,$updated=NULL,$author=NULL,$id=NULL
342 381 $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI);
343 382 $workspace = $feed->getWorkspace();
344   -
  383 +
345 384 $feed->newField('title', $folderName . ' ' . ucwords($feedType), $feed);
346   -
  385 +
347 386 // TODO dynamic?
348 387 $feedElement = $feed->newField('author');
349 388 $element = $feed->newField('name', 'System', $feedElement);
350 389 $feed->appendChild($feedElement);
351   -
352   - // id
  390 +
  391 + // id
353 392 $feed->newField('id', 'urn:uuid:' . $folderId . '-' . $feedType, $feed);
354 393  
355 394 // TODO get actual most recent update time, only use current if no other available
... ... @@ -359,7 +398,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
359 398 $link->appendChild($feed->newAttr('rel', 'self'));
360 399 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/folder/' . $folderId . '/' . $feedType));
361 400 $feed->appendChild($link);
362   -
  401 +
363 402 $link = $feed->newElement('link');
364 403 $link->appendChild($feed->newAttr('rel', 'service'));
365 404 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . 'servicedocument'));
... ... @@ -392,11 +431,11 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service {
392 431 public function GET_action()
393 432 {
394 433 $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
395   -
  434 +
396 435 $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
397 436  
398 437 $objectId = $this->params[0];
399   -
  438 +
400 439 // TODO this is "parents" in later versions of the specification
401 440 // update accordingly when updating to newer specification
402 441 if ($this->params[1] == 'parent')
... ... @@ -412,7 +451,7 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service {
412 451 else {
413 452 $response = $response['results'];
414 453 }
415   -
  454 +
416 455 // for now a document will only have one parent as KnowledgeTree does not support multi-filing
417 456 // TODO update this code if/when multi-filing support is added
418 457 $objectId = $response[0]['properties']['objectId']['value'];
... ... @@ -430,7 +469,7 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service {
430 469 // Expose the responseFeed
431 470 $this->responseFeed = $feed;
432 471 }
433   -
  472 +
434 473 /**
435 474 * Deals with DELETE actions for documents.
436 475 * This includes deletion of a specific version of a document (latest version) via deleteObject
... ... @@ -439,12 +478,12 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service {
439 478 * @return 204 on success, 500 on error
440 479 */
441 480 public function DELETE_action()
442   - {
  481 + {
443 482 $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
444   -
  483 +
445 484 $VersioningService = new KTVersioningService(KT_cmis_atom_service_helper::getKt());
446 485 $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
447   -
  486 +
448 487 // attempt delete
449 488 $response = $ObjectService->deleteObject($repositoryId, $this->params[0]);
450 489  
... ... @@ -454,15 +493,15 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service {
454 493 $this->responseFeed = $feed;
455 494 return null;
456 495 }
457   -
  496 +
458 497 // success
459   - $this->setStatus(self::STATUS_NO_CONTENT);
  498 + $this->setStatus(self::STATUS_NO_CONTENT);
460 499 }
461   -
  500 +
462 501 }
463 502  
464 503 class KT_cmis_atom_service_pwc extends KT_cmis_atom_service {
465   -
  504 +
466 505 protected $serviceType = 'PWC';
467 506  
468 507 /**
... ... @@ -472,7 +511,7 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service {
472 511 public function GET_action()
473 512 {
474 513 $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
475   -
  514 +
476 515 $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
477 516  
478 517 // determine whether we want the Private Working Copy entry feed or the actual physical Private Working Copy content.
... ... @@ -488,7 +527,7 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service {
488 527 // Expose the responseFeed
489 528 $this->responseFeed = $feed;
490 529 }
491   -
  530 +
492 531 /**
493 532 * Deals with DELETE actions for Private Working Copies.
494 533 * This includes deletion of a specific version of a document (latest version) via deleteObject
... ... @@ -499,79 +538,79 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service {
499 538 public function DELETE_action()
500 539 {
501 540 // call the cancel checkout function
502   -
503   - $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
  541 +
  542 + $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
504 543 $VersioningService = new KTVersioningService(KT_cmis_atom_service_helper::getKt());
505   -
  544 +
506 545 $response = $VersioningService->cancelCheckout($repositoryId, $this->params[0]);
507 546  
508 547 if ($response['status_code'] == 1) {
509 548 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response['message']);
510   - // Expose the responseFeed
  549 + // Expose the responseFeed
511 550 $this->responseFeed = $feed;
512 551 return null;
513 552 }
514   -
  553 +
515 554 $this->setStatus(self::STATUS_NO_CONTENT);
516 555 $this->responseFeed = null;
517 556 }
518   -
  557 +
519 558 public function PUT_action()
520 559 {
521 560 $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
522 561 $VersioningService = new KTVersioningService(KT_cmis_atom_service_helper::getKt());
523 562 $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
524   -
  563 +
525 564 // get object properties
526 565 $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisObjectProperties($this->rawContent);
527 566  
528 567 // check for content stream
529 568 $content = KT_cmis_atom_service_helper::getCmisContent($this->rawContent);
530 569 // NOTE not sure about the text type, will need testing, most content will be base64
531   - $cmisContent = (isset($content['cmisra:base64'])
532   - ? $content['cmisra:base64']
533   - : ((isset($content['cmisra:text']))
534   - ? $content['cmisra:text']
535   - : null));
  570 + $cmisContent = (isset($content['cmisra:base64'])
  571 + ? $content['cmisra:base64']
  572 + : ((isset($content['cmisra:text']))
  573 + ? $content['cmisra:text']
  574 + : null));
536 575  
537 576 // if we haven't found it now, the hack begins - retrieve the EXISTING content and submit this as the contentStream
538   - // this is needed because KnowledgeTree will not accept a checkin without a content stream but CMISSpaces (and possibly
  577 + // this is needed because KnowledgeTree will not accept a checkin without a content stream but CMISSpaces (and possibly
539 578 // other CMIS clients are the same, does not send a content stream on checkin nor does it offer the user a method to choose one)
540 579 // NOTE that if the content is INTENDED to be empty this and all the above checks will FAIL!
541 580 // FIXME this is horrible, terrible, ugly and bad!
542 581 if (empty($cmisContent)) {
543 582 $cmisContent = base64_encode(KT_cmis_atom_service_helper::getContentStream($this, $ObjectService, $repositoryId));
544 583 }
545   -
  584 +
546 585 // and if we don't have the content stream by now, we give up...but leave the error to be generated by the underlying KnowledgeTree code
547 586 // checkin function call
548   - // TODO dynamically detect version change type - leaving this for now as the CMIS clients tested do not appear to
  587 + // TODO dynamically detect version change type - leaving this for now as the CMIS clients tested do not appear to
549 588 // offer the choice to the user - perhaps it will turn out that this will come from somewhere else but for now
550 589 // we assume minor version updates only
551 590 $major = false;
552 591 $checkinComment = '';
553 592 $response = $VersioningService->checkIn($repositoryId, $this->params[0], $major, $cmisObjectProperties, $cmisContent, $checkinComment);
554   -
  593 +
555 594 if ($response['status_code'] == 1) {
556 595 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response['message']);
557 596 // Expose the responseFeed
558 597 $this->responseFeed = $feed;
559 598 return null;
560 599 }
561   -
  600 +
562 601 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $this->params[0]);
563 602  
564 603 // Expose the responseFeed
565 604 $this->responseFeed = $feed;
566 605 }
567   -
  606 +
568 607 }
569 608  
570 609 /**
571 610 * AtomPub Service: checkedout
572 611 */
573 612 class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
574   -
  613 +
575 614 /**
576 615 * Deals with GET actions for checkedout documents.
577 616 */
... ... @@ -581,31 +620,31 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
581 620 $NavigationService = new KTNavigationService(KT_cmis_atom_service_helper::getKt());
582 621  
583 622 $checkedout = $NavigationService->getCheckedOutDocs($repositoryId);
584   -
  623 +
585 624 // hack, for removing one level of access
586 625 $checkedout = $checkedout['results'];
587 626  
588 627 //Create a new response feed
589 628 $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI);
590 629 $workspace = $feed->getWorkspace();
591   -
  630 +
592 631 $feed->newField('title', 'Checked out Documents', $feed);
593   -
  632 +
594 633 // TODO dynamic?
595 634 $feedElement = $feed->newField('author');
596 635 $element = $feed->newField('name', 'admin', $feedElement);
597 636 $feed->appendChild($feedElement);
598   -
  637 +
599 638 $feed->appendChild($feed->newElement('id', 'urn:uuid:checkedout'));
600 639  
601 640 // TODO get actual most recent update time, only use current if no other available
602 641 $feed->appendChild($feed->newElement('updated', KT_cmis_atom_service_helper::formatDatestamp()));
603   -
  642 +
604 643 $link = $feed->newElement('link');
605 644 $link->appendChild($feed->newAttr('rel', 'self'));
606 645 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/checkedout'));
607 646 $feed->appendChild($link);
608   -
  647 +
609 648 $link = $feed->newElement('link');
610 649 $link->appendChild($feed->newAttr('rel','first'));
611 650 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/checkedout/pageNo=1&amp;pageSize=0'));
... ... @@ -628,7 +667,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
628 667 // Expose the responseFeed
629 668 $this->responseFeed = $feed;
630 669 }
631   -
  670 +
632 671 public function POST_action()
633 672 {
634 673 $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
... ... @@ -636,7 +675,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
636 675 $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
637 676  
638 677 $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisObjectProperties($this->rawContent);
639   -
  678 +
640 679 // check for existing object id as property of submitted object data
641 680 if (empty($cmisObjectProperties['cmis:objectId']))
642 681 {
... ... @@ -645,16 +684,16 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
645 684 $this->responseFeed = $feed;
646 685 return null;
647 686 }
648   -
  687 +
649 688 $response = $VersioningService->checkOut($repositoryId, $cmisObjectProperties['cmis:objectId']);
650   -
  689 +
651 690 if ($response['status_code'] == 1) {
652 691 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, 'No object was specified for checkout');
653 692 // Expose the responseFeed
654 693 $this->responseFeed = $feed;
655 694 return null;
656 695 }
657   -
  696 +
658 697 $this->setStatus(self::STATUS_CREATED);
659 698 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $cmisObjectProperties['cmis:objectId'], 'POST');
660 699  
... ... @@ -675,17 +714,17 @@ class KT_cmis_atom_service_types extends KT_cmis_atom_service {
675 714 $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService);
676 715  
677 716 $types = $RepositoryService->getTypes($repositoryId);
678   -
  717 +
679 718 // hack for removing one level of access
680 719 $types = $types['results'];
681   -
  720 +
682 721 $type = ((empty($this->params[0])) ? 'all' : $this->params[0]);
683 722 $feed = KT_cmis_atom_service_helper::getTypeFeed($type, $types);
684 723  
685 724 // Expose the responseFeed
686 725 $this->responseFeed = $feed;
687 726 }
688   -
  727 +
689 728 }
690 729  
691 730 /**
... ...
webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php
... ... @@ -7,7 +7,7 @@ class KT_cmis_atom_service_helper {
7 7  
8 8 public static $ktapi = null;
9 9 public static $repositoryId = null;
10   -
  10 +
11 11 /**
12 12 * Helper function to set internal repository id
13 13 *
... ... @@ -18,16 +18,16 @@ class KT_cmis_atom_service_helper {
18 18 if (is_null($RepositoryService)) {
19 19 $RepositoryService = new KTRepositoryService();
20 20 }
21   -
  21 +
22 22 $repositories = $RepositoryService->getRepositories();
23   -
  23 +
24 24 // hack for removing one level of access
25 25 $repositories = $repositories['results'];
26   -
  26 +
27 27 // TODO handle multiple repositories
28   - self::$repositoryId = $repositories[0]['repositoryId'];
  28 + self::$repositoryId = $repositories[0]['repositoryId'];
29 29 }
30   -
  30 +
31 31 /**
32 32 * Helper function to fetch internal repository id
33 33 *
... ... @@ -40,11 +40,11 @@ class KT_cmis_atom_service_helper {
40 40 * @return string
41 41 */
42 42 static public function getRepositoryId(&$RepositoryService = null, $set = true)
43   - {
  43 + {
44 44 if (empty(self::$repositoryId) || $set) {
45 45 self::setRepositoryId($RepositoryService);
46 46 }
47   -
  47 +
48 48 return self::$repositoryId;
49 49 }
50 50  
... ... @@ -60,7 +60,7 @@ class KT_cmis_atom_service_helper {
60 60 static public function getObjectFeed(&$service, $ObjectService, $repositoryId, $objectId, $method = 'GET')
61 61 {
62 62 self::$repositoryId = $repositoryId;
63   -
  63 +
64 64 $serviceType = $service->getServiceType();
65 65 $response = $ObjectService->getProperties($repositoryId, $objectId, false, false);
66 66  
... ... @@ -70,7 +70,7 @@ class KT_cmis_atom_service_helper {
70 70  
71 71 $cmisEntry = $response['results'];
72 72 $response = null;
73   -
  73 +
74 74 // POST/PWC responses only send back an entry, not a feed
75 75 if (($serviceType == 'PWC') || ($method == 'POST')) {
76 76 if ($method == 'POST') {
... ... @@ -88,10 +88,10 @@ class KT_cmis_atom_service_helper {
88 88  
89 89 if ($serviceType == 'PWC') $pwc = true; else $pwc = false;
90 90 KT_cmis_atom_service_helper::createObjectEntry($response, $cmisEntry, $cmisEntry['properties']['parentId']['value'], $pwc, $method);
91   -
  91 +
92 92 return $response;
93 93 }
94   -
  94 +
95 95 static public function createObjectFeed(&$feed, $entries, $folderName)
96 96 {
97 97 foreach($entries as $cmisEntry) {
... ... @@ -109,10 +109,10 @@ class KT_cmis_atom_service_helper {
109 109 * @param $method The request method used (POST/GET/...)
110 110 */
111 111 static public function createObjectEntry(&$feed, $cmisEntry, $parent, $pwc = false, $method = 'GET')
112   - {
  112 + {
113 113 $workspace = $feed->getWorkspace();
114 114  
115   - // create entry
  115 + // create entry
116 116 $entry = $feed->newEntry();
117 117  
118 118 // When request is a POST we will be returning only an object entry, not a full feed, and so this belongs here
... ... @@ -124,10 +124,10 @@ class KT_cmis_atom_service_helper {
124 124 $entry->appendChild($feed->newAttr('xmlns:cmis', 'http://docs.oasis-open.org/ns/cmis/core/200908/'));
125 125 $entry->appendChild($feed->newAttr('xmlns:cmisra', 'http://docs.oasis-open.org/ns/cmis/restatom/200908/'));
126 126 }
127   -
  127 +
128 128 self::createObjectEntryContent($entry, $feed, $workspace, $cmisEntry, $parent, $pwc, $method);
129 129 }
130   -
  130 +
131 131 /**
132 132 * Creates an AtomPub child feed for a CMIS entry and adds it to the supplied entry
133 133 *
... ... @@ -152,15 +152,15 @@ class KT_cmis_atom_service_helper {
152 152 // which does not directly support nesting - attempting to create a new feed and append it within the outer
153 153 // feed resulted in an empty cmisra:children node, so this approach was substituted
154 154 static public function createChildObjectEntry(&$childrenFeed, $cmisEntry, $workspace, $feed, $folderNam)
155   - {
  155 + {
156 156 $type = strtolower($cmisEntry['properties']['objectTypeId']['value']);
157   -
  157 +
158 158 // create entry
159 159 $entry = $feed->newElement('entry');
160 160 self::createObjectEntryContent($entry, $feed, $workspace, $cmisEntry);//, $parent, $pwc, $method);
161 161 $childrenFeed->appendChild($entry);
162 162 }
163   -
  163 +
164 164 /**
165 165 * Creates the actual object entry: this is shared between other functions which require this content
166 166 *
... ... @@ -174,59 +174,59 @@ class KT_cmis_atom_service_helper {
174 174 static public function createObjectEntryContent($entry, &$feed, $workspace, $cmisEntry, $parent = '', $pwc = false, $method = 'GET')
175 175 {
176 176 $type = $cmisEntry['properties']['objectTypeId']['value'];
177   -
  177 +
178 178 // TODO dynamic actual creator name
179 179 $responseElement = $feed->newField('author');
180 180 $element = $feed->newField('name', 'admin', $responseElement);
181 181 $entry->appendChild($responseElement);
182   -
  182 +
183 183 $typeString = str_replace('cmis:', '', $type);
184   -
  184 +
185 185 if (!empty($cmisEntry['properties']['contentStreamLength']['value']))
186 186 {
187 187 $field = $feed->newElement('content');
188 188 $field->appendChild($feed->newAttr('type', $cmisEntry['properties']['contentStreamMimeType']['value']));
189   - $field->appendChild($feed->newAttr('src', CMIS_APP_BASE_URI . $workspace . '/' . $typeString
190   - . '/' . $cmisEntry['properties']['objectId']['value']
191   - . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
  189 + $field->appendChild($feed->newAttr('src', CMIS_APP_BASE_URI . $workspace . '/' . $typeString
  190 + . '/' . $cmisEntry['properties']['objectId']['value']
  191 + . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
192 192 $entry->appendChild($field);
193 193 }
194   -
195   - // content & id tags
  194 +
  195 + // content & id tags
196 196 $id = $cmisEntry['properties']['objectId']['value'];
197 197 $feed->newField('id', 'urn:uuid:' . $id, $entry);
198 198  
199 199 // links
200 200 $link = $feed->newElement('link');
201 201 $link->appendChild($feed->newAttr('rel', 'self'));
202   - $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/'
203   - . (!$pwc ? $typeString : 'pwc') . '/'
204   - . $cmisEntry['properties']['objectId']['value']));
  202 + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/'
  203 + . (!$pwc ? $typeString : 'pwc') . '/'
  204 + . $cmisEntry['properties']['objectId']['value']));
205 205 $entry->appendChild($link);
206 206  
207 207 $link = $feed->newElement('link');
208 208 $link->appendChild($feed->newAttr('rel', 'edit'));
209   - $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString
210   - . '/' . $cmisEntry['properties']['objectId']['value']));
  209 + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString
  210 + . '/' . $cmisEntry['properties']['objectId']['value']));
211 211 $entry->appendChild($link);
212   -
213   - if ((strtolower($cmisEntry['properties']['objectTypeId']['value']) == 'cmis:document')
214   - && (!empty($cmisEntry['properties']['contentStreamLength']['value'])))
  212 +
  213 + if ((strtolower($cmisEntry['properties']['objectTypeId']['value']) == 'cmis:document')
  214 + && (!empty($cmisEntry['properties']['contentStreamLength']['value'])))
215 215 {
216 216 $link = $feed->newElement('link');
217 217 $link->appendChild($feed->newAttr('rel', 'edit-media'));
218 218 $link->appendChild($feed->newAttr('type', $cmisEntry['properties']['contentStreamMimeType']['value']));
219   - $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString
220   - . '/' . $cmisEntry['properties']['objectId']['value']
221   - . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
  219 + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString
  220 + . '/' . $cmisEntry['properties']['objectId']['value']
  221 + . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
222 222 $entry->appendChild($link);
223 223  
224 224 $link = $feed->newElement('link');
225 225 $link->appendChild($feed->newAttr('rel', 'enclosure'));
226 226 $link->appendChild($feed->newAttr('type', $cmisEntry['properties']['contentStreamMimeType']['value']));
227   - $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString
228   - . '/' . $cmisEntry['properties']['objectId']['value']
229   - . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
  227 + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString
  228 + . '/' . $cmisEntry['properties']['objectId']['value']
  229 + . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
230 230 $entry->appendChild($link);
231 231 }
232 232  
... ... @@ -235,7 +235,7 @@ class KT_cmis_atom_service_helper {
235 235 $link = $feed->newElement('link');
236 236 $link->appendChild($feed->newAttr('rel', 'http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions'));
237 237 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString . '/'
238   - . $cmisEntry['properties']['objectId']['value'] . '/allowableactions'));
  238 + . $cmisEntry['properties']['objectId']['value'] . '/allowableactions'));
239 239 $entry->appendChild($link);
240 240  
241 241 // according to spec this MUST be present, but spec says that links for function which are not supported
... ... @@ -243,12 +243,12 @@ class KT_cmis_atom_service_helper {
243 243 $link = $feed->newElement('link');
244 244 $link->appendChild($feed->newAttr('rel', 'http://docs.oasis-open.org/ns/cmis/link/200908/relationships'));
245 245 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString . '/'
246   - . $cmisEntry['properties']['objectId']['value'] . '/rels'));
  246 + . $cmisEntry['properties']['objectId']['value'] . '/rels'));
247 247 $entry->appendChild($link);
248   -
  248 +
249 249 // if there is no parent or parent is 0, do not add the parent link
250 250 // also if this is specifically the root folder, do not add the parent link
251   -// if (!empty($cmisEntry['properties']['parentId']['value']) && !CMISUtil::isRootFolder(self::$repositoryId, $cmisEntry['properties']['objectId']['value']))
  251 + // if (!empty($cmisEntry['properties']['parentId']['value']) && !CMISUtil::isRootFolder(self::$repositoryId, $cmisEntry['properties']['objectId']['value']))
252 252  
253 253 if (!CMISUtil::isRootFolder(self::$repositoryId, $cmisEntry['properties']['objectId']['value'], self::$ktapi))
254 254 {
... ... @@ -256,7 +256,7 @@ class KT_cmis_atom_service_helper {
256 256 $link = $feed->newElement('link');
257 257 $link->appendChild($feed->newAttr('rel', 'up'));
258 258 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/folder/'
259   - . $cmisEntry['properties']['parentId']['value']));
  259 + . $cmisEntry['properties']['parentId']['value']));
260 260 $entry->appendChild($link);
261 261 }
262 262  
... ... @@ -266,18 +266,18 @@ class KT_cmis_atom_service_helper {
266 266 $link = $feed->newElement('link');
267 267 $link->appendChild($feed->newAttr('rel', 'down'));
268 268 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/'
269   - . $typeString
270   - . '/' . $cmisEntry['properties']['objectId']['value']
271   - . '/children'));
  269 + . $typeString
  270 + . '/' . $cmisEntry['properties']['objectId']['value']
  271 + . '/children'));
272 272 $entry->appendChild($link);
273 273 $link = $feed->newElement('link');
274 274 $link->appendChild($feed->newAttr('rel', 'down'));
275 275 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/'
276   - . $typeString
277   - . '/' . $cmisEntry['properties']['objectId']['value']
278   - . '/descendants'));
  276 + . $typeString
  277 + . '/' . $cmisEntry['properties']['objectId']['value']
  278 + . '/descendants'));
279 279 $entry->appendChild($link);
280   -
  280 +
281 281 // TODO add folder tree link when we have folder tree implemented
282 282 // this will probably use (much) the same code as the folder children functionality
283 283 }
... ... @@ -290,9 +290,9 @@ class KT_cmis_atom_service_helper {
290 290 $link = $feed->newElement('link');
291 291 $link->appendChild($feed->newAttr('rel', 'stream'));
292 292 $link->appendChild($feed->newAttr('type', $cmisEntry['properties']['contentStreamMimeType']['value']));
293   - $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
294   - . '/' . $cmisEntry['properties']['objectId']['value']
295   - . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
  293 + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
  294 + . '/' . $cmisEntry['properties']['objectId']['value']
  295 + . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
296 296 $entry->appendChild($link);
297 297 }
298 298  
... ... @@ -303,24 +303,24 @@ class KT_cmis_atom_service_helper {
303 303 {
304 304 $link = $feed->newElement('link');
305 305 $link->appendChild($feed->newAttr('rel', 'pwc'));
306   - $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
307   - . '/' . $cmisEntry['properties']['objectId']['value']
308   - . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
  306 + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
  307 + . '/' . $cmisEntry['properties']['objectId']['value']
  308 + . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
309 309 $entry->appendChild($link);
310 310 $link = $feed->newElement('link');
311 311 $link->appendChild($feed->newAttr('rel', 'source'));
312   - $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
313   - . '/' . $cmisEntry['properties']['objectId']['value']
314   - . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
  312 + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
  313 + . '/' . $cmisEntry['properties']['objectId']['value']
  314 + . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
315 315 $entry->appendChild($link);
316 316 }
317 317  
318   -// $link = $feed->newElement('link');
319   -// $link->appendChild($feed->newAttr('rel', 'stream'));
320   -// $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
321   -// . '/' . $cmisEntry['properties']['objectId']['value']
322   -// . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
323   - }
  318 + // $link = $feed->newElement('link');
  319 + // $link->appendChild($feed->newAttr('rel', 'stream'));
  320 + // $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
  321 + // . '/' . $cmisEntry['properties']['objectId']['value']
  322 + // . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
  323 + }
324 324  
325 325 $link = $feed->newElement('link');
326 326 $link->appendChild($feed->newAttr('rel', 'describedby'));
... ... @@ -342,26 +342,26 @@ class KT_cmis_atom_service_helper {
342 342 $objectElement = $feed->newElement('cmisra:object');
343 343 $objectElement->appendChild(self::createEntryPropertiesElement($feed, $cmisEntry['properties']));
344 344 $entry->appendChild($objectElement);
345   -
  345 +
346 346 // TODO check determination of when to add app:edited tag
347   -// if ($method == 'POST') {
348   - $entry->appendChild($feed->newElement('app:edited', self::formatDatestamp()));
349   -// }
  347 + // if ($method == 'POST') {
  348 + $entry->appendChild($feed->newElement('app:edited', self::formatDatestamp()));
  349 + // }
350 350  
351 351 // TODO pathSegment entry
352   -
  352 +
353 353 // deal with child objects
354 354 if (isset($cmisEntry['children'])) {
355 355 // add children node and fill with child entries
356 356 $childrenFeed = $feed->newElement('feed');
357 357 self::createObjectChildrenFeed($childrenFeed, $cmisEntry['children'], $workspace, $feed, '' /*folderName not passed through*/);
358   -
  358 +
359 359 $childrenElement = $feed->newElement('cmisra:children');
360 360 $childrenElement->appendChild($childrenFeed);
361 361 $entry->appendChild($childrenElement);
362 362 }
363 363 }
364   -
  364 +
365 365 /**
366 366 * Shared function for creating an object properties node
367 367 *
... ... @@ -376,7 +376,7 @@ class KT_cmis_atom_service_helper {
376 376 foreach($properties as $propertyName => $property)
377 377 {
378 378 $propElement = $feed->newElement('cmis:' . $property['type']);
379   -// $propElement->appendChild($feed->newAttr('localName', 'rep-cmis:' . $propertyName));
  379 + // $propElement->appendChild($feed->newAttr('localName', 'rep-cmis:' . $propertyName));
380 380 $propElement->appendChild($feed->newAttr('propertyDefinitionId', 'cmis:' . $propertyName));
381 381 if (!empty($property['value']))
382 382 {
... ... @@ -387,7 +387,7 @@ class KT_cmis_atom_service_helper {
387 387 }
388 388 $propertiesElement->appendChild($propElement);
389 389 }
390   -
  390 +
391 391 return $propertiesElement;
392 392 }
393 393  
... ... @@ -419,12 +419,12 @@ class KT_cmis_atom_service_helper {
419 419 //Create a new response feed
420 420 $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI);
421 421 $workspace = $feed->getWorkspace();
422   -
  422 +
423 423 $feed->newField('title', $typesHeading, $feed);
424 424 $feed->newField('id', 'urn:uuid:' . $typesString, $feed);
425 425  
426 426 // TODO set page number correctly - to be done when we support paging the the API
427   -
  427 +
428 428 // author
429 429 // TODO generate this dynamically (based on???)\
430 430 $feedElement = $feed->newField('author');
... ... @@ -434,7 +434,7 @@ class KT_cmis_atom_service_helper {
434 434 foreach($types as $type)
435 435 {
436 436 $entry = $feed->newEntry();
437   -
  437 +
438 438 $feedElement = $feed->newField('author');
439 439 $element = $feed->newField('name', 'admin', $feedElement);
440 440 $entry->appendChild($feedElement);
... ... @@ -442,7 +442,7 @@ class KT_cmis_atom_service_helper {
442 442 $entry->appendChild($feedElement);
443 443  
444 444 $feed->newField('id', 'urn:uuid:type-' . $type['baseId'], $feed);
445   -
  445 +
446 446 // links
447 447 $link = $feed->newElement('link');
448 448 $link->appendChild($feed->newAttr('rel','self'));
... ... @@ -459,11 +459,11 @@ class KT_cmis_atom_service_helper {
459 459 $link->appendChild($feed->newAttr('rel','repository'));
460 460 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . '/servicedocument'));
461 461 $entry->appendChild($link);
462   -
  462 +
463 463 $entry->appendChild($feed->newElement('summary', 'Summary for ' . $type['baseId'] . ' type'));
464 464 $entry->appendChild($feed->newElement('title', $type['baseId']));
465 465 $entry->appendChild($feed->newElement('updated', self::formatDatestamp()));
466   -
  466 +
467 467 $objectElement = $feed->newElement('cmisra:type');
468 468 foreach($type as $property => $value) {
469 469 $feed->newField('cmis:' . $property, CMISUtil::boolToString($value), $objectElement);
... ... @@ -478,7 +478,7 @@ class KT_cmis_atom_service_helper {
478 478 {
479 479 $service->setStatus($status);
480 480 $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI);
481   -
  481 +
482 482 $feed->newField('title', 'Error: ' . $status, $feed);
483 483 $entry = $feed->newEntry();
484 484 $feed->newField('error', $message, $entry);
... ... @@ -493,31 +493,49 @@ class KT_cmis_atom_service_helper {
493 493 * @param object $ktapi KTAPI instance
494 494 */
495 495 // TODO make this much more efficient than this method
496   - static public function getFolderId($path, &$ktapi)
  496 + static public function getObjectId($path, &$ktapi, $shift = true)
497 497 {
498   - // lose first item
499   - array_shift($path);
  498 + // lose first item, if not specified to keep ($shift == false)
  499 + // NOTE the shift was for the way info comes from the Drupal module, which may now have changed
  500 + if ($shift) {
  501 + array_shift($path);
  502 + }
500 503  
  504 + // we always start at the root
  505 + $lastFolderId = $objectId = 1;
501 506 $numQ = count($path);
502   - $numFolders = $numQ;
503   - $folderId = 1;
504   -
  507 + $numObjects = $numQ;
505 508 $start = 0;
506   - while($start < $numFolders)
  509 + $type = FOLDER;
  510 +
  511 + while($start < $numObjects)
507 512 {
508   - $name = $path[$numQ-$numFolders+$start];
509   - // fix for possible url encoding issue
  513 + $name = $path[$numQ - $numObjects + $start];
  514 + // fix for possible url encoding issue - this was for the Drupal code and hopefully one day we can remove it
510 515 $name = str_replace('%2520', '%20', $name);
511 516  
512   - $folderName = urldecode($name);
513   - $folder = $ktapi->get_folder_by_name($folderName, $folderId);
514   - $folderId = $folder->get_folderid();
  517 + $objectName = urldecode($name);
  518 + // try to get a folder by that name
  519 + $object = $ktapi->get_folder_by_name($objectName, $lastFolderId);
  520 + if (PEAR::isError($object)) {
  521 + // probably not a folder, so let's try for a document by that name
  522 + $object = $ktapi->get_document_detail_by_name($lastFolderId, $objectName);
  523 + $objectId = $object['results']['document_id'];
  524 + // this must be the end (can't have sub-documents or sub-folders within a document
  525 + $type = DOCUMENT;
  526 + break;
  527 + }
  528 + else {
  529 + $objectId = $object->get_folderid();
  530 + $lastFolderId = $objectId;
  531 + }
  532 +
515 533 ++$start;
516 534 }
517   -
518   - return CMISUtil::encodeObjectId(FOLDER, $folderId);
  535 +
  536 + return CMISUtil::encodeObjectId($type, $objectId);
519 537 }
520   -
  538 +
521 539 static public function getCmisObjectProperties(&$xml)
522 540 {
523 541 $xmlReader = new XMLReader();
... ... @@ -551,10 +569,10 @@ class KT_cmis_atom_service_helper {
551 569 }
552 570 }
553 571 }
554   -
  572 +
555 573 return $cmisObjectPropertiesCollection;
556 574 }
557   -
  575 +
558 576 static public function getCmisContent(&$xml)
559 577 {
560 578 $xmlReader = new XMLReader();
... ... @@ -577,14 +595,14 @@ class KT_cmis_atom_service_helper {
577 595 $cmisObjectContent[$cmisContentProperty] = $xmlReader->value;
578 596 }
579 597 }
580   -
  598 +
581 599 return $cmisObjectContent;
582 600 }
583   -
  601 +
584 602 static public function getAtomValues(&$xml, $tag)
585 603 {
586 604 $returnTag = null;
587   -
  605 +
588 606 $xmlReader = new XMLReader();
589 607 $xmlReader->XML($xml);
590 608 $foundTag = false;
... ... @@ -603,14 +621,14 @@ class KT_cmis_atom_service_helper {
603 621 }
604 622 }
605 623 }
606   -
  624 +
607 625 return $returnTag;
608 626 }
609 627  
610 628 static public function getCmisPropertiesOld($xmlArray)
611 629 {
612 630 $properties = array();
613   -
  631 +
614 632 // find cmisra:object tag
615 633 $baseCmisObject = KT_cmis_atom_service_helper::findTag('cmisra:object', $xmlArray, null, false);
616 634 if(count($baseCmisObject) <= 0)
... ... @@ -618,7 +636,7 @@ class KT_cmis_atom_service_helper {
618 636 $entryObject = KT_cmis_atom_service_helper::findTag('entry', $xmlArray, null, false);
619 637 $baseCmisObject = KT_cmis_atom_service_helper::findTag('cmisra:object', $entryObject['@children'], null, true);
620 638 }
621   -
  639 +
622 640 if(count($baseCmisObject) > 0)
623 641 {
624 642 foreach($baseCmisObject[0]['@children'] as $key => $childElement)
... ... @@ -629,8 +647,8 @@ class KT_cmis_atom_service_helper {
629 647 {
630 648 foreach($cmisPropertyDefinition as $propertyType => $propertyDefinition)
631 649 {
632   - $properties[$propertyDefinition['@attributes']['cmis:name']]
633   - = $propertyDefinition['@children']['cmis:value'][0]['@value'];
  650 + $properties[$propertyDefinition['@attributes']['cmis:name']]
  651 + = $propertyDefinition['@children']['cmis:value'][0]['@value'];
634 652 }
635 653 }
636 654 }
... ... @@ -643,9 +661,9 @@ class KT_cmis_atom_service_helper {
643 661 static public function getAtomValuesOld($xmlArray, $tag)
644 662 {
645 663 if (!is_null($xmlArray['atom:'.$tag]))
646   - return $xmlArray['atom:'.$tag][0]['@value'];
  664 + return $xmlArray['atom:'.$tag][0]['@value'];
647 665 else if (!is_null($xmlArray[$tag]))
648   - return $xmlArray[$tag][0]['@value'];
  666 + return $xmlArray[$tag][0]['@value'];
649 667  
650 668 return null;
651 669 }
... ... @@ -655,23 +673,23 @@ class KT_cmis_atom_service_helper {
655 673 *
656 674 * @return object
657 675 */
658   - public static function getKt()
  676 + public static function getKt()
659 677 {
660   - if(!isset(self::$ktapi))
  678 + if(!isset(self::$ktapi))
661 679 {
662   - self::$ktapi = new KTAPI();
663   - $active = self::$ktapi->get_active_session(session_id());
664   -
665   - if (PEAR::isError($active))
666   - {
667   - // invoke auth code, session must be restarted
668   - if(!KT_atom_HTTPauth::isLoggedIn()) {
669   - KT_atom_HTTPauth::login('KnowledgeTree DMS', 'You must authenticate to enter this realm');
670   - }
671   - }
672   - }
673   - return self::$ktapi;
674   - }
  680 + self::$ktapi = new KTAPI();
  681 + $active = self::$ktapi->get_active_session(session_id());
  682 +
  683 + if (PEAR::isError($active))
  684 + {
  685 + // invoke auth code, session must be restarted
  686 + if(!KT_atom_HTTPauth::isLoggedIn()) {
  687 + KT_atom_HTTPauth::login('KnowledgeTree DMS', 'You must authenticate to enter this realm');
  688 + }
  689 + }
  690 + }
  691 + return self::$ktapi;
  692 + }
675 693  
676 694 // TODO adjust for time zones?
677 695 static public function formatDatestamp($time = null)
... ... @@ -679,7 +697,7 @@ class KT_cmis_atom_service_helper {
679 697 if (is_null($time)) $time = time();
680 698 return date('Y-m-d H:i:s', $time);
681 699 }
682   -
  700 +
683 701 /**
684 702 * Fetches the document content stream for internal use
685 703 *
... ... @@ -693,12 +711,12 @@ class KT_cmis_atom_service_helper {
693 711 if ($response['status_code'] == 1) {
694 712 return null;
695 713 }
696   -
  714 +
697 715 $contentStream = $ObjectService->getContentStream($repositoryId, $service->params[0]);
698   -
  716 +
699 717 // hack for removing one level of access
700 718 $contentStream = $contentStream['results'];
701   -
  719 +
702 720 return $contentStream;
703 721 }
704 722 /**
... ... @@ -719,41 +737,41 @@ class KT_cmis_atom_service_helper {
719 737 else {
720 738 $response = $response['results'];
721 739 }
722   -
  740 +
723 741 // TODO also check If-Modified-Since?
724   -// $service->headers['If-Modified-Since'] => 2009-07-24 17:16:54
  742 + // $service->headers['If-Modified-Since'] => 2009-07-24 17:16:54
725 743  
726 744 $service->setContentDownload(true);
727 745 $eTag = md5($response['properties']['lastModificationDate']['value'] . $response['properties']['contentStreamLength']['value']);
728   -
  746 +
729 747 if ($service->headers['If-None-Match'] == $eTag)
730 748 {
731 749 $service->setStatus(KT_cmis_atom_service::STATUS_NOT_MODIFIED);
732 750 $service->setContentDownload(false);
733 751 return null;
734 752 }
735   -
  753 +
736 754 $contentStream = $ObjectService->getContentStream($repositoryId, $service->params[0]);
737   -
  755 +
738 756 // hack for removing one level of access
739 757 $contentStream = $contentStream['results'];
740   -
  758 +
741 759 // headers specific to output
742 760 $service->setEtag($eTag);
743 761 $service->setHeader('Last-Modified', $response['properties']['lastModificationDate']['value']);
744 762  
745 763 if (!empty($response['properties']['contentStreamMimeType']['value'])) {
746   - $service->setHeader('Content-type', $response['properties']['contentStreamMimeType']['value'] . ';charset=utf-8');
  764 + $service->setHeader('Content-type', $response['properties']['contentStreamMimeType']['value'] . ';charset=utf-8');
747 765 }
748 766 else {
749   - $service->setHeader('Content-type', 'text/plain;charset=utf-8');
  767 + $service->setHeader('Content-type', 'text/plain;charset=utf-8');
750 768 }
751   -
  769 +
752 770 $service->setHeader('Content-Disposition', 'attachment;filename="' . $response['properties']['contentStreamFilename']['value'] . '"');
753   - $service->setHeader('Content-Length', $response['properties']['contentStreamLength']['value']);
  771 + $service->setHeader('Content-Length', $response['properties']['contentStreamLength']['value']);
754 772 $service->setOutput($contentStream);
755 773 }
756   -
  774 +
757 775 //TODO: Add key information to be able to find the same tag in the original struct (MarkH)
758 776 static public function findTag($tagName=NULL,$xml=array(),$tagArray=NULL,$deep=false)
759 777 {
... ... @@ -773,11 +791,11 @@ class KT_cmis_atom_service_helper {
773 791 //TODO: this is very ugly. Change it. (MarkH)
774 792 return self::rebaseArray($tagArray);
775 793 }
776   -
  794 +
777 795 static public function rebaseArray($arr=array()){
778 796 //Force Array
779 797 $arr=is_array($arr)?$arr:array();
780   -
  798 +
781 799 //Rebase recursively
782 800 if(count($arr)===1)$arr=self::rebaseArray($arr[0]);
783 801 return $arr;
... ...
webservice/atompub/cmis/index.php
... ... @@ -115,6 +115,9 @@ if ($workspace != &#39;servicedocument&#39;)
115 115 $APP->registerService('dms', 'type', 'KT_cmis_atom_service_type', 'Object Type Entry', null, 'type');
116 116 $APP->registerService('dms', 'document', 'KT_cmis_atom_service_document', 'Document Entry', null, 'document');
117 117 $APP->registerService('dms', 'pwc', 'KT_cmis_atom_service_pwc', 'Private Working Copy', null, 'pwc');
  118 + $APP->registerService('dms', 'objectbyid', 'KT_cmis_atom_service_objectbyid', 'Object By Id', null, 'objectbyid');
  119 + $APP->registerService('dms', 'objectbypath', 'KT_cmis_atom_service_objectbypath', 'Object By Path', null, 'objectbypath');
  120 + $APP->registerService('dms', 'typebyid', 'KT_cmis_atom_service_type', 'Type By Id', null, 'typebyid');
118 121 }
119 122  
120 123 //Execute the current url/header request
... ...
webservice/classes/atompub/cmis/KT_cmis_atom_server.inc.php
... ... @@ -69,21 +69,18 @@ class KT_cmis_atom_server extends KT_atom_server {
69 69 //Creating the Default Workspace for use with standard atomPub Clients
70 70 $ws = $service->newWorkspace();
71 71  
72   - $hadDetail=false;
73   - if(isset($this->workspaceDetail[$workspace]))
74   - {
75   - if(is_array($this->workspaceDetail[$workspace]))
76   - {
77   - foreach ($this->workspaceDetail[$workspace] as $wsTag=>$wsValue)
78   - {
79   - $ws->appendChild($service->newElement($wsTag,$wsValue));
  72 + $hadDetail = false;
  73 + if(isset($this->workspaceDetail[$workspace])) {
  74 + if(is_array($this->workspaceDetail[$workspace])) {
  75 + foreach ($this->workspaceDetail[$workspace] as $wsTag => $wsValue){
  76 + $ws->appendChild($service->newElement($wsTag, $wsValue));
80 77 $hadDetail=true;
81 78 }
82 79 }
83 80 }
84 81  
85 82 if(!$hadDetail) {
86   - $ws->appendChild($service->newElement('atom:title',$workspace));
  83 + $ws->appendChild($service->newElement('atom:title', $workspace));
87 84 }
88 85  
89 86 $ws->appendChild($service->newAttr('cmis:repositoryRelationship', $this->repositoryInfo['repositoryRelationship']));
... ... @@ -99,11 +96,9 @@ class KT_cmis_atom_server extends KT_atom_server {
99 96 if (!is_array($repoData)) {
100 97 $element->appendChild($service->newElement('cmis:' . $key, $repoData));
101 98 }
102   - else
103   - {
  99 + else {
104 100 $elementSub = $service->newElement('cmis:' . $key);
105   - foreach($repoData as $key2 => $data)
106   - {
  101 + foreach($repoData as $key2 => $data) {
107 102 $elementSub->appendChild($service->newElement('cmis:' . $key2, CMISUtil::boolToString($data)));
108 103 }
109 104 $element->appendChild($elementSub);
... ... @@ -111,21 +106,24 @@ class KT_cmis_atom_server extends KT_atom_server {
111 106 }
112 107 $ws->appendChild($element);
113 108  
  109 + // collections
  110 + // TODO check collectionType usage against spec
114 111 foreach($collection as $serviceName => $serviceInstance)
115 112 {
116 113 foreach($serviceInstance as $instance)
117 114 {
118 115 $collectionStr = CMIS_APP_BASE_URI . $workspace . '/' . $serviceName . '/'
119 116 . (is_array($instance['parameters']) ? implode('/', $instance['parameters']).'/' : '');
  117 + // FIXME? do we need to return the value from the function?
120 118 $col = $service->newCollection($collectionStr, $instance['title'], $instance['collectionType'], $instance['accept'], $ws);
121 119 }
122 120 }
  121 +
  122 + // uri templates - getObjectById, getObjectByPath, getTypeById
  123 + $ws->appendChild($service->uriTemplate('objectbyid', $workspace));
  124 + $ws->appendChild($service->uriTemplate('objectbypath', $workspace));
  125 + $ws->appendChild($service->uriTemplate('typebyid', $workspace));
123 126 }
124   -
125   -// ob_start();
126   -// readfile('C:\Users\Paul\Documents\Downloads\cmis_mod_kt.xml');
127   -// $this->output = ob_get_contents();
128   -// ob_end_clean();
129 127  
130 128 $this->output = $service->getAPPdoc();
131 129 }
... ...
webservice/classes/atompub/cmis/KT_cmis_atom_serviceDoc.inc.php
... ... @@ -83,7 +83,7 @@ class KT_cmis_atom_serviceDoc extends KT_atom_serviceDoc {
83 83 $this->DOM->appendChild($this->service);
84 84 }
85 85  
86   - public function &newCollection($url = NULL, $title = NULL, $cmisCollectionType = NULL, $accept = null, &$ws = NULL)
  86 + public function newCollection($url = NULL, $title = NULL, $cmisCollectionType = NULL, $accept = null, &$ws = NULL)
87 87 {
88 88 $collection=$this->newElement('collection');
89 89 $collection->appendChild($this->newAttr('href', $url));
... ... @@ -93,8 +93,45 @@ class KT_cmis_atom_serviceDoc extends KT_atom_serviceDoc {
93 93 $collection->appendChild($this->newElement('accept', $accept));
94 94 }
95 95 if(isset($ws))$ws->appendChild($collection);
  96 +
  97 + // FIXME? do we need to return the value from the function if $ws is supplied?
96 98 return $collection;
97 99 }
  100 +
  101 + /**
  102 + * Creates the specified URI template within the AtomPub response
  103 + *
  104 + * @param string $templateType
  105 + * @param string $workspace
  106 + * @return string $uriTemplate
  107 + *
  108 + * NOTE not adding in all the arguments for optional functionality not supported, e.g. ACL/Policies/Relationships/Renditions;
  109 + * arguments for functionality which is non-optional (filters/allowableActions) are included but not yet supported
  110 + * by the API code
  111 + */
  112 + public function uriTemplate($templateType, $workspace)
  113 + {
  114 + $content = array('template' => CMIS_APP_BASE_URI . $workspace, 'mediatype' => 'application/atom+xml;type=entry');
  115 +
  116 + switch($templateType) {
  117 + case 'objectbyid':
  118 + $content['template'] .= '/objectbyid/{id}/{filter}/{includeAllowableActions}';
  119 + break;
  120 + case 'objectbypath':
  121 + $content['template'] .= '/objectbypath/{path}/{filter}/{includeAllowableActions}';
  122 + break;
  123 + case 'typebyid':
  124 + $content['template'] .= '/typebyid/{id}';
  125 + break;
  126 + }
  127 +
  128 + $uriTemplate = $this->newElement('cmisra:uritemplate');
  129 + $uriTemplate->appendChild($this->newElement('cmisra:template', $content['template']));
  130 + $uriTemplate->appendChild($this->newElement('cmisra:type', $content));
  131 + $uriTemplate->appendChild($this->newElement('cmisra:mediatype', $content['mediatype']));
  132 +
  133 + return $uriTemplate;
  134 + }
98 135  
99 136 }
100 137  
... ...