Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
StringProxy
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
6 / 6
9
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 safe
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 __call
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 __toString
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 escape
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 unwrap
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Celemas\Boiler\Proxy;
6
7use Celemas\Boiler\Contract\PreservesSafety;
8use Celemas\Boiler\Contract\Wrapper;
9use Override;
10
11/**
12 * @api
13 *
14 * @implements Proxy<string>
15 */
16final class StringProxy implements Proxy
17{
18    private ?string $escaped = null;
19    private bool $safe = false;
20
21    public function __construct(
22        private readonly string $value,
23        private readonly Wrapper $wrapper,
24    ) {}
25
26    public static function safe(string $value, Wrapper $wrapper): self
27    {
28        $proxy = new self($value, $wrapper);
29        $proxy->safe = true;
30
31        return $proxy;
32    }
33
34    /**
35     * Dispatch filters as virtual methods: $title->sanitize(), $title->stripTags('<b>'), etc.
36     *
37     * @param array<array-key, mixed> $args
38     */
39    public function __call(string $name, array $args): self
40    {
41        $filter = $this->wrapper->filter($name);
42        $filtered = $filter->apply($this->value, ...$args);
43        $proxy = new self($filtered, $this->wrapper);
44        $proxy->safe = $filter->safe() || $this->safe && $filter instanceof PreservesSafety;
45
46        return $proxy;
47    }
48
49    public function __toString(): string
50    {
51        if ($this->safe) {
52            return $this->value;
53        }
54
55        return $this->escaped ??= $this->wrapper->escape($this->value);
56    }
57
58    public function escape(?string $escaper = null): string
59    {
60        return $this->wrapper->escape($this->value, $escaper);
61    }
62
63    #[Override]
64    public function unwrap(): string
65    {
66        return $this->value;
67    }
68}