You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by ri...@apache.org on 2013/07/03 04:39:57 UTC
svn commit: r1499181 - in /chemistry/phpclient/trunk/atom: ./ cmis-lib.php
cmis/ cmis/cmis_repository_wrapper.php cmis/cmis_service.php
Author: richardm
Date: Wed Jul 3 02:39:56 2013
New Revision: 1499181
URL: http://svn.apache.org/r1499181
Log:
Refactoring and adding CMIS 1.1 stubs
Added:
chemistry/phpclient/trunk/atom/
chemistry/phpclient/trunk/atom/cmis/
chemistry/phpclient/trunk/atom/cmis-lib.php
chemistry/phpclient/trunk/atom/cmis/cmis_repository_wrapper.php
chemistry/phpclient/trunk/atom/cmis/cmis_service.php
Added: chemistry/phpclient/trunk/atom/cmis-lib.php
URL: http://svn.apache.org/viewvc/chemistry/phpclient/trunk/atom/cmis-lib.php?rev=1499181&view=auto
==============================================================================
--- chemistry/phpclient/trunk/atom/cmis-lib.php (added)
+++ chemistry/phpclient/trunk/atom/cmis-lib.php Wed Jul 3 02:39:56 2013
@@ -0,0 +1,18 @@
+<?php
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+require_once('cmis/cmis_service.php');
\ No newline at end of file
Added: chemistry/phpclient/trunk/atom/cmis/cmis_repository_wrapper.php
URL: http://svn.apache.org/viewvc/chemistry/phpclient/trunk/atom/cmis/cmis_repository_wrapper.php?rev=1499181&view=auto
==============================================================================
--- chemistry/phpclient/trunk/atom/cmis/cmis_repository_wrapper.php (added)
+++ chemistry/phpclient/trunk/atom/cmis/cmis_repository_wrapper.php Wed Jul 3 02:39:56 2013
@@ -0,0 +1,764 @@
+<?php
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+define("HTTP_OK", 200);
+define("HTTP_CREATED", 201);
+define("HTTP_ACCEPTED", 202);
+define("HTTP_NONAUTHORITATIVE_INFORMATION", 203);
+define("HTTP_NO_CONTENT", 204);
+define("HTTP_RESET_CONTENT", 205);
+define("HTTP_PARTIAL_CONTENT", 206);
+define("HTTP_MULTIPLE_CHOICES", 300);
+define("HTTP_BAD_REQUEST", 400); // invalidArgument, filterNotValid
+define("HTTP_UNAUTHORIZED", 401);
+define("HTTP_FORBIDDEN", 403); // permissionDenied, streamNotSupported
+define("HTTP_NOT_FOUND", 404); // objectNotFound
+define("HTTP_METHOD_NOT_ALLOWED", 405); // notSupported
+define("HTTP_NOT_ACCEPTABLE", 406);
+define("HTTP_PROXY_AUTHENTICATION_REQUIRED", 407);
+define("xHTTP_REQUEST_TIMEOUT", 408); //Had to change this b/c HTTP_REQUEST_TIMEOUT conflicts with definition in Drupal 7
+define("HTTP_CONFLICT", 409); // constraint, contentAlreadyExists, versioning, updateConflict, nameConstraintViolation
+define("HTTP_UNSUPPORTED_MEDIA_TYPE", 415);
+define("HTTP_UNPROCESSABLE_ENTITY", 422);
+define("HTTP_INTERNAL_SERVER_ERROR", 500); // runtime, storage
+
+class CmisInvalidArgumentException extends Exception {}
+class CmisObjectNotFoundException extends Exception {}
+class CmisPermissionDeniedException extends Exception {}
+class CmisNotSupportedException extends Exception {}
+class CmisNotImplementedException extends Exception {}
+class CmisConstraintException extends Exception {}
+class CmisRuntimeException extends Exception {}
+
+/**
+ * @internal
+ */
+class CMISRepositoryWrapper
+{
+ // Handles --
+ // Workspace -- but only endpoints with a single repo
+ // Entry -- but only for objects
+ // Feeds -- but only for non-hierarchical feeds
+ // Does not handle --
+ // -- Hierarchical Feeds
+ // -- Types
+ // -- Others?
+ // Only Handles Basic Auth
+ // Very Little Error Checking
+ // Does not work against pre CMIS 1.0 Repos
+
+
+ /**
+ * @internal
+ */
+ var $url;
+
+ /**
+ * @internal
+ */
+ var $username;
+
+ /**
+ * @internal
+ */
+ var $password;
+
+ /**
+ * @internal
+ */
+ var $authenticated;
+
+ /**
+ * @internal
+ */
+ var $workspace;
+
+ /**
+ * @internal
+ */
+ var $last_request;
+
+ /**
+ * @internal
+ */
+ var $do_not_urlencode;
+
+ /**
+ * @internal
+ */
+ protected $_addlCurlOptions = array();
+
+
+ /**
+ * @internal
+ */
+ static $namespaces = array (
+ "cmis" => "http://docs.oasis-open.org/ns/cmis/core/200908/",
+ "cmisra" => "http://docs.oasis-open.org/ns/cmis/restatom/200908/",
+ "atom" => "http://www.w3.org/2005/Atom",
+ "app" => "http://www.w3.org/2007/app",
+
+ );
+
+ /**
+ * @internal
+ */
+ function __construct($url, $username = null, $password = null, $options = null, array $addlCurlOptions = array())
+ {
+ if (is_array($options) && $options["config:do_not_urlencode"]) {
+ $this->do_not_urlencode=true;
+ }
+ $this->_addlCurlOptions = $addlCurlOptions; // additional cURL options
+
+ $this->connect($url, $username, $password, $options);
+ }
+ /**
+ * @internal
+ */
+ static function getAsArray($prop) {
+ if ($prop == null) {
+ return array();
+ } elseif (!is_array($prop)) {
+ return array($prop);
+ } else {
+ return($prop);
+ }
+
+ }
+
+ /**
+ * @internal
+ */
+ static function getOpUrl($url, $options = null)
+ {
+ if (is_array($options) && (count($options) > 0))
+ {
+ $needs_question = strstr($url, "?") === false;
+ return $url . ($needs_question ? "?" : "&") . http_build_query($options);
+ } else
+ {
+ return $url;
+ }
+ }
+
+ /**
+ * @internal
+ */
+ function convertStatusCode($code, $message)
+ {
+ switch ($code) {
+ case HTTP_BAD_REQUEST:
+ return new CmisInvalidArgumentException($message, $code);
+ case HTTP_NOT_FOUND:
+ return new CmisObjectNotFoundException($message, $code);
+ case HTTP_FORBIDDEN:
+ return new CmisPermissionDeniedException($message, $code);
+ case HTTP_METHOD_NOT_ALLOWED:
+ return new CmisNotSupportedException($message, $code);
+ case HTTP_CONFLICT:
+ return new CmisConstraintException($message, $code);
+ default:
+ return new CmisRuntimeException($message, $code);
+ }
+ }
+
+ /**
+ * @internal
+ */
+ function connect($url, $username, $password, $options)
+ {
+ // TODO: Make this work with cookies
+ $this->url = $url;
+ $this->username = $username;
+ $this->password = $password;
+ $this->auth_options = $options;
+ $this->authenticated = false;
+ $retval = $this->doGet($this->url);
+ if ($retval->code == HTTP_OK || $retval->code == HTTP_CREATED)
+ {
+ $this->authenticated = true;
+ $this->workspace = CMISRepositoryWrapper :: extractWorkspace($retval->body);
+ }
+ }
+
+ /**
+ * @internal
+ */
+ function doGet($url)
+ {
+ $retval = $this->doRequest($url);
+ if ($retval->code != HTTP_OK)
+ {
+ throw $this->convertStatusCode($retval->code, $retval->body);
+ }
+ return $retval;
+ }
+
+ /**
+ * @internal
+ */
+ function doDelete($url)
+ {
+ $retval = $this->doRequest($url, "DELETE");
+ if ($retval->code != HTTP_NO_CONTENT)
+ {
+ throw $this->convertStatusCode($retval->code, $retval->body);
+ }
+ return $retval;
+ }
+
+ /**
+ * @internal
+ */
+ function doPost($url, $content, $contentType, $charset = null)
+ {
+ $retval = $this->doRequest($url, "POST", $content, $contentType);
+ if ($retval->code != HTTP_CREATED)
+ {
+ throw $this->convertStatusCode($retval->code, $retval->body);
+ }
+ return $retval;
+ }
+
+ /**
+ * @internal
+ */
+ function doPut($url, $content, $contentType, $charset = null)
+ {
+ $retval = $this->doRequest($url, "PUT", $content, $contentType);
+ if (($retval->code < HTTP_OK) || ($retval->code >= HTTP_MULTIPLE_CHOICES))
+ {
+ throw $this->convertStatusCode($retval->code, $retval->body);
+ }
+ return $retval;
+ }
+
+ /**
+ * @internal
+ */
+ function doRequest($url, $method = "GET", $content = null, $contentType = null, $charset = null)
+ {
+ // Process the HTTP request
+ // 'til now only the GET request has been tested
+ // Does not URL encode any inputs yet
+ if (is_array($this->auth_options))
+ {
+ $url = CMISRepositoryWrapper :: getOpUrl($url, $this->auth_options);
+ }
+ $session = curl_init($url);
+ curl_setopt($session, CURLOPT_HEADER, false);
+ curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
+ if ($this->username)
+ {
+ curl_setopt($session, CURLOPT_USERPWD, $this->username . ":" . $this->password);
+ }
+ curl_setopt($session, CURLOPT_CUSTOMREQUEST, $method);
+ if ($contentType)
+ {
+ curl_setopt($session, CURLOPT_HTTPHEADER, array (
+ "Content-Type: " . $contentType
+ ));
+ }
+ if ($content)
+ {
+ curl_setopt($session, CURLOPT_POSTFIELDS, $content);
+ }
+ if ($method == "POST")
+ {
+ curl_setopt($session, CURLOPT_POST, true);
+ }
+
+ // apply addl. cURL options
+ // WARNING: this may override previously set options
+ if (count($this->_addlCurlOptions)) {
+ foreach ($this->_addlCurlOptions as $key => $value) {
+ curl_setopt($session, $key, $value);
+ }
+ }
+
+
+ //TODO: Make this storage optional
+ $retval = new stdClass();
+ $retval->url = $url;
+ $retval->method = $method;
+ $retval->content_sent = $content;
+ $retval->content_type_sent = $contentType;
+ $retval->body = curl_exec($session);
+ $retval->code = curl_getinfo($session, CURLINFO_HTTP_CODE);
+ $retval->content_type = curl_getinfo($session, CURLINFO_CONTENT_TYPE);
+ $retval->content_length = curl_getinfo($session, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
+ curl_close($session);
+ $this->last_request = $retval;
+ return $retval;
+ }
+
+ function getLastRequest()
+ {
+ return $this->last_request;
+ }
+
+ function getLastRequestBody()
+ {
+ return $this->last_request->body;
+ }
+
+ function getLastRequestCode()
+ {
+ return $this->last_request->code;
+ }
+
+ function getLastRequestContentType()
+ {
+ return $this->last_request->content_type;
+ }
+
+ function getLastRequestContentLength()
+ {
+ return $this->last_request->content_length;
+ }
+
+ function getLastRequestURL()
+ {
+ return $this->last_request->url;
+ }
+
+ function getLastRequestMethod()
+ {
+ return $this->last_request->method;
+ }
+
+ function getLastRequestContentTypeSent()
+ {
+ return $this->last_request->content_type_sent;
+ }
+
+ function getLastRequestContentSent()
+ {
+ return $this->last_request->content_sent;
+ }
+
+ // Static Utility Functions
+ /**
+ * @internal
+ */
+ static function processTemplate($template, $values = array ())
+ {
+ // Fill in the blanks --
+ $retval = $template;
+ if (is_array($values))
+ {
+ foreach ($values as $name => $value)
+ {
+ $retval = str_replace("{" . $name . "}", $value, $retval);
+ }
+ }
+ // Fill in any unpoupated variables with ""
+ return preg_replace("/{[a-zA-Z0-9_]+}/", "", $retval);
+
+ }
+
+ /**
+ * @internal
+ */
+ static function doXQuery($xmldata, $xquery)
+ {
+ $doc = new DOMDocument();
+ $doc->loadXML($xmldata);
+ return CMISRepositoryWrapper :: doXQueryFromNode($doc, $xquery);
+ }
+
+ /**
+ * @internal
+ */
+ static function doXQueryFromNode($xmlnode, $xquery)
+ {
+ // Perform an XQUERY on a NODE
+ // Register the 4 CMIS namespaces
+ //THis may be a hopeless HACK!
+ //TODO: Review
+ if (!($xmlnode instanceof DOMDocument)) {
+ $xdoc=new DOMDocument();
+ $xnode = $xdoc->importNode($xmlnode,true);
+ $xdoc->appendChild($xnode);
+ $xpath = new DomXPath($xdoc);
+ } else {
+ $xpath = new DomXPath($xmlnode);
+ }
+ foreach (CMISRepositoryWrapper :: $namespaces as $nspre => $nsuri)
+ {
+ $xpath->registerNamespace($nspre, $nsuri);
+ }
+ return $xpath->query($xquery);
+
+ }
+
+ /**
+ * @internal
+ */
+ static function getLinksArray($xmlnode)
+ {
+ // Gets the links of an object or a workspace
+ // Distinguishes between the two "down" links
+ // -- the children link is put into the associative array with the "down" index
+ // -- the descendants link is put into the associative array with the "down-tree" index
+ // These links are distinquished by the mime type attribute, but these are probably the only two links that share the same rel ..
+ // so this was done as a one off
+ $links = array ();
+ $link_nodes = $xmlnode->getElementsByTagName("link");
+ foreach ($link_nodes as $ln)
+ {
+ if ($ln->attributes->getNamedItem("rel")->nodeValue == "down" && $ln->attributes->getNamedItem("type")->nodeValue == "application/cmistree+xml")
+ {
+ //Descendents and Childredn share same "rel" but different document type
+ $links["down-tree"] = $ln->attributes->getNamedItem("href")->nodeValue;
+ } else
+ {
+ $links[$ln->attributes->getNamedItem("rel")->nodeValue] = $ln->attributes->getNamedItem("href")->nodeValue;
+ }
+ }
+ return $links;
+ }
+
+ /**
+ * @internal
+ */
+ static function extractAllowableActions($xmldata)
+ {
+ $doc = new DOMDocument();
+ $doc->loadXML($xmldata);
+ return CMISRepositoryWrapper :: extractAllowableActionsFromNode($doc);
+ }
+
+ /**
+ * @internal
+ */
+ static function extractAllowableActionsFromNode($xmlnode)
+ {
+ $result = array();
+ $allowableActions = $xmlnode->getElementsByTagName("allowableActions");
+ if ($allowableActions->length > 0) {
+ foreach($allowableActions->item(0)->childNodes as $action)
+ {
+ if (isset($action->localName)) {
+ $result[$action->localName] = (preg_match("/^true$/i", $action->nodeValue) > 0);
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * @internal
+ */
+ static function extractObject($xmldata)
+ {
+ $doc = new DOMDocument();
+ $doc->loadXML($xmldata);
+ return CMISRepositoryWrapper :: extractObjectFromNode($doc);
+
+ }
+
+ /**
+ * @internal
+ */
+ static function extractObjectFromNode($xmlnode)
+ {
+ // Extracts the contents of an Object and organizes them into:
+ // -- Links
+ // -- Properties
+ // -- the Object ID
+ // RRM -- NEED TO ADD ALLOWABLEACTIONS
+ $retval = new stdClass();
+ $retval->links = CMISRepositoryWrapper :: getLinksArray($xmlnode);
+ $retval->properties = array ();
+ $prop_nodes = $xmlnode->getElementsByTagName("object")->item(0)->getElementsByTagName("properties")->item(0)->childNodes;
+ foreach ($prop_nodes as $pn)
+ {
+ if ($pn->attributes)
+ {
+ $propDefId = $pn->attributes->getNamedItem("propertyDefinitionId");
+ // TODO: Maybe use ->length=0 to even detect null values
+ if (!is_null($propDefId) && $pn->getElementsByTagName("value") && $pn->getElementsByTagName("value")->item(0))
+ {
+ if ($pn->getElementsByTagName("value")->length > 1) {
+ $retval->properties[$propDefId->nodeValue] = array();
+ for ($idx=0;$idx < $pn->getElementsByTagName("value")->length;$idx++) {
+ $retval->properties[$propDefId->nodeValue][$idx] = $pn->getElementsByTagName("value")->item($idx)->nodeValue;
+ }
+ } else {
+ $retval->properties[$propDefId->nodeValue] = $pn->getElementsByTagName("value")->item(0)->nodeValue;
+ }
+ }
+ }
+ }
+ $retval->uuid = $xmlnode->getElementsByTagName("id")->item(0)->nodeValue;
+ $retval->id = $retval->properties["cmis:objectId"];
+ //TODO: RRM FIX THIS
+ $children_node = $xmlnode->getElementsByTagName("children");
+ if (is_object($children_node)) {
+ $children_feed_c = $children_node->item(0);
+ }
+ if (is_object($children_feed_c)) {
+ $children_feed_l = $children_feed_c->getElementsByTagName("feed");
+ }
+ if (isset($children_feed_l) && is_object($children_feed_l) && is_object($children_feed_l->item(0))) {
+ $children_feed = $children_feed_l->item(0);
+ $children_doc = new DOMDocument();
+ $xnode = $children_doc->importNode($children_feed,true); // Avoid Wrong Document Error
+ $children_doc->appendChild($xnode);
+ $retval->children = CMISRepositoryWrapper :: extractObjectFeedFromNode($children_doc);
+ }
+ $retval->allowableActions = CMISRepositoryWrapper :: extractAllowableActionsFromNode($xmlnode);
+ return $retval;
+ }
+
+ /**
+ * @internal
+ */
+ function handleSpaces($path)
+ {
+ return $this->do_not_urlencode ? $path : rawurlencode($path);
+ }
+
+ /**
+ * @internal
+ */
+ static function extractTypeDef($xmldata)
+ {
+ $doc = new DOMDocument();
+ $doc->loadXML($xmldata);
+ return CMISRepositoryWrapper :: extractTypeDefFromNode($doc);
+
+ }
+
+ /**
+ * @internal
+ */
+ static function extractTypeDefFromNode($xmlnode)
+ {
+ // Extracts the contents of an Object and organizes them into:
+ // -- Links
+ // -- Properties
+ // -- the Object ID
+ // RRM -- NEED TO ADD ALLOWABLEACTIONS
+ $retval = new stdClass();
+ $retval->links = CMISRepositoryWrapper :: getLinksArray($xmlnode);
+ $retval->properties = array ();
+ $retval->attributes = array ();
+ $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmisra:type/*");
+ foreach ($result as $node)
+ {
+ if ((substr($node->nodeName, 0, 13) == "cmis:property") && (substr($node->nodeName, -10) == "Definition"))
+ {
+ $id = $node->getElementsByTagName("id")->item(0)->nodeValue;
+ $cardinality = $node->getElementsByTagName("cardinality")->item(0)->nodeValue;
+ $propertyType = $node->getElementsByTagName("propertyType")->item(0)->nodeValue;
+ // Stop Gap for now
+ $retval->properties[$id] = array (
+ "cmis:propertyType" => $propertyType,
+ "cmis:cardinality" => $cardinality,
+
+ );
+ } else
+ {
+ $retval->attributes[$node->nodeName] = $node->nodeValue;
+ }
+ $retval->id = $retval->attributes["cmis:id"];
+ }
+ //TODO: RRM FIX THIS
+ $children_node = $xmlnode->getElementsByTagName("children");
+ if (is_object($children_node)) {
+ $children_feed_c = $children_node->item(0);
+ }
+ if (is_object($children_feed_c)) {
+ $children_feed_l = $children_feed_c->getElementsByTagName("feed");
+ }
+ if (isset($childern_feed_l) && is_object($children_feed_l) && is_object($children_feed_l->item(0))) {
+ $children_feed = $children_feed_l->item(0);
+ $children_doc = new DOMDocument();
+ $xnode = $children_doc->importNode($children_feed,true); // Avoid Wrong Document Error
+ $children_doc->appendChild($xnode);
+ $retval->children = CMISRepositoryWrapper :: extractTypeFeedFromNode($children_doc);
+ }
+
+ /*
+ *
+
+
+
+ $prop_nodes = $xmlnode->getElementsByTagName("object")->item(0)->getElementsByTagName("properties")->item(0)->childNodes;
+ foreach ($prop_nodes as $pn) {
+ if ($pn->attributes) {
+ $retval->properties[$pn->attributes->getNamedItem("propertyDefinitionId")->nodeValue] = $pn->getElementsByTagName("value")->item(0)->nodeValue;
+ }
+ }
+ $retval->uuid=$xmlnode->getElementsByTagName("id")->item(0)->nodeValue;
+ $retval->id=$retval->properties["cmis:objectId"];
+ */
+ return $retval;
+ }
+
+ /**
+ * @internal
+ */
+ static function extractObjectFeed($xmldata)
+ {
+ //Assumes only one workspace for now
+ $doc = new DOMDocument();
+ $doc->loadXML($xmldata);
+ return CMISRepositoryWrapper :: extractObjectFeedFromNode($doc);
+ }
+
+ /**
+ * @internal
+ */
+ static function extractObjectFeedFromNode($xmlnode)
+ {
+ // Process a feed and extract the objects
+ // Does not handle hierarchy
+ // Provides two arrays
+ // -- one sequential array (a list)
+ // -- one hash table indexed by objectID
+ // and a property "numItems" that holds the total number of items available.
+ $retval = new stdClass();
+ // extract total number of items
+ $numItemsNode = CMISRepositoryWrapper::doXQueryFromNode($xmlnode, "/atom:feed/cmisra:numItems");
+ $retval->numItems = $numItemsNode->length ? (int) $numItemsNode->item(0)->nodeValue : -1; // set to negative value if info is not available
+
+ $retval->objectList = array ();
+ $retval->objectsById = array ();
+ $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "/atom:feed/atom:entry");
+ foreach ($result as $node)
+ {
+ $obj = CMISRepositoryWrapper :: extractObjectFromNode($node);
+ $retval->objectsById[$obj->id] = $obj;
+ $retval->objectList[] = & $retval->objectsById[$obj->id];
+ }
+ return $retval;
+ }
+
+ /**
+ * @internal
+ */
+ static function extractTypeFeed($xmldata)
+ {
+ //Assumes only one workspace for now
+ $doc = new DOMDocument();
+ $doc->loadXML($xmldata);
+ return CMISRepositoryWrapper :: extractTypeFeedFromNode($doc);
+ }
+
+ /**
+ * @internal
+ */
+ static function extractTypeFeedFromNode($xmlnode)
+ {
+ // Process a feed and extract the objects
+ // Does not handle hierarchy
+ // Provides two arrays
+ // -- one sequential array (a list)
+ // -- one hash table indexed by objectID
+ $retval = new stdClass();
+ $retval->objectList = array ();
+ $retval->objectsById = array ();
+ $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "/atom:feed/atom:entry");
+ foreach ($result as $node)
+ {
+ $obj = CMISRepositoryWrapper :: extractTypeDefFromNode($node);
+ $retval->objectsById[$obj->id] = $obj;
+ $retval->objectList[] = & $retval->objectsById[$obj->id];
+ }
+ return $retval;
+ }
+
+ /**
+ * @internal
+ */
+ static function extractWorkspace($xmldata)
+ {
+ //Assumes only one workspace for now
+ $doc = new DOMDocument();
+ $doc->loadXML($xmldata);
+ return CMISRepositoryWrapper :: extractWorkspaceFromNode($doc);
+ }
+
+ /**
+ * @internal
+ */
+ static function extractWorkspaceFromNode($xmlnode)
+ {
+ // Assumes only one workspace for now
+ // Load up the workspace object with arrays of
+ // links
+ // URI Templates
+ // Collections
+ // Capabilities
+ // General Repository Information
+ $retval = new stdClass();
+ $retval->links = CMISRepositoryWrapper :: getLinksArray($xmlnode);
+ $retval->uritemplates = array ();
+ $retval->collections = array ();
+ $retval->capabilities = array ();
+ $retval->repositoryInfo = array ();
+ $retval->permissions = array();
+ $retval->permissionsMapping = array();
+ $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmisra:uritemplate");
+ foreach ($result as $node)
+ {
+ $retval->uritemplates[$node->getElementsByTagName("type")->item(0)->nodeValue] = $node->getElementsByTagName("template")->item(0)->nodeValue;
+ }
+ $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//app:collection");
+ foreach ($result as $node)
+ {
+ $retval->collections[$node->getElementsByTagName("collectionType")->item(0)->nodeValue] = $node->attributes->getNamedItem("href")->nodeValue;
+ }
+ $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmis:capabilities/*");
+ foreach ($result as $node)
+ {
+ $retval->capabilities[$node->nodeName] = $node->nodeValue;
+ }
+ $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmisra:repositoryInfo/*[name()!='cmis:capabilities' and name()!='cmis:aclCapability']");
+ foreach ($result as $node)
+ {
+ $retval->repositoryInfo[$node->nodeName] = $node->nodeValue;
+ }
+ $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmis:aclCapability/cmis:permissions");
+ foreach ($result as $node)
+ {
+ $retval->permissions[$node->getElementsByTagName("permission")->item(0)->nodeValue] = $node->getElementsByTagName("description")->item(0)->nodeValue;
+ }
+ $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmis:aclCapability/cmis:mapping");
+ foreach ($result as $node)
+ {
+ $key = $node->getElementsByTagName("key")->item(0)->nodeValue;
+ $values = array();
+ foreach ($node->getElementsByTagName("permission") as $value)
+ {
+ array_push($values, $value->nodeValue);
+ }
+ $retval->permissionsMapping[$key] = $values;
+ }
+ $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmis:aclCapability/*[name()!='cmis:permissions' and name()!='cmis:mapping']");
+ foreach ($result as $node)
+ {
+ $retval->repositoryInfo[$node->nodeName] = $node->nodeValue;
+ }
+
+ return $retval;
+ }
+}
Added: chemistry/phpclient/trunk/atom/cmis/cmis_service.php
URL: http://svn.apache.org/viewvc/chemistry/phpclient/trunk/atom/cmis/cmis_service.php?rev=1499181&view=auto
==============================================================================
--- chemistry/phpclient/trunk/atom/cmis/cmis_service.php (added)
+++ chemistry/phpclient/trunk/atom/cmis/cmis_service.php Wed Jul 3 02:39:56 2013
@@ -0,0 +1,1230 @@
+<?php
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+require_once ('cmis_repository_wrapper.php');
+
+// Option Contants for Array Indexing
+// -- Generally optional flags that control how much information is returned
+// -- Change log token is an anomoly -- but included in URL as parameter
+define("OPT_MAX_ITEMS", "maxItems");
+define("OPT_SKIP_COUNT", "skipCount");
+define("OPT_FILTER", "filter");
+define("OPT_INCLUDE_PROPERTY_DEFINITIONS", "includePropertyDefinitions");
+define("OPT_INCLUDE_RELATIONSHIPS", "includeRelationships");
+define("OPT_INCLUDE_POLICY_IDS", "includePolicyIds");
+define("OPT_RENDITION_FILTER", "renditionFilter");
+define("OPT_INCLUDE_ACL", "includeACL");
+define("OPT_INCLUDE_ALLOWABLE_ACTIONS", "includeAllowableActions");
+define("OPT_DEPTH", "depth");
+define("OPT_CHANGE_LOG_TOKEN", "changeLogToken");
+define("OPT_CHECK_IN_COMMENT", "checkinComment");
+define("OPT_CHECK_IN", "checkin");
+define("OPT_MAJOR_VERSION", "major");
+
+define("COLLECTION_ROOT_FOLDER","root");
+define("COLLECTION_TYPES","types");
+define("COLLECTION_CHECKED_OUT","checkedout");
+define("COLLECTION_QUERY","query");
+define("COLLECTION_UNFILED","unfiled");
+
+define("URI_TEMPLATE_OBJECT_BY_ID","objectbyid");
+define("URI_TEMPLATE_OBJECT_BY_PATH","objectbypath");
+define("URI_TEMPLATE_TYPE_BY_ID","typebyid");
+define("URI_TEMPLATE_QUERY","query");
+
+define("LINK_SELF", "self");
+define("LINK_SERVICE","service");
+define("LINK_DESCRIBED_BY", "describedby");
+define("LINK_VIA","via");
+define("LINK_EDIT_MEDIA", "edit-media");
+define("LINK_EDIT","edit");
+define("LINK_ALTERNATE", "alternate");
+define("LINK_FIRST","first");
+define("LINK_PREVIOUS", "previous");
+define("LINK_NEXT","next");
+define("LINK_LAST", "last");
+define("LINK_UP","up");
+define("LINK_DOWN", "down");
+define("LINK_DOWN_TREE","down-tree");
+define("LINK_VERSION_HISTORY","version-history");
+define("LINK_CURRENT_VERSION", "current-version");
+
+
+define("LINK_ALLOWABLE_ACTIONS", "http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions");
+define("LINK_RELATIONSHIPS","http://docs.oasis-open.org/ns/cmis/link/200908/relationships");
+define("LINK_SOURCE","http://docs.oasis-open.org/ns/cmis/link/200908/source");
+define("LINK_TARGET","http://docs.oasis-open.org/ns/cmis/link/200908/target");
+define("LINK_POLICIES", "http://docs.oasis-open.org/ns/cmis/link/200908/policies");
+define("LINK_ACL","http://docs.oasis-open.org/ns/cmis/link/200908/acl");
+define("LINK_CHANGES","http://docs.oasis-open.org/ns/cmis/link/200908/changes");
+define("LINK_FOLDER_TREE","http://docs.oasis-open.org/ns/cmis/link/200908/foldertree");
+define("LINK_ROOT_DESCENDANTS","http://docs.oasis-open.org/ns/cmis/link/200908/rootdescendants");
+define("LINK_TYPE_DESCENDANTS","http://docs.oasis-open.org/ns/cmis/link/200908/typedescendants");
+
+define("MIME_ATOM_XML", 'application/atom+xml');
+define("MIME_ATOM_XML_ENTRY", 'application/atom+xml;type=entry');
+define("MIME_ATOM_XML_FEED", 'application/atom+xml;type=feed');
+define("MIME_CMIS_TREE", 'application/cmistree+xml');
+define("MIME_CMIS_QUERY", 'application/cmisquery+xml');
+
+// Many Links have a pattern to them based upon objectId -- but can that be depended upon?
+/**
+ * CMIS Service
+ *
+ * @api CMIS
+ * @since CMIS-1.0
+ */
+class CMISService extends CMISRepositoryWrapper {
+
+ /**
+ * @internal
+ */
+ var $_link_cache;
+
+ /**
+ * @internal
+ */
+ var $_title_cache;
+
+ /**
+ * @internal
+ */
+ var $_objTypeId_cache;
+
+ /**
+ * @internal
+ */
+ var $_type_cache;
+
+ /**
+ * @internal
+ */
+ var $_changeToken_cache;
+
+ /**
+ * Construct a new CMISService Connector
+ *
+ * @param String $url Endpoint URL
+ * @param String $username Username
+ * @param String $password Password
+ * @param mixed[] $options Connection Options
+ * @param mixed[] $addlCurlOptions Additional CURL Options
+ * @api CMIS-Service
+ * @since CMIS-1.0
+ */
+ function __construct($url, $username, $password, $options = null, array $addlCurlOptions = array ()) {
+ parent :: __construct($url, $username, $password, $options, $addlCurlOptions);
+ $this->_link_cache = array ();
+ $this->_title_cache = array ();
+ $this->_objTypeId_cache = array ();
+ $this->_type_cache = array ();
+ $this->_changeToken_cache = array ();
+ }
+
+ // Utility Methods -- Added Titles
+ // Should refactor to allow for single object
+
+ /**
+ * @internal
+ */
+ function cacheObjectInfo($obj) {
+ $this->_link_cache[$obj->id] = $obj->links;
+ $this->_title_cache[$obj->id] = $obj->properties["cmis:name"]; // Broad Assumption Here?
+ $this->_objTypeId_cache[$obj->id] = $obj->properties["cmis:objectTypeId"];
+ if (isset($obj->properties["cmis:changeToken"])) {
+ $this->_changeToken_cache[$obj->id] = $obj->properties["cmis:changeToken"];
+ }
+ }
+
+ /**
+ * Get an Object's property and return it as an array
+ *
+ * This returns an array even if it is a scalar or null
+ *
+ * @todo Allow the getProperty method to query the object type information and
+ * return multivalue properties as arrays even if empty or if only a single value
+ * is present.
+ * @param Object $obj Object
+ * @param String $propName Property Name
+ * @returns mixed[]
+ * @api CMIS-Helper
+ * @since CMIS-1.0
+ */
+ function getMultiValuedProp($obj,$propName) {
+ if (isset($obj->properties[$propName])) {
+ return CMISRepositoryWrapper::getAsArray($obj->properties[$propName]);
+ }
+ return array();
+ }
+
+ /**
+ * @internal
+ */
+ function cacheFeedInfo($objs) {
+ foreach ($objs->objectList as $obj) {
+ $this->cacheObjectInfo($obj);
+ }
+ }
+
+ /**
+ * @internal
+ */
+ function cacheTypeFeedInfo($typs) {
+ foreach ($typs->objectList as $typ) {
+ $this->cacheTypeInfo($typ);
+ }
+ }
+
+ /**
+ * @internal
+ */
+ function cacheTypeInfo($tDef) {
+ // TODO: Fix Type Caching with missing properties
+ $this->_type_cache[$tDef->id] = $tDef;
+ }
+
+ /**
+ * @internal
+ */
+ function getPropertyType($typeId, $propertyId) {
+ if (isset($this->_type_cache[$typeId])) {
+ if ($this->_type_cache[$typeId]->properties) {
+ return $this->_type_cache[$typeId]->properties[$propertyId]["cmis:propertyType"];
+ }
+ }
+ $obj = $this->getTypeDefinition($typeId);
+ return $obj->properties[$propertyId]["cmis:propertyType"];
+ }
+
+ /**
+ * @internal
+ */
+ function getObjectType($objectId) {
+ if ($this->_objTypeId_cache[$objectId]) {
+ return $this->_objTypeId_cache[$objectId];
+ }
+ $obj = $this->getObject($objectId);
+ return $obj->properties["cmis:objectTypeId"];
+ }
+
+ /**
+ * @internal
+ */
+ function getTitle($objectId) {
+ if ($this->_title_cache[$objectId]) {
+ return $this->_title_cache[$objectId];
+ }
+ $obj = $this->getObject($objectId);
+ return $obj->properties["cmis:name"];
+ }
+
+ /**
+ * @internal
+ */
+ function getTypeLink($typeId, $linkName) {
+ if ($this->_type_cache[$typeId]->links) {
+ return $this->_type_cache[$typeId]->links[$linkName];
+ }
+ $typ = $this->getTypeDefinition($typeId);
+ return $typ->links[$linkName];
+ }
+
+ /**
+ * @internal
+ */
+ function getLink($objectId, $linkName) {
+ if ($this->_link_cache[$objectId][$linkName]) {
+ return $this->_link_cache[$objectId][$linkName];
+ }
+ $obj = $this->getObject($objectId);
+ return $obj->links[$linkName];
+ }
+
+ // Repository Services
+ // TODO: Need to fix this for multiple repositories
+ /**
+ * Get an Object by Object Id
+ * @api CMIS-RepositoryServices-NotImplemented
+ * @since CMIS-1.0
+ */
+ function getRepositories() {
+ throw CmisNotImplementedException("getRepositories");
+ }
+
+ /**
+ * Get Repository Information
+ * @returns Object
+ * @api CMIS-RepositoryServices
+ * @since CMIS-1.0
+ */
+ function getRepositoryInfo() {
+ return $this->workspace;
+ }
+
+ /**
+ * Get a set of object-types that are descendants of the specified type
+ *
+ * If typeId is null, then the repository MUST return all types and ignore the depth parameter.
+ *
+ * @param String $typeId The typeId of an object-type specified in the repository
+ * @param $depth the number of levels in the hierarchy to return (-1 == all)
+ * @returns Object The set of descendant object-types defined for the given typeId.
+ * @api CMIS-RepositoryServices
+ * @since CMIS-1.0
+ */
+ function getTypeDescendants($typeId = null, $depth, $options = array ()) {
+ // TODO: Refactor Type Entries Caching
+ $varmap = $options;
+ if ($typeId) {
+ $hash_values = $options;
+ $hash_values[OPT_DEPTH] = $depth;
+ $myURL = $this->getTypeLink($typeId, LINK_DOWN_TREE);
+ $myURL = CMISRepositoryWrapper :: getOpUrl($myURL, $hash_values);
+ } else {
+ $myURL = $this->processTemplate($this->workspace->links[LINK_TYPE_DESCENDANTS], $varmap);
+ }
+ $ret = $this->doGet($myURL);
+ $typs = $this->extractTypeFeed($ret->body);
+ $this->cacheTypeFeedInfo($typs);
+ return $typs;
+ }
+
+ /**
+ * Get a list of object-types that are children of the specified type
+ *
+ * If typeId is null, then the repository MUST return all base object-types.
+ *
+ * @param String $typeId The typeId of an object-type specified in the repository
+ * @returns Object The list of child object-types defined for the given typeId.
+ * @api CMIS-RepositoryServices
+ * @since CMIS-1.0
+ */
+ function getTypeChildren($typeId = null, $options = array ()) {
+ // TODO: Refactor Type Entries Caching
+ $varmap = $options;
+ if ($typeId) {
+ $myURL = $this->getTypeLink($typeId, "down");
+ //TODO: Need GenURLQueryString Utility
+ } else {
+ //TODO: Need right URL
+ $myURL = $this->processTemplate($this->workspace->collections['types'], $varmap);
+ }
+ $ret = $this->doGet($myURL);
+ $typs = $this->extractTypeFeed($ret->body);
+ $this->cacheTypeFeedInfo($typs);
+ return $typs;
+ }
+
+ /**
+ * Gets the definition of the specified object-type.
+ *
+ * @param String $typeId Object Type Id
+ * @returns Object Type Definition of the Specified Object
+ * @api CMIS-RepositoryServices
+ * @since CMIS-1.0
+ */
+ function getTypeDefinition($typeId, $options = array ()) { // Nice to have
+ $varmap = $options;
+ $varmap["id"] = $typeId;
+ $myURL = $this->processTemplate($this->workspace->uritemplates['typebyid'], $varmap);
+ $ret = $this->doGet($myURL);
+ $obj = $this->extractTypeDef($ret->body);
+ $this->cacheTypeInfo($obj);
+ return $obj;
+ }
+
+ /**
+ * Get an Object's Property Type by Object Id
+ * @param String $objectId Object Id
+ * @returns Object Type Definition of the Specified Object
+ * @api CMIS-Helper
+ * @since CMIS-1.0
+ */
+ function getObjectTypeDefinition($objectId) { // Nice to have
+ $myURL = $this->getLink($objectId, "describedby");
+ $ret = $this->doGet($myURL);
+ $obj = $this->extractTypeDef($ret->body);
+ $this->cacheTypeInfo($obj);
+ return $obj;
+ }
+ //Repository Services -- New for 1.1
+ /**
+ * Creates a new type definition.
+ *
+ * Creates a new type definition that is a subtype of an existing specified parent type.
+ * Only properties that are new to this type (not inherited) are passed to this service.
+ *
+ * @param String $objectType A type definition object with the property definitions that are to change.
+ * @returns Object Type Definition of the Specified Object
+ * @api CMIS-RepositoryServices-NotImplemented
+ * @since CMIS-1.1
+ */
+ function createType($objectType) {
+ throw CmisNotImplementedException("createType");
+ }
+
+ /**
+ * Updates a type definition
+ *
+ * If you add an optional property to a type in error. There is no way to remove it/correct it - without
+ * deleting the type.
+ *
+ * @param String $objectType A type definition object with the property definitions that are to change.
+ * @returns Object The updated object-type including all property definitions.
+ * @api CMIS-RepositoryServices-NotImplemented
+ * @since CMIS-1.1
+ */
+ function updateType($objectType) {
+ throw CmisNotImplementedException("updateType");
+ }
+
+ /**
+ * Deletes a type definition
+ *
+ * If there are object instances present of the type being deleted then this operation MUST fail.
+ *
+ * @param String $typeId The typeId of an object-type specified in the repository.
+ * @api CMIS-RepositoryServices-NotImplemented
+ * @since CMIS-1.1
+ */
+ function deleteType($typeId) {
+ throw CmisNotImplementedException("deleteType");
+ }
+ //Navigation Services
+ /**
+ * Get the list of descendant folders contained in the specified folder.
+ *
+ * @param String $folderId the Object ID of the folder
+ * @param String $depth The number of levels of depth in the folder hierarchy from which to return results (-1 == ALL).
+ * @returns Object[] A tree of the child objects for the specified folder.
+ * @api CMIS-NavigationServices
+ * @since CMIS-1.0
+ */
+ function getFolderTree($folderId, $depth, $options = array ()) {
+ $hash_values = $options;
+ $hash_values[OPT_DEPTH] = $depth;
+ $myURL = $this->getLink($folderId, "http://docs.oasis-open.org/ns/cmis/link/200908/foldertree");
+ $myURL = CMISRepositoryWrapper :: getOpUrl($myURL, $hash_values);
+ $ret = $this->doGet($myURL);
+ $objs = $this->extractObjectFeed($ret->body);
+ $this->cacheFeedInfo($objs);
+ return $objs;
+ }
+
+ /**
+ * Get the list of descendant objects contained in the specified folder.
+ *
+ * @param String $folderId the Object ID of the folder
+ * @param String $depth The number of levels of depth in the folder hierarchy from which to return results (-1 == ALL).
+ * @returns Object[] A tree of the child objects for the specified folder.
+ * @api CMIS-NavigationServices
+ * @since CMIS-1.0
+ */
+ function getDescendants($folderId, $depth, $options = array ()) { // Nice to have
+ $hash_values = $options;
+ $hash_values[OPT_DEPTH] = $depth;
+ $myURL = $this->getLink($folderId, LINK_DOWN_TREE);
+ $myURL = CMISRepositoryWrapper :: getOpUrl($myURL, $hash_values);
+ $ret = $this->doGet($myURL);
+ $objs = $this->extractObjectFeed($ret->body);
+ $this->cacheFeedInfo($objs);
+ return $objs;
+ }
+
+ /**
+ * Get the list of child objects contained in the specified folder.
+ *
+ * @param String $folderId the Object ID of the folder
+ * @returns Object[] A list of the child objects for the specified folder.
+ * @api CMIS-NavigationServices
+ * @since CMIS-1.0
+ */
+ function getChildren($folderId, $options = array ()) {
+ $myURL = $this->getLink($folderId, LINK_DOWN);
+ //TODO: Need GenURLQueryString Utility
+ $ret = $this->doGet($myURL);
+ $objs = $this->extractObjectFeed($ret->body);
+ $this->cacheFeedInfo($objs);
+ return $objs;
+ }
+
+ /**
+ * Get the parent folder of the specified folder.
+ *
+ * @param String $folderId the Object ID of the folder
+ * @returns Object the parent folder.
+ * @api CMIS-NavigationServices
+ * @since CMIS-1.0
+ */
+ function getFolderParent($folderId, $options = array ()) { //yes
+ $myURL = $this->getLink($folderId, LINK_UP);
+ //TODO: Need GenURLQueryString Utility
+ $ret = $this->doGet($myURL);
+ $obj = $this->extractObjectEntry($ret->body);
+ $this->cacheObjectInfo($obj);
+ return $obj;
+ }
+
+ /**
+ * Get the parent folder(s) for the specified fileable object.
+ *
+ * @param String $objectId the Object ID of the Object
+ * @returns Object[] list of the parent folder(s) of the specified object.
+ * @api CMIS-NavigationServices
+ * @since CMIS-1.0
+ */
+ function getObjectParents($objectId, $options = array ()) { // yes
+ $myURL = $this->getLink($objectId, LINK_UP);
+ //TODO: Need GenURLQueryString Utility
+ $ret = $this->doGet($myURL);
+ $objs = $this->extractObjectFeed($ret->body);
+ $this->cacheFeedInfo($objs);
+ return $objs;
+ }
+
+ /**
+ * Get the list of documents that are checked out that the user has access to..
+ *
+ * @returns Object[] list of checked out documents.
+ * @api CMIS-NavigationServices
+ * @since CMIS-1.0
+ */
+ function getCheckedOutDocs($options = array ()) {
+ $obj_url = $this->workspace->collections[COLLECTION_CHECKED_OUT];
+ $ret = $this->doGet($obj_url);
+ $objs = $this->extractObjectFeed($ret->body);
+ $this->cacheFeedInfo($objs);
+ return $objs;
+ }
+
+ //Discovery Services
+ /**
+ * @internal
+ */
+ static function getQueryTemplate() {
+ ob_start();
+ echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' . "\n";
+?>
+<cmis:query xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
+xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/"
+xmlns:atom="http://www.w3.org/2005/Atom"
+xmlns:app="http://www.w3.org/2007/app"
+xmlns:cmisra="http://docs.oasisopen.org/ns/cmis/restatom/200908/">
+<cmis:statement>{q}</cmis:statement>
+<cmis:searchAllVersions>{searchAllVersions}</cmis:searchAllVersions>
+<cmis:includeAllowableActions>{includeAllowableActions}</cmis:includeAllowableActions>
+<cmis:includeRelationships>{includeRelationships}</cmis:includeRelationships>
+<cmis:renditionFilter>{renditionFilter}</cmis:renditionFilter>
+<cmis:maxItems>{maxItems}</cmis:maxItems>
+<cmis:skipCount>{skipCount}</cmis:skipCount>
+</cmis:query>
+<?php
+
+
+ return ob_get_clean();
+ }
+
+ /**
+ * Execute a CMIS Query
+ * @param String $statement Query Statement
+ * @param mixed[] $options Options
+ * @returns Object[] List of object propery values from query
+ * @api CMIS-DiscoveryServices
+ * @since CMIS-1.0
+ */
+ function query($statement, $options = array ()) {
+ static $query_template;
+ if (!isset ($query_template)) {
+ $query_template = CMISService :: getQueryTemplate();
+ }
+ $hash_values = $options;
+ $hash_values['q'] = $statement;
+ $post_value = CMISRepositoryWrapper :: processTemplate($query_template, $hash_values);
+ $ret = $this->doPost($this->workspace->collections['query'], $post_value, MIME_CMIS_QUERY);
+ $objs = $this->extractObjectFeed($ret->body);
+ $this->cacheFeedInfo($objs);
+ return $objs;
+ }
+
+ /**
+ * @internal
+ */
+ function checkURL($url,$functionName=null) {
+ if (!$url) {
+ throw new CmisNotSupportedException($functionName?$functionName:"UnspecifiedMethod");
+ }
+ }
+
+ /**
+ * Get Content Changes
+ * @param mixed[] $options Options
+ * @returns Object[] List of Change Events
+ * @api CMIS-DiscoveryServices
+ * @since CMIS-1.0
+ */
+ function getContentChanges($options = array()) {
+ $myURL = CMISRepositoryWrapper :: processTemplate($this->workspace->links[LINK_CHANGES],$options);
+ $this->checkURL($myURL,"getContentChanges");
+ $ret = $this->doGet($myURL);
+ $objs = $this->extractObjectFeed($ret->body);
+ $this->cacheFeedInfo($objs);
+ return $objs;
+ }
+
+ //Object Services
+ /**
+ * @internal
+ */
+ static function getEntryTemplate() {
+ ob_start();
+ echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' . "\n";
+?>
+<atom:entry xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
+xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/"
+xmlns:atom="http://www.w3.org/2005/Atom"
+xmlns:app="http://www.w3.org/2007/app"
+xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/">
+<atom:title>{title}</atom:title>
+{SUMMARY}
+{CONTENT}
+<cmisra:object><cmis:properties>{PROPERTIES}</cmis:properties></cmisra:object>
+</atom:entry>
+<?php
+
+
+ return ob_get_clean();
+ }
+
+
+ /**
+ * @internal
+ */
+ static function getPropertyTemplate() {
+ ob_start();
+?>
+ <cmis:property{propertyType} propertyDefinitionId="{propertyId}">
+ <cmis:value>{properties}</cmis:value>
+ </cmis:property{propertyType}>
+<?php
+
+
+ return ob_get_clean();
+ }
+
+
+ /**
+ * @internal
+ */
+ function processPropertyTemplates($objectType, $propMap) {
+ static $propTemplate;
+ static $propertyTypeMap;
+ if (!isset ($propTemplate)) {
+ $propTemplate = CMISService :: getPropertyTemplate();
+ }
+ if (!isset ($propertyTypeMap)) { // Not sure if I need to do this like this
+ $propertyTypeMap = array (
+ "integer" => "Integer",
+ "boolean" => "Boolean",
+ "datetime" => "DateTime",
+ "decimal" => "Decimal",
+ "html" => "Html",
+ "id" => "Id",
+ "string" => "String",
+ "url" => "Url",
+ "xml" => "Xml",
+
+
+ );
+ }
+ $propertyContent = "";
+ $hash_values = array ();
+ foreach ($propMap as $propId => $propValue) {
+ $hash_values['propertyType'] = $propertyTypeMap[$this->getPropertyType($objectType, $propId)];
+ $hash_values['propertyId'] = $propId;
+ if (is_array($propValue)) {
+ $first_one = true;
+ $hash_values['properties'] = "";
+ foreach ($propValue as $val) {
+ //This is a bit of a hack
+ if ($first_one) {
+ $first_one = false;
+ } else {
+ $hash_values['properties'] .= "</cmis:value>\n<cmis:value>";
+ }
+ $hash_values['properties'] .= $val;
+ }
+ } else {
+ $hash_values['properties'] = $propValue;
+ }
+ //echo "HASH:\n";
+ //print_r(array("template" =>$propTemplate, "Hash" => $hash_values));
+ $propertyContent .= CMISRepositoryWrapper :: processTemplate($propTemplate, $hash_values);
+ }
+ return $propertyContent;
+ }
+ /**
+ * @internal
+ */
+ static function getContentEntry($content, $content_type = "application/octet-stream") {
+ static $contentTemplate;
+ if (!isset ($contentTemplate)) {
+ $contentTemplate = CMISService :: getContentTemplate();
+ }
+ if ($content) {
+ return CMISRepositoryWrapper :: processTemplate($contentTemplate, array (
+ "content" => base64_encode($content),
+ "content_type" => $content_type
+ ));
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @internal
+ */
+ static function getSummaryTemplate() {
+ ob_start();
+?>
+ <atom:summary>{summary}</atom:summary>
+<?php
+
+
+ return ob_get_clean();
+ }
+
+ /**
+ * @internal
+ */
+ static function getContentTemplate() {
+ ob_start();
+?>
+ <cmisra:content>
+ <cmisra:mediatype>
+ {content_type}
+ </cmisra:mediatype>
+ <cmisra:base64>
+ {content}
+ </cmisra:base64>
+ </cmisra:content>
+<?php
+
+
+ return ob_get_clean();
+ }
+ /**
+ * @internal
+ */
+ static function createAtomEntry($name, $properties) {
+
+ }
+
+ /**
+ * Get an Object by Object Id
+ * @param String $objectId Object ID
+ * @param mixed[] $options Options
+ * @returns Object
+ * @api CMIS-ObjectServices
+ * @since CMIS-1.0
+ */
+ function getObject($objectId, $options = array ()) {
+ $varmap = $options;
+ $varmap["id"] = $objectId;
+ $obj_url = $this->processTemplate($this->workspace->uritemplates['objectbyid'], $varmap);
+ $ret = $this->doGet($obj_url);
+ $obj = $this->extractObject($ret->body);
+ $this->cacheObjectInfo($obj);
+ return $obj;
+ }
+
+ /**
+ * Get an Object by its Path
+ * @param String $path Path To Object
+ * @param mixed[] $options Options
+ * @returns Object
+ * @api CMIS-ObjectServices
+ * @since CMIS-1.0
+ */
+ function getObjectByPath($path, $options = array ()) {
+ $varmap = $options;
+ $varmap["path"] = $this->handleSpaces($path);
+ $obj_url = $this->processTemplate($this->workspace->uritemplates['objectbypath'], $varmap);
+ $ret = $this->doGet($obj_url);
+ $obj = $this->extractObject($ret->body);
+ $this->cacheObjectInfo($obj);
+ return $obj;
+ }
+
+ /**
+ * Get an Object's Properties by Object Id
+ * @param String $objectId Object Id
+ * @param mixed[] $options Options
+ * @returns Object
+ * @api CMIS-ObjectServices
+ * @since CMIS-1.0
+ */
+ function getProperties($objectId, $options = array ()) {
+ // May need to set the options array default --
+ return $this->getObject($objectId, $options);
+ }
+
+ /**
+ * Get an Object's Allowable Actions
+ * @param String $objectId Object Id
+ * @param mixed[] $options Options
+ * @returns mixed[]
+ * @api CMIS-ObjectServices
+ * @since CMIS-1.0
+ */
+ function getAllowableActions($objectId, $options = array ()) {
+ $myURL = $this->getLink($objectId, LINK_ALLOWABLE_ACTIONS);
+ $ret = $this->doGet($myURL);
+ $result = $this->extractAllowableActions($ret->body);
+ return $result;
+ }
+
+ /**
+ * Get the list of associated renditions for the specified object
+ *
+ * Only rendition attributes are returned, not rendition stream.
+ * @param String $objectId Object Id
+ * @param mixed[] $options Options
+ * @returns Object[]
+ * @api CMIS-ObjectServices
+ * @since CMIS-1.0
+ */
+ function getRenditions($objectId, $options = array (
+ OPT_RENDITION_FILTER => "*"
+ )) {
+ return getObject($objectId, $options);
+ }
+
+ /**
+ * Get an Object's Allowable Actions
+ * @param String $objectId Object Id
+ * @param mixed[] $options Options
+ * @returns String
+ * @api CMIS-ObjectServices
+ * @since CMIS-1.0
+ */
+ function getContentStream($objectId, $options = array ()) { // Yes
+ $myURL = $this->getLink($objectId, "edit-media");
+ $ret = $this->doGet($myURL);
+ // doRequest stores the last request information in this object
+ return $ret->body;
+ }
+
+ /**
+ * @internal
+ */
+ function legacyPostObject($folderId, $objectName, $objectType, $properties = array (), $content = null, $content_type = "application/octet-stream", $options = array ())
+ { // Yes
+ $myURL = $this->getLink($folderId, "down");
+ // TODO: Need Proper Query String Handling
+ // Assumes that the 'down' link does not have a querystring in it
+ $myURL = CMISRepositoryWrapper :: getOpUrl($myURL, $options);
+ static $entry_template;
+ if (!isset ($entry_template))
+ {
+ $entry_template = CMISService :: getEntryTemplate();
+ }
+ if (is_array($properties))
+ {
+ $hash_values = $properties;
+ } else
+ {
+ $hash_values = array ();
+ }
+ if (!isset ($hash_values["cmis:objectTypeId"]))
+ {
+ $hash_values["cmis:objectTypeId"] = $objectType;
+ }
+ $properties_xml = $this->processPropertyTemplates($hash_values["cmis:objectTypeId"], $hash_values);
+ if (is_array($options))
+ {
+ $hash_values = $options;
+ } else
+ {
+ $hash_values = array ();
+ }
+ $hash_values["PROPERTIES"] = $properties_xml;
+ $hash_values["SUMMARY"] = CMISService :: getSummaryTemplate();
+ if ($content)
+ {
+ $hash_values["CONTENT"] = CMISService :: getContentEntry($content, $content_type);
+ }
+ if (!isset ($hash_values['title']))
+ {
+ $hash_values['title'] = $objectName;
+ }
+ if (!isset ($hash_values['summary']))
+ {
+ $hash_values['summary'] = $objectName;
+ }
+ $post_value = CMISRepositoryWrapper :: processTemplate($entry_template, $hash_values);
+ $ret = $this->doPost($myURL, $post_value, MIME_ATOM_XML_ENTRY);
+ // print "DO_POST\n";
+ // print_r($ret);
+ $obj = $this->extractObject($ret->body);
+ $this->cacheObjectInfo($obj);
+ return $obj;
+ }
+
+ /**
+ * @internal
+ */
+ function postObject($folderId, $objectName, $objectType, $properties = array (), $content = null, $content_type = "application/octet-stream", $options = array ()) {
+ $myURL = $this->getLink($folderId, "down");
+ // TODO: Need Proper Query String Handling
+ // Assumes that the 'down' link does not have a querystring in it
+ if (is_array($properties)) {
+ $hash_values = $properties;
+ } else {
+ $hash_values = array ();
+ }
+ if (!isset ($hash_values["cmis:objectTypeId"])) {
+ $hash_values["cmis:objectTypeId"] = $objectType;
+ }
+ if (!isset ($hash_values['title'])) {
+ $hash_values['title'] = $objectName;
+ }
+ if (!isset ($hash_values['summary'])) {
+ $hash_values['summary'] = $objectName;
+ }
+ $this->postEntry($myURL, $hash_values);
+ }
+
+ /**
+ * @internal
+ */
+ function postEntry($url, $properties = array (), $content = null, $content_type = "application/octet-stream", $options = array ()) {
+ // TODO: Fix Hack HERE -- get type if it is there otherwise retrieve it --
+ $objectType ="";
+ if (isset($properties['cmis:objectTypeId'])) {
+ $objType = $properties['cmis:objectTypeId'];
+ } else if (isset($properties["cmis:objectId"])) {
+ $objType=$this->getObjectType($properties["cmis:objectId"]);
+ }
+ $myURL = CMISRepositoryWrapper :: getOpUrl($url, $options);
+ //DEBUG
+ print("DEBUG: postEntry: myURL = " . $myURL);
+ static $entry_template;
+ if (!isset ($entry_template)) {
+ $entry_template = CMISService :: getEntryTemplate();
+ }
+ print("DEBUG: postEntry: entry_template = " . $entry_template);
+ $properties_xml = $this->processPropertyTemplates($objType, $properties);
+ print("DEBUG: postEntry: properties_xml = " . $properties_xml);
+ if (is_array($options)) {
+ $hash_values = $options;
+ } else {
+ $hash_values = array ();
+ }
+ $hash_values["PROPERTIES"] = $properties_xml;
+ $hash_values["SUMMARY"] = CMISService :: getSummaryTemplate();
+ if ($content) {
+ $hash_values["CONTENT"] = CMISService :: getContentEntry($content, $content_type);
+ }
+ print("DEBUG: postEntry: hash_values = " . print_r($hash_values,true));
+ $post_value = CMISRepositoryWrapper :: processTemplate($entry_template, $hash_values);
+ print("DEBUG: postEntry: post_value = " . $post_value);
+ $ret = $this->doPost($myURL, $post_value, MIME_ATOM_XML_ENTRY);
+ $obj = $this->extractObject($ret->body);
+ $this->cacheObjectInfo($obj);
+ return $obj;
+ }
+
+ function createDocument($folderId, $fileName, $properties = array (), $content = null, $content_type = "application/octet-stream", $options = array ()) { // Yes
+ return $this->postObject($folderId, $fileName, "cmis:document", $properties, $content, $content_type, $options);
+ }
+
+ function createDocumentFromSource() { //Yes?
+ throw new CmisNotSupportedException("createDocumentFromSource is not supported by the AtomPub binding!");
+ }
+
+ function createFolder($folderId, $folderName, $properties = array (), $options = array ()) { // Yes
+ return $this->legacyPostObject($folderId, $folderName, "cmis:folder", $properties, null, null, $options);
+ }
+
+ function createRelationship() { // Not in first Release
+ throw CmisNotImplementedException("createRelationship");
+ }
+
+ function createPolicy() { // Not in first Release
+ throw CmisNotImplementedException("createPolicy");
+ }
+
+ function createItem() {
+ throw CmisNotImplementedException("createItem");
+ }
+
+ function updateProperties($objectId, $properties = array (), $options = array ()) { // Yes
+ $varmap = $options;
+ $varmap["id"] = $objectId;
+ $objectName = $this->getTitle($objectId);
+ $objectType = $this->getObjectType($objectId);
+ $obj_url = $this->getLink($objectId, "edit");
+ $obj_url = CMISRepositoryWrapper :: getOpUrl($obj_url, $options);
+ static $entry_template;
+ if (!isset ($entry_template)) {
+ $entry_template = CMISService :: getEntryTemplate();
+ }
+ if (is_array($properties)) {
+ $hash_values = $properties;
+ } else {
+ $hash_values = array ();
+ }
+ if ($this->_changeToken_cache[$objectId] != null) {
+ $properties['cmis:changeToken'] = $this->_changeToken_cache[$objectId];
+ }
+
+ $properties_xml = $this->processPropertyTemplates($objectType, $hash_values);
+ if (is_array($options)) {
+ $hash_values = $options;
+ } else {
+ $hash_values = array ();
+ }
+ $hash_values["PROPERTIES"] = $properties_xml;
+ $hash_values["SUMMARY"] = CMISService :: getSummaryTemplate();
+ if (!isset ($hash_values['title'])) {
+ $hash_values['title'] = $objectName;
+ }
+ if (!isset ($hash_values['summary'])) {
+ $hash_values['summary'] = $objectName;
+ }
+ $put_value = CMISRepositoryWrapper :: processTemplate($entry_template, $hash_values);
+ // print $put_value; // RRM DEBUG
+ $ret = $this->doPut($obj_url, $put_value, MIME_ATOM_XML_ENTRY);
+ $obj = $this->extractObject($ret->body);
+ $this->cacheObjectInfo($obj);
+ return $obj;
+ }
+
+ // New for 1.1
+ function bulkUpdateProperties() {
+ throw CmisNotImplementedException("bulkUpdateProperties");
+ }
+
+ function moveObject($objectId, $targetFolderId, $sourceFolderId, $options = array ()) { //yes
+ $options['sourceFolderId'] = $sourceFolderId;
+ return $this->postObject($targetFolderId, $this->getTitle($objectId), $this->getObjectType($objectId), array (
+ "cmis:objectId" => $objectId
+ ), null, null, $options);
+ }
+
+ /**
+ * Delete an Object
+ * @param String $objectId Object ID
+ * @param mixed[] $options Options
+ * @api CMIS-ObjectServices
+ * @since CMIS-1.0
+ */
+ function deleteObject($objectId, $options = array ()) { //Yes
+ $varmap = $options;
+ $varmap["id"] = $objectId;
+ $obj_url = $this->getLink($objectId, "edit");
+ $ret = $this->doDelete($obj_url);
+ return;
+ }
+
+ /**
+ * Delete an Object Tree
+ * @param String $folderId Folder Object ID
+ * @param mixed[] $options Options
+ * @return Object[] Array of problem objects
+ * @api CMIS-ObjectServices
+ * @since CMIS-1.0
+ */
+ function deleteTree($folderId, $options = array ()) { // Nice to have
+ $hash_values = $options;
+ $myURL = $this->getLink($folderId, LINK_DOWN_TREE);
+ $myURL = CMISRepositoryWrapper :: getOpUrl($myURL, $hash_values);
+ $ret = $this->doDelete($myURL);
+ //List of problem objects
+ $objs = $this->extractObjectFeed($ret->body);
+ $this->cacheFeedInfo($objs);
+ return $objs;
+ }
+
+ /**
+ * Set an Objects Content Stream
+ * @param String $objectId Object ID
+ * @param String $content Content to be appended
+ * @param String $content_type Content Mime Type
+ * @param mixed[] $options Options
+ * @returns Object
+ * @api CMIS-ObjectServices
+ * @since CMIS-1.0
+ */
+ function setContentStream($objectId, $content, $content_type, $options = array ()) { //Yes
+ $myURL = $this->getLink($objectId, "edit-media");
+ $ret = $this->doPut($myURL, $content, $content_type);
+ }
+
+ // New for 1.1
+ /**
+ * Append Content to an Objects Content Stream
+ * @param String $objectId Object ID
+ * @param String $content Content to be appended
+ * @param String $content_type Content Mime Type
+ * @param mixed[] $options Options
+ * @returns Object
+ * @api CMIS-ObjectServices-NotImplemented
+ * @since CMIS-1.0
+ */
+ function appendContentStream($objectId, $content, $content_type, $options = array ()) { //Yes
+ throw CmisNotImplementedException("appendContentStream");
+ }
+
+ /**
+ * Delete an Objects Content Stream
+ * @param String $objectId Object ID
+ * @param mixed[] $options Options
+ * @api CMIS-ObjectServices
+ * @since CMIS-1.0
+ */
+ function deleteContentStream($objectId, $options = array ()) { //yes
+ $myURL = $this->getLink($objectId, "edit-media");
+ $ret = $this->doDelete($myURL);
+ return;
+ }
+
+ //Versioning Services
+ function getPropertiesOfLatestVersion($objectId, $major = false, $options = array ()) {
+ return $this->getObjectOfLatestVersion($objectId, $major, $options);
+ }
+
+ function getObjectOfLatestVersion($objectId, $major = false, $options = array ()) {
+ return $this->getObject($objectId, $options); // Won't be able to handle major/minor distinction
+ // Need to add this -- "current-version"
+ /*
+ * Headers: CMIS-filter, CMIS-returnVersion (enumReturnVersion)
+ * HTTP Arguments: filter, returnVersion
+ * Enum returnVersion: This, Latest, Major
+ */
+ }
+
+ function getAllVersions() {
+ throw CmisNotImplementedException("getAllVersions");
+ }
+
+ /**
+ * Checkout
+ * @param String $objectId Object ID
+ * @param mixed[] $options Options
+ * @return Object The working copy
+ * @api CMIS-VersionServices
+ * @since CMIS-1.0
+ */
+ function checkOut($objectId,$options = array()) {
+ $myURL = $this->workspace->collections[COLLECTION_CHECKED_OUT];
+ $myURL = CMISRepositoryWrapper :: getOpUrl($myURL, $options);
+ $ret = $this->postEntry($myURL, array ("cmis:objectId" => $objectId));
+ $obj = $this->extractObject($ret->body);
+ $this->cacheObjectInfo($obj);
+ return $obj;
+ }
+
+ /**
+ * Checkin
+ * @param String $objectId Object ID
+ * @param mixed[] $options Options
+ * @return Object The checked in object
+ * @api CMIS-VersionServices
+ * @since CMIS-1.0
+ */
+ function checkIn($objectId,$options = array()) {
+ $myURL = $this->workspace->collections[COLLECTION_CHECKED_OUT];
+ $myURL = CMISRepositoryWrapper :: getOpUrl($myURL, $options);
+ $ret = $this->postEntry($myURL, array ("cmis:objectId" => $objectId));
+ $obj = $this->extractObject($ret->body);
+ $this->cacheObjectInfo($obj);
+ return $obj;
+ }
+
+ /**
+ * Cancel Checkout
+ * @param String $objectId Object ID
+ * @param mixed[] $options Options
+ * @api CMIS-VersionServices
+ * @since CMIS-1.0
+ */
+ function cancelCheckOut($objectId,$options = array()) {
+ // TODO: Look at links "via" and "working-copy"
+ $varmap = $options;
+ $varmap["id"] = $objectId;
+ $via = $this->getLink($objectId,"via");
+ print("DEBUG: cancelCheckOut VIA="+$via);
+ if (!$via) {
+ throw new CmisInvalidArgumentException("Not a WORKING COPY!");
+ }
+ $obj_url = $this->getLink($objectId, "edit");
+ $ret = $this->doDelete($obj_url);
+ return;
+ }
+
+ function deleteAllVersions() {
+ throw CmisNotImplementedException("deleteAllVersions");
+ }
+
+ //Relationship Services
+ function getObjectRelationships() {
+ // get stripped down version of object (for the links) and then get the relationships?
+ // Low priority -- can get all information when getting object
+ throw CmisNotImplementedException("getObjectRelationships");
+ }
+
+ //Multi-Filing ServicesRelation
+ function addObjectToFolder($objectId, $targetFolderId, $options = array ()) { // Probably
+ return $this->postObject($targetFolderId, $this->getTitle($objectId), $this->getObjectType($objectId), array (
+ "cmis:objectId" => $objectId
+ ), null, null, $options);
+ }
+
+ function removeObjectFromFolder($objectId, $targetFolderId, $options = array ()) { //Probably
+ $hash_values = $options;
+ $myURL = $this->workspace->collections['unfiled'];
+ $myURL = CMISRepositoryWrapper :: getOpUrl($myURL, $hash_values);
+ $ret = $this->postEntry($myURL, array ("cmis:objectId" => $objectId),null,null,array("removeFrom" => $targetFolderId));
+ $obj = $this->extractObject($ret->body);
+ $this->cacheObjectInfo($obj);
+ return $obj;
+ }
+
+ //Policy Services
+ function getAppliedPolicies() {
+ throw CmisNotImplementedException("getAppliedPolicies");
+ }
+
+ function applyPolicy() {
+ throw CmisNotImplementedException("applyPolicy");
+ }
+
+ function removePolicy() {
+ throw CmisNotImplementedException("removePolicy");
+ }
+
+ //ACL Services
+ function getACL() {
+ throw CmisNotImplementedException("getACL");
+ }
+
+ function applyACL() {
+ throw CmisNotImplementedException("applyACL");
+ }
+}
\ No newline at end of file