BatchDisplayController.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  */
12 
24 
25 /**
26  * BatchDisplayController is used to load a tree of Node instances recursivly and
27  * return them in lists of a given size. The reconstruction of the tree must be
28  * handled by the client.
29  *
30  * The controller supports the following actions:
31  *
32  * <div class="controller-action">
33  * <div> __Action__ _default_ </div>
34  * <div>
35  * Load the Nodes.
36  * | Parameter | Description
37  * |---------------------------|-------------------------
38  * | _in_ / _out_ `oid` | The object id of the Node to start loading from
39  * | _in_ `translateValues` | Boolean whether list values should be translated to their display values (optional, default: _true_)
40  * | _in_ `nodesPerCall` | The number of Node instances to load in one call (default: 50)
41  * | _out_ `list` | Array of Node instances
42  * </div>
43  * </div>
44  *
45  * For additional actions and parameters see [BatchController actions](@ref BatchController).
46  *
47  * @author ingo herwig <ingo@wemove.com>
48  */
50 
51  // session name constants
52  const REGISTRY_VAR = 'registry';
53 
54  // persistent iterator id
55  const ITERATOR_ID_VAR = 'BatchDisplayController.iteratorid';
56 
57  // default values, maybe overriden by corresponding request values (see above)
58  const NODES_PER_CALL = 50;
59 
60  /**
61  * @see Controller::initialize()
62  */
63  public function initialize(Request $request, Response $response) {
64  // initialize controller
65  if ($request->getAction() != 'continue') {
66  $session = $this->getSession();
67 
68  // set defaults (will be stored with first request)
69  if (!$request->hasValue('nodesPerCall')) {
70  $request->setValue('nodesPerCall', self::NODES_PER_CALL);
71  }
72  if (!$request->hasValue('translateValues')) {
73  $request->setValue('translateValues', true);
74  }
75 
76  // initialize session variables
77  $this->setLocalSessionValue(self::REGISTRY_VAR, []);
78 
79  // reset iterator
80  PersistentIterator::reset(self::ITERATOR_ID_VAR, $session);
81  }
82  // initialize parent controller after default request values are set
83  parent::initialize($request, $response);
84  }
85 
86  /**
87  * @see Controller::validate()
88  */
89  protected function validate() {
90  $request = $this->getRequest();
91  $response = $this->getResponse();
92  if ($request->getAction() != 'continue') {
93  $oid = ObjectId::parse($request->getValue('oid'));
94  if(!$oid) {
95  $response->addError(ApplicationError::get('OID_INVALID',
96  ['invalidOids' => [$request->getValue('oid')]]));
97  return false;
98  }
99  if (!$this->checkLanguageParameter()) {
100  return false;
101  }
102  }
103  // do default validation
104  return parent::validate();
105  }
106 
107  /**
108  * @see BatchController::getWorkPackage()
109  */
110  protected function getWorkPackage($number) {
111  if ($number == 0) {
112  return ['name' => $this->getMessage()->getText('Loading'),
113  'size' => 1, 'oids' => [1], 'callback' => 'startProcess'];
114  }
115  else {
116  return null;
117  }
118  }
119 
120  /**
121  * Initialize the iterator (object ids parameter will be ignored)
122  * @param $oids The object ids to process
123  */
124  protected function startProcess($oids) {
125  $session = $this->getSession();
126  $persistenceFacade = $this->getPersistenceFacade();
127 
128  // restore the request oid from session
129  $nodeOID = ObjectId::parse($this->getRequestValue('oid'));
130 
131  // do the action
132  $iterator = new PersistentIterator(self::ITERATOR_ID_VAR, $persistenceFacade, $session, $nodeOID);
133  $iterator->save();
134 
135  // display the first node in order to reduce the number of calls
136  $this->loadNode($iterator->current());
137 
138  $iterator->next();
139 
140  // proceed if nodes are left
141  if ($iterator->valid()) {
142  $iterator->save();
143 
144  $name = $this->getMessage()->getText('Loading tree: continue with %0%',
145  [$iterator->current()]);
146  $this->addWorkPackage($name, 1, [null], 'loadNodes');
147  }
148  else {
149  // set the result and finish
150  $this->endProcess();
151  }
152  }
153 
154  /**
155  * Load nodes provided by the persisted iterator (object ids parameter will be ignored)
156  * @param $oids The object ids to process
157  */
158  protected function loadNodes($oids) {
159  $session = $this->getSession();
160  $persistenceFacade = $this->getPersistenceFacade();
161 
162  // check for iterator in session
163  $iterator = PersistentIterator::load(self::ITERATOR_ID_VAR, $persistenceFacade, $session);
164 
165  // no iterator, finish
166  if ($iterator == null || !$iterator->valid()) {
167  // set the result and finish
168  $this->endProcess();
169  }
170 
171  // process nodes
172  $counter = 0;
173  $nodesPerCall = $this->getRequestValue('nodesPerCall');
174  while ($iterator->valid() && $counter < $nodesPerCall) {
175  $currentOID = $iterator->current();
176  $this->loadNode($currentOID);
177 
178  $iterator->next();
179  $counter++;
180  }
181 
182  // decide what to do next
183  if ($iterator->valid()) {
184  // proceed with current iterator
185  $iterator->save();
186 
187  $name = $this->getMessage()->getText('Loading tree: continue with %0%',
188  [$iterator->current()]);
189  $this->addWorkPackage($name, 1, [null], 'loadNodes');
190  }
191  else {
192  // set the result and finish
193  $this->endProcess();
194  }
195  }
196 
197  /**
198  * Finish the process and set the result
199  */
200  protected function endProcess() {
201  // nothing to do, nodes are added to response during the process already
202  }
203 
204  /**
205  * Load the node with the given object id and assign it to the response.
206  * @param $oid The object id of the node to copy
207  */
208  protected function loadNode(ObjectId $oid) {
209  // check if we already loaded the node
210  if ($this->isRegistered($oid)) {
211  return;
212  }
213  $persistenceFacade = $this->getPersistenceFacade();
214 
215  // restore the request values from session
216  $language = $this->getRequestValue('language');
217  $translateValues = StringUtil::getBoolean($this->getRequestValue('translateValues'));
218 
219  // load the node
220  $node = $persistenceFacade->load($oid);
221  if ($node == null) {
222  throw new PersistenceException("Can't load node '".$oid."'");
223  }
224 
225  // translate all nodes to the requested language if requested
226  if ($this->isLocalizedRequest()) {
227  $localization = $this->getLocalization();
228  $node = $localization->loadTranslation($node, $language, true, true);
229  }
230 
231  // translate values if requested
232  if ($translateValues) {
233  $nodes = [$node];
234  if ($this->isLocalizedRequest()) {
235  NodeUtil::translateValues($nodes, $language);
236  }
237  else {
239  }
240  }
241 
242  // assign it to the response
243  $this->addNodeToResponse($node);
244 
245  $this->register($oid);
246 
247  $logger = $this->getLogger();
248  if ($logger->isInfoEnabled()) {
249  $logger->info("Loaded: ".$node->getOID());
250  }
251  if ($logger->isDebugEnabled()) {
252  $logger->debug($node->toString());
253  }
254  }
255 
256  /**
257  * Register an object id in the registry
258  * @param $oid The object id to register
259  */
260  protected function register(ObjectId $oid) {
261  $registry = $this->getLocalSessionValue(self::REGISTRY_VAR);
262  $registry[] = $oid->__toString();
263  $this->setLocalSessionValue(self::REGISTRY_VAR, $registry);
264  }
265 
266  /**
267  * Check if an object id is registered in the registry
268  * @param $oid The object id to check
269  * @return Boolean whether the object id is registered or not
270  */
271  protected function isRegistered(ObjectId $oid) {
272  $registry = $this->getLocalSessionValue(self::REGISTRY_VAR);
273  return in_array($oid->__toString(), $registry);
274  }
275 
276  /**
277  * Add a given node to the list variable of the response
278  * @param $node The Node instance to add
279  */
280  protected function addNodeToResponse(Node $node) {
281  $response = $this->getResponse();
282  if (!$response->hasValue('list')) {
283  $objects = [];
284  $response->setValue('list', $objects);
285  }
286 
287  $objects = $response->getValue('list');
288  $objects[] = $node;
289  $response->setValue('list', $objects);
290  }
291 }
292 ?>
Response holds the response values that are used as output from Controller instances.
Definition: Response.php:20
Request holds the request values that are used as input to Controller instances.
Definition: Request.php:18
endProcess()
Finish the process and set the result.
startProcess($oids)
Initialize the iterator (object ids parameter will be ignored)
PersistenceException signals an exception in the persistence service.
static getBoolean($string)
Get the boolean value of a string.
Definition: StringUtil.php:405
__toString()
Get a string representation of the object id.
Definition: ObjectId.php:215
PersistentIterator is used to iterate over a tree/list built of persistent objects using a Depth-Firs...
getLocalSessionValue($key, $default=null)
Set the value of a local session variable.
Definition: Controller.php:443
hasValue($name)
Check for existence of a value.
StringUtil provides support for string manipulation.
Definition: StringUtil.php:18
static reset($id, Session $session)
Reset the iterator with the given id.
ObjectId is the unique identifier of an object.
Definition: ObjectId.php:28
initialize(Request $request, Response $response)
getAction()
Get the name of the action.
getLogger()
Get the Logger instance.
Definition: Controller.php:267
getMessage()
Get the Message instance.
Definition: Controller.php:315
static translateValues(&$nodes, $language=null, $itemDelim=", ")
Translate all list values in a list of Nodes.
Definition: NodeUtil.php:249
setLocalSessionValue($key, $value)
Get the value of a local session variable.
Definition: Controller.php:454
ApplicationError is used to signal errors that occur while processing a request.
static parse($oid)
Parse a serialized object id string into an ObjectId instance.
Definition: ObjectId.php:135
BatchDisplayController is used to load a tree of Node instances recursivly and return them in lists o...
static get($code, $data=null)
Factory method for retrieving a predefined error instance.
getRequestValue($name)
Get a value from the initial request.
getPersistenceFacade()
Get the PersistenceFacade instance.
Definition: Controller.php:283
setValue($name, $value)
Set a value.
getRequest()
Get the Request instance.
Definition: Controller.php:251
Node adds the concept of relations to PersistentObject.
Definition: Node.php:34
loadNode(ObjectId $oid)
Load the node with the given object id and assign it to the response.
Application controllers.
Definition: namespaces.php:3
loadNodes($oids)
Load nodes provided by the persisted iterator (object ids parameter will be ignored)
BatchController is used to process complex, longer running actions, that need to be divided into seve...
getLocalization()
Get the Localization instance.
Definition: Controller.php:307
addWorkPackage($name, $size, array $oids, $callback, $args=null)
Add a work package to session.
static load($id, $persistenceFacade, $session)
Load an iterator state from the session.
Controller is the base class of all controllers.
Definition: Controller.php:49
isLocalizedRequest()
Check if the current request is localized.
Definition: Controller.php:366
isRegistered(ObjectId $oid)
Check if an object id is registered in the registry.
getResponse()
Get the Response instance.
Definition: Controller.php:259
setValue($name, $value, $forceSet=false, $trackChange=true)
Definition: Node.php:125
NodeUtil provides services for the Node class.
Definition: NodeUtil.php:28
addNodeToResponse(Node $node)
Add a given node to the list variable of the response.
getSession()
Get the Session instance.
Definition: Controller.php:275
checkLanguageParameter()
Checks the language request parameter and adds an response error, if it is not contained in the Local...
Definition: Controller.php:381