ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
AbstractLayoutModification.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
23use Closure;
24use LogicException;
25use ReflectionFunction;
26use ReflectionException;
27
33{
34 private int $priority;
35 private ?Closure $modification = null;
36
37 public function isFinal(): bool
38 {
39 return false;
40 }
41
45 public function getPriority(): int
46 {
47 return $this->priority ?? LayoutModification::PRIORITY_LOW;
48 }
49
53 final public function withPriority(int $priority): LayoutModification
54 {
55 if ((self::PRIORITY_LOW > $priority) || ($priority > self::PRIORITY_HIGH)) {
56 throw new LogicException("\$priority MUST be between LayoutModification::PRIORITY_LOW, LayoutModification::PRIORITY_MEDIUM or LayoutModification::PRIORITY_HIGH");
57 }
58 $clone = clone $this;
59 $clone->priority = $priority;
60
61 return $clone;
62 }
63
67 final public function withHighPriority(): LayoutModification
68 {
69 $clone = clone $this;
70 $clone->priority = LayoutModification::PRIORITY_HIGH;
71
72 return $clone;
73 }
74
78 final public function withLowPriority(): LayoutModification
79 {
80 $clone = clone $this;
81 $clone->priority = LayoutModification::PRIORITY_LOW;
82
83 return $clone;
84 }
85
90 final public function withModification(Closure $closure): LayoutModification
91 {
92 $clone = clone $this;
93 $clone->modification = $closure;
94
95 return $clone;
96 }
97
101 final public function getModification(): Closure
102 {
103 return $this->modification;
104 }
105
109 final public function hasValidModification(): bool
110 {
111 try {
112 return $this->checkClosure();
113 } catch (\Throwable $e) {
114 if (defined('DEVMODE') && (bool) DEVMODE) {
115 throw $e;
116 }
117 return false;
118 }
119 }
120
124 private function checkClosure(): bool
125 {
126 $closure = $this->modification;
127 if (!$closure instanceof Closure) {
128 return false;
129 //throw new InvalidModification($this, "Modification is not a Closure");
130 }
131
132 try {
133 $r = new ReflectionFunction($closure);
134
135 $requested_return_type = $this->getClosureReturnType();
136 $requested_first_argument_type = $this->getClosureFirstArgumentType();
137
138 // First Argument
139 $param = $r->getParameters()[0] ?? null;
140 // No first argument
141 if ($param === null) {
142 throw new InvalidModification($this, "Modification has no first parameter");
143 }
144 // First argument has no type
145 if (!$param->hasType()) {
146 throw new InvalidModification($this, "Modification's first parameter has no type");
147 }
148 // First argument has wrong type
149 if ($param->getType()->getName() !== $requested_first_argument_type) {
150 throw new InvalidModification($this, "Modification's first parameter does not match the requested type");
151 }
152 // First argument nullable
153 if ($this->firstArgumentAllowsNull() && !$param->allowsNull()) {
154 throw new InvalidModification($this, "Modification's first parameter must be nullable");
155 }
156
157 // Return type
158
159 // Return type not available
160 if (!$r->hasReturnType()) {
161 throw new InvalidModification($this, "Modification has no return type");
162 }
163 // return type check
164 if ($r->getReturnType()->getName() !== $requested_return_type) {
165 throw new InvalidModification($this, "Modification's return type does not match the requested type");
166 }
167
168 // Return type nullable
169 if ($this->returnTypeAllowsNull() && !$r->getReturnType()->allowsNull()) {
170 throw new InvalidModification($this, "Modification's return type must be nullable");
171 }
172 } catch (ReflectionException) {
173 throw new InvalidModification($this, "Modification threw an exception while checking the closure");
174 }
175
176 return true;
177 }
178}
$param
Definition: xapitoken.php:46