diff --git a/ktapi/KTAPIDocument.inc.php b/ktapi/KTAPIDocument.inc.php index 52e92b4..a51643c 100644 --- a/ktapi/KTAPIDocument.inc.php +++ b/ktapi/KTAPIDocument.inc.php @@ -2099,6 +2099,25 @@ class KTAPI_Document extends KTAPI_FolderItem $oDocumentTransaction = new DocumentTransaction($this->document, 'Document downloaded', 'ktcore.transactions.download', $aOptions); $oDocumentTransaction->create(); } + + /** + * Function to fetch the actual file content of a document + * + * @return $content the document file content + */ + function get_document_content() + { + // fetch the content + $content = KTDocumentUtil::getDocumentContent($this->document); + + // TODO what if the file could not be found? + + // Log the transaction + $this->download(); + + // return the document content + return $content; + } /** * This returns the transaction history for the document. diff --git a/lib/api/ktcmis/classes/CMISBaseObject.inc.php b/lib/api/ktcmis/classes/CMISBaseObject.inc.php index 31964ca..caa976f 100644 --- a/lib/api/ktcmis/classes/CMISBaseObject.inc.php +++ b/lib/api/ktcmis/classes/CMISBaseObject.inc.php @@ -56,6 +56,7 @@ abstract class CMISBaseObject { protected $queryable; protected $includedInSupertypeQuery; protected $controllable; // NOTE deprecated? part of policy objects specification, policy objects are indicated as TODO remove + protected $contentStreamAllowed = 'notAllowed'; protected $properties; // list of property objects which define the additional properties for this object diff --git a/lib/api/ktcmis/classes/CMISPropertyCollection.inc.php b/lib/api/ktcmis/classes/CMISPropertyCollection.inc.php index d70ab7a..95c31b0 100644 --- a/lib/api/ktcmis/classes/CMISPropertyCollection.inc.php +++ b/lib/api/ktcmis/classes/CMISPropertyCollection.inc.php @@ -67,8 +67,11 @@ abstract class CMISPropertyCollection { 'LastModifiedBy' => 'propertyString', 'LastModificationDate' => 'propertyDateTime', 'Name' => 'propertyString', + 'ContentStreamAllowed' => 'propertyString', 'ContentStreamLength' => 'propertyInteger', 'ContentStreamMimeType' => 'propertyString', + 'ContentStreamFilename' => 'propertyString', + 'ContentStreamUri' => 'propertyUri', 'Uri' => 'propertyUri', 'AllowedChildObjectTypeIds' => 'propertyId', 'CreatedBy' => 'propertyString', diff --git a/lib/api/ktcmis/ktcmis.inc.php b/lib/api/ktcmis/ktcmis.inc.php index b9fe28a..f3917ff 100644 --- a/lib/api/ktcmis/ktcmis.inc.php +++ b/lib/api/ktcmis/ktcmis.inc.php @@ -592,6 +592,32 @@ class KTObjectService extends KTCMISBase { } /** + * Fetches the content stream data for an object + * + * @param string $repositoryId + * @param string $objectId + * @return string $contentStream (binary or text data) + */ + function getContentStream($repositoryId, $objectId) + { + try { + $contentStream = $this->ObjectService->getContentStream($repositoryId, $objectId); + } + catch (Exception $e) + { + return array( + "status_code" => 1, + "message" => $e->getMessage() + ); + } + + return array( + 'status_code' => 0, + 'results' => $contentStream + ); + } + + /** * Moves a fileable object from one folder to another. * * @param object $repositoryId diff --git a/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php b/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php index 557afc4..3f9cbc7 100644 --- a/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php +++ b/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php @@ -49,7 +49,6 @@ require_once(CMIS_DIR . '/util/CMISUtil.inc.php'); class CMISDocumentObject extends CMISBaseObject { protected $versionable; - protected $contentStreamAllowed; private $ktapi; private $uri; @@ -167,11 +166,10 @@ class CMISDocumentObject extends CMISBaseObject { $this->_setPropertyInternal('VersionSeriesCheckedOutId', $checkedOutId); // TODO currently not returned by KnowledgeTree? $this->_setPropertyInternal('CheckinComment', null); - // TODO if we implement content streams $this->_setPropertyInternal('ContentStreamLength', $objectProperties['filesize']); $this->_setPropertyInternal('ContentStreamMimeType', $objectProperties['mime_type']); - $this->_setPropertyInternal('ContentStreamFilename', null); - $this->_setPropertyInternal('ContentStreamUri', null); + $this->_setPropertyInternal('ContentStreamFilename', $objectProperties['filename']); + $this->_setPropertyInternal('ContentStreamUri', $this->getProperty('ObjectId') . '/' . $objectProperties['filename']); $this->_setPropertyInternal('Author', $objectProperties['created_by']); } diff --git a/lib/api/ktcmis/services/CMISObjectService.inc.php b/lib/api/ktcmis/services/CMISObjectService.inc.php index d6d6f4b..65ce3ef 100644 --- a/lib/api/ktcmis/services/CMISObjectService.inc.php +++ b/lib/api/ktcmis/services/CMISObjectService.inc.php @@ -31,55 +31,6 @@ class CMISObjectService { } /** - * Fetches the properties for the specified object - * - * @param string $repositoryId - * @param string $objectId - * @param boolean $includeAllowableActions - * @param boolean $includeRelationships - * @param boolean $returnVersion - * @param string $filter - * @return object CMIS object properties - */ - // TODO optional parameter support - // TODO FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid - public function getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships, - $returnVersion = false, $filter = '') - { - $repository = new CMISRepository($repositoryId); - - // TODO a better default value? - $properties = array(); - - $objectId = CMISUtil::decodeObjectId($objectId, $typeId); - - if ($typeId == 'Unknown') - { - throw new ObjectNotFoundException('The type of the requested object could not be determined'); - } - - switch($typeId) - { - case 'Document': - $CMISObject = new CMISDocumentObject($objectId, $this->ktapi, $repository->getRepositoryURI()); - break; - case 'Folder': - $CMISObject = new CMISFolderObject($objectId, $this->ktapi, $repository->getRepositoryURI()); - break; - } - - // check that we were actually able to retrieve a real object - $objectId = $CMISObject->getProperty('ObjectId'); - if (empty($objectId)) { - throw new ObjectNotFoundException('The requested object could not be found'); - } - - $properties = $CMISObject->getProperties(); - - return $properties; - } - - /** * Creates a new document within the repository * * @param string $repositoryId The repository to which the document must be added @@ -232,7 +183,6 @@ class CMISObjectService { ); } - // TODO fetch author name based on logged in user $user = $this->ktapi->get_user(); if (!PEAR::isError($user)) { @@ -257,7 +207,7 @@ class CMISObjectService { ); /** - * Try to determine mime type which maps to one of the following: + * Try to determine mime type which maps to one of the following KnowledgetTree document types: * * Audio * Image @@ -408,6 +358,104 @@ class CMISObjectService { } /** + * Fetches the properties for the specified object + * + * @param string $repositoryId + * @param string $objectId + * @param boolean $includeAllowableActions + * @param boolean $includeRelationships + * @param boolean $returnVersion + * @param string $filter + * @return object CMIS object properties + */ + // TODO optional parameter support + // TODO FilterNotValidException: The Repository SHALL throw this exception if this property filter input parameter is not valid + public function getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships, + $returnVersion = false, $filter = '') + { + $repository = new CMISRepository($repositoryId); + + // TODO a better default value? + $properties = array(); + + $objectId = CMISUtil::decodeObjectId($objectId, $typeId); + + if ($typeId == 'Unknown') + { + throw new ObjectNotFoundException('The type of the requested object could not be determined'); + } + + switch($typeId) + { + case 'Document': + $CMISObject = new CMISDocumentObject($objectId, $this->ktapi, $repository->getRepositoryURI()); + break; + case 'Folder': + $CMISObject = new CMISFolderObject($objectId, $this->ktapi, $repository->getRepositoryURI()); + break; + } + + // check that we were actually able to retrieve a real object + $objectId = $CMISObject->getProperty('ObjectId'); + if (empty($objectId)) { + throw new ObjectNotFoundException('The requested object could not be found'); + } + + $properties = $CMISObject->getProperties(); + + return $properties; + } + + /** + * Fetches the content stream data for an object + * + * @param string $repositoryId + * @param string $objectId + * @return string $contentStream (binary or text data) + */ + // NOTE streamNotSupportedException: The Repository SHALL throw this exception if the Object-Type definition + // specified by the objectId parameter’s “contentStreamAllowed” attribute is set to “not allowed”. + // + function getContentStream($repositoryId, $objectId) + { + $contentStream = null; + + // decode $objectId + $objectId = CMISUtil::decodeObjectId($objectId, $typeId); + + // unknown object type? + if ($typeId == 'Unknown') { + throw new ObjectNotFoundException('The type of the requested object could not be determined'); + } + + // fetch type definition of supplied object type + $objectClass = 'CMIS' . $typeId . 'Object'; + $CMISObject = new $objectClass($objectId, $this->ktapi); + + // if content stream is not allowed for this object type definition, throw a ConstraintViolationException + if (($CMISObject->getAttribute('contentStreamAllowed') == 'notAllowed')) + { + // NOTE spec version 0.61c specifies both a ConstraintViolationException and a StreamNotSupportedException + // for this case. Choosing to throw StreamNotSupportedException until the specification is clarified + // as it is a more specific exception + throw new StreamNotSupportedException('Content Streams are not allowed for this object type'); + } + + // now go on to fetching the content stream + // TODO allow fetching of partial streams + // from the CMIS specification (0.61): + // "Each CMIS protocol binding SHALL provide a way for fetching a sub-range within a content stream, in a manner appropriate to that protocol." + + // steps to fetch content stream: + // 1. find actual physical document (see zip/download code) + // TODO move this into a ktapi function + $document = $this->ktapi->get_document_by_id($objectId); + $contentStream = $document->get_document_content(); + + return $contentStream; + } + + /** * Moves a fileable object from one folder to another. * * @param object $repositoryId @@ -675,6 +723,8 @@ class CMISObjectService { if ($tmpTypeId != 'Unknown') $documentId = $tmpObjectId; + // TODO deal with other types except documents + // fetch type definition of supplied document $CMISDocument = new CMISDocumentObject($documentId, $this->ktapi); diff --git a/lib/api/ktcmis/util/CMISUtil.inc.php b/lib/api/ktcmis/util/CMISUtil.inc.php index ae786d4..b9b19aa 100644 --- a/lib/api/ktcmis/util/CMISUtil.inc.php +++ b/lib/api/ktcmis/util/CMISUtil.inc.php @@ -252,14 +252,21 @@ class CMISUtil { return $hierarchy; } + /** + * Creates a properties entry array for the given entry + * + * TODO make this just dynamically convert all properties instead of selected. + * NOTE current version is a legacy of how we thought things needed to be for the SOAP webservices. + * + * @param object $properties + * @return + */ static public function createObjectPropertiesEntry($properties) { - // TODO better dynamic style fetching of object properties into array for output $object = array(); $object['Author'] = array('value' => $properties->getValue('Author')); - // TODO additional properties to be returned $object['properties']['BaseType'] = array('type' => $properties->getFieldType('BaseType'), 'value' => $properties->getValue('BaseType')); @@ -300,29 +307,32 @@ class CMISUtil { if (strtolower($properties->getValue('ObjectTypeId')) == 'document') { - - $object['properties']['ChangeToken'] = array('type' => $properties->getFieldType('ChangeToken'), + $object['properties']['ChangeToken'] = array('type' => $properties->getFieldType('ChangeToken'), 'value' => $properties->getValue('ChangeToken')); $contentStreamLength = $properties->getValue('ContentStreamLength'); if (!empty($contentStreamLength)) { $contentStreamLength = $properties->getValue('ContentStreamLength'); + $object['properties']['ContentStreamAllowed'] = array('type' => $properties->getFieldType('ContentStreamAllowed'), + 'value' => $properties->getValue('ContentStreamAllowed')); $object['properties']['ContentStreamLength'] = array('type' => $properties->getFieldType('ContentStreamLength'), 'value' => $properties->getValue('ContentStreamLength')); $object['properties']['ContentStreamMimeType'] = array('type' => $properties->getFieldType('ContentStreamMimeType'), 'value' => $properties->getValue('ContentStreamMimeType')); + $object['properties']['ContentStreamFilename'] = array('type' => $properties->getFieldType('ContentStreamFilename'), + 'value' => $properties->getValue('ContentStreamFilename')); + $object['properties']['ContentStreamUri'] = array('type' => $properties->getFieldType('ContentStreamUri'), + 'value' => $properties->getValue('ContentStreamUri')); } } // if we have found a child/parent with one or more children/parents, recurse into the child/parent object - if (count($entry['items']) > 0) - { + if (count($entry['items']) > 0) { $object[$linkText] = CMISUtil::decodeObjectHierarchy($entry['items'], $linkText); } // NOTE may need to set a null value here in case webservices don't like it unset // so we'll set it just in case... - else - { + else { $object[$linkText] = null; } diff --git a/lib/documentmanagement/documentutil.inc.php b/lib/documentmanagement/documentutil.inc.php index b77d608..7768c9b 100644 --- a/lib/documentmanagement/documentutil.inc.php +++ b/lib/documentmanagement/documentutil.inc.php @@ -1564,6 +1564,40 @@ $sourceDocument->getName(), DBUtil::commit(); } + + public static function getDocumentContent($oDocument) + { + global $default; + + //get the path to the document on the server + //$docRoot = $default->documentRoot; + $oConfig =& KTConfig::getSingleton(); + $docRoot = $oConfig->get('urls/documentRoot'); + + $path = $docRoot .'/'. $oDocument->getStoragePath(); + + // Ensure the file exists + if (file_exists($path)) + { + // Get the mime type - this is not relevant at the moment... + $mimeId = $oDocument->getMimeTypeID(); + $mimetype = KTMime::getMimeTypeName($mimeId); + + if ($bIsCheckout && $default->fakeMimetype) { + // note this does not work for "image" types in some browsers + $mimetype = 'application/x-download'; + } + + $sFileName = $oDocument->getFileName( ); + $iFileSize = $oDocument->getFileSize(); + } else { + return null; + } + + $content = file_get_contents($path); + + return $content; + } } class KTMetadataValidationError extends PEAR_Error { diff --git a/tests/ktcmis/myf5429.tmp b/tests/ktcmis/myf5429.tmp deleted file mode 100644 index aa6ee5b..0000000 --- a/tests/ktcmis/myf5429.tmp +++ /dev/null @@ -1 +0,0 @@ -this is some text \ No newline at end of file diff --git a/tests/ktcmis/myf7FFE.tmp b/tests/ktcmis/myf7FFE.tmp deleted file mode 100644 index aa6ee5b..0000000 --- a/tests/ktcmis/myf7FFE.tmp +++ /dev/null @@ -1 +0,0 @@ -this is some text \ No newline at end of file diff --git a/tests/ktcmis/myf8F68.tmp b/tests/ktcmis/myf8F68.tmp deleted file mode 100644 index aa6ee5b..0000000 --- a/tests/ktcmis/myf8F68.tmp +++ /dev/null @@ -1 +0,0 @@ -this is some text \ No newline at end of file diff --git a/webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php b/webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php index 6e7b87c..8b396e5 100644 --- a/webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php +++ b/webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php @@ -42,7 +42,7 @@ include_once 'KT_cmis_atom_service_helper.inc.php'; /** * AtomPub Service: folder */ -class KT_cmis_atom_service_folder extends KT_atom_service { +class KT_cmis_atom_service_folder extends KT_cmis_atom_service { /** * Deals with GET actions for folders. @@ -337,7 +337,7 @@ class KT_cmis_atom_service_folder extends KT_atom_service { /** * AtomPub Service: types */ -class KT_cmis_atom_service_types extends KT_atom_service { +class KT_cmis_atom_service_types extends KT_cmis_atom_service { public function GET_action() { @@ -358,7 +358,7 @@ class KT_cmis_atom_service_types extends KT_atom_service { /** * AtomPub Service: type */ -class KT_cmis_atom_service_type extends KT_atom_service { +class KT_cmis_atom_service_type extends KT_cmis_atom_service { public function GET_action() { @@ -433,7 +433,7 @@ class KT_cmis_atom_service_type extends KT_atom_service { * AtomPub Service: checkedout */ // NOTE this is always an empty document, underlying API code still to be implemented -class KT_cmis_atom_service_checkedout extends KT_atom_service { +class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { /** * Deals with GET actions for checkedout documents. @@ -507,6 +507,14 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service { $repositories = $RepositoryService->getRepositories(); $repositoryId = $repositories[0]['repositoryId']; + + // determine whether we want the document entry feed or the actual physical document content. + // this depends on $this->params[1] + if (!empty($this->params[1])) + { + $this->getContentStream($ObjectService, $repositoryId); + return null; + } $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $this->params[0]); @@ -548,6 +556,46 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service { $this->setStatus(self::STATUS_NO_CONTENT); } + private function getContentStream(&$ObjectService, $repositoryId) + { + $response = $ObjectService->getProperties($repositoryId, $this->params[0], false, false); + if (PEAR::isError($response)) { + $feed = KT_cmis_atom_service_helper::getErrorFeed($this, KT_cmis_atom_service::STATUS_SERVER_ERROR, $response->getMessage()); + $this->responseFeed = $feed; + return null; + } + + // TODO also check If-Modified-Since? +// $this->headers['If-Modified-Since'] => 2009-07-24 17:16:54 + + $this->contentDownload = true; + $eTag = md5($response['properties']['LastModificationDate']['value'] . $response['properties']['ContentStreamLength']['value']); + + if ($this->headers['If-None-Match'] == $eTag) + { + $this->setStatus(self::STATUS_NOT_MODIFIED); + $this->contentDownload = false; + return null; + } + + $contentStream = $ObjectService->getContentStream($repositoryId, $this->params[0]); + + // headers specific to output + $this->setEtag($eTag); + $this->setHeader('Last-Modified', $response['properties']['LastModificationDate']['value']); + + if (!empty($response['properties']['ContentStreamMimeType']['value'])) { + $this->setHeader('Content-type', $response['properties']['ContentStreamMimeType']['value'] . ';charset=utf-8'); + } + else { + $this->setHeader('Content-type', 'text/plain;charset=utf-8'); + } + + $this->setHeader('Content-Disposition', 'attachment;filename="' . $response['properties']['ContentStreamFilename']['value'] . '"'); + $this->setHeader('Content-Length', $response['properties']['ContentStreamLength']['value']); + $this->output = $contentStream; + } + } ?> \ No newline at end of file diff --git a/webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php b/webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php index 29b9013..38e931e 100644 --- a/webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php +++ b/webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php @@ -52,6 +52,7 @@ class KT_cmis_atom_service_helper { static public function createObjectEntry(&$response, $cmisEntry, $parent, $method = 'GET') { $workspace = $response->getWorkspace(); + $type = strtolower($cmisEntry['properties']['ObjectTypeId']['value']); // create entry $entry = $response->newEntry(); @@ -68,24 +69,53 @@ class KT_cmis_atom_service_helper { $responseElement = $response->newField('author'); $element = $response->newField('name', 'admin', $responseElement); $entry->appendChild($responseElement); + + if (!empty($cmisEntry['properties']['ContentStreamLength']['value'])) + { + $field = $response->newElement('content'); + $field->appendChild($response->newAttr('type', $cmisEntry['properties']['ContentStreamMimeType']['value'])); + $field->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type + . '/' . $cmisEntry['properties']['ObjectId']['value'] + . '/' . $cmisEntry['properties']['ContentStreamFilename']['value'])); + $entry->appendChild($field); + } // content & id tags $id = $cmisEntry['properties']['ObjectId']['value']; - $entry->appendChild($response->newField('content', $id)); + $response->newField('id', 'urn:uuid:' . $id, $entry); - $type = strtolower($cmisEntry['properties']['ObjectTypeId']['value']); - // links $link = $response->newElement('link'); - $link->appendChild($response->newAttr('rel','self')); + $link->appendChild($response->newAttr('rel', 'self')); $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type . '/' . $cmisEntry['properties']['ObjectId']['value'])); $entry->appendChild($link); $link = $response->newElement('link'); - $link->appendChild($response->newAttr('rel','edit')); - $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type . '/' . $cmisEntry['properties']['ObjectId']['value'])); + $link->appendChild($response->newAttr('rel', 'edit')); + $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type + . '/' . $cmisEntry['properties']['ObjectId']['value'])); $entry->appendChild($link); + + if ((strtolower($cmisEntry['properties']['ObjectTypeId']['value']) == 'document') + && (!empty($cmisEntry['properties']['ContentStreamLength']['value']))) + { + $link = $response->newElement('link'); + $link->appendChild($response->newAttr('rel', 'edit-media')); + $link->appendChild($response->newAttr('type', $cmisEntry['properties']['ContentStreamMimeType']['value'])); + $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type + . '/' . $cmisEntry['properties']['ObjectId']['value'] + . '/' . $cmisEntry['properties']['ContentStreamFilename']['value'])); + $entry->appendChild($link); + + $link = $response->newElement('link'); + $link->appendChild($response->newAttr('rel', 'enclosure')); + $link->appendChild($response->newAttr('type', $cmisEntry['properties']['ContentStreamMimeType']['value'])); + $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type + . '/' . $cmisEntry['properties']['ObjectId']['value'] + . '/' . $cmisEntry['properties']['ContentStreamFilename']['value'])); + $entry->appendChild($link); + } // according to spec this MUST be present, but spec says that links for function which are not supported // do not need to be present, so unsure for the moment @@ -115,14 +145,14 @@ class KT_cmis_atom_service_helper { if (strtolower($cmisEntry['properties']['ObjectTypeId']['value']) == 'folder') { $link = $response->newElement('link'); - $link->appendChild($response->newAttr('rel','children')); + $link->appendChild($response->newAttr('rel', 'children')); $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type . '/' . $cmisEntry['properties']['ObjectId']['value'] . '/children')); $entry->appendChild($link); $link = $response->newElement('link'); - $link->appendChild($response->newAttr('rel','descendants')); + $link->appendChild($response->newAttr('rel', 'descendants')); $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type . '/' . $cmisEntry['properties']['ObjectId']['value'] @@ -151,8 +181,10 @@ class KT_cmis_atom_service_helper { { $link = $response->newElement('link'); $link->appendChild($response->newAttr('rel', 'stream')); - $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type . '/' - . $cmisEntry['properties']['ObjectId']['value'])); + $link->appendChild($response->newAttr('type', $cmisEntry['properties']['ContentStreamMimeType']['value'])); + $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type + . '/' . $cmisEntry['properties']['ObjectId']['value'] + . '/' . $cmisEntry['properties']['ContentStreamFilename']['value'])); $entry->appendChild($link); } @@ -164,15 +196,21 @@ class KT_cmis_atom_service_helper { // $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type . '/' . $cmisEntry['properties']['ParentId']['value'])); // $entry->appendChild($link); // } +// +// $link = $response->newElement('link'); +// $link->appendChild($response->newAttr('rel', 'stream')); +// $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type +// . '/' . $cmisEntry['properties']['ObjectId']['value'] +// . '/' . $cmisEntry['properties']['ContentStreamFilename']['value'])); } $link = $response->newElement('link'); - $link->appendChild($response->newAttr('rel','type')); + $link->appendChild($response->newAttr('rel', 'type')); $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/type/' . $type)); $entry->appendChild($link); $link = $response->newElement('link'); - $link->appendChild($response->newAttr('rel','repository')); + $link->appendChild($response->newAttr('rel', 'repository')); $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . '/servicedocument')); $entry->appendChild($link); @@ -198,7 +236,11 @@ class KT_cmis_atom_service_helper { { $propElement = $response->newElement('cmis:' . $property['type']); $propElement->appendChild($response->newAttr('cmis:name', $propertyName)); - if (!empty($property['value'])) { + if (!empty($property['value'])) + { + if ($propertyName == 'ContentStreamUri') { + $property['value'] = CMIS_APP_BASE_URI . $workspace . '/' . $type . '/' .$property['value']; + } $response->newField('cmis:value', CMISUtil::boolToString($property['value']), $propElement); } $propertiesElement->appendChild($propElement); diff --git a/webservice/atompub/cmis/index.php b/webservice/atompub/cmis/index.php index a6dc97b..d52013a 100644 --- a/webservice/atompub/cmis/index.php +++ b/webservice/atompub/cmis/index.php @@ -82,7 +82,7 @@ if ($workspace == 'servicedocument') // CMIS service document setup $APP->initServiceDocument(); // User defined title tag - $APP->addWorkspaceTag('dms','atom:title',$APP->repositoryInfo['repositoryName']); + $APP->addWorkspaceTag('dms','atom:title', $APP->repositoryInfo['repositoryName']); } /** @@ -108,13 +108,10 @@ $APP->registerService('dms', 'checkedout', 'KT_cmis_atom_service_checkedout', 'C $APP->registerService('dms', 'types', 'KT_cmis_atom_service_types', 'Object Type Collection', null, 'typeschildren'); $APP->registerService('dms', 'types', 'KT_cmis_atom_service_types', 'Object Type Collection', null, 'typesdescendants'); -// NOTE $requestParams is meaningless if not actually requesting this service, so not a good way to register the service really if ($workspace != 'servicedocument') { - // should check this per workspace??? - $APP->registerService('dms', 'type', 'KT_cmis_atom_service_type', 'Object Type Collection', explode('/', $requestParams), 'typesdescendants'); - // FIXME HACK! see above, this one for documents - $APP->registerService('dms', 'document', 'KT_cmis_atom_service_document', 'Object Type Collection', explode('/', $requestParams), 'typesdescendants'); + $APP->registerService('dms', 'type', 'KT_cmis_atom_service_type', 'Object Type Entry', null, 'type'); + $APP->registerService('dms', 'document', 'KT_cmis_atom_service_document', 'Document Entry', null, 'document'); } //Execute the current url/header request diff --git a/webservice/classes/atompub/cmis/KT_cmis_atom_server.inc.php b/webservice/classes/atompub/cmis/KT_cmis_atom_server.inc.php index 1bd7711..de38ebe 100644 --- a/webservice/classes/atompub/cmis/KT_cmis_atom_server.inc.php +++ b/webservice/classes/atompub/cmis/KT_cmis_atom_server.inc.php @@ -7,6 +7,37 @@ class KT_cmis_atom_server extends KT_atom_server { // override and extend as needed public $repositoryInfo; + public $headersSet = false; + + protected function hook_beforeDocRender($doc) + { + if ($doc->isContentDownload()) + { + // not going to create a feed/entry response, just returning the raw data + $this->output = $doc->getOutput(); + + // generic headers for all content downloads + header('Cache-Control: must-revalidate'); + // these two are to override the default header values + header('Expires:'); + header('Pragma:'); + + // prevent output of standard text/xml header + $this->headersSet = true; + + return false; + } + else if ($doc->notModified()) + { + // prevent output of standard text/xml header + $this->headersSet = true; + $this->setNoContent(true); + + return false; + } + + return true; + } public function initServiceDocument() { @@ -56,13 +87,11 @@ class KT_cmis_atom_server extends KT_atom_server { $element = $service->newElement('cmis:repositoryInfo'); foreach($this->repositoryInfo as $key => $repoData) { - if ($key == 'rootFolderId') - { + if ($key == 'rootFolderId') { $repoData = CMIS_APP_BASE_URI . $workspace . '/folder/' . rawurlencode($repoData); } - if (!is_array($repoData)) - { + if (!is_array($repoData)) { $element->appendChild($service->newElement('cmis:' . $key, $repoData)); } else @@ -112,13 +141,19 @@ class KT_cmis_atom_server extends KT_atom_server { public function getRegisteredService($workspace, $serviceName = NULL) { $serviceName = strtolower(trim($serviceName)); - if(isset($this->services[$workspace][$serviceName])) - { + if(isset($this->services[$workspace][$serviceName])) { return $this->services[$workspace][$serviceName][0]; } return false; } + + public function render() + { + ob_end_clean(); + if (!$this->headersSet) header('Content-type: text/xml'); + if ($this->renderBody) echo $this->output; + } } diff --git a/webservice/classes/atompub/cmis/KT_cmis_atom_service.inc.php b/webservice/classes/atompub/cmis/KT_cmis_atom_service.inc.php index 26225ab..3266cd1 100644 --- a/webservice/classes/atompub/cmis/KT_cmis_atom_service.inc.php +++ b/webservice/classes/atompub/cmis/KT_cmis_atom_service.inc.php @@ -5,6 +5,28 @@ include_once(KT_ATOM_LIB_FOLDER.'KT_atom_service.inc.php'); class KT_cmis_atom_service extends KT_atom_service { // override and extend as needed + + protected $contentDownload = false; + + public public function isContentDownload() + { + return $this->contentDownload; + } + + public function notModified() + { + return $this->status == self::STATUS_NOT_MODIFIED; + } + + public function getOutput() + { + return $this->output; + } + + protected function setHeader($header = null, $value = null) + { + if ($header) header($header . ': ' . $value); + } } ?> \ No newline at end of file diff --git a/webservice/classes/atompub/cmis/ObjectService.inc.php b/webservice/classes/atompub/cmis/ObjectService.inc.php index 2eb22b6..4ca408d 100644 --- a/webservice/classes/atompub/cmis/ObjectService.inc.php +++ b/webservice/classes/atompub/cmis/ObjectService.inc.php @@ -84,6 +84,25 @@ class ObjectService extends KTObjectService { } /** + * Fetches the content stream data for an object + * + * @param string $repositoryId + * @param string $objectId + * @return string $contentStream (binary or text data) + */ + function getContentStream($repositoryId, $objectId) + { + $result = parent::getContentStream($repositoryId, $objectId); + + if ($result['status_code'] == 0) { + return $result['results']; + } + else { + return new PEAR_Error($result['message']); + } + } + + /** * Moves a fileable object from one folder to another. * * @param object $repositoryId