wCMF  3.6
 All Classes Namespaces Files Functions Variables Groups Pages
class.XMLUtil.php
Go to the documentation of this file.
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2014 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of any of the following licenses
7  * at your choice:
8  *
9  * - GNU Lesser General Public License (LGPL)
10  * http://www.gnu.org/licenses/lgpl.html
11  * - Eclipse Public License (EPL)
12  * http://www.eclipse.org/org/documents/epl-v10.php
13  *
14  * See the license.txt file distributed with this work for
15  * additional information.
16  *
17  * $Id: class.XMLUtil.php 1462 2014-02-04 23:52:27Z iherwig $
18  */
19 require_once(BASE."wcmf/3rdparty/PhpXmlDb/xmldb.php");
20 require_once(BASE."wcmf/lib/persistence/class.PersistenceFacade.php");
21 require_once(BASE."wcmf/lib/core/class.WCMFException.php");
22 
23 function XMLUtilErrorHandler($errno, $errstr, $errfile, $errline)
24 {
25  switch ($errno)
26  {
27  case E_USER_NOTICE:
28  WCMFException::throwEx($errstr, $errfile, $errline);
29  break;
30  default:
31  break;
32  }
33 }
34 define("ROOT_NODE_NAME", 'XmlDatabase');
35 
36 /**
37  * @class XMLUtil
38  * @ingroup Util
39  * @brief XMLUtil helps in using XML files as storage.
40  * XMLUtil is a subclass of CXmlDb that is customized for use with the wemove cms framework.
41  *
42  * @author ingo herwig <ingo@wemove.com>
43  */
44 class XMLUtil extends CXmlDb
45 {
46  var $_errorMsg = '';
47  var $_idName = 'id';
48 
49  /**
50  * Get last error message.
51  * @return The error string
52  */
53  function getErrorMsg()
54  {
55  return $this->_errorMsg;
56  }
57  /**
58  * Get the root node name.
59  * @return The root node name
60  */
61  function getRootNodeName()
62  {
63  return ROOT_NODE_NAME;
64  }
65  /**
66  * Get the object id of the root node.
67  * @return The object id of the root node
68  */
69  function getRootOID()
70  {
71  return PersistenceFacade::composeOID(array('type' => ROOT_NODE_NAME, 'id' => array('')));
72  }
73  /**
74  * Load Node data.
75  *
76  * @param oid The OID of the Node to load the data for.
77  * @param elementName The name of the DATATYPE_ELEMENT field of the Node (content will be mapped here).
78  * @return An assoziative array holding key value pairs of all Node data (attributes and content)
79  * 0 on failure / error string provided by getErrorMsg()
80  */
81  function GetNodeData($oid, $elementName)
82  {
83  $old_error_handler = set_error_handler("XMLUtilErrorHandler");
84  $iResult = 0;
85 
86  if ($this->_CheckAction('GetNodeData'))
87  {
88  // Call the internal version of the function.
89  $iResult = $this->_GetNodeData($oid, $elementName);
90  }
91 
92  set_error_handler($old_error_handler);
93  return $iResult;
94  }
95  /**
96  * Load Node child data.
97  *
98  * @param oid The OID of the Node to load the child data for.
99  * @return An array holding assoziative arrays with key value pairs of child data (keys 'type', 'id')
100  * 0 on failure / error string provided by getErrorMsg()
101  */
102  function GetChildData($oid)
103  {
104  $old_error_handler = set_error_handler("XMLUtilErrorHandler");
105  $iResult = 0;
106 
107  if ($this->_CheckAction('GetChildData'))
108  {
109  // Call the internal version of the function.
110  $iResult = $this->_GetChildData($oid);
111  }
112 
113  set_error_handler($old_error_handler);
114  return $iResult;
115  }
116  /**
117  * Get Node OID from a XPath query.
118  *
119  * @param nodeQuery The XPath query.
120  * @return Array of OIDs on success, 0 on failure / error string provided by getErrorMsg()
121  */
122  function GetOIDs($nodeQuery)
123  {
124  $oids = array();
125  $nodePathArray = $this->XmlDb->evaluate($nodeQuery);
126  foreach ($nodePathArray as $nodePath)
127  array_push($oids, $this->_GetOID($nodePath));
128  return $oids;
129  }
130  /**
131  * Add a new Node to the Node with given parentOID.
132  *
133  * @param node The Node to add
134  * @param parentOID The OID of the parent Node [maybe null to add to root].
135  * @return The ID of the new Node that was added on success, 0 on failure / error string provided by getErrorMsg()
136  */
137  function InsertNode(&$node, $parentOID)
138  {
139  $old_error_handler = set_error_handler("XMLUtilErrorHandler");
140  $iResult = 0;
141 
142  if ($this->_CheckAction('InsertNode'))
143  {
144  // Call the internal version of the function.
145  $iResult = $this->_InsertNode($node, $parentOID);
146 
147  // If node was added, set the Modify Flag to TRUE
148  if ($iResult)
149  $this->bModifyFlag = true;
150  }
151 
152  set_error_handler($old_error_handler);
153  return $iResult;
154  }
155  /**
156  * Save a Node to the XmlDb.
157  *
158  * @param node The Node to save
159  * @return 1 on success, 0 on failure / error string provided by getErrorMsg()
160  */
161  function UpdateNode(&$node)
162  {
163  $old_error_handler = set_error_handler("XMLUtilErrorHandler");
164  $iResult = 0;
165 
166  if ($this->_CheckAction('UpdateNode'))
167  {
168  // Call the internal version of the function.
169  $iResult = $this->_UpdateNode($node);
170 
171  // If node was added, set the Modify Flag to TRUE
172  if ($iResult)
173  $this->bModifyFlag = true;
174  }
175 
176  set_error_handler($old_error_handler);
177  return $iResult;
178  }
179  /**
180  * Remove a Node from the XmlDb.
181  *
182  * @param oid The OID of the Node to remove
183  * @return 1 on success, 0 on failure / error string provided by getErrorMsg()
184  */
185  function RemoveNode($oid)
186  {
187  $old_error_handler = set_error_handler("XMLUtilErrorHandler");
188  $iResult = 0;
189 
190  if ($this->_CheckAction('RemoveNode'))
191  {
192  // Call the internal version of the function.
193  $iResult = $this->_RemoveNode($oid);
194 
195  // If node was added, set the Modify Flag to TRUE
196  if ($iResult)
197  $this->bModifyFlag = true;
198  }
199 
200  set_error_handler($old_error_handler);
201  return $iResult;
202  }
203  /**
204  * Get the next record id.
205  *
206  * @return The next ID for insertion
207  */
208  function GetNextInsertId()
209  {
210  $nextID = 1;
211 
212  $idTable = 'nextID';
213  $idTablePath = '/*/'.$idTable;
214 
215  $idPaths = $this->XmlDb->evaluate($idTablePath);
216  if (sizeof($idPaths) == 0)
217  {
218  // add id table
219  $rootPathArray = $this->XmlDb->evaluate("/*");
220  $newID = $nextID+1;
221  $idNode = "<$idTable>$newID</$idTable>";
222  $this->XmlDb->appendChild($rootPathArray[0], $idNode);
223  }
224  else
225  {
226  // get next id
227  $nextID = intval($this->XmlDb->getData($idTablePath));
228  $newID = $nextID+1;
229  $this->XmlDb->replaceData($idPaths[0], $newID);
230  }
231  return $nextID;
232  }
233 
234 
235  /**
236  * Internal version of GetNodeData.
237  *
238  * @param oid The OID of the Node to load the data for.
239  * @param elementName The name of the DATATYPE_ELEMENT field of the Node (content will be mapped here).
240  * @return An assoziative array holding key value pairs of all Node data (attributes and content)
241  * 0 on failure / error string provided by getErrorMsg()
242  */
243  function _GetNodeData($oid, $elementName)
244  {
245  $iResult = 0;
246 
247  // get the node path
248  $nodePath = $this->_GetNodePath($oid);
249  if ($nodePath != '')
250  {
251  // get the attributes
252  $iResult = $this->XmlDb->getAttributes($nodePath);
253  // get the element
254  $iResult[$elementName] = $this->XmlDb->getData($nodePath);
255  // get ptype and pid
256  $parentPath = $this->XmlDb->getParentXPath($nodePath);
257  $iResult['ptype'] = array_pop($this->_GetTypes($parentPath));
258  $parentAttributes = $this->XmlDb->getAttributes($parentPath);
259  $iResult['pid'] = $parentAttributes[$this->_idName];
260  }
261  return $iResult;
262  }
263  /**
264  * Internal version of GetChildData.
265  *
266  * @param oid The OID of the Node to load the child data for.
267  * @return An array holding assoziative arrays with key value pairs of child data (keys 'type', 'id')
268  * 0 on failure / error string provided by getErrorMsg()
269  */
270  function _GetChildData($oid)
271  {
272  $iResult = 0;
273 
274  // get the node path
275  $nodePath = $this->_GetNodePath($oid);
276  if ($nodePath != '')
277  {
278  $iResult = array();
279  // get the attributes
280  $childrenPathArray = $this->XmlDb->evaluate($nodePath.'/*');
281  foreach($childrenPathArray as $childPath)
282  {
283  // get type and id of child
284  $childType = array_pop($this->_GetTypes($childPath));
285  $childAttributes = $this->XmlDb->getAttributes($childPath);
286  $childId = $childAttributes[$this->_idName];
287  array_push($iResult, array('type' => $childType, 'id' => $childId));
288  }
289  }
290  return $iResult;
291  }
292  /**
293  * Internal version of InsertNode.
294  *
295  * @param node The Node to add
296  * @param parentOID The OID of the parent Node [maybe null to add to root].
297  * @return The ID of the new Node that was added on success, 0 on failure / error string provided by getErrorMsg()
298  */
299  function _InsertNode(&$node, $parentOID)
300  {
301  $iResult = 0;
302 
303  // get the parent path
304  if ($parentOID != null)
305  $parentPath = $this->_GetNodePath($parentOID);
306  else
307  $parentPath = $this->_GetNodePath($this->getRootOID());;
308 
309  // get the new id
310  $newId = $this->GetNextInsertId();
311 
312  // define element content
313  $nodeContent = '';
314  $elementNames = $node->getValueNames(DATATYPE_ELEMENT);
315  foreach($elementNames as $elementName)
316  $nodeContent .= $node->getValue($elementName, DATATYPE_ELEMENT);
317 
318  // define element
319  $nodeDef = PersistenceFacade::decomposeOID($node->getOID());
320  $nodeString = "<".$nodeDef['type'].">".$nodeContent."</".$nodeDef['type'].">";
321 
322  // add node
323  $nodePath = $this->XmlDb->appendChild($parentPath, $nodeString);
324 
325  // define attributes
326  $addAttributes = array();
327  $addAttributes[$this->_idName] = $newId;
328  $attributeNames = $node->getValueNames(DATATYPE_ATTRIBUTE);
329  foreach($attributeNames as $attributeName)
330  $addAttributes[$attributeName] = $node->getValue($attributeName, DATATYPE_ATTRIBUTE);
331 
332  // set attributes
333  $this->XmlDb->setAttributes($nodePath, $addAttributes);
334 
335  // set the new id on the node
336  $node->setOID(PersistenceFacade::composeOID(array('type' => $node->getType(), 'id' => $newId)));
337 
338  $iResult = $newId;
339  return $iResult;
340  }
341  /**
342  * Internal version of UpdateNode.
343  *
344  * @param node The Node to save
345  * @return 1 on success, 0 on failure / error string provided by getErrorMsg()
346  */
347  function _UpdateNode(&$node)
348  {
349  $iResult = 0;
350 
351  // get the node path (take the first matching node)
352  $nodePath = $this->_GetNodePath($node->getOID());
353 
354  // define element content
355  $nodeContent = '';
356  $elementNames = $node->getValueNames(DATATYPE_ELEMENT);
357  foreach($elementNames as $elementName)
358  $nodeContent .= $node->getValue($elementName, DATATYPE_ELEMENT);
359 
360  // replace node
361  $this->XmlDb->replaceData($nodePath, $nodeContent);
362 
363  // define attributes
364  $addAttributes = array();
365  $attributeNames = $node->getValueNames(DATATYPE_ATTRIBUTE);
366  foreach($attributeNames as $attributeName)
367  $addAttributes[$attributeName] = $node->getValue($attributeName, DATATYPE_ATTRIBUTE);
368 
369  // set attributes
370  $this->XmlDb->setAttributes($nodePath, $addAttributes);
371 
372  return 1;
373  }
374  /**
375  * Internal version of RemoveNode.
376  *
377  * @param oid The OID of the Node to remove
378  * @return 1 on success, 0 on failure / error string provided by getErrorMsg()
379  */
380  function _RemoveNode($oid)
381  {
382  // remove node
383  $this->_RemoveRecord(array($this->_GetNodePath($oid)));
384 
385  return 1;
386  }
387  /**
388  * Check if execution of an action is possible.
389  *
390  * @param action The action to execute
391  * @return True/False whether execution is possible
392  */
393  function _CheckAction($action)
394  {
395  if (!$this->_FunctionPermitted($action))
396  {
397  $this->_errorMsg = 'The function call is not allowed.';
398  return false;
399  }
400  if (!$this->bFileOpen)
401  {
402  $this->_errorMsg = 'The Open call did not open the file successfully.';
403  return false;
404  }
405  if (!$this->bWriteAccess)
406  {
407  $this->_errorMsg = 'To alter the database, you need to open it with write access.';
408  return false;
409  }
410 
411  return true;
412  }
413  /**
414  * Get the path to a Node.
415  *
416  * @param oid The OID of the Node
417  * @return The path to the Node
418  */
419  function _GetNodePath($oid)
420  {
421  // get the node path (take the first matching node)
422  $nodeDef = PersistenceFacade::decomposeOID($oid);
423 
424  // the root node has no id
425  if ($nodeDef['type'] == $this->getRootNodeName())
426  $nodeQuery = "descendant::".$nodeDef['type'];
427  else
428  $nodeQuery = "descendant::".$nodeDef['type']."[@".$this->_idName."='".$nodeDef['id']."']";
429 
430  $nodePathArray = $this->XmlDb->evaluate($nodeQuery);
431  return $nodePathArray[0];
432  }
433  /**
434  * Get the Node types contained in a path.
435  *
436  * @param path The path to get the types for
437  * @return An array containing the types sorted from parent to children
438  */
439  function _GetTypes($path)
440  {
441  preg_match_all('/\/(.+)\[[0-9]+\]/U', $path, $matches);
442  return $matches[1];
443  }
444  /**
445  * Get Node OID from a path.
446  *
447  * @param nodePath The path to the Node
448  * @return OID on success, 0 on failure / error string provided by getErrorMsg()
449  */
450  function _GetOID($nodePath)
451  {
452  $old_error_handler = set_error_handler("XMLUtilErrorHandler");
453  $iResult = 0;
454 
455  // get type and id
456  $type = array_pop($this->_GetTypes($nodePath));
457  $nodeAttributes = $this->XmlDb->getAttributes($nodePath);
458  $id = $nodeAttributes[$this->_idName];
459  $iResult = PersistenceFacade::composeOID(array('type' => $type, 'id' => $id));
460 
461  set_error_handler($old_error_handler);
462  return $iResult;
463  }
464 }
465 ?>
getRootNodeName()
GetNodeData($oid, $elementName)
_GetNodeData($oid, $elementName)
UpdateNode(&$node)
GetChildData($oid)
const DATATYPE_ATTRIBUTE
const DATATYPE_ELEMENT
const ROOT_NODE_NAME
throwEx($message, $file='', $line='')
_GetChildData($oid)
XMLUtil helps in using XML files as storage. XMLUtil is a subclass of CXmlDb that is customized for u...
_InsertNode(&$node, $parentOID)
_UpdateNode(&$node)
decomposeOID($oid, $validate=true)
_GetTypes($path)
_GetNodePath($oid)
InsertNode(&$node, $parentOID)
_CheckAction($action)
RemoveNode($oid)
XMLUtilErrorHandler($errno, $errstr, $errfile, $errline)
_RemoveNode($oid)
_GetOID($nodePath)
GetOIDs($nodeQuery)