Commit f3438102dd2a8d7b0796e0cfdee57224bab544a3

Authored by Paul Barrett
1 parent c8de4448

Beginnings of link media types and complete atom node data

Story ID:2713417. CMIS working with PHP client

Committed by: Paul Barrett
webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 2
3 /** 3 /**
4 * Any feed must be a valid atom Feed document and conform to the guidelines below: 4 * Any feed must be a valid atom Feed document and conform to the guidelines below:
5 -1. Updated will be the latest time the folder or its contents was updated. If unknown by the underlying repository, it should be the current time. 5 +1. Updated will be the latest time the folder or its contents was updated. If unknown by the underlying repository, it MUST be the current time.
6 2. Author/name will be the CMIS property createdBy 6 2. Author/name will be the CMIS property createdBy
7 3. Title will be the CMIS property name 7 3. Title will be the CMIS property name
8 4. App:edited will be the CMIS property lastModifiedDate 8 4. App:edited will be the CMIS property lastModifiedDate
@@ -145,14 +145,12 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { @@ -145,14 +145,12 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
145 $folderId = $this->params[0]; 145 $folderId = $this->params[0];
146 } 146 }
147 147
148 - if (!empty($this->params[1]) && (($this->params[1] == 'children') || ($this->params[1] == 'descendants')))  
149 - { 148 + $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt());
  149 + if (!empty($this->params[1]) && (($this->params[1] == 'children') || ($this->params[1] == 'descendants'))) {
150 $NavigationService = new KTNavigationService(KT_cmis_atom_service_helper::getKt()); 150 $NavigationService = new KTNavigationService(KT_cmis_atom_service_helper::getKt());
151 - $feed = $this->getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $this->params[1]); 151 + $feed = $this->getFolderChildrenFeed($NavigationService, $ObjectService, $repositoryId, $folderId, $folderName, $this->params[1]);
152 } 152 }
153 - else  
154 - {  
155 - $ObjectService = new KTObjectService(KT_cmis_atom_service_helper::getKt()); 153 + else {
156 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $folderId); 154 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $folderId);
157 } 155 }
158 156
@@ -305,6 +303,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { @@ -305,6 +303,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
305 $this->setStatus(self::STATUS_SERVER_ERROR); 303 $this->setStatus(self::STATUS_SERVER_ERROR);
306 304
307 $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI); 305 $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI);
  306 + // FIXME? this should perhaps use a different status code?
308 $feed->newField('title', 'Error: Failed to delete all objects in tree: ' . self::STATUS_SERVER_ERROR, $feed); 307 $feed->newField('title', 'Error: Failed to delete all objects in tree: ' . self::STATUS_SERVER_ERROR, $feed);
309 308
310 foreach($response as $failed) 309 foreach($response as $failed)
@@ -337,8 +336,17 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { @@ -337,8 +336,17 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
337 * @param string $feedType children or descendants 336 * @param string $feedType children or descendants
338 * @return string CMIS AtomPub feed 337 * @return string CMIS AtomPub feed
339 */ 338 */
340 - private function getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $feedType = 'children') 339 + private function getFolderChildrenFeed(&$NavigationService, &$ObjectService, $repositoryId, $folderId, $folderName, $feedType = 'children')
341 { 340 {
  341 + // fetch properties of parent folder for which children/descendants are being retrieved
  342 + try {
  343 + $rootProperties = $ObjectService->getProperties($repositoryId, $folderId);
  344 + }
  345 + catch (Exception $e) {
  346 + $this->responseFeed = KT_cmis_atom_service_helper::getErrorFeed($this, $this->getStatusCode($e), $e->getMessage());
  347 + return null;
  348 + }
  349 +
342 if ($feedType == 'children') { 350 if ($feedType == 'children') {
343 try { 351 try {
344 $entries = $NavigationService->getChildren($repositoryId, $folderId, false, false); 352 $entries = $NavigationService->getChildren($repositoryId, $folderId, false, false);
@@ -373,30 +381,39 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { @@ -373,30 +381,39 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
373 381
374 $feed->newField('title', $folderName . ' ' . ucwords($feedType), $feed); 382 $feed->newField('title', $folderName . ' ' . ucwords($feedType), $feed);
375 383
376 - // TODO dynamic?  
377 $feedElement = $feed->newField('author'); 384 $feedElement = $feed->newField('author');
378 - $element = $feed->newField('name', 'System', $feedElement); 385 + $element = $feed->newField('name', $rootProperties['properties']['createdBy']['value'], $feedElement);
379 $feed->appendChild($feedElement); 386 $feed->appendChild($feedElement);
380 387
381 // id 388 // id
382 $feed->newField('id', 'urn:uuid:' . $folderId . '-' . $feedType, $feed); 389 $feed->newField('id', 'urn:uuid:' . $folderId . '-' . $feedType, $feed);
383 390
384 - // TODO get actual most recent update time, only use current if no other available  
385 - $feed->newField('updated', KT_cmis_atom_service_helper::formatDatestamp(), $feed); 391 + $updated = null;
  392 + if ($rootProperties['properties']['lastModificationDate']['value'] != '0000-00-00 00:00:00') {
  393 + $updated = $rootProperties['properties']['lastModificationDate']['value'];
  394 + }
  395 + else if ($rootProperties['properties']['creationDate']['value'] != '0000-00-00 00:00:00') {
  396 + $updated = $rootProperties['properties']['creationDate']['value'];
  397 + }
  398 +
  399 + $feed->newField('updated', KT_cmis_atom_service_helper::formatDatestamp($updated), $feed);
386 400
387 $link = $feed->newElement('link'); 401 $link = $feed->newElement('link');
388 $link->appendChild($feed->newAttr('rel', 'self')); 402 $link->appendChild($feed->newAttr('rel', 'self'));
389 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/folder/' . $folderId . '/' . $feedType)); 403 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/folder/' . $folderId . '/' . $feedType));
390 $feed->appendChild($link); 404 $feed->appendChild($link);
391 405
  406 + // TODO this link must specify the workspace
392 $link = $feed->newElement('link'); 407 $link = $feed->newElement('link');
393 $link->appendChild($feed->newAttr('rel', 'service')); 408 $link->appendChild($feed->newAttr('rel', 'service'));
394 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . 'servicedocument')); 409 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . 'servicedocument'));
  410 + $link->appendChild($feed->newAttr('type', 'application/atomsvc+xml'));
395 $feed->appendChild($link); 411 $feed->appendChild($link);
396 412
397 $link = $feed->newElement('link'); 413 $link = $feed->newElement('link');
398 $link->appendChild($feed->newAttr('rel', 'via')); 414 $link->appendChild($feed->newAttr('rel', 'via'));
399 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/folder/' . $folderId)); 415 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/folder/' . $folderId));
  416 + $link->appendChild($feed->newAttr('type', 'application/atom+xml;type=entry'));
400 $feed->appendChild($link); 417 $feed->appendChild($link);
401 418
402 KT_cmis_atom_service_helper::createObjectFeed($feed, $entries, $folderName); 419 KT_cmis_atom_service_helper::createObjectFeed($feed, $entries, $folderName);
@@ -553,10 +570,10 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service { @@ -553,10 +570,10 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service {
553 $content = KT_cmis_atom_service_helper::getCmisContent($this->rawContent); 570 $content = KT_cmis_atom_service_helper::getCmisContent($this->rawContent);
554 // NOTE not sure about the text type, will need testing, most content will be base64 571 // NOTE not sure about the text type, will need testing, most content will be base64
555 $cmisContent = (isset($content['cmisra:base64']) 572 $cmisContent = (isset($content['cmisra:base64'])
556 - ? $content['cmisra:base64']  
557 - : ((isset($content['cmisra:text']))  
558 - ? $content['cmisra:text']  
559 - : null)); 573 + ? $content['cmisra:base64']
  574 + : ((isset($content['cmisra:text']))
  575 + ? $content['cmisra:text']
  576 + : null));
560 577
561 // if we haven't found it now, the hack begins - retrieve the EXISTING content and submit this as the contentStream 578 // if we haven't found it now, the hack begins - retrieve the EXISTING content and submit this as the contentStream
562 // this is needed because KnowledgeTree will not accept a checkin without a content stream but CMISSpaces (and possibly 579 // this is needed because KnowledgeTree will not accept a checkin without a content stream but CMISSpaces (and possibly
@@ -618,14 +635,14 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { @@ -618,14 +635,14 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
618 635
619 $feed->newField('title', 'Checked out Documents', $feed); 636 $feed->newField('title', 'Checked out Documents', $feed);
620 637
621 - // TODO dynamic? 638 + // Since checked out documents do not necessarily share the same creator, we use a default value
622 $feedElement = $feed->newField('author'); 639 $feedElement = $feed->newField('author');
623 - $element = $feed->newField('name', 'admin', $feedElement); 640 + $element = $feed->newField('name', 'Administrator', $feedElement);
624 $feed->appendChild($feedElement); 641 $feed->appendChild($feedElement);
625 642
626 $feed->appendChild($feed->newElement('id', 'urn:uuid:checkedout')); 643 $feed->appendChild($feed->newElement('id', 'urn:uuid:checkedout'));
627 644
628 - // TODO get actual most recent update time, only use current if no other available 645 + // Since checked out documents are not necessarily from a single folder, we don't know the time last updated, so we use current
629 $feed->appendChild($feed->newElement('updated', KT_cmis_atom_service_helper::formatDatestamp())); 646 $feed->appendChild($feed->newElement('updated', KT_cmis_atom_service_helper::formatDatestamp()));
630 647
631 $link = $feed->newElement('link'); 648 $link = $feed->newElement('link');
@@ -671,8 +688,8 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { @@ -671,8 +688,8 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
671 // in the helper code, but I don't feel that throwing an exception is necessary or always wanted; 688 // in the helper code, but I don't feel that throwing an exception is necessary or always wanted;
672 // alternative is to send the name of the Exception but not an instance, and do an is_a check on the other side, 689 // alternative is to send the name of the Exception but not an instance, and do an is_a check on the other side,
673 // but since it will only be needed to this and similar calls, it seems wasteful to do that for every other case 690 // but since it will only be needed to this and similar calls, it seems wasteful to do that for every other case
674 - $this->responseFeed = KT_cmis_atom_service_helper::getErrorFeed($this, $this->getStatusCode(new InvalidArgumentException()),  
675 - 'No object was specified for checkout'); 691 + $this->responseFeed = KT_cmis_atom_service_helper::getErrorFeed($this, $this->getStatusCode(new InvalidArgumentException()),
  692 + 'No object was specified for checkout');
676 return null; 693 return null;
677 } 694 }
678 695
@@ -683,7 +700,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { @@ -683,7 +700,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
683 $this->responseFeed = KT_cmis_atom_service_helper::getErrorFeed($this, $this->getStatusCode($e), $e->getMessage()); 700 $this->responseFeed = KT_cmis_atom_service_helper::getErrorFeed($this, $this->getStatusCode($e), $e->getMessage());
684 return null; 701 return null;
685 } 702 }
686 - 703 +
687 $this->setStatus(self::STATUS_CREATED); 704 $this->setStatus(self::STATUS_CREATED);
688 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $cmisObjectProperties['cmis:objectId'], 'POST'); 705 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $cmisObjectProperties['cmis:objectId'], 'POST');
689 706
@@ -776,6 +793,7 @@ class KT_cmis_atom_service_type extends KT_cmis_atom_service { @@ -776,6 +793,7 @@ class KT_cmis_atom_service_type extends KT_cmis_atom_service {
776 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . 'type/' . $this->params[0] . '/' . $this->params[1] . '?pageNo=1&pageSize=0')); 793 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . 'type/' . $this->params[0] . '/' . $this->params[1] . '?pageNo=1&pageSize=0'));
777 $link->appendChild($feed->newAttr('type', 'application/atom+xml;type=feed')); 794 $link->appendChild($feed->newAttr('type', 'application/atom+xml;type=feed'));
778 795
  796 + // Since types do not have associated dates, we don't know the time last updated, so we use current
779 $feed->newField('updated', KT_cmis_atom_service_helper::formatDatestamp(), $feed); 797 $feed->newField('updated', KT_cmis_atom_service_helper::formatDatestamp(), $feed);
780 $feed->newField('cmis:hasMoreItems', 'false', $feed); 798 $feed->newField('cmis:hasMoreItems', 'false', $feed);
781 799
webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php
@@ -54,6 +54,7 @@ class KT_cmis_atom_service_helper { @@ -54,6 +54,7 @@ class KT_cmis_atom_service_helper {
54 * @return string CMIS AtomPub feed 54 * @return string CMIS AtomPub feed
55 */ 55 */
56 // TODO enable this to work on an existing set of object properties if submitted 56 // TODO enable this to work on an existing set of object properties if submitted
  57 + // TODO this might be better as an entry rather than a feed - see Alfresco example
57 static public function getObjectFeed(&$service, $ObjectService, $repositoryId, $objectId, $method = 'GET') 58 static public function getObjectFeed(&$service, $ObjectService, $repositoryId, $objectId, $method = 'GET')
58 { 59 {
59 self::$repositoryId = $repositoryId; 60 self::$repositoryId = $repositoryId;
@@ -173,9 +174,8 @@ class KT_cmis_atom_service_helper { @@ -173,9 +174,8 @@ class KT_cmis_atom_service_helper {
173 { 174 {
174 $type = $cmisEntry['properties']['objectTypeId']['value']; 175 $type = $cmisEntry['properties']['objectTypeId']['value'];
175 176
176 - // TODO dynamic actual creator name  
177 $responseElement = $feed->newField('author'); 177 $responseElement = $feed->newField('author');
178 - $element = $feed->newField('name', 'admin', $responseElement); 178 + $element = $feed->newField('name', $cmisEntry['properties']['createdBy']['value'], $responseElement);
179 $entry->appendChild($responseElement); 179 $entry->appendChild($responseElement);
180 180
181 $typeString = str_replace('cmis:', '', $type); 181 $typeString = str_replace('cmis:', '', $type);
@@ -206,6 +206,7 @@ class KT_cmis_atom_service_helper { @@ -206,6 +206,7 @@ class KT_cmis_atom_service_helper {
206 $link->appendChild($feed->newAttr('rel', 'edit')); 206 $link->appendChild($feed->newAttr('rel', 'edit'));
207 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString 207 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString
208 . '/' . $cmisEntry['properties']['objectId']['value'])); 208 . '/' . $cmisEntry['properties']['objectId']['value']));
  209 + $link->appendChild($feed->newAttr('type', 'application/atom+xml;type=entry'));
209 $entry->appendChild($link); 210 $entry->appendChild($link);
210 211
211 if ((strtolower($cmisEntry['properties']['objectTypeId']['value']) == 'cmis:document') 212 if ((strtolower($cmisEntry['properties']['objectTypeId']['value']) == 'cmis:document')
@@ -218,14 +219,6 @@ class KT_cmis_atom_service_helper { @@ -218,14 +219,6 @@ class KT_cmis_atom_service_helper {
218 . '/' . $cmisEntry['properties']['objectId']['value'] 219 . '/' . $cmisEntry['properties']['objectId']['value']
219 . '/' . $cmisEntry['properties']['contentStreamFilename']['value'])); 220 . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));
220 $entry->appendChild($link); 221 $entry->appendChild($link);
221 -  
222 - $link = $feed->newElement('link');  
223 - $link->appendChild($feed->newAttr('rel', 'enclosure'));  
224 - $link->appendChild($feed->newAttr('type', $cmisEntry['properties']['contentStreamMimeType']['value']));  
225 - $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $typeString  
226 - . '/' . $cmisEntry['properties']['objectId']['value']  
227 - . '/' . $cmisEntry['properties']['contentStreamFilename']['value']));  
228 - $entry->appendChild($link);  
229 } 222 }
230 223
231 // according to spec this MUST be present, but spec says that links for function which are not supported 224 // according to spec this MUST be present, but spec says that links for function which are not supported
@@ -255,6 +248,7 @@ class KT_cmis_atom_service_helper { @@ -255,6 +248,7 @@ class KT_cmis_atom_service_helper {
255 $link->appendChild($feed->newAttr('rel', 'up')); 248 $link->appendChild($feed->newAttr('rel', 'up'));
256 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/folder/' 249 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/folder/'
257 . $cmisEntry['properties']['parentId']['value'])); 250 . $cmisEntry['properties']['parentId']['value']));
  251 + $link->appendChild($feed->newAttr('type', 'application/atom+xml;type=entry'));
258 $entry->appendChild($link); 252 $entry->appendChild($link);
259 } 253 }
260 254
@@ -267,13 +261,16 @@ class KT_cmis_atom_service_helper { @@ -267,13 +261,16 @@ class KT_cmis_atom_service_helper {
267 . $typeString 261 . $typeString
268 . '/' . $cmisEntry['properties']['objectId']['value'] 262 . '/' . $cmisEntry['properties']['objectId']['value']
269 . '/children')); 263 . '/children'));
  264 + $link->appendChild($feed->newAttr('type', 'application/atom+xml;type=feed'));
270 $entry->appendChild($link); 265 $entry->appendChild($link);
  266 +
271 $link = $feed->newElement('link'); 267 $link = $feed->newElement('link');
272 $link->appendChild($feed->newAttr('rel', 'down')); 268 $link->appendChild($feed->newAttr('rel', 'down'));
273 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' 269 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/'
274 . $typeString 270 . $typeString
275 . '/' . $cmisEntry['properties']['objectId']['value'] 271 . '/' . $cmisEntry['properties']['objectId']['value']
276 . '/descendants')); 272 . '/descendants'));
  273 + $link->appendChild($feed->newAttr('type', 'application/cmistree+xml'));
277 $entry->appendChild($link); 274 $entry->appendChild($link);
278 275
279 // TODO add folder tree link when we have folder tree implemented 276 // TODO add folder tree link when we have folder tree implemented
@@ -323,18 +320,33 @@ class KT_cmis_atom_service_helper { @@ -323,18 +320,33 @@ class KT_cmis_atom_service_helper {
323 $link = $feed->newElement('link'); 320 $link = $feed->newElement('link');
324 $link->appendChild($feed->newAttr('rel', 'describedby')); 321 $link->appendChild($feed->newAttr('rel', 'describedby'));
325 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/type/' . $type)); 322 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/type/' . $type));
  323 + $link->appendChild($feed->newAttr('type', 'application/atomsvc+xml'));
326 $entry->appendChild($link); 324 $entry->appendChild($link);
327 325
  326 + // TODO this link must specify the workspace
328 $link = $feed->newElement('link'); 327 $link = $feed->newElement('link');
329 $link->appendChild($feed->newAttr('rel', 'service')); 328 $link->appendChild($feed->newAttr('rel', 'service'));
330 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . '/servicedocument')); 329 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . '/servicedocument'));
  330 + $link->appendChild($feed->newAttr('type', 'application/atom+xml;type=entry'));
331 $entry->appendChild($link); 331 $entry->appendChild($link);
332 332
333 - // TODO proper date  
334 - $entry->appendChild($feed->newField('published', self::formatDatestamp())); 333 + $updated = null;
  334 + $published = null;
  335 + if ($cmisEntry['properties']['lastModificationDate']['value'] != '0000-00-00 00:00:00') {
  336 + $updated = $cmisEntry['properties']['lastModificationDate']['value'];
  337 + }
  338 + else if ($cmisEntry['properties']['creationDate']['value'] != '0000-00-00 00:00:00') {
  339 + $updated = $cmisEntry['properties']['creationDate']['value'];
  340 + }
  341 +
  342 + if ($cmisEntry['properties']['creationDate']['value'] != '0000-00-00 00:00:00') {
  343 + $published = $cmisEntry['properties']['creationDate']['value'];
  344 + }
  345 +
  346 + $entry->appendChild($feed->newField('published', self::formatDatestamp($published)));
335 $entry->appendChild($feed->newElement('summary', $cmisEntry['properties']['name']['value'])); 347 $entry->appendChild($feed->newElement('summary', $cmisEntry['properties']['name']['value']));
336 $entry->appendChild($feed->newElement('title', $cmisEntry['properties']['name']['value'])); 348 $entry->appendChild($feed->newElement('title', $cmisEntry['properties']['name']['value']));
337 - $entry->appendChild($feed->newField('updated', self::formatDatestamp())); 349 + $entry->appendChild($feed->newField('updated', self::formatDatestamp($updated)));
338 350
339 // main CMIS entry 351 // main CMIS entry
340 $objectElement = $feed->newElement('cmisra:object'); 352 $objectElement = $feed->newElement('cmisra:object');
@@ -343,7 +355,14 @@ class KT_cmis_atom_service_helper { @@ -343,7 +355,14 @@ class KT_cmis_atom_service_helper {
343 355
344 // TODO check determination of when to add app:edited tag 356 // TODO check determination of when to add app:edited tag
345 // if ($method == 'POST') { 357 // if ($method == 'POST') {
346 - $entry->appendChild($feed->newElement('app:edited', self::formatDatestamp())); 358 + $edited = null;
  359 + if ($cmisEntry['properties']['lastModificationDate']['value'] != '0000-00-00 00:00:00') {
  360 + $edited = $cmisEntry['properties']['lastModificationDate']['value'];
  361 + }
  362 + else if ($cmisEntry['properties']['creationDate']['value'] != '0000-00-00 00:00:00') {
  363 + $edited = $cmisEntry['properties']['creationDate']['value'];
  364 + }
  365 + $entry->appendChild($feed->newElement('app:edited', self::formatDatestamp($edited)));
347 // } 366 // }
348 367
349 // TODO pathSegment entry 368 // TODO pathSegment entry
@@ -424,17 +443,20 @@ class KT_cmis_atom_service_helper { @@ -424,17 +443,20 @@ class KT_cmis_atom_service_helper {
424 // TODO set page number correctly - to be done when we support paging the the API 443 // TODO set page number correctly - to be done when we support paging the the API
425 444
426 // author 445 // author
427 - // TODO generate this dynamically (based on???)\ 446 + // since types are/should be always created by system admin, we use a default value - this may be set later but for now is unset
  447 + // for a type which is not an instantiated object
428 $feedElement = $feed->newField('author'); 448 $feedElement = $feed->newField('author');
429 - $element = $feed->newField('name', 'admin', $feedElement); 449 + $element = $feed->newField('name', 'Administrator', $feedElement);
430 $feed->appendChild($feedElement); 450 $feed->appendChild($feedElement);
431 451
432 foreach($types as $type) 452 foreach($types as $type)
433 { 453 {
434 $entry = $feed->newEntry(); 454 $entry = $feed->newEntry();
435 455
  456 + // since types are/should be always created by system admin, we use a default value - this may be set later but for now is unset
  457 + // for a type which is not an instantiated object
436 $feedElement = $feed->newField('author'); 458 $feedElement = $feed->newField('author');
437 - $element = $feed->newField('name', 'admin', $feedElement); 459 + $element = $feed->newField('name', 'Administrator', $feedElement);
438 $entry->appendChild($feedElement); 460 $entry->appendChild($feedElement);
439 $feedElement = $feed->newField('content', 'Type definition for ' . $type['baseId']); 461 $feedElement = $feed->newField('content', 'Type definition for ' . $type['baseId']);
440 $entry->appendChild($feedElement); 462 $entry->appendChild($feedElement);
@@ -449,17 +471,20 @@ class KT_cmis_atom_service_helper { @@ -449,17 +471,20 @@ class KT_cmis_atom_service_helper {
449 // TODO type link MUST point to base type 471 // TODO type link MUST point to base type
450 // KnowledgeTree currently only supports base types so this is not important 472 // KnowledgeTree currently only supports base types so this is not important
451 // at the present time as it will always point at the base type. 473 // at the present time as it will always point at the base type.
  474 +
452 $link = $feed->newElement('link'); 475 $link = $feed->newElement('link');
453 $link->appendChild($feed->newAttr('rel','type')); 476 $link->appendChild($feed->newAttr('rel','type'));
454 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/type/' . strtolower($type['baseId']))); 477 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/type/' . strtolower($type['baseId'])));
455 $entry->appendChild($link); 478 $entry->appendChild($link);
  479 +
456 $link = $feed->newElement('link'); 480 $link = $feed->newElement('link');
457 $link->appendChild($feed->newAttr('rel','repository')); 481 $link->appendChild($feed->newAttr('rel','repository'));
458 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . '/servicedocument')); 482 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . '/servicedocument'));
459 $entry->appendChild($link); 483 $entry->appendChild($link);
460 484
461 - $entry->appendChild($feed->newElement('summary', 'Summary for ' . $type['baseId'] . ' type'));  
462 - $entry->appendChild($feed->newElement('title', $type['baseId'])); 485 + $entry->appendChild($feed->newElement('summary', 'Summary for ' . $type['displayName'] . ' type'));
  486 + $entry->appendChild($feed->newElement('title', $type['displayName']));
  487 + // Since types do not have associated dates, we don't know the time last updated, so we use current
463 $entry->appendChild($feed->newElement('updated', self::formatDatestamp())); 488 $entry->appendChild($feed->newElement('updated', self::formatDatestamp()));
464 489
465 $objectElement = $feed->newElement('cmisra:type'); 490 $objectElement = $feed->newElement('cmisra:type');
@@ -479,13 +504,14 @@ class KT_cmis_atom_service_helper { @@ -479,13 +504,14 @@ class KT_cmis_atom_service_helper {
479 // appear to be seen by browser based clients (I am not sure of non-browser clients) 504 // appear to be seen by browser based clients (I am not sure of non-browser clients)
480 // NOTE just added a check and only send back the header containing 404, no text, and this works, we get a 404 header 505 // NOTE just added a check and only send back the header containing 404, no text, and this works, we get a 404 header
481 // plus a readable AtomPub response 506 // plus a readable AtomPub response
  507 + // THEORY is that Apache is generating the html response when given a '404 Not Found' header, overriding the desired output
482 if (!strstr($status, '404')) { 508 if (!strstr($status, '404')) {
483 $service->setStatus($status); 509 $service->setStatus($status);
484 } 510 }
485 else { 511 else {
486 $service->setStatus('404'); 512 $service->setStatus('404');
487 } 513 }
488 - 514 +
489 $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI); 515 $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI);
490 516
491 $feed->newField('title', 'Error: ' . $status, $feed); 517 $feed->newField('title', 'Error: ' . $status, $feed);
@@ -697,13 +723,21 @@ class KT_cmis_atom_service_helper { @@ -697,13 +723,21 @@ class KT_cmis_atom_service_helper {
697 } 723 }
698 } 724 }
699 } 725 }
  726 +
700 return self::$ktapi; 727 return self::$ktapi;
701 } 728 }
702 729
703 // TODO adjust for time zones? 730 // TODO adjust for time zones?
704 static public function formatDatestamp($time = null) 731 static public function formatDatestamp($time = null)
705 { 732 {
706 - if (is_null($time)) $time = time(); 733 + if (is_null($time)) {
  734 + $time = time();
  735 + }
  736 + else {
  737 + // assumes format is 'yyyy-mm-dd hh:mm:ss' or some other string representation, and not a unix timestamp
  738 + $time = strtotime($time);
  739 + }
  740 +
707 return date('Y-m-d H:i:s', $time); 741 return date('Y-m-d H:i:s', $time);
708 } 742 }
709 743
@@ -768,6 +802,7 @@ class KT_cmis_atom_service_helper { @@ -768,6 +802,7 @@ class KT_cmis_atom_service_helper {
768 $service->setHeader('Content-type', $response['properties']['contentStreamMimeType']['value'] . ';charset=utf-8'); 802 $service->setHeader('Content-type', $response['properties']['contentStreamMimeType']['value'] . ';charset=utf-8');
769 } 803 }
770 else { 804 else {
  805 + // FIXME what should the default type be? application/unknown?
771 $service->setHeader('Content-type', 'text/plain;charset=utf-8'); 806 $service->setHeader('Content-type', 'text/plain;charset=utf-8');
772 } 807 }
773 808
webservice/classes/atompub/cmis/KT_cmis_atom_response.inc.php
@@ -19,6 +19,21 @@ class KT_cmis_atom_response extends KT_atom_response { @@ -19,6 +19,21 @@ class KT_cmis_atom_response extends KT_atom_response {
19 { 19 {
20 return $this->workspace; 20 return $this->workspace;
21 } 21 }
  22 +
  23 + protected function constructFeedHeader(){
  24 + $feed = $this->newElement('feed');
  25 + $feed->appendChild($this->newAttr('xmlns','http://www.w3.org/2005/Atom'));
  26 + $this->feed = &$feed;
  27 + $this->DOM->appendChild($this->feed);
  28 + }
  29 +
  30 + public function &newEntry()
  31 + {
  32 + $entry = $this->newElement('atom:entry');
  33 + $this->feed->appendChild($entry);
  34 +
  35 + return $entry;
  36 + }
22 37
23 // TODO try to get rid of this function 38 // TODO try to get rid of this function
24 function appendChild($element) 39 function appendChild($element)
webservice/classes/atompub/cmis/KT_cmis_atom_server.inc.php
@@ -22,14 +22,14 @@ class KT_cmis_atom_server extends KT_atom_server { @@ -22,14 +22,14 @@ class KT_cmis_atom_server extends KT_atom_server {
22 header('Expires:'); 22 header('Expires:');
23 header('Pragma:'); 23 header('Pragma:');
24 24
25 - // prevent output of standard text/xml header 25 + // prevent output of regular headers for AtomPub responses
26 $this->headersSet = true; 26 $this->headersSet = true;
27 27
28 return false; 28 return false;
29 } 29 }
30 else if ($doc->notModified()) 30 else if ($doc->notModified())
31 { 31 {
32 - // prevent output of standard text/xml header 32 + // prevent output of regular headers for AtomPub responses
33 $this->headersSet = true; 33 $this->headersSet = true;
34 $this->setNoContent(true); 34 $this->setNoContent(true);
35 35
@@ -114,6 +114,15 @@ class KT_cmis_atom_server extends KT_atom_server { @@ -114,6 +114,15 @@ class KT_cmis_atom_server extends KT_atom_server {
114 } 114 }
115 } 115 }
116 116
  117 + // TODO add other links once their services are supported
  118 + // links
  119 + $link = $service->newElement('atom:link');
  120 + $link->appendChild($service->newAttr('title', 'root descendants'));
  121 + $link->appendChild($service->newAttr('type', 'application/cmistree+xml'));
  122 + $link->appendChild($service->newAttr('rel', 'http://docs.oasis-open.org/ns/cmis/link/200908/rootdescendants'));
  123 + $link->appendChild($service->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/folder/Root%20Folder/descendants'));
  124 + $ws->appendChild($link);
  125 +
117 // uri templates - getObjectById, getObjectByPath, getTypeById 126 // uri templates - getObjectById, getObjectByPath, getTypeById
118 $ws->appendChild($service->uriTemplate('objectbyid', $workspace)); 127 $ws->appendChild($service->uriTemplate('objectbyid', $workspace));
119 $ws->appendChild($service->uriTemplate('objectbypath', $workspace)); 128 $ws->appendChild($service->uriTemplate('objectbypath', $workspace));