summaryrefslogtreecommitdiff
path: root/lib/SkinContext.php
blob: 69a6f91519496aaea73dcee42c1647ac0030627b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<?php

class SkinContext {

    protected string $ns;
    protected array $data = [];
    protected static ?string $root = null;

    public static function setRootDirectory(string $root): void {
        self::$root = $root;
    }

    public function __construct(string $namespace) {
        $this->ns = $namespace;
        require_once self::$root.'/'.str_replace('\\', '/', $namespace).'.skin.php';
    }

    public function __call($name, array $arguments) {
        $plain_args = array_is_list($arguments);

        $fn = '\\skin\\'.$this->ns.'\\'.$name;
        $refl = new ReflectionFunction($fn);
        $fparams = $refl->getParameters();
        assert(count($fparams) == count($arguments)+1, "$fn: invalid number of arguments (".count($fparams)." != ".(count($arguments)+1).")");

        foreach ($fparams as $n => $param) {
            if ($n == 0)
                continue; // skip $ctx

            $key = $plain_args ? $n-1 : $param->name;
            if (!$plain_args && !array_key_exists($param->name, $arguments)) {
                if (!$param->isDefaultValueAvailable())
                    throw new InvalidArgumentException('argument '.$param->name.' not found');
                else
                    continue;
            }

            if (is_string($arguments[$key]) || $arguments[$key] instanceof SkinString) {
                if (is_string($arguments[$key]))
                    $arguments[$key] = new SkinString($arguments[$key]);

                if (($pos = strpos($param->name, '_')) !== false) {
                    $mod_type = match(substr($param->name, 0, $pos)) {
                        'unsafe' => SkinStringModificationType::RAW,
                        'urlencoded' => SkinStringModificationType::URL,
                        default => SkinStringModificationType::HTML
                    };
                } else {
                    $mod_type = SkinStringModificationType::HTML;
                }
                $arguments[$key]->setModType($mod_type);
            }
        }

        array_unshift($arguments, $this);
        return call_user_func_array($fn, $arguments);
    }

    public function __get(string $name) {
        $fn = '\\skin\\'.$this->ns.'\\'.$name;
        if (function_exists($fn))
            return [$this, $name];

        if (array_key_exists($name, $this->data))
            return $this->data[$name];
    }

    public function __set(string $name, $value) {
        $this->data[$name] = $value;
    }

    public function if_not($cond, $callback, ...$args) {
        return $this->_if_condition(!$cond, $callback, ...$args);
    }

    public function if_true($cond, $callback, ...$args) {
        return $this->_if_condition($cond, $callback, ...$args);
    }

    public function if_then_else($cond, $cb1, $cb2) {
        return $cond ? $this->_return_callback($cb1) : $this->_return_callback($cb2);
    }

    protected function _if_condition($condition, $callback, ...$args) {
        if ($condition)
            return $this->_return_callback($callback, $args);
        return '';
    }

    protected function _return_callback($callback, $args = []) {
        if (is_callable($callback))
            return call_user_func_array($callback, $args);
        else if (is_string($callback))
            return $callback;
    }

    public function for_each(array $iterable, callable $callback) {
        $html = '';
        foreach ($iterable as $k => $v)
            $html .= call_user_func($callback, $v, $k);
        return $html;
    }

}