Completed
Push — master ( 5a1c08...4a9651 )
by Vladimir
30:46
created

JailedDocument   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 155
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 50%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 1
dl 0
loc 155
ccs 20
cts 40
cp 0.5
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A __call() 0 22 5
A __debugInfo() 0 30 5
A _coreInstanceOf() 0 4 2
A offsetExists() 0 4 1
A offsetGet() 0 4 1
A offsetSet() 0 4 1
A offsetUnset() 0 4 1
A getIterator() 0 4 1
A jsonSerialize() 0 4 1
1
<?php
2
3
/**
4
 * @copyright 2018 Vladimir Jimenez
5
 * @license   https://github.com/stakx-io/stakx/blob/master/LICENSE.md MIT
6
 */
7
8
namespace allejo\stakx\Document;
9
10
/**
11
 * A wrapper object to only allow certain functions on the white list to be called and will redirect "jailed" function
12
 * calls to their appropriate jailed calls. This is used in order to limit which functions a user can call from
13
 * templates to prevent unexpected behavior.
14
 */
15
class JailedDocument implements \ArrayAccess, \IteratorAggregate, \JsonSerializable
16
{
17
    /** @var string[] */
18
    private $whiteListFunctions;
19
20
    /** @var string[] */
21
    private $jailedFunctions;
22
23
    /** @var TemplateReadyDocument */
24
    private $object;
25
26
    /** @var array */
27
    private $debugInfo;
28
29
    /**
30
     * JailObject constructor.
31
     *
32
     * @param TemplateReadyDocument $object             the object that will be jailed
33
     * @param array                 $whiteListFunctions a list of function names that can be called
34
     * @param array                 $jailedFunctions    a list of functions that will be redirected to another function
35
     */
36 53
    public function __construct(TemplateReadyDocument &$object, array $whiteListFunctions, array $jailedFunctions = [])
37
    {
38 53
        $this->object = &$object;
39 53
        $this->whiteListFunctions = $whiteListFunctions;
40 53
        $this->jailedFunctions = $jailedFunctions;
41 53
        $this->debugInfo = [];
42 53
    }
43
44 11
    public function __call($name, $arguments)
45
    {
46
        // White listed functions will always be getter functions, so somehow get the name of a possible getter function
47
        // name.
48 11
        $lcName = lcfirst($name);
49 11
        $getFxnCall = ($lcName[0] === '_' || strpos($lcName, 'get') === 0) ? $lcName : sprintf('get%s', ucfirst($name));
50
51
        // Check if our function call is a jailed call, meaning the function should be mapped to special "jailed"
52
        // jailed version of the function call.
53 11
        if (array_key_exists($getFxnCall, $this->jailedFunctions))
54
        {
55 3
            return call_user_func_array([$this->object, $this->jailedFunctions[$getFxnCall]], $arguments);
56
        }
57
58
        // Otherwise, test to see if the function call is in our white list and call it
59 8
        if (in_array($getFxnCall, $this->whiteListFunctions))
60
        {
61 7
            return call_user_func_array([$this->object, $getFxnCall], $arguments);
62
        }
63
64 1
        throw new \BadMethodCallException();
65
    }
66
67
    public function __debugInfo()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
68
    {
69
        if (!empty($this->debugInfo))
70
        {
71
            return $this->debugInfo;
72
        }
73
74
        if ($this->object instanceof FrontMatterDocument)
75
        {
76
            $this->debugInfo = $this->object->getFrontMatter(true);
77
        }
78
79
        foreach ($this->whiteListFunctions as $function)
80
        {
81
            $value = preg_replace('/^(get|is)/', '', $function);
82
            $value = lcfirst($value);
83
84
            try
85
            {
86
                $this->debugInfo[$value] = call_user_func([$this, $function]);
87
            }
88
            catch (\BadMethodCallException $e)
89
            {
90
                // Just throw away this information because there's no point in listing an accessible value in this
91
                // object that doesn't actually exist.
92
            }
93
        }
94
95
        return $this->debugInfo;
96
    }
97
98
    /**
99
     * Check if the jailed object is an instance of a given class.
100
     *
101
     * @param string $class
102
     *
103
     * @return bool
104
     */
105
    public function _coreInstanceOf($class)
106
    {
107
        return ($this->object instanceof $class) || is_subclass_of($this->object, $class);
108
    }
109
110
    ///
111
    // ArrayAccess Implementation
112
    ///
113
114
    /**
115
     * {@inheritdoc}
116
     */
117 22
    public function offsetExists($offset)
118
    {
119 22
        return $this->object->offsetExists($offset);
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125 32
    public function offsetGet($offset)
126
    {
127 32
        return $this->object->offsetGet($offset);
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133
    public function offsetSet($offset, $value)
134
    {
135
        throw new \LogicException('A jailed document is read-only.');
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    public function offsetUnset($offset)
142
    {
143
        throw new \LogicException('A jailed document is read-only.');
144
    }
145
146
    ///
147
    // IteratorAggregate implementation
148
    ///
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 19
    public function getIterator()
154
    {
155 19
        return $this->object->getIterator();
156
    }
157
158
    ///
159
    // JsonSerializable implementation
160
    ///
161
162
    /**
163
     * {@inheritdoc}
164
     */
165
    public function jsonSerialize()
166
    {
167
        return $this->object->jsonSerialize();
168
    }
169
}
170