AbstractQuery.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;
12 
20 
21 /**
22  * AbstractQuery is the base class for all query classes.
23  *
24  * @author ingo herwig <ingo@wemove.com>
25  */
26 abstract class AbstractQuery {
27 
28  private $selectStmt = null;
29 
30  /**
31  * Get the logger
32  * @return Logger
33  */
34  protected abstract function getLogger();
35 
36  /**
37  * Get the name of the entity type that should be queried
38  * @return String
39  */
40  public abstract function getQueryType();
41 
42  /**
43  * Execute the query
44  * @param $buildDepth One of the BUILDDEPTH constants or a number describing the number of generations to load (except BuildDepth::REQUIRED)
45  * or false if only object ids should be returned
46  * @param $orderby An array holding names of attributes to order by, maybe appended with 'ASC', 'DESC' (maybe null) (default: _null_)
47  * @param $pagingInfo A reference paging info instance (optional, default: _null_)
48  * @return A list of objects that match the given conditions or a list of object ids
49  */
50  public function execute($buildDepth, $orderby=null, $pagingInfo=null) {
51  // build the query
52  $this->selectStmt = $this->buildQuery($buildDepth, $orderby, $pagingInfo);
53 
54  $result = $this->executeInternal($this->selectStmt, $buildDepth, $pagingInfo);
55  $logger = $this->getLogger();
56  if ($logger && $logger->isDebugEnabled()) {
57  $logger->debug("Executed query: ".$this->selectStmt->__toString());
58  $logger->debug("With parameters: ".json_encode($this->selectStmt->getParameters()));
59  $logger->debug("Result: ".join(", ", array_map(function($item) {
60  return preg_replace( "/\r|\n/", " ", $item->__toString());
61  }, $result)));
62  }
63  return $result;
64  }
65 
66  /**
67  * Get the query serialized to a string. Placeholder are replaced with quoted values.
68  * @param $buildDepth One of the BUILDDEPTH constants or a number describing the number of generations to load (except BuildDepth::REQUIRED)
69  * or false if only object ids should be returned (optional, default: _BuildDepth::SINGLE_)
70  * @param $orderby An array holding names of attributes to order by, maybe appended with 'ASC', 'DESC' (optional, default: _null_)
71  * @return String
72  */
73  public function getQueryString($buildDepth=BuildDepth::SINGLE, $orderby=null) {
74  $selectStmt = $this->buildQuery($buildDepth, $orderby);
75  $str = $selectStmt->__toString();
76  $mapper = self::getMapper($selectStmt->getType());
77  foreach ($selectStmt->getParameters() as $key => $value) {
78  $value = is_string($value) ? $mapper->quoteValue($value) : $value;
79  $str = preg_replace('/'.$key.'/', $value, $str, 1);
80  }
81  return $str;
82  }
83 
84  /**
85  * Get the query last executed serialized to a string.
86  * @return String
87  */
88  public function getLastQueryString() {
89  if ($this->selectStmt != null) {
90  return $this->selectStmt->__toString();
91  }
92  return "";
93  }
94 
95  /**
96  * Build the query
97  * @param $buildDepth One of the BUILDDEPTH constants or a number describing the number of generations to load (except BuildDepth::REQUIRED)
98  * or false if only object ids should be returned
99  * @param $orderby An array holding names of attributes to order by, maybe appended with 'ASC', 'DESC' (optional, default: _null_)
100  * @param $pagingInfo A reference paging info instance (optional, default: _null_)
101  * @return SelectStatement instance
102  */
103  protected abstract function buildQuery($buildDepth, $orderby=null, PagingInfo $pagingInfo=null);
104 
105  /**
106  * Execute the query and return the results.
107  * @param $selectStmt A SelectStatement instance
108  * @param $buildDepth One of the BUILDDEPTH constants or a number describing the number of generations to load (except BuildDepth::REQUIRED)
109  * or false if only object ids should be returned
110  * @param $pagingInfo A reference paging info instance (default: _null_)
111  * @return A list of objects that match the given conditions or a list of object ids
112  */
113  protected function executeInternal(SelectStatement $selectStmt, $buildDepth, PagingInfo $pagingInfo=null) {
114  $type = $this->getQueryType();
115  $mapper = self::getMapper($type);
116  $permissionManager = ObjectFactory::getInstance('permissionManager');
117  $loadOidsOnly = ($buildDepth === false);
118 
119  // execute the query
120  $result = [];
121  if ($loadOidsOnly) {
122  $data = $mapper->select($selectStmt, $pagingInfo);
123 
124  // collect oids
125  for ($i=0, $count=sizeof($data); $i<$count; $i++) {
126  $oid = $mapper->constructOID($data[$i]);
127  if ($permissionManager->authorize($oid, '', PersistenceAction::READ)) {
128  $result[] = $oid;
129  }
130  }
131  }
132  else {
133  $objects = $mapper->loadObjectsFromSQL($selectStmt, $buildDepth, $pagingInfo);
134 
135  // remove objects for which the user is not authorized
136  $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
137  $tx = $persistenceFacade->getTransaction();
138 
139  // remove objects for which the user is not authorized
140  for ($i=0, $count=sizeof($objects); $i<$count; $i++) {
141  $object = $objects[$i];
142  $oid = $object->getOID();
143  if ($permissionManager->authorize($oid, '', PersistenceAction::READ)) {
144  // call lifecycle callback
145  $object->afterLoad();
146  $result[] = $object;
147  }
148  else {
149  $tx->detach($oid);
150  }
151  // TODO remove attribute values for which the user is not authorized
152  // should use some pre-check if restrictions on the entity type exist
153  }
154  }
155  return $result;
156  }
157 
158  /**
159  * Get the database connection of the given node type.
160  * @param $type The node type to get the connection from connection
161  * @return The connection
162  */
163  protected static function getConnection($type) {
164  $mapper = self::getMapper($type);
165  $conn = $mapper->getConnection();
166  return $conn;
167  }
168 
169  /**
170  * Get the mapper for a Node and check if it is a supported one.
171  * @param $type The type of Node to get the mapper for
172  * @return RDBMapper instance
173  */
174  protected static function getMapper($type) {
175  $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
176  $mapper = $persistenceFacade->getMapper($type);
177  if (!($mapper instanceof RDBMapper)) {
178  throw new PersistenceException('Only PersistenceMappers of type RDBMapper are supported.');
179  }
180  return $mapper;
181  }
182 }
183 ?>
RDBMapper defines the interface for mapper classes that map to relational databases.
Definition: RDBMapper.php:24
getLogger()
Get the logger.
PersistenceException signals an exception in the persistence service.
buildQuery($buildDepth, $orderby=null, PagingInfo $pagingInfo=null)
Build the query.
static getConnection($type)
Get the database connection of the given node type.
execute($buildDepth, $orderby=null, $pagingInfo=null)
Execute the query.
getQueryType()
Get the name of the entity type that should be queried.
getLastQueryString()
Get the query last executed serialized to a string.
BuildDepth values are used to define the depth when loading object trees.
Definition: BuildDepth.php:19
static getMapper($type)
Get the mapper for a Node and check if it is a supported one.
getQueryString($buildDepth=BuildDepth::SINGLE, $orderby=null)
Get the query serialized to a string.
AbstractQuery is the base class for all query classes.
static getInstance($name, $dynamicConfiguration=[])
PagingInfo contains information about a paged list.
Definition: PagingInfo.php:18
Node related interfaces and classes.
Definition: namespaces.php:26
executeInternal(SelectStatement $selectStmt, $buildDepth, PagingInfo $pagingInfo=null)
Execute the query and return the results.
PersistenceAction values are used to define actions on PersistentObject instances.
ObjectFactory implements the service locator pattern by wrapping a Factory instance and providing sta...