NodeUtil.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;
12 
22 
23 /**
24  * NodeUtil provides services for the Node class. All methods are static.
25  *
26  * @author ingo herwig <ingo@wemove.com>
27  */
28 class NodeUtil {
29 
30  /**
31  * Get the shortest paths that connect a type to another type.
32  * @param $type The type to start from
33  * @param $otherRole The role of the type at the other end (maybe null, if only type shoudl match)
34  * @param $otherType The type at the other end (maybe null, if only role shoudl match)
35  * @param $hierarchyType The hierarchy type that the other type has in relation to this type
36  * 'parent', 'child', 'undefined' or 'all' to get all relations (default: 'all')
37  * @return An array of PathDescription instances
38  */
39  public static function getConnections($type, $otherRole, $otherType, $hierarchyType='all') {
40  $paths = array();
41  self::getConnectionsImpl($type, $otherRole, $otherType, $hierarchyType, $paths);
42  $minLength = -1;
43  $shortestPaths = array();
44  foreach ($paths as $curPath) {
45  $curLength = $curPath->getPathLength();
46  if ($minLength == -1 || $minLength > $curLength) {
47  $minLength = $curLength;
48  $shortestPaths = array($curPath);
49  }
50  elseif ($curLength == $minLength) {
51  $shortestPaths[] = $curPath;
52  }
53  }
54  return $shortestPaths;
55  }
56 
57  /**
58  * Get the relations that connect a type to another type.
59  * @param $type The type to start from
60  * @param $otherRole The role of the type at the other end (maybe null, if only type shoudl match)
61  * @param $otherType The type at the other end (maybe null, if only role shoudl match)
62  * @param $hierarchyType The hierarchy type that the other type has in relation to this type
63  * 'parent', 'child', 'undefined' or 'all' to get all relations (default: 'all')
64  * @param $result Array of PathDescriptions after execution
65  * @param $currentPath Internal use only
66  */
67  protected static function getConnectionsImpl($type, $otherRole, $otherType,
68  $hierarchyType, array &$result=array(), array $currentPath=array()) {
69  $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
70  $mapper = $persistenceFacade->getMapper($type);
71 
72  // check relations
73  $relationDescs = $mapper->getRelations($hierarchyType);
74  foreach ($relationDescs as $relationDesc) {
75  // loop detection
76  $loopDetected = false;
77  foreach ($currentPath as $pathPart) {
78  if ($relationDesc->isSameRelation($pathPart)) {
79  $loopDetected = true;
80  break;
81  }
82  }
83  if ($loopDetected) {
84  // continue with next relation
85  continue;
86  }
87 
88  $pathFound = null;
89  $nextType = $relationDesc->getOtherType();
90  $nextRole = $relationDesc->getOtherRole();
91  $otherTypeFq = $otherType != null ? $persistenceFacade->getFullyQualifiedType($otherType) : null;
92  if (($otherRole != null && $nextRole == $otherRole) || ($otherType != null && $nextType == $otherTypeFq)) {
93  // other end found -> terminate
94  $pathFound = $currentPath;
95  $pathFound[] = $relationDesc;
96  }
97  else {
98  // nothing found -> proceed with next generation
99  $nextCurrentPath = $currentPath;
100  $nextCurrentPath[] = $relationDesc;
101  self::getConnectionsImpl($nextType, $otherRole, $otherType, $hierarchyType, $result, $nextCurrentPath);
102  }
103 
104  // if a path is found, add it to the result
105  if ($pathFound) {
106  $result[] = new PathDescription($pathFound);
107  }
108  }
109  }
110 
111  /**
112  * Get the query condition used to select all related Nodes of a given role.
113  * @param $node The Node to select the relatives for
114  * @param $otherRole The role of the other nodes
115  * @return The condition string to be used with StringQuery.
116  */
117  public static function getRelationQueryCondition($node, $otherRole) {
118  $mapper = $node->getMapper();
119  $relationDescription = $mapper->getRelation($otherRole);
120  $otherType = $relationDescription->getOtherType();
121 
122  $query = new ObjectQuery($otherType, __CLASS__.__METHOD__.$node->getType().$otherRole);
123  // add the primary keys of the node
124  // using the role name as alias (avoids ambiguous paths)
125  $nodeTpl = $query->getObjectTemplate($node->getType(), $relationDescription->getThisRole());
126  $oid = $node->getOID();
127  $ids = $oid->getId();
128  $i = 0;
129  foreach ($mapper->getPkNames() as $pkName) {
130  $nodeTpl->setValue($pkName, Criteria::asValue("=", $ids[$i++]));
131  }
132  // add the other type in the given relation
133  $otherTpl = $query->getObjectTemplate($otherType);
134  $nodeTpl->addNode($otherTpl, $otherRole);
135  $condition = $query->getQueryCondition();
136  // prevent selecting all objects, if the condition is empty
137  if (strlen($condition) == 0) {
138  $condition = 0;
139  }
140  return $condition;
141  }
142 
143  /**
144  * Get the display value for a Node defined by the 'display_value' property.
145  * If the 'display_value' is an array ('|' separated strings) the pieces will be put together with ' - '.
146  * If search for 'display_value' gives no result the function returns an empty string.
147  * Example: 'name|text' shows the name of the Node together with the content of the text attribute
148  * @param $node A reference to the Node to display
149  * @param $language The language if values should be localized. Optional, default is Localization::getDefaultLanguage()
150  * @note The display type is configured via the display_type property of a value. It describes how the value should be displayed.
151  * The description is of the form @code type @endcode or @code type[attributes] @endcode
152  * - type: text|image|link
153  * - attributes: a string of attributes used in the HTML definition (e.g. 'height="50"')
154  * @return The display string
155  */
156  public static function getDisplayValue(Node $node, $language=null) {
157  return join(' - ', array_values(self::getDisplayValues($node, $language)));
158  }
159 
160  /**
161  * Does the same as NodeUtil::getDisplayValue but returns the display value as associative array
162  * @param $node A reference to the Node to display
163  * @param $language The language if values should be localized. Optional, default is Localization::getDefaultLanguage()
164  * @return The display array
165  */
166  public static function getDisplayValues(Node $node, $language=null) {
167  // localize node if requested
168  $localization = ObjectFactory::getInstance('localization');
169  if ($language != null) {
170  $node = $localization->loadTranslation($node, $language);
171  }
172 
173  $displayArray = array();
174  $displayValueDef = $node->getProperty('display_value');
175  if (strlen($displayValueDef) > 0) {
176  $displayValuesNames = preg_split('/\|/', $displayValueDef);
177  $mapper = $node->getMapper();
178  foreach($displayValuesNames as $displayValueName) {
179  $inputType = ''; // needed for the translation of a list value
180  if ($displayValueName != '') {
181  if ($mapper->hasAttribute($displayValueName)) {
182  $attribute = $mapper->getAttribute($displayValueName);
183  $inputType = $attribute->getInputType();
184  }
185  $tmpDisplay = $node->getValue($displayValueName);
186  }
187 
188  // translate any list value
189  $tmpDisplay = ValueListProvider::translateValue($tmpDisplay, $inputType, $language);
190  if (strlen($tmpDisplay) == 0) {
191  // fallback to oid
192  $tmpDisplay = $node->getOID();
193  }
194 
195  $displayArray[$displayValueName] = $tmpDisplay;
196  }
197  }
198  return $displayArray;
199  }
200 
201  /**
202  * Make all urls matching a given base url in a Node relative.
203  * @param $node A reference to the Node the holds the value
204  * @param $baseUrl The baseUrl to which matching urls will be made relative
205  * @param $recursive Boolean whether to recurse into child Nodes or not (default: true)
206  */
207  public static function makeNodeUrlsRelative(Node $node, $baseUrl, $recursive=true) {
208  // use NodeValueIterator to iterate over all Node values
209  // and call the global convert function on each
210  $iter = new NodeValueIterator($node, $recursive);
211  for($iter->rewind(); $iter->valid(); $iter->next()) {
212  self::makeValueUrlsRelative($iter->currentNode(), $iter->key(), $baseUrl);
213  }
214  }
215 
216  /**
217  * Make the urls matching a given base url in a PersistentObject value relative.
218  * @param $node A reference to the Node the holds the value
219  * @param $valueName The name of the value
220  * @param $baseUrl The baseUrl to which matching urls will be made relative
221  */
222  private static function makeValueUrlsRelative(PersistentObject $object, $valueName, $baseUrl) {
223  $value = $object->getValue($valueName);
224 
225  // find urls in texts
226  $urls = StringUtil::getUrls($value);
227  // find direct attribute urls
228  if (strpos($value, 'http://') === 0 || strpos($value, 'https://') === 0) {
229  $urls[] = $value;
230  }
231  // process urls
232  foreach ($urls as $url) {
233  // convert absolute urls matching baseUrl
234  $urlConv = $url;
235  if (strpos($url, $baseUrl) === 0) {
236  $urlConv = str_replace($baseUrl, '', $url);
237  }
238  // replace url
239  $value = str_replace($url, $urlConv, $value);
240  }
241  $object->setValue($valueName, $value);
242  }
243 
244  /**
245  * Translate all list values in a list of Nodes.
246  * @note Translation in this case refers to mapping list values from the key to the value
247  * and should not be confused with localization, although values maybe localized using the
248  * language parameter.
249  * @param $nodes A reference to the array of Nodes
250  * @param $language The language code, if the translated values should be localized.
251  * Optional, default is Localizat$objectgetDefaultLanguage()
252  */
253  public static function translateValues(&$nodes, $language=null) {
254  // translate the node values
255  for($i=0; $i<sizeof($nodes); $i++) {
256  $iter = new NodeValueIterator($nodes[$i], false);
257  for($iter->rewind(); $iter->valid(); $iter->next()) {
258  self::translateValue($iter->currentNode(), $iter->key(), $language);
259  }
260  }
261  }
262 
263  /**
264  * Translate a PersistentObject list value.
265  * @param $object The object whose value to translate
266  * @param $valueName The name of the value to translate
267  * @param $language The language to use
268  */
269  private static function translateValue(PersistentObject $object, $valueName, $language) {
270  $value = $object->getValue($valueName);
271  // translate list values
272  $value = ValueListProvider::translateValue($value, $object->getValueProperty($valueName, 'input_type'), true, null, $language);
273  // force set (the rendered value may not be satisfy validation rules)
274  $object->setValue($valueName, $value, true);
275  }
276 
277  /**
278  * Remove all values from a Node that are not a display value.
279  * @param $node The Node instance
280  */
281  public static function removeNonDisplayValues(Node $node) {
282  $displayValueStr = $node->getProperty('display_value');
283  $displayValues = preg_split('/\|/', $displayValueStr);
284  $valueNames = $node->getValueNames();
285  foreach($valueNames as $name) {
286  if (!in_array($name, $displayValues)) {
287  $node->removeValue($name);
288  }
289  }
290  }
291 
292  /**
293  * Remove all values from a Node that are not a primary key value.
294  * @param $node The Node instance
295  */
296  public static function removeNonPkValues(Node $node) {
297  $mapper = $node->getMapper();
298  $pkValues = $mapper->getPkNames();
299  $valueNames = $node->getValueNames();
300  foreach($valueNames as $name) {
301  if (!in_array($name, $pkValues)) {
302  $node->removeValue($name);
303  }
304  }
305  }
306 }
307 ?>
static getDisplayValues(Node $node, $language=null)
Does the same as NodeUtil::getDisplayValue but returns the display value as associative array...
Definition: NodeUtil.php:166
getValue($name)
Definition: Node.php:91
Node related interfaces and classes.
Definition: namespaces.php:26
static getRelationQueryCondition($node, $otherRole)
Get the query condition used to select all related Nodes of a given role.
Definition: NodeUtil.php:117
static translateValues(&$nodes, $language=null)
Translate all list values in a list of Nodes.
Definition: NodeUtil.php:253
NodeValueIterator is used to iterate over all persistent values of a Node (not including relations)...
ObjectQuery implements a template based object query.
static translateValue($value, $inputType, $language=null)
Translate a value with use of it's assoziated input type e.g get the location string from a location ...
static asValue($operator, $value)
Factory method for constructing a Critera that may be used as value on a PersistentObject's attribute...
Definition: Criteria.php:58
static getInstance($name, $dynamicConfiguration=array())
static removeNonDisplayValues(Node $node)
Remove all values from a Node that are not a display value.
Definition: NodeUtil.php:281
getObjectTemplate($type, $alias=null, $combineOperator=Criteria::OPERATOR_AND)
Get an object template for a given type.
getQueryCondition()
Get the condition part of the query.
getValue($name)
Get the value of a named item.
static getConnectionsImpl($type, $otherRole, $otherType, $hierarchyType, array &$result=array(), array $currentPath=array())
Get the relations that connect a type to another type.
Definition: NodeUtil.php:67
static getUrls($string)
Extraxt urls from a string.
Definition: StringUtil.php:135
setValue($name, $value, $forceSet=false, $trackChange=true)
Set the value of a named item if it exists.
static makeNodeUrlsRelative(Node $node, $baseUrl, $recursive=true)
Make all urls matching a given base url in a Node relative.
Definition: NodeUtil.php:207
static removeNonPkValues(Node $node)
Remove all values from a Node that are not a primary key value.
Definition: NodeUtil.php:296
static getConnections($type, $otherRole, $otherType, $hierarchyType='all')
Get the shortest paths that connect a type to another type.
Definition: NodeUtil.php:39
NodeUtil provides services for the Node class.
Definition: NodeUtil.php:28
getValueProperty($name, $property)
Get the value of one property of a named item.
static getDisplayValue(Node $node, $language=null)
Get the display value for a Node defined by the 'display_value' property.
Definition: NodeUtil.php:156
PathDescription describes a path between two types.
getValueNames($includeRelations=true)
Get the names of all items.
Definition: Node.php:71
Node adds the concept of relations to PersistentObject.
Definition: Node.php:34
PersistentObject defines the interface of all persistent objects.