1<?php declare(strict_types=1); 2 3namespace ILIAS\GlobalScreen\Scope; 4 5use Closure; 6use ILIAS\UI\Component\Component; 7use LogicException; 8use ReflectionFunction; 9use ReflectionType; 10 11/** 12 * Trait ComponentDecoratorTrait 13 * 14 * @package ILIAS\GlobalScreen\Scope 15 * 16 * @author Fabian Schmid <fs@studer-raimann.ch> 17 */ 18trait ComponentDecoratorTrait 19{ 20 21 /** 22 * @var Closure 23 */ 24 private $component_decorator; 25 26 27 /** 28 * @param Closure $component_decorator 29 * 30 * @return isGlobalScreenItem 31 */ 32 public function addComponentDecorator(Closure $component_decorator) : isGlobalScreenItem 33 { 34 if (!$this->checkClosure($component_decorator)) { 35 throw new LogicException('first argument and return value of closure must be type-hinted to \ILIAS\UI\Component\Component'); 36 } 37 if ($this->component_decorator instanceof Closure) { 38 $existing = $this->component_decorator; 39 $this->component_decorator = static function (Component $c) use ($component_decorator, $existing) : Component { 40 $component = $existing(); 41 42 return $component_decorator($component); 43 }; 44 } else { 45 $this->component_decorator = $component_decorator; 46 } 47 48 return $this; 49 } 50 51 52 /** 53 * @return Closure|null 54 */ 55 public function getComponentDecorator() : ?Closure 56 { 57 return $this->component_decorator; 58 } 59 60 61 private function checkClosure(Closure $c) : bool 62 { 63 try { 64 $r = new ReflectionFunction($c); 65 if (count($r->getParameters()) !== 1) { 66 return false; 67 } 68 $first_param_type = $r->getParameters()[0]->getType(); 69 if ($first_param_type instanceof ReflectionType && $first_param_type->getName() !== Component::class) { 70 return false; 71 } 72 $return_type = $r->getReturnType(); 73 if ($return_type === null) { 74 return false; 75 } 76 if ($return_type->getName() !== Component::class) { 77 return false; 78 } 79 80 return true; 81 } catch (\Throwable $i) { 82 return false; 83 } 84 } 85} 86