Completed
Push — master ( 5df787...e18a07 )
by Michael
02:59
created

Curty::renderValue()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.2
c 0
b 0
f 0
cc 4
eloc 6
nc 3
nop 1
1
<?php
2
3
namespace Schnittstabil\Curty;
4
5
use stdClass;
6
use Closure;
7
use Schnittstabil\Get\Get;
8
9
/**
10
 * Curty micro templating.
11
 */
12
class Curty
13
{
14
    private static $notFoundSymbol = null;
15
16
    /**
17
     * @var callable Callable to get values and object properties from contexts
18
     */
19
    protected $get;
20
21
    /**
22
     * Create a Curty template renderer.
23
     *
24
     * @param callable Callable to get values and object properties from contexts
25
     */
26
    public function __construct(callable $get = null)
27
    {
28
        $this->get = $get ?? [Get::class, 'value'];
29
    }
30
31
    /**
32
     * Render template until a fixed point is reached.
33
     *
34
     * @param string       $tpl     Curty template
35
     * @param object|array $context Variable mapping
36
     *
37
     * @return string
38
     */
39
    public function __invoke(string $tpl, $context) : string
40
    {
41
        do {
42
            $old = $tpl;
43
            $tpl = $this->render($tpl, $context);
44
        } while ($tpl !== $old);
45
46
        return $tpl;
47
    }
48
49
    /**
50
     * Render template.
51
     *
52
     * @param string       $tpl     Curty template
53
     * @param object|array $context Variable mapping
54
     *
55
     * @return string
56
     */
57
    public function render(string $tpl, $context) : string
58
    {
59
        if (!preg_match_all('/{{([^{]+?)}}/', $tpl, $matches)) {
60
            return $tpl;
61
        }
62
63
        foreach ($matches[1] as $key) {
64
            $replace = $this->getValue($key, $context);
65
            if ($replace !== static::getNotFoundSymbol()) {
66
                $tpl = str_replace('{{'.$key.'}}', $this->renderValue($replace), $tpl);
67
            }
68
        }
69
70
        return $tpl;
71
    }
72
73
    protected function getValue(string $key, $context)
74
    {
75
        $get = $this->get;
76
        $value = $get($key, $context, static::getNotFoundSymbol());
77
78
        if ($value instanceof Closure) {
79
            return $value($this);
80
        }
81
82
        return $value;
83
    }
84
85
    protected function renderValue($value) : string
86
    {
87
        if (is_bool($value)) {
88
            return var_export($value, true);
89
        }
90
91
        if (is_scalar($value) || method_exists($value, '__toString')) {
92
            return (string) $value;
93
        }
94
95
        return @json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION);
96
    }
97
98
    protected static function getNotFoundSymbol()
99
    {
100
        if (self::$notFoundSymbol === null) {
101
            self::$notFoundSymbol = new stdClass();
102
        }
103
104
        return self::$notFoundSymbol;
105
    }
106
}
107