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