.
*
* You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
* California 94120-7775, or email info@knowledgetree.com.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "Powered by
* KnowledgeTree" logo and retain the original copyright notice. If the display of the
* logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
* must display the words "Powered by KnowledgeTree" and retain the original
* copyright notice.
*
* @copyright 2008-2009, KnowledgeTree Inc.
* @license GNU General Public License version 3
* @author KnowledgeTree Team
* @package KTCMIS
* @version Version 0.9
*/
/**
* Split into individual classes to handle each section of functionality.
* This is really just a handling layer between CMIS and the web services.
*/
// TODO implement exceptions in various calls (in the underlying classes)
// FIXME none of the error handling actually does anything, it's leftover from copy/paste of some ktapi code
require_once(realpath(dirname(__FILE__) . '/../../../config/dmsDefaults.php'));
require_once(KT_DIR . '/ktapi/ktapi.inc.php');
define ('CMIS_DIR', KT_LIB_DIR . '/api/ktcmis');
require_once(CMIS_DIR . '/exceptions/PermissionDeniedException.inc.php');
require_once(CMIS_DIR . '/services/CMISRepositoryService.inc.php');
require_once(CMIS_DIR . '/services/CMISNavigationService.inc.php');
require_once(CMIS_DIR . '/services/CMISObjectService.inc.php');
require_once(CMIS_DIR . '/util/CMISUtil.inc.php');
/**
* Base class for all KT CMIS classes
* Handles authentication
*/
class KTCMISBase {
// we want all child classes to share the ktapi and session instances, no matter where they are set from,
// so we declare them as static
static protected $ktapi;
static protected $session;
// public function __construct($username = null, $password = null)
// {
// $this->startSession($username, $password);
// }
// TODO try to pick up existing session if possible, i.e. if the $session value is not empty
public function startSession($username, $password)
{
// echo $username." :: ".$password."
";
// attempt to recover session if one exists
if (!is_null(self::$session) && !PEAR::isError(self::$session))
{
// echo "ATTEMPT TO RECOVER SESSION: ".print_r(self::$session, true)."
\n";
self::$session =& self::$ktapi->get_active_session(self::$session->get_sessionid());
}
// start new session if no existing session or problem getting existing session (expired, etc...)
if (is_null(self::$session) || PEAR::isError(self::$session))
{
// echo "ATTEMPT TO START NEW SESSION
\n";
self::$ktapi = new KTAPI();
self::$session =& self::$ktapi->start_session($username, $password);
}
// failed authentication?
if (PEAR::isError(self::$session))
{
throw new PermissionDeniedException('You must be authenticated to perform this action');
}
// print_r(self::$ktapi);
return self::$session;
}
public function getInterface()
{
return self::$ktapi;
}
public function getSession()
{
return self::$session;
}
// TODO what about destroying sessions? only on logout (which is not offered by the CMIS clients tested so far)
}
/**
* Handles low level repository information queries
*/
class KTRepositoryService extends KTCMISBase {
protected $RepositoryService;
public function __construct()
{
// instantiate underlying CMIS service
$this->RepositoryService = new CMISRepositoryService();
}
/**
* Fetch a list of all available repositories
*
* NOTE Since we only have one repository at the moment, this is expected to only return one result
*
* @return repositoryList[]
*/
public function getRepositories()
{
$repositories = $this->RepositoryService->getRepositories();
if (PEAR::isError($repositories))
{
return array(
"status_code" => 1,
"message" => "Failed getting repositories"
);
}
// extract the required info fields into array format for easy encoding;
$count = 0;
$repositoryList = array();
foreach ($repositories as $repository)
{
$repositoryList[$count]['repositoryId'] = $repository->getRepositoryId();
$repositoryList[$count]['repositoryName'] = $repository->getRepositoryName();
$repositoryList[$count]['repositoryURI'] = $repository->getRepositoryURI();
++$count;
}
return array(
"status_code" => 0,
"results" => $repositoryList
);
}
/**
* Fetches information about the selected repository
*
* @param string $repositoryId
*/
public function getRepositoryInfo($repositoryId)
{
$repositoryInfo = $this->RepositoryService->getRepositoryInfo($repositoryId);
if (PEAR::isError($repositoryInfo))
{
return array(
"status_code" => 1,
"message" => "Failed getting repository information"
);
}
// TODO output this manually, the function works but only for some objects so rather avoid it completely?
// NOTE the problems appear to be due to recursive objects
return array (
"status_code" => 0,
"results" => CMISUtil::objectToArray($repositoryInfo)
);
}
/**
* Fetch the list of supported object types for the selected repository
*
* @param string $repositoryId
*/
public function getTypes($repositoryId, $typeId = '', $returnPropertyDefinitions = false,
$maxItems = 0, $skipCount = 0, &$hasMoreItems = false)
{
try {
$repositoryObjectTypeResult = $this->RepositoryService->getTypes($repositoryId, $typeId, $returnPropertyDefinitions,
$maxItems, $skipCount, $hasMoreItems);
}
catch (Exception $e)
{
return array(
"status_code" => 1,
"message" => $e->getMessage()
);
}
// format as array style output
// NOTE only concerned with attributes at this time
// TODO add support for properties
foreach($repositoryObjectTypeResult as $key => $objectType)
{
$repositoryObjectTypes[$key] = $objectType['attributes'];
// TODO properties
// $repositoryObjectTypes[$key]['properties'] = $objectType['properties'];
}
return array (
"status_code" => 0,
"results" => $repositoryObjectTypes
);
}
/**
* Fetch the object type definition for the requested type
*
* @param string $repositoryId
* @param string $typeId
*/
public function getTypeDefinition($repositoryId, $typeId)
{
try {
$typeDefinitionResult = $this->RepositoryService->getTypeDefinition($repositoryId, $typeId);
}
catch (Exception $e)
{
return array(
"status_code" => 1,
"message" => $e->getMessage()
);
}
// format as array style output
// NOTE only concerned with attributes at this time
// TODO add support for properties
$typeDefinition = $typeDefinitionResult['attributes'];
return array (
"status_code" => 0,
"results" => $typeDefinition
);
}
}
/*
* Handles repository navigation
*/
class KTNavigationService extends KTCMISBase {
protected $NavigationService;
public function __construct()
{
// instantiate underlying CMIS service
$this->NavigationService = new CMISNavigationService();
}
public function startSession($username, $password)
{
parent::startSession($username, $password);
$this->setInterface();
return self::$session;
}
public function setInterface()
{
$this->NavigationService->setInterface(self::$ktapi);
}
/**
* Get descendents of the specified folder, up to the depth indicated
*
* @param string $repositoryId
* @param string $folderId
* @param boolean $includeAllowableActions
* @param boolean $includeRelationships
* @param string $typeID
* @param int $depth
* @param string $filter
* @return array $descendants
*/
public function getDescendants($repositoryId, $folderId, $includeAllowableActions, $includeRelationships,
$depth = 1, $typeID = 'Any', $filter = '')
{
// TODO optional parameters
$descendantsResult = $this->NavigationService->getDescendants($repositoryId, $folderId, $includeAllowableActions,
$includeRelationships, $depth);
if (PEAR::isError($descendantsResult))
{
return array(
"status_code" => 1,
"message" => "Failed getting descendants for folder"
);
}
// format for webservices consumption
// NOTE this will almost definitely be changing in the future, this is just to get something working
$descendants = CMISUtil::decodeObjectHierarchy($descendantsResult, 'child');
return array (
"status_code" => 0,
"results" => $descendants
);
}
/**
* Get direct children of the specified folder
*
* @param string $repositoryId
* @param string $folderId
* @param boolean $includeAllowableActions
* @param boolean $includeRelationships
* @param string $typeID
* @param string $filter
* @param int $maxItems
* @param int $skipCount
* @return array $descendants
*/
public function getChildren($repositoryId, $folderId, $includeAllowableActions, $includeRelationships,
$typeID = 'Any', $filter = '', $maxItems = 0, $skipCount = 0)
{
// TODO paging
// TODO optional parameters
$childrenResult = $this->NavigationService->getChildren($repositoryId, $folderId, $includeAllowableActions, $includeRelationships);
if (PEAR::isError($childrenResult))
{
return array(
"status_code" => 1,
"message" => "Failed getting descendants for folder"
);
}
$children = CMISUtil::decodeObjectHierarchy($childrenResult, 'child');
return array(
"status_code" => 0,
"results" => $children
);
}
/**
* Gets the parent of the selected folder
*
* @param string $repositoryId
* @param string $folderId
* @param boolean $includeAllowableActions
* @param boolean $includeRelationships
* @param boolean $returnToRoot
* @param string $filter
* @return ancestry[]
*/
public function getFolderParent($repositoryId, $folderId, $includeAllowableActions, $includeRelationships, $returnToRoot, $filter = '')
{
$ancestryResult = $this->NavigationService->getFolderParent($repositoryId, $folderId, $includeAllowableActions,
$includeRelationships, $returnToRoot);
if (PEAR::isError($ancestryResult))
{
return array(
"status_code" => 1,
"message" => "Failed getting ancestry for folder"
);
}
$ancestry = CMISUtil::decodeObjectHierarchy($ancestryResult, 'child');
return array(
"status_code" => 0,
"results" => $ancestry
);
}
/**
* Gets the parents for the selected object
*
* @param string $repositoryId
* @param string $folderId
* @param boolean $includeAllowableActions
* @param boolean $includeRelationships
* @param string $filter
* @return ancestry[]
*/
function getObjectParents($repositoryId, $objectId, $includeAllowableActions, $includeRelationships, $filter = '')
{
$ancestryResult = $this->NavigationService->getObjectParents($repositoryId, $objectId, $includeAllowableActions,
$includeRelationships);
if (PEAR::isError($ancestryResult))
{
return array(
"status_code" => 1,
"message" => "Failed getting ancestry for object"
);
}
$ancestry = CMISUtil::decodeObjectHierarchy($ancestryResult, 'child');
return array(
"status_code" => 0,
"results" => $ancestry
);
}
/**
* Returns a list of checked out documents from the selected repository
*
* @param string $repositoryId
* @param string $folderId The folder for which checked out docs are requested
* @param string $filter
* @param int $maxItems
* @param int $skipCount
* @return array $checkedout The collection of checked out documents
*/
function getCheckedoutDocs($repositoryId, $folderId = null, $filter = '', $maxItems = 0, $skipCount = 0)
{
$checkedout = $this->NavigationService->getObjectParents($repositoryId, $objectId, $includeAllowableActions,
$includeRelationships);
if (PEAR::isError($ancestryResult))
{
return array(
"status_code" => 1,
"message" => "Failed getting list of checked out documents"
);
}
return array(
"status_code" => 0,
"results" => $checkedout
);
}
}
/**
* Handles requests for and actions on Folders and Documents
*/
class KTObjectService extends KTCMISBase {
protected $ObjectService;
public function __construct()
{
// instantiate underlying CMIS service
$this->ObjectService = new CMISObjectService();
}
public function startSession($username, $password)
{
parent::startSession($username, $password);
$this->setInterface();
return self::$session;
}
public function setInterface()
{
$this->ObjectService->setInterface(self::$ktapi);
}
/**
* Gets the properties for the selected object
*
* @param string $repositoryId
* @param string $objectId
* @param boolean $includeAllowableActions
* @param boolean $includeRelationships
* @param string $returnVersion
* @param string $filter
* @return properties[]
*/
public function getProperties($repositoryId, $objectId, $includeAllowableActions, $includeRelationships,
$returnVersion = false, $filter = '')
{
try {
$propertyCollection = $this->ObjectService->getProperties($repositoryId, $objectId, $includeAllowableActions,
$includeRelationships);
}
catch (Exception $e)
{
return array(
"status_code" => 1,
"message" => $e->getMessage()
);
}
$properties = CMISUtil::createObjectPropertiesEntry($propertyCollection);
return array(
"status_code" => 0,
"results" => $properties
);
}
/**
* Creates a new document within the repository
*
* @param string $repositoryId The repository to which the document must be added
* @param string $typeId Object Type id for the document object being created
* @param array $properties Array of properties which must be applied to the created document object
* @param string $folderId The id of the folder which will be the parent of the created document object
* This parameter is optional IF unfilingCapability is supported
* @param contentStream $contentStream optional content stream data
* @param string $versioningState optional version state value: checkedout/major/minor
* @return string $objectId The id of the created folder object
*/
function createDocument($repositoryId, $typeId, $properties, $folderId = null,
$contentStream = null, $versioningState = null)
{
$objectId = null;
try {
$objectId = $this->ObjectService->createDocument($repositoryId, $typeId, $properties, $folderId,
$contentStream, $versioningState);
}
catch (Exception $e)
{
return array(
"status_code" => 1,
"message" => $e->getMessage()
);
}
return array(
'status_code' => 0,
'results' => $objectId
);
}
/**
* Creates a new folder within the repository
*
* @param string $repositoryId The repository to which the folder must be added
* @param string $typeId Object Type id for the folder object being created
* @param array $properties Array of properties which must be applied to the created folder object
* @param string $folderId The id of the folder which will be the parent of the created folder object
* @return string $objectId The id of the created folder object
*/
function createFolder($repositoryId, $typeId, $properties, $folderId)
{
$objectId = null;
try {
$objectId = $this->ObjectService->createFolder($repositoryId, $typeId, $properties, $folderId);
}
catch (Exception $e)
{
return array(
"status_code" => 1,
"message" => $e->getMessage()
);
}
return array(
'status_code' => 0,
'results' => $objectId
);
}
/**
* Sets the content stream data for an existing document
*
* if $overwriteFlag = TRUE, the new content stream is applied whether or not the document has an existing content stream
* if $overwriteFlag = FALSE, the new content stream is applied only if the document does not have an existing content stream
*
* NOTE A Repository MAY automatically create new Document versions as part of this service method.
* Therefore, the documentId output NEED NOT be identical to the documentId input.
*
* @param string $repositoryId
* @param string $documentId
* @param boolean $overwriteFlag
* @param string $contentStream
* @param string $changeToken
* @return string $documentId
*/
function setContentStream($repositoryId, $documentId, $overwriteFlag, $contentStream, $changeToken = null)
{
try {
$objectId = $this->ObjectService->setContentStream($repositoryId, $documentId, $overwriteFlag, $contentStream, $changeToken);
}
catch (Exception $e)
{
return array(
"status_code" => 1,
"message" => $e->getMessage()
);
}
return array(
'status_code' => 0,
'results' => $documentId
);
}
}
?>