DionysosNodeSerializer.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\model\impl;
12 
19 
20 /**
21  * DionysosNodeSerializer is used to serialize Nodes into the Dionysos format and
22  * vice versa. The format of serialized Nodes is defined in the Dionysos
23  * specification (See: http://olympos.svn.sourceforge.net/viewvc/olympos/trunk/olympos/dionysos/docs/Dionysos%20Specification%20JSON.odt)
24  *
25  * The array representation is an associative array where the keys are:
26  *
27  * - className: The type of the Node (optional, if oid is given)
28  * - oid: The object id of the Node (optional, if className is given)
29  * - isReference: Boolean whether this Node is a reference or complete
30  * - lastChange: A timestamp defining the point in time of the last change of the Node
31  * - attributes: An associative array with the value names as keys and the appropriate values
32  * Relations to other Nodes are also contained in this array, where the relation
33  * name is the array key
34  * @author ingo herwig <ingo@wemove.com>
35  */
37 
38  const NODE_KEYS = [
39  'className',
40  'oid',
41  'isReference',
42  'lastChange',
43  'attributes'
44  ];
45  private $serializedOIDs = [];
46 
47  /**
48  * @see NodeSerializer::isSerializedNode
49  */
50  public function isSerializedNode($data) {
51  if (is_object($data)) {
52  $data = (array)$data;
53  }
54  $syntaxOk = (is_array($data) &&
55  (isset($data['oid']) || isset($data['className'])) &&
56  isset($data['attributes']));
57  // check for oid variables
58  if ($syntaxOk && isset($data['oid']) && preg_match('/^\{.+\}$/', $data['oid'])) {
59  $syntaxOk = false;
60  }
61  return $syntaxOk;
62  }
63 
64  /**
65  * @see NodeSerializer::deserializeNode
66  */
67  public function deserializeNode($data, Node $parent=null, $role=null) {
68  if (!isset($data['className']) && !isset($data['oid'])) {
69  throw new IllegalArgumentException("Serialized Node data must contain an 'className' or 'oid' parameter");
70  }
71  // create a dummy oid, if not given
72  $oid = null;
73  if (!isset($data['oid'])) {
74  $oid = new ObjectId($data['className']);
75  }
76  else {
77  $oid = ObjectId::parse($data['oid']);
78  if ($oid == null) {
79  throw new IllegalArgumentException("The object id '".$oid."' is invalid");
80  }
81  }
82 
83  // create request node
84  $node = $this->getNodeTemplate($oid);
85  if (isset($data['attributes'])) {
86  foreach($data['attributes'] as $key => $value) {
87  $this->deserializeValue($node, $key, $value);
88  }
89  }
90 
91  // set oid after attributes in order to
92  // avoid it being changed from missing pk values
93  $node->setOID($oid);
94 
95  // create hierarchy
96  if ($parent != null) {
97  $parent->addNode($node, $role);
98  }
99 
100  // get remaining part of data
101  foreach ($data as $key => $value) {
102  if (in_array($key, self::NODE_KEYS)) {
103  unset($data[$key]);
104  }
105  }
106  return ['node' => $node, 'data' => $data];
107  }
108 
109  /**
110  * @see NodeSerializer::serializeNode
111  */
112  public function serializeNode($node) {
113  if (!($node instanceof Node)) {
114  return null;
115  }
116  $curResult = [];
117  $curResult['className'] = $node->getType();
118  $curResult['oid'] = $node->getOID()->__toString();
119  $curResult['lastChange'] = strtotime($node->getValue('modified'));
120 
121  $oidStr = $node->getOID()->__toString();
122  if (in_array($oidStr, $this->serializedOIDs)) {
123  // the node is serialized already
124  $curResult['isReference'] = true;
125  }
126  else {
127  // the node is not serialized yet
128  $curResult['isReference'] = false;
129  $this->serializedOIDs[] = $oidStr;
130 
131  // serialize attributes
132  // use NodeValueIterator to iterate over all Node values
133  $values = [];
134  $valueIter = new NodeValueIterator($node, false);
135  foreach($valueIter as $valueName => $value) {
136  $values[$valueName] = $value;
137  }
138  $curResult['attributes'] = $values;
139 
140  // add related objects by creating an attribute that is named as the role of the object
141  // multivalued relations will be serialized into an array
142  $mapper = $node->getMapper();
143  foreach ($mapper->getRelations() as $relation) {
144  $role = $relation->getOtherRole();
145  $relatedNodes = $node->getValue($role);
146  if ($relatedNodes) {
147  // serialize the nodes
148  $isMultiValued = $relation->isMultiValued();
149  if ($isMultiValued) {
150  $curResult['attributes'][$role] = [];
151  foreach ($relatedNodes as $relatedNode) {
152  $data = $this->serializeNode($relatedNode);
153  if ($data != null) {
154  // add the data to the relation attribute
155  $curResult['attributes'][$role][] = $data;
156  }
157  }
158  }
159  else {
160  $data = $this->serializeNode($relatedNodes);
161  if ($data != null) {
162  // add the data to the relation attribute
163  $curResult['attributes'][$role] = $data;
164  }
165  }
166  }
167  }
168  }
169  return $curResult;
170  }
171 }
172 ?>
NodeSerializer implementations are used to serialize Nodes into an array representation or deserializ...
NodeValueIterator is used to iterate over all persistent values of a Node (not including relations).
IllegalArgumentException signals an exception in method arguments.
deserializeValue(Node $node, $key, $value)
Deserialize a node value.
ObjectId is the unique identifier of an object.
Definition: ObjectId.php:27
static parse($oid)
Parse a serialized object id string into an ObjectId instance.
Definition: ObjectId.php:134
deserializeNode($data, Node $parent=null, $role=null)
getNodeTemplate($oid)
Get a Node instance based on the original values to merge the deserialized values into.
NodeSerializerBase is a base class for NodeSerialize implementations.
Node adds the concept of relations to PersistentObject.
Definition: Node.php:34
DionysosNodeSerializer is used to serialize Nodes into the Dionysos format and vice versa.