ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilLSPlayer.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
25 use ILIAS\Refinery;
28 
33 {
34  public const PARAM_LSO_COMMAND = 'lsocmd';
35  public const PARAM_LSO_PARAMETER = 'lsov';
36 
37  public const LSO_CMD_NEXT = 'lsonext'; //with param directions
38  public const LSO_CMD_GOTO = 'lsogoto'; //with param ref_id
39  public const LSO_CMD_SUSPEND = 'lsosuspend';
40  public const LSO_CMD_FINISH = 'lsofinish';
41 
42  public const GS_DATA_LS_KIOSK_MODE = 'ls_kiosk_mode';
43  public const GS_DATA_LS_CONTENT = 'ls_content';
44  public const GS_DATA_LS_MAINBARCONTROLS = 'ls_mainbar_controls';
45  public const GS_DATA_LS_METABARCONTROLS = 'ls_metabar_controls';
46 
47  public function __construct(
48  protected ilLSLearnerItemsQueries $ls_items,
49  protected LSControlBuilder $control_builder,
50  protected LSUrlBuilder $url_builder,
51  protected ilLSCurriculumBuilder $curriculum_builder,
52  protected ilLSViewFactory $view_factory,
53  protected ilKioskPageRenderer $page_renderer,
54  protected Factory $ui_factory,
55  protected ScreenContext $current_context,
56  protected Refinery\Factory $refinery
57  ) {
58  }
59 
60  public function play(RequestWrapper $get): ?string
61  {
62  $items = $this->ls_items->getItems();
63 
64  if (count($items) === 0) {
65  return null;
66  }
67 
68  $current_item = $this->getNextAvailableItem($items, $this->getCurrentItem($items));
69  if ($current_item === null) {
70  return null;
71  }
72 
73  $view = $this->view_factory->getViewFor($current_item);
74  $state = $this->ls_items->getStateFor($current_item, $view);
75  $state = $this->updateViewState($state, $view, $get);
76  //reload items after update viewState
77  $items = $this->ls_items->getItems();
78 
79  $current_item_ref_id = $current_item->getRefId();
80  //now, digest parameter:
81  $command = null;
82  if ($get->has(self::PARAM_LSO_COMMAND)) {
83  $command = $get->retrieve(self::PARAM_LSO_COMMAND, $this->refinery->kindlyTo()->string());
84  }
85  $param = null;
86  if ($get->has(self::PARAM_LSO_PARAMETER)) {
87  $param = $get->retrieve(self::PARAM_LSO_PARAMETER, $this->refinery->kindlyTo()->int());
88  }
89 
90  switch ($command) {
91  case self::LSO_CMD_SUSPEND:
92  case self::LSO_CMD_FINISH:
93  $this->ls_items->storeState($state, $current_item_ref_id, $current_item_ref_id);
94  return 'EXIT::' . $command;
95  case self::LSO_CMD_NEXT:
96  $next_item = $this->getNextItem($items, $current_item, $param);
97  if ($next_item->getAvailability() !== Step::AVAILABLE) {
98  $next_item = $current_item;
99  }
100  break;
101  case self::LSO_CMD_GOTO:
102  list(, $next_item) = $this->findItemByRefId($items, $param);
103  break;
104  default: //view-internal / unknown command
105  $next_item = $current_item;
106  }
107  //write State to DB
108  $this->ls_items->storeState($state, $current_item_ref_id, $next_item->getRefId());
109 
110  //get proper view
111  if ($next_item != $current_item) {
112  $view = $this->view_factory->getViewFor($next_item);
113  $state = $this->ls_items->getStateFor($next_item, $view);
114  }
115 
116  //content
117  $obj_title = $next_item->getTitle();
118  $icon = $this->ui_factory->symbol()->icon()->standard(
119  $next_item->getType(),
120  $next_item->getType(),
121  'medium'
122  );
123 
124  $content = $this->renderComponentView($state, $view);
125 
126  $panel = $this->ui_factory->panel()->standard(
127  '',
128  $content
129  );
130  $content = [$panel];
131 
132  $items = $this->ls_items->getItems(); //reload items after renderComponentView content
133 
134  //get position
135  list($item_position, $item) = $this->findItemByRefId($items, $next_item->getRefId());
136 
137  //have the view build controls
138  $control_builder = $this->control_builder;
139  $view->buildControls($state, $control_builder);
140 
141  //amend controls not set by the view
142  $control_builder = $this->buildDefaultControls($control_builder, $item, $item_position, $items);
143 
144  $rendered_body = $this->page_renderer->render(
145  $control_builder,
146  $obj_title,
147  $icon,
148  $content
149  );
150 
151  $metabar_controls = [
152  'exit' => $control_builder->getExitControl()
153  ];
154 
155  $curriculum_slate = $this->page_renderer->buildCurriculumSlate(
156  $this->curriculum_builder
157  ->getLearnerCurriculum(true)
158  ->withActive($item_position)
159  );
160  $mainbar_controls = [
161  'curriculum' => $curriculum_slate
162  ];
163 
164  $toc = $control_builder->getToc();
165  if ($toc) {
166  $toc_slate = $this->page_renderer->buildToCSlate($toc, $icon);
167  $mainbar_controls['toc'] = $toc_slate;
168  }
169 
170  $cc = $this->current_context;
171  $cc->addAdditionalData(self::GS_DATA_LS_KIOSK_MODE, true);
172  $cc->addAdditionalData(self::GS_DATA_LS_METABARCONTROLS, $metabar_controls);
173  $cc->addAdditionalData(self::GS_DATA_LS_MAINBARCONTROLS, $mainbar_controls);
174  $cc->addAdditionalData(self::GS_DATA_LS_CONTENT, $rendered_body);
175 
176  return null;
177  }
178 
182  protected function getCurrentItem(array $items): LSLearnerItem
183  {
184  $current_item = $items[0];
185  $current_item_ref_id = $this->ls_items->getCurrentItemRefId();
186  if ($current_item_ref_id !== 0) {
187  $valid_ref_ids = array_map(
188  fn($item) => $item->getRefId(),
189  array_values($this->ls_items->getItems())
190  );
191  if (in_array($current_item_ref_id, $valid_ref_ids)) {
192  list(, $current_item) = $this->findItemByRefId($items, $current_item_ref_id);
193  }
194  }
195  return $current_item;
196  }
197 
198  protected function getNextAvailableItem(
199  array $items,
200  LSLearnerItem $current_item
201  ): ?LSLearnerItem {
202  if ($current_item->getAvailability() === Step::AVAILABLE) {
203  return $current_item;
204  }
205 
206  $new_next_item = null;
207  $idx = array_search($current_item, $items);
208 
209  for ($i = $idx - 1; $i >= 0; $i--) {
210  if ($items[$i]->getAvailability() === Step::AVAILABLE) {
211  $new_next_item = $items[$i];
212  continue;
213  }
214  }
215  if ($new_next_item === null) {
216  for ($i = $idx + 1; $i < count($items); $i++) {
217  if ($items[$i]->getAvailability() === Step::AVAILABLE) {
218  $new_next_item = $items[$i];
219  continue;
220  }
221  }
222  }
223  return $new_next_item;
224  }
225 
226  protected function updateViewState(
227  ILIAS\KioskMode\State $state,
228  ILIAS\KioskMode\View $view,
229  RequestWrapper $get
230  ): ILIAS\KioskMode\State {
231  if ($get->has(self::PARAM_LSO_COMMAND) && $get->has(self::PARAM_LSO_PARAMETER)) {
232  $command = $get->retrieve(self::PARAM_LSO_COMMAND, $this->refinery->kindlyTo()->string());
233  $param = $get->retrieve(self::PARAM_LSO_PARAMETER, $this->refinery->kindlyTo()->int());
234  $state = $view->updateGet($state, $command, $param);
235  }
236  return $state;
237  }
238 
242  protected function getNextItem(array $items, LSLearnerItem $current_item, int $direction): LSLearnerItem
243  {
244  list($position) = $this->findItemByRefId($items, $current_item->getRefId());
245  $next = $position + $direction;
246  if ($next >= 0 && $next < count($items)) {
247  return $items[$next];
248  }
249  return $current_item;
250  }
251 
255  protected function findItemByRefId(array $items, int $ref_id): array
256  {
257  foreach ($items as $index => $item) {
258  if ($item->getRefId() === $ref_id) {
259  return [$index, $item];
260  }
261  }
262  throw new \Exception("This is not a valid item.", 1);
263  }
264 
265  protected function buildDefaultControls(
266  LSControlBuilder $control_builder,
267  LSLearnerItem $item,
268  int $item_position,
269  array $items
270  ): ControlBuilder {
271  $is_first = $item_position === 0;
272  $is_last = $item_position === count($items) - 1;
273 
274  if (!$control_builder->getExitControl()) {
275  $cmd = self::LSO_CMD_SUSPEND;
276  if ($is_last) {
277  $cmd = self::LSO_CMD_FINISH;
278  }
279  $control_builder = $control_builder->exit($cmd);
280  }
281 
282  if (!$control_builder->getPreviousControl()) {
283  $direction_prev = -1;
284  $cmd = ''; //disables control
285 
286  if (!$is_first) {
287  $available = $this->getNextItem($items, $item, $direction_prev)
288  ->getAvailability() === Step::AVAILABLE;
289 
290  if ($available) {
291  $cmd = self::LSO_CMD_NEXT;
292  }
293  }
294 
295  $control_builder = $control_builder
296  ->previous($cmd, $direction_prev);
297  }
298 
299  if (!$control_builder->getNextControl()) {
300  $direction_next = 1;
301  $cmd = '';
302  if (!$is_last) {
303  $available = $this->getNextItem($items, $item, $direction_next)
304  ->getAvailability() === Step::AVAILABLE;
305 
306  if ($available) {
307  $cmd = self::LSO_CMD_NEXT;
308  }
309  }
310 
311  $control_builder = $control_builder
312  ->next($cmd, $direction_next);
313  }
314 
315  return $control_builder;
316  }
317 
318  protected function renderComponentView($state, ILIAS\KioskMode\View $view): Component
319  {
320  return $view->render(
321  $state,
322  $this->ui_factory,
323  $this->url_builder,
324  []
325  );
326  }
327 
329  {
330  $item = $this->getCurrentItem($this->ls_items->getItems());
331  return $item->getLearningProgressStatus();
332  }
333 }
buildDefaultControls(LSControlBuilder $control_builder, LSLearnerItem $item, int $item_position, array $items)
play(RequestWrapper $get)
const GS_DATA_LS_KIOSK_MODE
getCurrentItem(array $items)
Interface Observer Contains several chained tasks and infos about them.
getRefId()
Definition: LSItem.php:93
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const LSO_CMD_SUSPEND
renderComponentView($state, ILIAS\KioskMode\View $view)
findItemByRefId(array $items, int $ref_id)
const PARAM_LSO_PARAMETER
getNextItem(array $items, LSLearnerItem $current_item, int $direction)
$direction is either -1 or 1;
exit(string $command)
An exit control allows the user to gracefully leave the object providing the kiosk mode...
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
$ref_id
Definition: ltiauth.php:65
getNextAvailableItem(array $items, LSLearnerItem $current_item)
const LSO_CMD_FINISH
$param
Definition: xapitoken.php:46
Builds data types.
Definition: Factory.php:35
const GS_DATA_LS_MAINBARCONTROLS
next(string $command, ?int $parameter=null)
A next control allows the user to progress to the next item in the object.
previous(string $command, ?int $parameter=null)
A previous control allows the user to go back to the previous item in the object. ...
This combines calls to ProgressDB and StateDB to handle learner-items in the context of a specific LS...
updateViewState(ILIAS\KioskMode\State $state, ILIAS\KioskMode\View $view, RequestWrapper $get)
retrieve(string $key, Transformation $transformation)
Implementation of KioskMode Player.
const PARAM_LSO_COMMAND
Build controls for the view.
getCurrentItemLearningProgress()
const GS_DATA_LS_CONTENT
__construct(protected ilLSLearnerItemsQueries $ls_items, protected LSControlBuilder $control_builder, protected LSUrlBuilder $url_builder, protected ilLSCurriculumBuilder $curriculum_builder, protected ilLSViewFactory $view_factory, protected ilKioskPageRenderer $page_renderer, protected Factory $ui_factory, protected ScreenContext $current_context, protected Refinery\Factory $refinery)
Builds the overview (curriculum) of a LearningSequence.
const GS_DATA_LS_METABARCONTROLS
Add learning progress and availability information to the LSItem.