ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
BasicPersistence.php
Go to the documentation of this file.
1 <?php
2 
4 
14 
15 class BasicPersistence implements Persistence
16 {
17 
21  protected static $instance;
25  protected static $buckets = [];
41  protected static $tasks = [];
45  protected $connector = null;
46 
50  protected function __construct()
51  {
52  $this->valueHashToValueContainerId = new \SplObjectStorage();
53  $this->bucketHashToObserverContainerId = new \SplObjectStorage();
54  $this->taskHashToTaskContainerId = new \SplObjectStorage();
55  }
56 
57  public static function instance() : self
58  {
59  if (!self::$instance) {
60  self::$instance = new BasicPersistence();
61  }
62 
63  return self::$instance;
64  }
65 
66 
67 
68 
75  {
76  $this->connector = $connector;
77  }
78 
79 
85  public function saveBucketAndItsTasks(Bucket $bucket)
86  {
87  $bucket->checkIntegrity();
88 
89  $this->saveObserver($bucket);
90  }
91 
92 
98  public function updateBucket(Bucket $bucket)
99  {
100  $bucketContainer = new BucketContainer($this->getBucketContainerId($bucket), $this->connector);
101 
102  // The basic information about the task.
103  $bucketContainer->setUserId($bucket->getUserId());
104  $bucketContainer->setState($bucket->getState());
105  $bucketContainer->setTotalNumberoftasks(count($bucket->getTask()->unfoldTask()));
106  $bucketContainer->setPercentage($bucket->getOverallPercentage());
107  $bucketContainer->setTitle($bucket->getTitle());
108  $bucketContainer->setLastHeartbeat($bucket->getLastHeartbeat());
109  $bucketContainer->setDescription($bucket->getDescription());
110  $bucketContainer->setCurrentTaskid($this->getTaskContainerId($bucket->getCurrentTask()));
111  $bucketContainer->setRootTaskid($this->getTaskContainerId($bucket->getTask()));
112 
113  // Save and store the container to bucket instance.
114  $bucketContainer->update();
115  }
116 
117 
121  public function getBucketIdsOfUser($user_id, $order_by = "id", $order_direction = "ASC")
122  {
123  return BucketContainer::where(['user_id' => $user_id])
124  ->orderBy($order_by, $order_direction)
125  ->getArray(null, 'id');
126  }
127 
128 
134  public function getBucketMetaOfUser($user_id)
135  {
136  $buckets = BucketContainer::where(['user_id' => $user_id])->get();
137  $bucketMetas = array_map(function (BucketContainer $bucketContainer) {
138  $bucketMeta = new BasicBucketMeta();
139 
140  $bucketMeta->setUserId($bucketContainer->getUserId());
141  $bucketMeta->setState($bucketContainer->getState());
142  $bucketMeta->setTitle($bucketContainer->getTitle());
143  $bucketMeta->setDescription($bucketContainer->getDescription());
144  $bucketMeta->setOverallPercentage($bucketContainer->getPercentage());
145 
146  return $bucketMeta;
147  }, $buckets);
148 
149  return $bucketMetas;
150  }
151 
152 
156  public function getBucketIdsByState($state)
157  {
158  $buckets = BucketContainer::where(['state' => $state])->get();
159  $ids = array_map(function (BucketContainer $bucket_container) {
160  return $bucket_container->getId();
161  }, $buckets);
162 
163  return $ids;
164  }
165 
166 
173  protected function saveObserver(Bucket $bucket)
174  {
175  // If the instance has a known container we use it, otherwise we create a new container.
176  if ($this->bucketHashToObserverContainerId->contains($bucket)) {
177  $bucketContainer = new BucketContainer($this->bucketHashToObserverContainerId[$bucket], $this->connector);
178  } else {
179  $bucketContainer = new BucketContainer(0, $this->connector);
180  }
181 
182  // The basic information about the task.
183  $bucketContainer->setUserId($bucket->getUserId());
184  $bucketContainer->setState($bucket->getState());
185  $bucketContainer->setTitle($bucket->getTitle());
186  $bucketContainer->setDescription($bucket->getDescription());
187  $bucketContainer->setTotalNumberoftasks(count($bucket->getTask()->unfoldTask()));
188  $bucketContainer->setPercentage($bucket->getOverallPercentage());
189 
190  // We want to store the bucket ID in every sub task and value. Thus we need to create an id if not available yet.
191  if (!$bucketContainer->getId()) {
192  $bucketContainer->create();
193  }
194 
195  // The recursive part.
196  $this->saveTask($bucket->getTask(), $bucketContainer->getId());
197  if (!$bucket->getCurrentTask()) {
198  $bucket->setCurrentTask($bucket->getTask());
199  }
200  $bucketContainer->setCurrentTaskid($this->getTaskContainerId($bucket->getCurrentTask()));
201  $bucketContainer->setRootTaskid($this->getTaskContainerId($bucket->getTask()));
202 
203  // Save and store the container to bucket instance.
204  $bucketContainer->save();
205  $this->bucketHashToObserverContainerId[$bucket] = $bucketContainer->getId();
206  }
207 
208 
216  protected function saveTask(Task $task, $bucketId)
217  {
218  // If the instance has a known container we use it, otherwise we create a new container.
219  if ($this->taskHashToTaskContainerId->contains($task)) {
220  $taskContainer = new TaskContainer($this->taskHashToTaskContainerId[$task], $this->connector);
221  } else {
222  $taskContainer = new TaskContainer(0, $this->connector);
223  }
224 
225  // The basic information about the task.
226  $taskContainer->setType($task->getType());
227  $taskContainer->setBucketId($bucketId);
228  $reflection = new \ReflectionClass(get_class($task));
229  $taskContainer->setClassName(get_class($task));
230  // bugfix mantis 23503
231  $absolute_class_path = $reflection->getFileName();
232  // $relative_class_path = str_replace(ILIAS_ABSOLUTE_PATH,".",$absolute_class_path);
233  $taskContainer->setClassPath($reflection->getFileName());
234 
235  // Recursivly save the inputs and link them to this task.
236  foreach ($task->getInput() as $k => $input) {
237  $this->saveValue($input, $bucketId, $k);
238  }
239  $this->saveValueToTask($task, $taskContainer, $bucketId);
240 
241  // Save and store the container to the task instance.
242  $taskContainer->save();
243  $this->taskHashToTaskContainerId[$task] = $taskContainer->getId();
244  }
245 
246 
255  protected function saveValueToTask(Task $task, TaskContainer $taskContainer, $bucketId)
256  {
257  // If we have previous values to task associations we delete them.
258  if ($taskContainer->getId()) {
260  $olds = ValueToTaskContainer::where(['task_id' => $taskContainer->getId()])->get();
261  foreach ($olds as $old) {
262  $old->delete();
263  }
264  } else {
265  // We need a valid ID to link the inputs
266  $taskContainer->save();
267  }
268 
269  // We create the new 1 to n relation.
270  foreach ($task->getInput() as $k => $inputValue) {
271  $v = new ValueToTaskContainer(0, $this->connector);
272  $v->setTaskId($taskContainer->getId());
273  $v->setPosition($k);
274  $v->setBucketId($bucketId);
275  $v->setValueId($this->getValueContainerId($inputValue));
276  $v->save();
277  }
278  }
279 
280 
288  protected function saveValue(Value $value, $bucketId, $position)
289  {
290  // If we have previous values to task associations we delete them.
291  if ($this->valueHashToValueContainerId->contains($value)) {
292  $valueContainer = new ValueContainer($this->valueHashToValueContainerId[$value], $this->connector);
293  } else {
294  $valueContainer = new ValueContainer(0, $this->connector);
295  }
296 
297  // Save information about the value
298  $reflection = new \ReflectionClass(get_class($value));
299  $valueContainer->setClassName(get_class($value));
300  // bugfix mantis 23503
301  // $absolute_class_path = $reflection->getFileName();
302  // $relative_class_path = str_replace(ILIAS_ABSOLUTE_PATH,".",$absolute_class_path);
303  // $valueContainer->setClassPath($relative_class_path);
304  $valueContainer->setType($value->getType());
305  $valueContainer->setHasParenttask($value->hasParentTask());
306  $valueContainer->setBucketId($bucketId);
307  $valueContainer->setPosition($position);
308  $valueContainer->setHash($value->getHash());
309  $valueContainer->setSerialized($value->serialize());
310 
311  // If the value is a thunk value we also store its parent.
312  if ($value->hasParentTask()) {
313  $this->saveTask($value->getParentTask(), $bucketId);
314  $valueContainer->setParentTaskid($this->getTaskContainerId($value->getParentTask()));
315  }
316 
317  // We save the container and store the instance to container association.
318  $valueContainer->save();
319  $this->valueHashToValueContainerId->attach($value, $valueContainer->getId());
320  }
321 
322 
329  public function getBucketContainerId(Bucket $bucket)
330  {
331  if (!$this->bucketHashToObserverContainerId->contains(($bucket))) {
332  throw new SerializationException("Could not resolve container id of task: "
333  . print_r($bucket, true));
334  }
335 
336  return $this->bucketHashToObserverContainerId[$bucket];
337  }
338 
339 
346  protected function getTaskContainerId(Task $task)
347  {
348  if (!$this->taskHashToTaskContainerId->contains($task)) {
349  throw new SerializationException("Could not resolve container id of task: "
350  . print_r($task, true));
351  }
352 
353  return $this->taskHashToTaskContainerId[$task];
354  }
355 
356 
363  protected function getValueContainerId($value) : int
364  {
365  if (!$this->valueHashToValueContainerId->contains($value)) {
366  throw new SerializationException("Could not resolve container id of value: "
367  . print_r($value, true));
368  }
369 
370  return (int) $this->valueHashToValueContainerId[$value];
371  }
372 
373 
380  public function loadBucket($bucket_id)
381  {
382  if (isset(self::$buckets[$bucket_id])) {
383  return self::$buckets[$bucket_id];
384  }
386  $bucketContainer = BucketContainer::find($bucket_id);
387  if (!$bucketContainer) {
388  throw new BucketNotFoundException("The requested bucket with container id $bucket_id could not be found in the database.");
389  }
390  $bucket = new BasicBucket();
391 
392  $bucket->setUserId($bucketContainer->getUserId());
393  $bucket->setState($bucketContainer->getState());
394  $bucket->setTitle($bucketContainer->getTitle());
395  $bucket->setDescription($bucketContainer->getDescription());
396  $bucket->setOverallPercentage($bucketContainer->getPercentage());
397  $bucket->setLastHeartbeat($bucketContainer->getLastHeartbeat());
398  $bucket->setTask($this->loadTask($bucketContainer->getRootTaskid(), $bucket, $bucketContainer));
399 
400  $this->bucketHashToObserverContainerId[$bucket] = $bucket_id;
401 
402  return $bucket;
403  }
404 
405 
417  private function loadTask($taskContainerId, Bucket $bucket, BucketContainer $bucketContainer)
418  {
419  global $DIC;
420  $factory = $DIC->backgroundTasks()->taskFactory();
422  $taskContainer = TaskContainer::find($taskContainerId);
425  $task = $factory->createTask($taskContainer->getClassName());
426 
427  // Bugfix 0023775
428  // Added additional orderBy for the id to ensure that the items are returned in the right order.
429 
431  $valueToTasks = ValueToTaskContainer::where(['task_id' => $taskContainerId])
432  ->orderBy('task_id')
433  ->orderBy('position')
434  ->orderBy('id')
435  ->get();
436  $inputs = [];
437  foreach ($valueToTasks as $valueToTask) {
438  $inputs[] = $this->loadValue($valueToTask->getValueId(), $bucket, $bucketContainer);
439  }
440  $task->setInput($inputs);
441 
442  if ($taskContainerId == $bucketContainer->getCurrentTaskid()) {
443  $bucket->setCurrentTask($task);
444  }
445 
446  $this->taskHashToTaskContainerId[$task] = $taskContainerId;
447 
448  return $task;
449  }
450 
451 
452  private function loadValue($valueContainerId, Bucket $bucket, BucketContainer $bucketContainer)
453  {
454  global $DIC;
455  $factory = $DIC->backgroundTasks()->injector();
456 
458  $valueContainer = ValueContainer::find($valueContainerId);
462  $value = $factory->createInstance($valueContainer->getClassName());
463 
464  $value->unserialize($valueContainer->getSerialized());
465  if ($valueContainer->getHasParenttask()) {
466  $value->setParentTask($this->loadTask($valueContainer->getParentTaskid(), $bucket, $bucketContainer));
467  }
468 
469  $this->valueHashToValueContainerId[$value] = $valueContainerId;
470 
471  return $value;
472  }
473 
474 
475  public function deleteBucketById($bucket_id)
476  {
477 // return;
479  $buckets = BucketContainer::where(['id' => $bucket_id])->get();
480  array_map(function (\ActiveRecord $item) {
481  $item->delete();
482  }, $buckets);
483 
485  $tasks = TaskContainer::where(['bucket_id' => $bucket_id])->get();
486  array_map(function (\ActiveRecord $item) {
487  $item->delete();
488  }, $tasks);
489 
491  $values = ValueContainer::where(['bucket_id' => $bucket_id])->get();
492  array_map(function (\ActiveRecord $item) {
493  $item->delete();
494  }, $values);
495 
497  $valueToTasks = ValueToTaskContainer::where(['bucket_id' => $bucket_id])->get();
498  array_map(function (\ActiveRecord $item) {
499  $item->delete();
500  }, $valueToTasks);
501  }
502 
503 
507  public function deleteBucket($bucket)
508  {
509  $id = $this->getBucketContainerId($bucket);
510  $this->deleteBucketById($id);
511  $this->bucketHashToObserverContainerId->detach($bucket);
512  }
513 
514 
520  public function loadBuckets($bucket_container_id)
521  {
522  $buckets = [];
523  foreach ($bucket_container_id as $bucket_id) {
524  try {
525  $buckets[] = $this->loadBucket($bucket_id);
526  } catch (\Throwable $t) {
527  $this->deleteBucketById($bucket_id);
528  }
529  }
530 
531  return $buckets;
532  }
533 }
setConnector(\arConnector $connector)
Currently for testing only.
Class ActiveRecord.
global $DIC
Definition: saml.php:7
deleteBucket($bucket)
Delete the bucket and all its stuff.Bucketvoid
$factory
Definition: metadata.php:43
if(!array_key_exists('StateId', $_REQUEST)) $id
Class arConnector.
static where($where, $operator=null)
if(!array_key_exists('stateid', $_REQUEST)) $state
Handle linkback() response from LinkedIn.
Definition: linkback.php:10
$values
updateBucket(Bucket $bucket)
Updates only the bucket! Use this if e.g.
getLastHeartbeat()
When was the last time that something happened on this bucket?
saveBucketAndItsTasks(Bucket $bucket)
Fully updates or creates an Observer and all its tasks into the database.
getBucketIdsByState($state)
intint[] Returns a list of bucket ids for the given Observer State
deleteBucketById($bucket_id)
Deletes the Observer AND all its tasks and values.
getBucketIdsOfUser($user_id, $order_by="id", $order_direction="ASC")
[] Returns an array of bucket ids for the given user Id.
loadBucket($bucket_container_id)