MDL-45774 fix trailing whitespace
[moodle.git] / lib / alfresco / Service / Node.php
blob71bc3623ff0674f174f7e1a06dadccabdb8869e4
1 <?php
2 /*
3 * Copyright (C) 2005-2010 Alfresco Software Limited.
5 * This file is part of Alfresco
7 * Alfresco is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * Alfresco is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
21 require_once $CFG->libdir.'/alfresco/Service/Store.php';
22 require_once $CFG->libdir.'/alfresco/Service/ChildAssociation.php';
23 require_once $CFG->libdir.'/alfresco/Service/Association.php';
24 require_once $CFG->libdir.'/alfresco/Service/NamespaceMap.php';
25 require_once $CFG->libdir.'/alfresco/Service/ContentData.php';
26 require_once $CFG->libdir.'/alfresco/Service/VersionHistory.php';
27 require_once $CFG->libdir.'/alfresco/Service/Version.php';
29 class Node extends BaseObject
31 private $_session;
32 private $_store;
33 private $_id;
34 private $_type;
35 private $_aspects;
36 private $_properties;
37 private $_children;
38 private $_parents;
39 private $_primaryParent;
40 private $_isNewNode;
41 private $_associations;
42 private $_versionHistory;
43 private $origionalProperties;
44 private $addedAspects;
45 private $removedAspects;
46 private $addedChildren;
47 private $addedParents;
48 private $addedAssociations;
49 private $removedAssociations;
51 /**
52 * Constructor
54 public function __construct($session, $store, $id)
56 $this->_session = $session;
57 $this->_store = $store;
58 $this->_id = $id;
59 $this->_isNewNode = false;
60 $this->addedChildren = array();
61 $this->addedParents = array();
62 $this->addedAssociations = array();
65 /**
66 * Util method to create a node from a web service node structure.
68 public static function createFromWebServiceData($session, $webServiceNode)
70 $scheme = $webServiceNode->reference->store->scheme;
71 $address = $webServiceNode->reference->store->address;
72 $id = $webServiceNode->reference->uuid;
74 $store = $session->getStore($address, $scheme);
75 $node = $session->getNode($store, $id);
76 $node->populateFromWebServiceNode($webServiceNode);
78 return $node;
81 public function setPropertyValues($properties)
83 // Check that the properties of the node have been populated
84 $this->populateProperties();
86 // Set the property values
87 foreach ($properties as $name=>$value)
89 $name = $this->_session->namespaceMap->getFullName($name);
90 $this->_properties[$name] = $value;
94 public function updateContent($property, $mimetype, $encoding="UTF-8", $content=null)
96 list($property) = $this->_session->namespaceMap->getFullNames(array($property));
97 $contentData = new ContentData($this, $property, $mimetype, $encoding);
98 if ($content != null)
100 $contentData->content = $content;
102 $this->_properties[$property] = $contentData;
104 return $contentData;
107 public function hasAspect($aspect)
109 list($aspect) = $this->_session->namespaceMap->getFullNames(array($aspect));
110 $this->populateProperties();
111 return in_array($aspect, $this->_aspects);
114 public function addAspect($aspect, $properties = null)
116 list($aspect) = $this->_session->namespaceMap->getFullNames(array($aspect));
117 $this->populateProperties();
119 if (in_array($aspect, $this->_aspects) == false)
121 $this->_aspects[] = $aspect;
122 if ($properties != null)
124 foreach ($properties as $name=>$value)
126 $name = $this->_session->namespaceMap->getFullName($name);
127 $this->_properties[$name] = $value;
131 $this->remove_array_value($aspect, $this->removedAspects);
132 $this->addedAspects[] = $aspect;
136 public function removeAspect($aspect)
138 list($aspect) = $this->_session->namespaceMap->getFullNames(array($aspect));
139 $this->populateProperties();
141 if (in_array($aspect, $this->_aspects) == true)
143 $this->remove_array_value($aspect, $this->_aspects);
144 $this->remove_array_value($aspect, $this->addedAspects);
145 $this->removedAspects[] = $aspect;
149 public function createChild($type, $associationType, $associationName)
151 list($type, $associationType, $associationName) = $this->_session->namespaceMap->getFullNames(array($type, $associationType, $associationName));
153 $id = $this->_session->nextSessionId();
154 $newNode = new Node($this->_session, $this->_store, $id);
155 $childAssociation = new ChildAssociation($this, $newNode, $associationType, $associationName, true);
157 $newNode->_isNewNode = true;
159 $newNode->_properties = array();
160 $newNode->_aspects = array();
161 $newNode->_properties = array();
162 $newNode->_children = array();
163 $newNode->origionalProperties = array();
164 $newNode->addedAspects = array();
165 $newNode->removedAspects = array();
167 $newNode->_type = $type;
168 $newNode->_parents = array();
169 $newNode->addedParents = array($this->__toString() => $childAssociation);
170 $newNode->_primaryParent = $this;
172 $this->addedChildren[$newNode->__toString()] = $childAssociation;
174 $this->_session->addNode($newNode);
176 return $newNode;
179 public function addChild($node, $associationType, $associationName)
181 list($associationType, $associationName) = $this->_session->namespaceMap->getFullNames(array($associationType, $associationName));
183 $childAssociation = new ChildAssociation($this, $node, $associationType, $associationName, false);
184 $this->addedChildren[$node->__toString()] = $childAssociation;
185 $node->addedParents[$this->__toString()] = $childAssociation;
188 public function removeChild($childAssociation)
193 public function addAssociation($to, $associationType)
195 list($associationType) = $this->_session->namespaceMap->getFullNames(array($associationType));
197 $association = new Association($this, $to, $associationType);
198 $this->addedAssociations[$to->__toString()] = $association;
201 public function removeAssociation($association)
206 public function createVersion($description=null, $major=false)
208 // We can only create a version if there are no outstanding changes for this node
209 if ($this->isDirty() == true)
211 throw new Exception("You must save any outstanding modifications before a new version can be created.");
214 // TODO implement major flag ...
216 $client = WebServiceFactory::getAuthoringService($this->_session->repository->connectionUrl, $this->_session->ticket);
217 $result = $client->createVersion(
218 array("items" => array("nodes" => $this->__toArray()),
219 "comments" => array("name" => "description", "value" => $description),
220 "versionChildren" => false));
222 // Clear the properties and aspects
223 $this->_properties = null;
224 $this->_aspects = null;
226 // Get the version details
227 // TODO get some of the other details too ...
228 $versionId = $result->createVersionReturn->versions->id->uuid;
229 $versionStoreScheme = $result->createVersionReturn->versions->id->store->scheme;
230 $versionStoreAddress = $result->createVersionReturn->versions->id->store->address;
232 // Create the version object to return
233 return new Version($this->_session, new Store($this->_session, $versionStoreAddress, $versionStoreScheme), $versionId);
236 private function isDirty()
238 $result = true;
239 if ($this->_isNewNode == false &&
240 count($this->getModifiedProperties()) == 0 &&
241 ($this->addedAspects == null || count($this->addedAspects) == 0) &&
242 ($this->removedAssociations == null || count($this->removedAssociations) == 0) &&
243 ($this->addedChildren == null || count($this->addedChildren) == 0) &&
244 ($this->addedAssociations == null || count($this->addedAssociations) == 0))
246 $result = false;
248 return $result;
251 public function __get($name)
253 $fullName = $this->_session->namespaceMap->getFullName($name);
254 if ($fullName != $name)
256 $this->populateProperties();
257 if (array_key_exists($fullName, $this->_properties) == true)
259 return $this->_properties[$fullName];
261 else
263 return null;
266 else
268 return parent::__get($name);
272 public function __set($name, $value)
274 $fullName = $this->_session->namespaceMap->getFullName($name);
275 if ($fullName != $name)
277 $this->populateProperties();
278 $this->_properties[$fullName] = $value;
280 // Ensure that the node and property details are stored on the contentData object
281 if ($value instanceof ContentData)
283 $value->setPropertyDetails($this, $fullName);
286 else
288 parent::__set($name, $value);
293 * toString method. Returns node as a node reference style string.
295 public function __toString()
297 return Node::__toNodeRef($this->_store, $this->id);
300 public static function __toNodeRef($store, $id)
302 return $store->scheme . "://" . $store->address . "/" . $id;
305 public function __toArray()
307 return array("store" => $this->_store->__toArray(),
308 "uuid" => $this->_id);
311 public function getSession()
313 return $this->_session;
316 public function getStore()
318 return $this->_store;
321 public function getId()
323 return $this->_id;
326 public function getIsNewNode()
328 return $this->_isNewNode;
331 public function getType()
333 $this->populateProperties();
334 return $this->_type;
337 public function getAspects()
339 $this->populateProperties();
340 return $this->_aspects;
343 public function getProperties()
345 $this->populateProperties();
346 return $this->_properties;
349 public function setProperties($properties)
351 $this->populateProperties();
352 $this->_properties = $properties;
356 * Accessor for the versionHistory property.
358 * @return VersionHistory the versionHistory for the node, null is none
360 public function getVersionHistory()
362 if ($this->_versionHistory == null)
364 $this->_versionHistory = new VersionHistory($this);
366 return $this->_versionHistory;
369 public function getChildren()
371 if ($this->_children == null)
373 $this->populateChildren();
375 return $this->_children + $this->addedChildren;
378 public function getParents()
380 if ($this->_parents == null)
382 $this->populateParents();
384 return $this->_parents + $this->addedParents;
387 public function getPrimaryParent()
389 if ($this->_primaryParent == null)
391 $this->populateParents();
393 return $this->_primaryParent;
396 public function getAssociations()
398 if ($this->_associations == null)
400 $this->populateAssociations();
402 return $this->_associations + $this->addedAssociations;
405 /** Methods used to populate node details from repository */
407 private function populateProperties()
409 if ($this->_isNewNode == false && $this->_properties == null)
411 $result = $this->_session->repositoryService->get(array (
412 "where" => array (
413 "nodes" => array(
414 "store" => $this->_store->__toArray(),
415 "uuid" => $this->_id))));
417 $this->populateFromWebServiceNode($result->getReturn);
421 private function populateFromWebServiceNode($webServiceNode)
423 $this->_type = $webServiceNode->type;
425 // Get the aspects
426 $this->_aspects = array();
427 $aspects = $webServiceNode->aspects;
428 if (is_array($aspects) == true)
430 foreach ($aspects as $aspect)
432 $this->_aspects[] = $aspect;
435 else
437 $this->_aspects[] = $aspects;
440 // Set the property values
441 // NOTE: do we need to be concerned with identifying whether this is an array or not when there is
442 // only one property on a node
443 $this->_properties = array();
444 foreach ($webServiceNode->properties as $propertyDetails)
446 $name = $propertyDetails->name;
447 $isMultiValue = $propertyDetails->isMultiValue;
448 $value = null;
449 if ($isMultiValue == false)
451 $value = $propertyDetails->value;
452 if ($this->isContentData($value) == true)
454 $value = new ContentData($this, $name);
457 else
459 $value = $propertyDetails->value;
461 $this->_properties[$name] = $value;
465 $this->origionalProperties = $this->_properties;
466 $this->addedAspects = array();
467 $this->removedAspects = array();
471 private function populateChildren()
473 // TODO should do some sort of limited pull here
474 $result = $this->_session->repositoryService->queryChildren(array("node" => $this->__toArray()));
475 $resultSet = $result->queryReturn->resultSet;
477 $children = array();
478 $map = $this->resultSetToMap($resultSet);
479 foreach($map as $value)
481 $id = $value["{http://www.alfresco.org/model/system/1.0}node-uuid"];
482 $store_scheme = $value["{http://www.alfresco.org/model/system/1.0}store-protocol"];
483 $store_address = $value["{http://www.alfresco.org/model/system/1.0}store-identifier"];
484 $assoc_type = $value["associationType"];
485 $assoc_name = $value["associationName"];
486 $isPrimary = $value["isPrimary"];
487 $nthSibling = $value["nthSibling"];
489 $child = $this->_session->getNode(new Store($this->_session, $store_address, $store_scheme), $id);
490 $children[$child->__toString()] = new ChildAssociation($this, $child, $assoc_type, $assoc_name, $isPrimary, $nthSibling);
493 $this->_children = $children;
496 private function populateAssociations()
498 // TODO should do some sort of limited pull here
499 $result = $this->_session->repositoryService->queryAssociated(array("node" => $this->__toArray(),
500 "association" => array("associationType" => null,
501 "direction" => null)));
502 $resultSet = $result->queryReturn->resultSet;
504 $associations = array();
505 $map = $this->resultSetToMap($resultSet);
506 foreach($map as $value)
508 $id = $value["{http://www.alfresco.org/model/system/1.0}node-uuid"];
509 $store_scheme = $value["{http://www.alfresco.org/model/system/1.0}store-protocol"];
510 $store_address = $value["{http://www.alfresco.org/model/system/1.0}store-identifier"];
511 $assoc_type = $value["associationType"];
513 $to = $this->_session->getNode(new Store($this->_session, $store_address, $store_scheme), $id);
514 $associations[$to->__toString()] = new Association($this, $to, $assoc_type);
517 $this->_associations = $associations;
520 private function populateParents()
522 // TODO should do some sort of limited pull here
523 $result = $this->_session->repositoryService->queryParents(array("node" => $this->__toArray()));
524 $resultSet = $result->queryReturn->resultSet;
526 $parents = array();
527 $map = $this->resultSetToMap($resultSet);
528 foreach($map as $value)
530 $id = $value["{http://www.alfresco.org/model/system/1.0}node-uuid"];
531 $store_scheme = $value["{http://www.alfresco.org/model/system/1.0}store-protocol"];
532 $store_address = $value["{http://www.alfresco.org/model/system/1.0}store-identifier"];
533 $assoc_type = $value["associationType"];
534 $assoc_name = $value["associationName"];
535 $isPrimary = $value["isPrimary"];
536 $nthSibling = $value["nthSibling"];
538 $parent = $this->_session->getNode(new Store($this->_session, $store_address, $store_scheme), $id);
539 if ($isPrimary == "true" or $isPrimary == true)
541 $this->_primaryParent = $parent;
543 $parents[$parent->__toString()] = new ChildAssociation($parent, $this, $assoc_type, $assoc_name, $isPrimary, $nthSibling);
546 $this->_parents = $parents;
549 public function onBeforeSave(&$statements)
551 if ($this->_isNewNode == true)
553 $childAssociation = $this->addedParents[$this->_primaryParent->__toString()];
555 $parentArray = array();
556 $parent = $this->_primaryParent;
557 if ($parent->_isNewNode == true)
559 $parentArray["parent_id"] = $parent->id;
560 $parentArray["associationType"] = $childAssociation->type;
561 $parentArray["childName"] = $childAssociation->name;
563 else
565 $parentArray["parent"] = array(
566 "store" => $this->_store->__toArray(),
567 "uuid" => $this->_primaryParent->_id,
568 "associationType" => $childAssociation->type,
569 "childName" => $childAssociation->name);
572 $this->addStatement($statements, "create",
573 array("id" => $this->_id) +
574 $parentArray +
575 array(
576 "type" => $this->_type,
577 "property" => $this->getPropertyArray($this->_properties)));
579 else
581 // Add the update statement for the modified properties
582 $modifiedProperties = $this->getModifiedProperties();
583 if (count($modifiedProperties) != 0)
585 $this->addStatement($statements, "update", array("property" => $this->getPropertyArray($modifiedProperties)) + $this->getWhereArray());
588 // TODO deal with any deleted properties
591 // Update any modified content properties
592 if ($this->_properties != null)
594 foreach($this->_properties as $name=>$value)
596 if (($value instanceof ContentData) && $value->isDirty == true)
598 $value->onBeforeSave($statements, $this->getWhereArray());
603 // Add the addAspect statements
604 if ($this->addedAspects != null)
606 foreach($this->addedAspects as $aspect)
608 $this->addStatement($statements, "addAspect", array("aspect" => $aspect) + $this->getWhereArray());
612 // Add the removeAspect
613 if ($this->removedAspects != null)
615 foreach($this->removedAspects as $aspect)
617 $this->addStatement($statements, "removeAspect", array("aspect" => $aspect) + $this->getWhereArray());
621 // Add non primary children
622 foreach($this->addedChildren as $childAssociation)
624 if ($childAssociation->isPrimary == false)
627 $assocDetails = array("associationType" => $childAssociation->type, "childName" => $childAssociation->name);
629 $temp = array();
630 if ($childAssociation->child->_isNewNode == true)
632 $temp["to_id"] = $childAssociation->child->_id;
633 $temp = $temp + $assocDetails;
635 else
637 $temp["to"] = array(
638 "store" => $this->_store->__toArray(),
639 "uuid" => $childAssociation->child->_id) +
640 $assocDetails;
642 $temp = $temp + $this->getWhereArray();
643 $this->addStatement($statements, "addChild", $temp);
647 // Add associations
648 foreach($this->addedAssociations as $association)
650 $temp = array("association" => $association->type);
651 $temp = $temp + $this->getPredicateArray("from", $this) + $this->getPredicateArray("to", $association->to);
652 $this->addStatement($statements, "createAssociation", $temp);
656 private function addStatement(&$statements, $statement, $body)
658 $result = array();
659 if (array_key_exists($statement, $statements) == true)
661 $result = $statements[$statement];
663 $result[] = $body;
664 $statements[$statement] = $result;
667 private function getWhereArray()
669 return $this->getPredicateArray("where", $this);
672 private function getPredicateArray($label, $node)
674 if ($node->_isNewNode == true)
676 return array($label."_id" => $node->_id);
678 else
680 return array(
681 $label => array(
682 "nodes" => $node->__toArray()
683 ));
687 private function getPropertyArray($properties)
689 $result = array();
690 foreach ($properties as $name=>$value)
692 // Ignore content properties
693 if (($value instanceof ContentData) == false)
695 // TODO need to support multi values
696 $result[] = array(
697 "name" => $name,
698 "isMultiValue" => false,
699 "value" => $value);
702 return $result;
705 private function getModifiedProperties()
707 $modified = $this->_properties;
708 $origional = $this->origionalProperties;
709 $result = array();
710 if ($modified != null)
712 foreach ($modified as $key=>$value)
714 // Ignore content properties
715 if (($value instanceof ContentData) == false)
717 if (array_key_exists($key, $origional) == true)
719 // Check to see if the value have been modified
720 if ($value != $origional[$key])
722 $result[$key] = $value;
725 else
727 $result[$key] = $value;
732 return $result;
735 public function onAfterSave($idMap)
737 if (array_key_exists($this->_id, $idMap ) == true)
739 $uuid = $idMap[$this->_id];
740 if ($uuid != null)
742 $this->_id = $uuid;
746 if ($this->_isNewNode == true)
748 $this->_isNewNode = false;
750 // Clear the properties and aspect
751 $this->_properties = null;
752 $this->_aspects = null;
755 // Update any modified content properties
756 if ($this->_properties != null)
758 foreach($this->_properties as $name=>$value)
760 if (($value instanceof ContentData) && $value->isDirty == true)
762 $value->onAfterSave();
767 $this->origionalProperties = $this->_properties;
769 if ($this->_aspects != null)
771 // Calculate the updated aspect list
772 if ($this->addedAspects != null)
774 $this->_aspects = $this->_aspects + $this->addedAspects;
776 if ($this->removedAspects != null)
778 foreach ($this->_aspects as $aspect)
780 if (in_array($aspect, $this->removedAspects) == true)
782 $this->remove_array_value($aspect, $this->_aspects);
787 $this->addedAspects = array();
788 $this->removedAspects = array();
790 if ($this->_parents != null)
792 $this->_parents = $this->_parents + $this->addedParents;
794 $this->addedParents = array();
796 if ($this->_children != null)
798 $this->_children = $this->_children + $this->addedChildren;
800 $this->addedChildren = array();
802 if ($this->_associations != null)
804 $this->_associations = $this->_associations + $this->addedAssociations;
806 $this->addedAssociations = array();