| Total Complexity | 80 | 
| Total Lines | 503 | 
| Duplicated Lines | 0 % | 
| Changes | 1 | ||
| Bugs | 0 | Features | 0 | 
Complex classes like Context often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Context, and based on these observations, apply Extract Interface, too.
| 1 | <?php | ||
| 61 | class Context | ||
| 62 | { | ||
| 63 | /** | ||
| 64 | * The local scopes | ||
| 65 | * @var array<int, array<string, mixed>> | ||
| 66 | */ | ||
| 67 | protected array $assigns = []; | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Registers for non-variable state data | ||
| 71 | * @var array<string, mixed> | ||
| 72 | */ | ||
| 73 | protected array $registers = []; | ||
| 74 | |||
| 75 | /** | ||
| 76 | * Global scopes | ||
| 77 | * @var array<string, mixed> | ||
| 78 | */ | ||
| 79 | protected array $environments = []; | ||
| 80 | |||
| 81 | /** | ||
| 82 | * The filter collection instance | ||
| 83 | * @var FilterCollection | ||
| 84 | */ | ||
| 85 | protected FilterCollection $filters; | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Called "sometimes" while rendering. | ||
| 89 | * For example to abort the execution of a rendering. | ||
| 90 | * @var callable|null | ||
| 91 | */ | ||
| 92 | protected $tickCallback = null; | ||
| 93 | |||
| 94 | /** | ||
| 95 | * The parser instance | ||
| 96 | * @var Parser | ||
| 97 | */ | ||
| 98 | protected Parser $parser; | ||
| 99 | |||
| 100 | |||
| 101 | /** | ||
| 102 | * Create new instance | ||
| 103 | * @param array<string, mixed> $assigns | ||
| 104 | * @param array<string, mixed> $registers | ||
| 105 | */ | ||
| 106 | public function __construct(array $assigns = [], array $registers = []) | ||
| 107 |     { | ||
| 108 | $this->assigns = [$assigns]; | ||
| 109 | $this->registers = $registers; | ||
| 110 | $this->filters = new FilterCollection(); | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * Set the parser instance | ||
| 115 | * @param Parser $parser | ||
| 116 | * @return $this | ||
| 117 | */ | ||
| 118 | public function setParser(Parser $parser): self | ||
| 119 |     { | ||
| 120 | $this->parser = $parser; | ||
| 121 | |||
| 122 | return $this; | ||
| 123 | } | ||
| 124 | |||
| 125 | |||
| 126 | /** | ||
| 127 | * Set tick callback | ||
| 128 | * @param callable|null $tickCallback | ||
| 129 | * @return $this | ||
| 130 | */ | ||
| 131 | public function setTickCallback(?callable $tickCallback) | ||
| 132 |     { | ||
| 133 | $this->tickCallback = $tickCallback; | ||
| 134 | |||
| 135 | return $this; | ||
| 136 | } | ||
| 137 | |||
| 138 | /** | ||
| 139 | * Add filter | ||
| 140 | * @param class-string $filter | ||
|  | |||
| 141 | * @return $this | ||
| 142 | */ | ||
| 143 | public function addFilter(string $filter): self | ||
| 144 |     { | ||
| 145 | $this->filters->addFilter($filter); | ||
| 146 | |||
| 147 | return $this; | ||
| 148 | } | ||
| 149 | |||
| 150 | /** | ||
| 151 | * Invokes the filter with the given name | ||
| 152 | * @param string $name | ||
| 153 | * @param mixed $value | ||
| 154 | * @param array<int, mixed> $args | ||
| 155 | * @return mixed | ||
| 156 | */ | ||
| 157 | public function invokeFilter(string $name, $value, array $args = []) | ||
| 158 |     { | ||
| 159 |         try { | ||
| 160 | return $this->filters->invoke($name, $value, $args); | ||
| 161 |         } catch (TypeError $ex) { | ||
| 162 | throw new TemplateException($ex->getMessage(), 0, $ex); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | /** | ||
| 167 | * Merges the given assigns into the current assigns | ||
| 168 | * @param array<string, mixed> $assigns | ||
| 169 | * @return void | ||
| 170 | */ | ||
| 171 | public function merge(array $assigns): void | ||
| 172 |     { | ||
| 173 | $this->assigns[0] = array_merge($this->assigns[0], $assigns); | ||
| 174 | } | ||
| 175 | |||
| 176 | /** | ||
| 177 | * Push new local scope on the stack. | ||
| 178 | * @return bool | ||
| 179 | */ | ||
| 180 | public function push(): bool | ||
| 181 |     { | ||
| 182 | array_unshift($this->assigns, []); | ||
| 183 | |||
| 184 | return true; | ||
| 185 | } | ||
| 186 | |||
| 187 | public function pop(): bool | ||
| 188 |     { | ||
| 189 |         if (count($this->assigns) === 1) { | ||
| 190 |             throw new TemplateException('No elements to retrieve (pop) from context'); | ||
| 191 | } | ||
| 192 | array_shift($this->assigns); | ||
| 193 | |||
| 194 | return true; | ||
| 195 | } | ||
| 196 | |||
| 197 | /** | ||
| 198 | * Return the context value for the given key | ||
| 199 | * @param string $key | ||
| 200 | * @return mixed | ||
| 201 | */ | ||
| 202 | public function get(string $key) | ||
| 203 |     { | ||
| 204 | return $this->resolve($key); | ||
| 205 | } | ||
| 206 | |||
| 207 | /** | ||
| 208 | * Set the value for the given key | ||
| 209 | * @param string $key | ||
| 210 | * @param mixed $value | ||
| 211 | * @param bool $global | ||
| 212 | * @return void | ||
| 213 | */ | ||
| 214 | public function set(string $key, $value, bool $global = false): void | ||
| 215 |     { | ||
| 216 |         if ($global) { | ||
| 217 | $count = count($this->assigns); | ||
| 218 |             for ($i = 0; $i < $count; $i++) { | ||
| 219 | $this->assigns[$i][$key] = $value; | ||
| 220 | } | ||
| 221 |         } else { | ||
| 222 | $this->assigns[0][$key] = $value; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | /** | ||
| 227 | * Returns true if the given key will properly resolve | ||
| 228 | * @param string $key | ||
| 229 | * @return bool | ||
| 230 | */ | ||
| 231 | public function hasKey(string $key): bool | ||
| 232 |     { | ||
| 233 | return $this->resolve($key) !== null; | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 237 | * Check whether the given register exists | ||
| 238 | * @param string $name | ||
| 239 | * @return bool | ||
| 240 | */ | ||
| 241 | public function hasRegister(string $name): bool | ||
| 242 |     { | ||
| 243 | return isset($this->registers[$name]); | ||
| 244 | } | ||
| 245 | |||
| 246 | /** | ||
| 247 | * Clear the given register | ||
| 248 | * @param string $name | ||
| 249 | * @return $this | ||
| 250 | */ | ||
| 251 | public function clearRegister(string $name): self | ||
| 252 |     { | ||
| 253 | unset($this->registers[$name]); | ||
| 254 | |||
| 255 | return $this; | ||
| 256 | } | ||
| 257 | |||
| 258 | /** | ||
| 259 | * Return the value for the given register | ||
| 260 | * @param string $name | ||
| 261 | * @return mixed|null | ||
| 262 | */ | ||
| 263 | public function getRegister(string $name) | ||
| 264 |     { | ||
| 265 |         if ($this->hasRegister($name)) { | ||
| 266 | return $this->registers[$name]; | ||
| 267 | } | ||
| 268 | |||
| 269 | return null; | ||
| 270 | } | ||
| 271 | |||
| 272 | /** | ||
| 273 | * Set the register value | ||
| 274 | * @param string $name | ||
| 275 | * @param mixed $value | ||
| 276 | * @return $this | ||
| 277 | */ | ||
| 278 | public function setRegister(string $name, $value): self | ||
| 279 |     { | ||
| 280 | $this->registers[$name] = $value; | ||
| 281 | |||
| 282 | return $this; | ||
| 283 | } | ||
| 284 | |||
| 285 | /** | ||
| 286 | * Check whether the given environment exists | ||
| 287 | * @param string $name | ||
| 288 | * @return bool | ||
| 289 | */ | ||
| 290 | public function hasEnvironment(string $name): bool | ||
| 291 |     { | ||
| 292 | return isset($this->environments[$name]); | ||
| 293 | } | ||
| 294 | |||
| 295 | /** | ||
| 296 | * Return the value for the given environment | ||
| 297 | * @param string $name | ||
| 298 | * @return mixed|null | ||
| 299 | */ | ||
| 300 | public function getEnvironment(string $name) | ||
| 301 |     { | ||
| 302 |         if ($this->hasEnvironment($name)) { | ||
| 303 | return $this->environments[$name]; | ||
| 304 | } | ||
| 305 | |||
| 306 | return null; | ||
| 307 | } | ||
| 308 | |||
| 309 | /** | ||
| 310 | * Set the environment value | ||
| 311 | * @param string $name | ||
| 312 | * @param mixed $value | ||
| 313 | * @return $this | ||
| 314 | */ | ||
| 315 | public function setEnvironment(string $name, $value): self | ||
| 316 |     { | ||
| 317 | $this->environments[$name] = $value; | ||
| 318 | |||
| 319 | return $this; | ||
| 320 | } | ||
| 321 | |||
| 322 | /** | ||
| 323 | * Call the tick callback | ||
| 324 | * @return void | ||
| 325 | */ | ||
| 326 | public function tick(): void | ||
| 333 | } | ||
| 334 | |||
| 335 | /** | ||
| 336 | * Resolve a key by either returning the appropriate literal | ||
| 337 | * or by looking up the appropriate variable | ||
| 338 | * @param string $key | ||
| 339 | * @return mixed|null | ||
| 340 | */ | ||
| 341 | protected function resolve(string $key) | ||
| 373 | } | ||
| 374 | |||
| 375 | /** | ||
| 376 | * Fetches the current key in all the scopes | ||
| 377 | * @param string $key | ||
| 378 | * @return mixed|null | ||
| 379 | */ | ||
| 380 | protected function fetch(string $key) | ||
| 381 |     { | ||
| 382 |         if (array_key_exists($key, $this->environments)) { | ||
| 399 | } | ||
| 400 | |||
| 401 | /** | ||
| 402 | * Resolved the name spaced queries gracefully. | ||
| 403 | * @param string $key | ||
| 404 | * @return mixed|null | ||
| 405 | */ | ||
| 406 | protected function variable(string $key) | ||
| 564 | } | ||
| 565 | } | ||
| 566 | } | ||
| 567 |