wCMF  3.6
All Classes Namespaces Files Functions Variables Groups Pages
class.ObjectQuery.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.ObjectQuery.php 1462 2014-02-04 23:52:27Z iherwig $
18  */
19 require_once(BASE."wcmf/lib/core/class.WCMFException.php");
20 require_once(BASE."wcmf/lib/util/class.Log.php");
21 require_once(BASE."wcmf/lib/util/class.Message.php");
22 require_once(BASE."wcmf/lib/model/class.NodeIterator.php");
23 require_once(BASE."wcmf/lib/persistence/class.PersistenceFacade.php");
24 require_once(BASE."wcmf/lib/persistence/class.ChangeListener.php");
25 require_once(BASE."wcmf/lib/model/class.NodeProcessor.php");
26 
27 /**
28  * Some constants describing the build process
29  */
30 define("QUERYOP_AND", 'AND'); // the and operator
31 define("QUERYOP_OR", 'OR'); // the or operator
32 
33 /**
34  * ObjectQuery attributes
35  */
37  "pre_operator",
38  "inter_operator",
39  "query_condition",
40  "table_name"
41 );
42 
43 /**
44  * @class ObjectQuery
45  * @ingroup Persistence
46  * @brief ObjectQuery is the base class for object queries. This class provides the
47  * user with object templates on which query conditions may be set. Object templates
48  * are Node instances whose attribute values are used as conditions on the
49  * appropriate attributes. A value inludes the operator to be applied to it. For
50  * example $authorTpl->setValue("name", "LIKE '%ingo%'") means searching for authors
51  * whose name contains 'ingo'. Operator and value should be separated by a space. If
52  * no operator is given LIKE '%...%' is assumed.
53  *
54  * All value conditions of one template are joined with the same operator ('AND', 'OR')
55  * given in the "inter_operator" (DATATYPE_IGNORE) value of the template.
56  * The set of conditions of a template is preceded by the operator ('AND', 'OR', 'NOT')
57  * given in the "pre_operator" (DATATYPE_IGNORE) value (default: 'AND') of the template
58  * (see ObjectQuery::getObjectTemplate()).
59  *
60  * Multiple conditions for one value are built using different object templates of the
61  * same type. Conditions sets of different object templates are grouped with brackets if
62  * they are passed to ObjectQuery::makeGroup().
63  *
64  * @note: If there are two object templates of the same type as the query type linked in
65  * a parent child relation, than the nodes that are selected depend on the attributes of
66  * the first object template that is received by ObjectQuery::getObjectTemplate.
67  *
68  * The following example shows the usage:
69  *
70  * @code
71  * // The code builds the following query condition:
72  * // WHERE (Author.name LIKE '%ingo%' AND Author.email LIKE '%wemove%') OR (Author.name LIKE '%herwig%') AND
73  * // (Recipe.created >= '2004-01-01') AND (Recipe.created < '2005-01-01') AND ((Recipe.name LIKE '%Salat%') OR (Recipe.portions = 4))
74  *
75  * $query = &PersistenceFacade::createObjectQuery('Author');
76  *
77  * // (Author.name LIKE '%ingo%' AND Author.email LIKE '%wemove%')
78  * $authorTpl1 = &$query->getObjectTemplate('Author');
79  * $authorTpl1->setValue("name", "ingo", DATATYPE_ATTRIBUTE);
80  * $authorTpl1->setValue("email", "LIKE '%wemove%'", DATATYPE_ATTRIBUTE);
81  *
82  * // OR Author.name LIKE '%herwig%'
83  * $authorTpl2 = &$query->getObjectTemplate('Author', QUERYOP_OR);
84  * $authorTpl2->setValue("name", "herwig", DATATYPE_ATTRIBUTE);
85  *
86  * // Recipe.created >= '2004-01-01' AND Recipe.created < '2005-01-01'
87  * $recipeTpl1 = &$query->getObjectTemplate('Recipe');
88  * $recipeTpl1->setValue("created", ">= '2004-01-01'", DATATYPE_ATTRIBUTE);
89  * $recipeTpl2 = &$query->getObjectTemplate('Recipe');
90  * $recipeTpl2->setValue("created", "< '2005-01-01'", DATATYPE_ATTRIBUTE);
91  *
92  * // AND (Recipe.name LIKE '%Salat%' OR Recipe.portions = 4)
93  * // could have be built using one template, but this demonstrates the usage
94  * // of the ObjectQuery::makeGroup() method
95  * $recipeTpl3 = &$query->getObjectTemplate('Recipe');
96  * $recipeTpl3->setValue("name", "Salat", DATATYPE_ATTRIBUTE);
97  * $recipeTpl4 = &$query->getObjectTemplate('Recipe');
98  * $recipeTpl4->setValue("portions", "= 4", DATATYPE_ATTRIBUTE);
99  * $query->makeGroup(array(&$recipeTpl3, &$recipeTpl4), QUERYOP_AND, QUERYOP_OR);
100  *
101  * $authorTpl1->addChild($recipeTpl1);
102  * $authorTpl1->addChild($recipeTpl2);
103  * $authorTpl1->addChild($recipeTpl3);
104  * $authorTpl1->addChild($recipeTpl4);
105  * $authorList = $query->execute(BUILDDEPTH_SINGLE);
106  * @endcode
107  *
108  * @note There are some limitations when using this class:
109  * - This class works only with Nodes as PersistentObjects
110  * - This class only works for Nodes mapped by NodeUnifiedRDBMapper subclasses.
111  * - All objects have to reside in the same datastore (the connection is taken from the first mapper)
112  * - Since the query values are set together with the operator in a single string,
113  * they must be converted to data store format already
114  *
115  * @author ingo herwig <ingo@wemove.com>
116  */
118 {
119  var $_id = '';
120  var $_typeNode = null;
121  var $_root = null;
122  var $_conditions = array();
123  var $_groups = array();
124  var $_groupedOIDs = array();
125  var $_query = '';
126 
127  /**
128  * Constructor.
129  * @param type The type to search for.
130  */
131  function ObjectQuery($type)
132  {
133  $persistenceFacade = &PersistenceFacade::getInstance();
134  $this->_typeNode = &$persistenceFacade->create($type, BUILDDEPTH_SINGLE);
135  $this->_root = new Node('ROOT');
136  $this->_id = $this->_root->getOID();
137  }
138  /**
139  * Get an object template for a given type.
140  * @param type The type to query for
141  * @param preOperator One of the QUERYOP constants that precedes the conditions described in the template [default: QUERYOP_AND]
142  * @param interOperator One of the QUERYOP constants that is used to join the conditions described in the template [default: QUERYOP_AND]
143  * @return A newly created instance of a Node subclass, that defines
144  * the requested type.
145  */
146  function &getObjectTemplate($type, $preOperator=QUERYOP_AND, $interOperator=QUERYOP_AND)
147  {
148  $persistenceFacade = &PersistenceFacade::getInstance();
149  $template = &$persistenceFacade->create($type, BUILDDEPTH_SINGLE);
150  $template->setValue("pre_operator", $preOperator, DATATYPE_IGNORE);
151  $template->setValue("inter_operator", $interOperator, DATATYPE_IGNORE);
152  $template->addChangeListener($this);
153  $this->_root->addChild($template);
154  return $template;
155  }
156  /**
157  * Register an object template at the query.
158  * @param template A reference to the template to register (must be an instance of PersistentObject)
159  * @param preOperator One of the QUERYOP constants that precedes the conditions described in the template [default: QUERYOP_AND]
160  * @param interOperator One of the QUERYOP constants that is used to join the conditions described in the template [default: QUERYOP_AND]
161  */
162  function registerObjectTemplate(&$template, $preOperator=QUERYOP_AND, $interOperator=QUERYOP_AND)
163  {
164  if ($template != null)
165  {
166  $mapper = &ObjectQuery::getMapper($template);
167  if ($mapper == null)
168  return;
169 
170  $template->addChangeListener($this);
171 
172  // set the oid values so that they are used in the query
173  if (!PersistenceFacade::isDummyId($template->getDBID()))
174  {
175  $oidParts = PersistenceFacade::decomposeOID($template->getOID());
176  $i = 0;
177  foreach ($mapper->getPkNames() as $pkName => $pkValueType)
178  $template->setValue($pkName, $oidParts['id'][$i++], $pkValueType, true);
179  }
180  // set the values so that they are used in the query
181  $template->copyValues($template, array(DATATYPE_ATTRIBUTE));
182 
183  $template->setValue("pre_operator", $preOperator, DATATYPE_IGNORE);
184  $template->setValue("inter_operator", $interOperator, DATATYPE_IGNORE);
185  $this->_root->addChild($template);
186  }
187  }
188  /**
189  * Group different templates together to realize brackets in the query.
190  * @note Grouped templates will be ignored, when iterating over the object tree and appended at the end.
191  * @param templates An array of references to the templates contained in the group
192  * @param preOperator One of the QUERYOP constants that precedes the group [default: QUERYOP_AND]
193  * @param interOperator One of the QUERYOP constants that is used to join the conditions inside the group [default: QUERYOP_OR]
194  */
195  function makeGroup($templates, $preOperator=QUERYOP_AND, $interOperator=QUERYOP_OR)
196  {
197  $this->groups[sizeof($this->groups)] = array('tpls' => $templates, 'pre_operator' => $preOperator, 'inter_operator' => $interOperator);
198  // store grouped nodes in an extra array to separate them from the others
199  for ($i=0; $i<sizeof($templates); $i++)
200  {
201  if ($templates[$i] != null)
202  $this->_groupedOIDs[sizeof($this->_groupedOIDs)] = $templates[$i]->getOID();
203  else
204  WCMFException::throwEx(Message::get("null value found in group"), __FILE__, __LINE__);
205  }
206  }
207  /**
208  * Escape a value for using it in a query.
209  * @param value The value.
210  * @return The escaped value.
211  */
212  function escapeValue($value)
213  {
214  $value = str_replace("'", "\'", $value);
215  return $value;
216  }
217  /**
218  * Execute the object query
219  * @param buildDepth One of the BUILDDEPTH constants or a number describing the number of generations to load (except BUILDDEPTH_REQUIRED)
220  * or false if only oids should be returned
221  * @param orderby An array holding names of attributes to ORDER by (maybe null). [default: null]
222  * @param pagingInfo A reference paging info instance (optional, default null does not work in PHP4).
223  * @param attribs An array of attributes to load (null to load all, if buildDepth != false). [default: null]
224  * @return A list of objects that match the given conditions or a list of oids
225  */
226  function execute($buildDepth, $orderby=null, &$pagingInfo, $attribs=null)
227  {
228  // build the query
229  $this->_query = $this->buildQuery($buildDepth, $attribs);
230 
231  return ObjectQuery::executeString($this->_typeNode->getType(), $this->_query, $buildDepth, $orderby, $pagingInfo, $attribs);
232  }
233  /**
234  * Execute a serialized object query
235  * @note This method maybe called staticly
236  * @param type The type to query
237  * @param query The serialized query as string (as provided by ObjectQuery::toString)
238  * @param buildDepth One of the BUILDDEPTH constants or a number describing the number of generations to load (except BUILDDEPTH_REQUIRED)
239  * or false if only oids should be returned
240  * @param orderby An array holding names of attributes to ORDER by (maybe null). [default: null]
241  * @param pagingInfo A reference paging info instance (optional, default null does not work in PHP4).
242  * @return A list of objects that match the given conditions or a list of oids
243  */
244  function executeString($type, $query, $buildDepth, $orderby=null, &$pagingInfo)
245  {
246  $result = array();
247 
248  if (strlen($query) == 0)
249  return $result;
250 
251  $persistenceFacade = &PersistenceFacade::getInstance();
252  $this->_typeNode = &$persistenceFacade->create($type, BUILDDEPTH_SINGLE);
253  $mapper = &ObjectQuery::getMapper($this->_typeNode);
254  if ($mapper == null)
255  return $result;
256 
257  // add orderby clause
258  $query .= ObjectQuery::getOrderby($type, $query, $orderby);
259 
260  // execute the query
261  $rows = $mapper->select($query, $pagingInfo);
262  foreach ($rows as $row)
263  {
264  // construct oids or objects depending on builddepth
265  if ($buildDepth === false)
266  {
267  $oid = $mapper->constructOID($type, $row);
268  $result[] = $oid;
269  }
270  else
271  {
272  $obj = &$mapper->createObjectFromData($this->_typeNode->getValueNames(), $row);
273  $mapper->appendChildData($obj, $buildDepth);
274  $result[sizeof($result)] = &$obj;
275  }
276  }
277  return $result;
278  }
279  /**
280  * Get the query serialized to a string.
281  * @param buildDepth @see ObjectQuery::execute() [default: BUILDDEPTH_SINGLE]
282  * @param attribs An array of attributes to load (null to load all, if buildDepth != false). [default: null]
283  * @return The sql query string
284  */
285  function toString($buildDepth=BUILDDEPTH_SINGLE, $attribs=null)
286  {
287  return $this->buildQuery($buildDepth, $attribs);
288  }
289  /**
290  * Build the query
291  * @param buildDepth @see ObjectQuery::execute()
292  * @param attribs An array of attributes to load (null to load all, if buildDepth != false). [default: null]
293  * @return The sql query string
294  */
295  function buildQuery($buildDepth, $attribs=null)
296  {
297  $mapper = &ObjectQuery::getMapper($this->_typeNode);
298  if ($mapper == null)
299  return;
300 
301  // initialize query parts
302  $attributeStr = '';
303  $tableArray = array();
304  $relationArray = array();
305  $conditionStr = '';
306 
307  // if no object template is created, we use the typeNode as object template
308  if ($this->_root->getNumChildren() == 0)
309  $this->_root->addChild($this->_typeNode);
310 
311  // create attribute string (use the default select from the mapper, since we are only interested in the attributes)
312  $tablename = ObjectQuery::getTableName($this->_typeNode);
313  if ($buildDepth === false)
314  $attribs = array();
315  $select = $mapper->getSelectSQL('', null, $attribs, true);
316  $attributeStr = $select['attributeStr'];
317 
318  // process all nodes in the tree except for root and grouped nodes
319  $iterator = new NodeIterator($this->_root);
320  while(!($iterator->isEnd()))
321  {
322  $currentObject = &$iterator->getCurrentObject();
323  if ($currentObject->getOID() != $this->_root->getOID() && !in_array($currentObject->getOID(), $this->_groupedOIDs))
324  $this->processObjectTemplate($currentObject, $tableArray, $conditionStr, $relationArray);
325 
326  $iterator->proceed();
327  }
328 
329  // process groups
330  for ($i=0; $i<sizeof($this->groups); $i++)
331  {
332  $group = $this->groups[$i];
333  $groupConditionStr = '';
334  for ($j=0; $j<sizeof($group['tpls']); $j++)
335  {
336  $tpl = &$group['tpls'][$j];
337 
338  // override the pre_operator by the inter_operator of the group
339  $tpl->removeChangeListener($this);
340  $tpl->setValue("pre_operator", $group['inter_operator'], DATATYPE_IGNORE);
341  $tpl->addChangeListener($this);
342 
343  $this->processObjectTemplate($tpl, $tableArray, $groupConditionStr, $relationArray);
344  }
345  if (strlen($conditionStr) > 0)
346  $conditionStr .= ' '.$group['pre_operator'].' ';
347  $conditionStr .= '('.$groupConditionStr.')';
348  }
349 
350  // add table array to table string from mapper
351  $tableStr = $select['tableStr'];
352  foreach ($tableArray as $table)
353  {
354  if (preg_match('/\b'.$table.'\b/', $tableStr) == 0)
355  $tableStr = $table.", ".$tableStr;
356  }
357 
358  // assemble the final query
359  $query = 'SELECT DISTINCT '.$attributeStr.' FROM '.$tableStr;
360  if (strlen($conditionStr) > 0)
361  $query .= ' WHERE '.$conditionStr;
362  else
363  $query .= ' WHERE 1';
364  if (sizeof($relationArray) > 0)
365  $query .= ' AND '.join(' AND ', array_unique($relationArray));
366 
367  return $query;
368  }
369  /**
370  * Process an object template
371  * @param tpl The object template
372  * @param tableArray An array of table names, where the tablename of the templates will be added
373  * @param conditionStr A string of conditions, where the conditions described in the template will be added
374  * @param relationArray An array of relation strings, where the relations of the template will be added
375  * @return An assoziative array with the following keys: 'attributes', 'table', 'conditions'
376  */
377  function processObjectTemplate(&$tpl, &$tableArray, &$conditionStr, &$relationArray)
378  {
379  // add table
380  array_push($tableArray, ObjectQuery::getTableName($tpl, true));
381 
382  // add conditions
383  $processor = new NodeProcessor('makeConditionStr', array($tpl->getValue("inter_operator", DATATYPE_IGNORE)), $this);
384  $processor->run($tpl, false);
385  $curConditionStr = $tpl->getValue("query_condition", DATATYPE_IGNORE);
386  if (strlen($curConditionStr) > 0)
387  {
388  if (strlen($conditionStr) > 0)
389  $conditionStr .= ' '.$tpl->getValue("pre_operator", DATATYPE_IGNORE).' ';
390  $conditionStr .= '('.$curConditionStr.')';
391  }
392 
393  // add relations
394  $children = &$tpl->getChildren();
395  for($i=0; $i<sizeof($children); $i++)
396  {
397  $relationStr = ObjectQuery::getRelationCondition($tpl, $children[$i]);
398  array_push($relationArray, $relationStr);
399  }
400  }
401  /**
402  * Get the table name for the template.
403  * @param tpl The object template
404  * @param asAliasString Return the table name in the form 'table as alias' [default: false]
405  * @return An table name
406  */
407  function getTableName(&$tpl, $asAliasString=false)
408  {
409  $mapper = &ObjectQuery::getMapper($tpl);
410  if ($mapper == null)
411  return '';
412 
413  $tablename = '';
414  $mapperTablename = $mapper->getTableName();;
415 
416  if ($tpl->hasValue("table_name", DATATYPE_IGNORE))
417  {
418  $tablename = $tpl->getValue("table_name", DATATYPE_IGNORE);
419  }
420  else
421  {
422  $tablename = $mapperTablename;
423 
424  // if the template is the child of another node of the same type,
425  // we must use a table alias
426  if (sizeof($tpl->getParentsEx(null, $tpl->getType(), null, null)) > 0)
427  $tablename .= time();
428 
429  // set the table name for later reference
430  $tpl->setValue("table_name", $tablename, DATATYPE_IGNORE);
431  }
432 
433  if ($asAliasString && $tablename != $mapperTablename)
434  return $mapperTablename.' as '.$tablename;
435  else
436  return $tablename;
437  }
438  /**
439  * Get the relation condition between a parent and a child node.
440  * @param parentTpl The parent template node
441  * @param childTpl The child template node
442  * @return The condition string
443  */
444  function getRelationCondition(&$parentTpl, &$childTpl)
445  {
446  $parentMapper = &ObjectQuery::getMapper($parentTpl);
447  $childMapper = &ObjectQuery::getMapper($childTpl);
448  if ($parentMapper != null && $childMapper != null)
449  {
450  // foreign key names are defined by NodeUnifiedRDBMapper
451  $pkColumns = $parentMapper->getPKColumnNames();
452  $fkColumn = $childMapper->getMyFKColumnName($parentTpl->getType(), false);
453  $relationStr = ObjectQuery::getTableName($childTpl).'.'.$fkColumn.' = '.ObjectQuery::getTableName($parentTpl).'.'.$pkColumns[0];
454  return $relationStr;
455  }
456  return '';
457  }
458  /**
459  * Get the order by string from given array of attribute names.
460  * If the orderby parameter is null, the default order is taken.
461  * @param type The node type to get the order by for
462  * @param query The query to set the order by on
463  * @param orderby Array of attribute names
464  */
465  function getOrderby($type, $query, $orderby)
466  {
467  $persistenceFacade = &PersistenceFacade::getInstance();
468  $mapper = &$persistenceFacade->getMapper($type);
469  if(ObjectQuery::checkMapper($mapper))
470  {
471  // get default order if not given
472  if ($orderby == null)
473  $orderby = $mapper->getOrderBy();
474 
475  // get the table/alias name from the query
476  preg_match('/^SELECT DISTINCT ([^\.]+?)\./', $query, $matches);
477  $tablename = $matches[1];
478 
479  if ($orderby != null && is_array($orderby))
480  {
481  // add table name for attributes of the search type if missing
482  // (referenced values must not get the table name)
483  for($i=0; $i<sizeof($orderby); $i++)
484  {
485  if (strpos($orderby[$i], '.') === false && $mapper->isAttribute($orderby[$i]))
486  $orderby[$i] = $tablename.'.'.$orderby[$i];
487  }
488  return " ORDER BY ".$mapper->translateAppToDatabase(join(', ', $orderby));
489  }
490  }
491  return '';
492  }
493  /**
494  * Build a condition string from an object template. Used as a callback for a NodeProcessor.
495  * Adds each value condition to the "query_condition" value (DATATYPE_IGNORE)
496  * @param node A reference to the Node the holds the value (the template)
497  * @param valueName The name of the value
498  * @param dataType The dataType of the value
499  * @param operator The operator to connect the value conditions with
500  * @see NodeProcessor
501  */
502  function makeConditionStr(&$node, $valueName, $dataType, $operator)
503  {
504  // check if the value was set when building the query
505  if (isset($this->_conditions[$node->getOID()][$dataType][$valueName]))
506  {
507  // check if the value is a foreign key and ignore it if true
508  $mapper = &ObjectQuery::getMapper($node);
509  if ($mapper && $mapper->isForeignKey($valueName))
510  return;
511 
512  $currentCondition = $node->getValue("query_condition", DATATYPE_IGNORE);
513  if (strlen($currentCondition))
514  $currentCondition .= ' '.$operator.' ';
515 
516  $value = $node->getValue($valueName, $dataType);
517 
518  // set default LIKE '%...%' if no operator given
519  $parts = split(' ', $value);
520  if (sizeof($parts) == 1)
521  {
522  if (!in_array($valueName, array_keys($mapper->getPkNames()))) {
523  $value = "LIKE '%".$this->escapeValue($value)."%'";
524  }
525  else {
526  // don't search for pk names with LIKE
527  $value = "= '".$this->escapeValue($value)."'";
528  }
529  }
530 
531  $colName = $mapper->getColumnName($valueName, $dataType);
532  if ($colName !== null)
533  {
534  $currentCondition .= ObjectQuery::getTableName($node).'.'.$colName.' '.$value;
535  }
536  else
537  {
538  // set neutral element if the column does not exist
539  if ($operator == QUERYOP_AND)
540  $currentCondition .= "TRUE";
541  else
542  $currentCondition .= "FALSE";
543  }
544 
545  $node->removeChangeListener($this);
546  $node->setValue("query_condition", $currentCondition, DATATYPE_IGNORE);
547  $node->addChangeListener($this);
548  }
549  }
550  /**
551  * Get the database connection of the given node type.
552  * @param type The node type to get the connection from connection
553  * @return The connection
554  */
555  function &getConnection($type)
556  {
557  $persistenceFacade = &PersistenceFacade::getInstance();
558  $mapper = &$persistenceFacade->getMapper($type);
559  $conn = &$mapper->getConnection();
560  return $conn;
561  }
562  /**
563  * Get the mapper for a Node and check if it is a supported one.
564  * @param node A reference to the Node to get the mapper for
565  * @return The mapper
566  */
567  function &getMapper(&$node)
568  {
569  if ($node != null)
570  {
571  $mapper = &$node->getMapper();
572  if(ObjectQuery::checkMapper($mapper))
573  return $mapper;
574  }
575  return null;
576  }
577  /**
578  * Check if a mapper is a supported one.
579  * @param mapper A reference to the PersistenceMapper
580  * @return True/False, causes an error if false
581  */
582  function checkMapper(&$mapper)
583  {
584  if (!is_a($mapper, 'nodeunifiedrdbmapper') && !is_a($mapper, 'NodeUnifiedRDBMapper'))
585  {
586  WCMFException::throwEx(Message::get('%1% does only support PersistenceMappers of type NodeUnifiedRDBMapper.', array(get_class($this))), __FILE__, __LINE__);
587  return false;
588  }
589  return true;
590  }
591 
592  /**
593  * ChangeListener interface implementation
594  */
595 
596  /**
597  * @see ChangeListener::getId()
598  */
599  function getId()
600  {
601  return $this->_id;
602  }
603  /**
604  * @see ChangeListener::valueChanged()
605  */
606  function valueChanged(&$object, $name, $type, $oldValue, $newValue)
607  {
608  if ( !($type == DATATYPE_IGNORE && in_array($name, $GLOBALS['OQ_ATTRIBUTES'])) )
609  {
610  $oid = $object->getOID();
611  // store change in internal array to have it when constructing the query
612  if (!isset($this->_conditions[$oid]))
613  $this->_conditions[] = array();
614  if (!isset($this->_conditions[$oid][$type]))
615  $this->_conditions[$oid][$type] = array();
616 
617  $this->_conditions[$oid][$type][$name] = $newValue;
618  }
619  }
620  /**
621  * @see ChangeListener::propertyChanged()
622  */
623  function propertyChanged(&$object, $name, $oldValue, $newValue) {}
624  /**
625  * @see ChangeListener::stateChanged()
626  */
627  function stateChanged(&$object, $oldValue, $newValue) {}
628 }
629 ?>
executeString($type, $query, $buildDepth, $orderby=null, &$pagingInfo)
ObjectQuery is the base class for object queries. This class provides the user with object templates ...
& getObjectTemplate($type, $preOperator=QUERYOP_AND, $interOperator=QUERYOP_AND)
buildQuery($buildDepth, $attribs=null)
ChangeListener defines an interface for classes that want to be notified when a value of an persisten...
getOrderby($type, $query, $orderby)
get($message, $parameters=null, $domain='', $lang='')
Node is the basic component for building trees (although a Node can have one than more parents)...
Definition: class.Node.php:118
const QUERYOP_AND
makeGroup($templates, $preOperator=QUERYOP_AND, $interOperator=QUERYOP_OR)
const DATATYPE_ATTRIBUTE
NodeIterator is used to iterate over a tree/list build of objects using a Depth-First-Algorithm. Classes used with the NodeIterator must implement the getChildren() and getOID() methods. NodeIterator implements the 'Iterator Pattern'. The base class NodeIterator defines the interface for all specialized Iterator classes.
NodeProcessor is used to iterate over all values of a Node and apply a given callback function...
const QUERYOP_OR
getRelationCondition(&$parentTpl, &$childTpl)
throwEx($message, $file='', $line='')
stateChanged(&$object, $oldValue, $newValue)
makeConditionStr(&$node, $valueName, $dataType, $operator)
propertyChanged(&$object, $name, $oldValue, $newValue)
& getMapper(&$node)
$OQ_ATTRIBUTES
valueChanged(&$object, $name, $type, $oldValue, $newValue)
const DATATYPE_IGNORE
decomposeOID($oid, $validate=true)
toString($buildDepth=BUILDDEPTH_SINGLE, $attribs=null)
getTableName(&$tpl, $asAliasString=false)
processObjectTemplate(&$tpl, &$tableArray, &$conditionStr, &$relationArray)
$GLOBALS['gJSONData']
registerObjectTemplate(&$template, $preOperator=QUERYOP_AND, $interOperator=QUERYOP_AND)
const BUILDDEPTH_SINGLE
checkMapper(&$mapper)
execute($buildDepth, $orderby=null, &$pagingInfo, $attribs=null)
& getConnection($type)