ListController.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  */
12 
23 
24 /**
25  * ListController is used to load Node lists.
26  *
27  * The controller supports the following actions:
28  *
29  * <div class="controller-action">
30  * <div> __Action__ _default_ </div>
31  * <div>
32  * Load the specified list of Node instances.
33  * | Parameter | Description
34  * |------------------------|-------------------------
35  * | _in_ `className` | The entity type to list instances of
36  * | _in_ `limit` | The maximum number of instances to return. If omitted, all instances (beginning at the offset parameter) will be returned (optional)
37  * | _in_ `offset` | The index of the first instance to return, based on the current sorting. The index is 0-based. If omitted, 0 is assumed (optional)
38  * | _in_ `sortFieldName` | The field name to sort the list by. Must be one of the fields of the type selected by the className parameter. If omitted, the sorting is undefined (optional)
39  * | _in_ `sortDirection` | The direction to sort the list. Must be either _asc_ for ascending or _desc_ for descending (optional, default: _asc_)
40  * | _in_ `query` | A query condition to be used with StringQuery::setConditionString()
41  * | _in_ `translateValues` | Boolean whether list values should be translated to their display values (optional, default: _false_)
42  * | _in_ `completeObjects` | Boolean whether to return all object attributes or only the display values using NodeUtil::removeNonDisplayValues (optional, default: _true_)
43  * | _out_ `list` | Array of Node instances according to the given input parameters
44  * | _out_ `totalCount` | The total number of instances matching the passed parameters
45  * | __Response Actions__ | |
46  * | `ok` | In all cases
47  * </div>
48  * </div>
49  *
50  * @author ingo herwig <ingo@wemove.com>
51  */
52 class ListController extends Controller {
53 
54  /**
55  * @see Controller::validate()
56  */
57  protected function validate() {
58  $request = $this->getRequest();
59  $response = $this->getResponse();
60  if($request->hasValue('limit') && intval($request->getValue('limit')) < 0) {
61  $this->getLogger()->warn(ApplicationError::get('LIMIT_NEGATIVE'));
62  }
63  if($request->hasValue('sortDirection')) {
64  $sortDirection = $request->getValue('sortDirection');
65  if (strtolower($sortDirection) != 'asc' && strtolower($sortDirection) != 'desc') {
66  $response->addError(ApplicationError::get('SORT_DIRECTION_UNKNOWN'));
67  }
68  }
69  if (!$this->checkLanguageParameter()) {
70  return false;
71  }
72  // we can't check for offset out of bounds here
73  // do default validation
74  return parent::validate();
75  }
76 
77  /**
78  * @see Controller::doExecute()
79  */
80  protected function doExecute() {
81  $request = $this->getRequest();
82  $permissionManager = $this->getPermissionManager();
83 
84  // unveil the query value if it is ofuscated
85  $query = null;
86  if ($request->hasValue('query')) {
87  $query = $request->getValue('query');
88  if (strlen($query) > 0) {
89  $obfuscator = new Obfuscator($this->getSession());
90  $unveiled = $obfuscator->unveil($query);
91  if (strlen($unveiled) > 0) {
92  $query = stripslashes($unveiled);
93  }
94  }
95  }
96 
97  // get objects using the paging parameters
98  $pagingInfo = null;
99  if ($request->hasValue('limit')) {
100  $pagingInfo = new PagingInfo($request->getValue('limit'));
101  $pagingInfo->setOffset($request->getValue('offset'));
102  }
103  $className = $request->getValue('className');
104 
105  // add sort term
106  $sortArray = null;
107  $orderBy = $request->getValue('sortFieldName');
108  if (strlen($orderBy) > 0) {
109  $sortArray = array($orderBy." ".$request->getValue('sortDirection'));
110  }
111  // get the object ids
112  $objects = $this->getObjects($className, $query, $sortArray, $pagingInfo);
113 
114  // collect the nodes
115  $nodes = array();
116  for($i=0,$count=sizeof($objects); $i<$count; $i++) {
117  $curObject = $objects[$i];
118 
119  // check if we can read the object
120  if ($permissionManager->authorize($curObject->getOID(), '', PersistenceAction::READ)) {
121  $nodes[] = $curObject;
122  }
123  }
124  $totalCount = $pagingInfo != null ? $pagingInfo->getTotalCount() : sizeof($nodes);
125 
126  // translate all nodes to the requested language if requested
127  if ($this->isLocalizedRequest()) {
128  $localization = $this->getLocalization();
129  for ($i=0,$count=sizeof($nodes); $i<$count; $i++) {
130  $nodes[$i] = $localization->loadTranslation($nodes[$i], $this->_request->getValue('language'), true, true);
131  }
132  }
133 
134  // allow subclasses to modify the model
135  $this->modifyModel($nodes);
136 
137  // assign response values
138  $response = $this->getResponse();
139  $response->setValue('list', $nodes);
140  $response->setValue('totalCount', $totalCount);
141 
142  // success
143  $response->setAction('ok');
144  }
145 
146  /**
147  * Get the object to display. The default implementation uses a StringQuery instance for the
148  * object retrieval. Subclasses may override this. If filter is an empty string, all nodes of the given
149  * type will be selected.
150  * @param $type The object type
151  * @param $queryCondition The query condition passed from the view (to be used with StringQuery).
152  * @param $sortArray An array of attributes to order by (with an optional ASC|DESC appended)
153  * @param $pagingInfo A reference to the current paging information (PagingInfo instance)
154  * @return Array of Node instances
155  */
156  protected function getObjects($type, $queryCondition, $sortArray, $pagingInfo) {
157  $persistenceFacade = $this->getPersistenceFacade();
158  if (!$persistenceFacade->isKnownType($type)) {
159  return array();
160  }
161  $permissionManager = $this->getPermissionManager();
162  if (!$permissionManager->authorize($type, '', PersistenceAction::READ)) {
163  $message = $this->getMessage();
164  throw new AuthorizationException($message->getText("Authorization failed for action '%0%' on '%1%'.",
165  array($message->getText('read'), $persistenceFacade->getSimpleType($type))));
166  }
167  $objects = array();
168  $query = new StringQuery($type);
169  $query->setConditionString($queryCondition);
170  try {
171  $objects = $query->execute(BuildDepth::SINGLE, $sortArray, $pagingInfo);
172  }
173  catch (UnknownFieldException $ex) {
174  // check if the sort field is illegal
175  $response = $this->getResponse();
176  $request = $this->getRequest();
177  if($request->hasValue('sortFieldName')) {
178  $sortFieldName = $request->getValue('sortFieldName');
179  if ($sortFieldName == $ex->getField()) {
180  $response->addError(ApplicationError::get('SORT_FIELD_UNKNOWN'));
181  }
182  }
183  }
184  $this->getLogger()->debug("Load objects with query: ".$query->getLastQueryString());
185  return $objects;
186  }
187 
188  /**
189  * Modify the model passed to the view.
190  * @note subclasses will override this to implement special application requirements.
191  * @param $nodes A reference to the array of node references passed to the view
192  */
193  protected function modifyModel($nodes) {
194  $request = $this->getRequest();
195  // TODO: put this into subclass ListController
196 
197  // remove all attributes except for display_values
198  if ($request->getBooleanValue('completeObjects', true) == false) {
199  for($i=0,$count=sizeof($nodes); $i<$count; $i++) {
201  }
202  }
203  // render values
204  if ($request->getBooleanValue('translateValues', false) == true) {
206  }
207  }
208 }
209 ?>
setOffset($offset)
Set the current offset (also selects the page).
Definition: PagingInfo.php:92
getRequest()
Get the Request instance.
Definition: Controller.php:190
StringQuery executes queries from a string representation.
Definition: StringQuery.php:40
getObjects($type, $queryCondition, $sortArray, $pagingInfo)
Get the object to display.
modifyModel($nodes)
Modify the model passed to the view.
getMessage()
Get the Message instance.
Definition: Controller.php:254
Controller is the base class of all controllers.
Definition: Controller.php:48
static translateValues(&$nodes, $language=null)
Translate all list values in a list of Nodes.
Definition: NodeUtil.php:253
AuthorizationException signals an exception in authorization.
getPermissionManager()
Get the PermissionManager instance.
Definition: Controller.php:230
UnknownFieldException signals an exception in a message.
isLocalizedRequest()
Check if the current request is localized.
Definition: Controller.php:300
getLocalization()
Get the Localization instance.
Definition: Controller.php:246
PagingInfo contains information about a paged list.
Definition: PagingInfo.php:18
ListController is used to load Node lists.
checkLanguageParameter()
Checks the language request parameter and adds an response error, if it is not contained in the Local...
Definition: Controller.php:315
static removeNonDisplayValues(Node $node)
Remove all values from a Node that are not a display value.
Definition: NodeUtil.php:281
Obfuscator allows to obfuscate strings.
Definition: Obfuscator.php:23
Application controllers.
Definition: namespaces.php:3
static get($code, $data=null)
Factory method for retrieving a predefind error instance.
getLogger()
Get the Logger instance.
Definition: Controller.php:206
getResponse()
Get the Response instance.
Definition: Controller.php:198
getSession()
Get the Session instance.
Definition: Controller.php:214
getPersistenceFacade()
Get the PersistenceFacade instance.
Definition: Controller.php:222