Completed
Push — master ( 89bfcf...4ab803 )
by Vladimir
02:41
created

JailedDocument   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 114
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 75.86%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 0
dl 0
loc 114
ccs 22
cts 29
cp 0.7586
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
B __call() 0 22 5
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 __construct() 0 13 4
A coreInstanceOf() 0 4 1
1
<?php
2
3
/**
4
 * @copyright 2017 Vladimir Jimenez
5
 * @license   https://github.com/allejo/stakx/blob/master/LICENSE.md MIT
6
 */
7
8
namespace allejo\stakx\Document;
9
10
/**
11
 * Class JailObject.
12
 *
13
 * A wrapper object to only allow certain functions on the white list to be called. This is used in order to limit which
14
 * functions a user can call from Twig templates to prevent unexpected behavior.
15
 */
16
class JailedDocument implements \ArrayAccess, \IteratorAggregate
17
{
18
    /**
19
     * @var string[]
20
     */
21
    private $whiteListFunctions;
22
23
    /**
24
     * @var string[]
25
     */
26
    private $jailedFunctions;
27
28
    /**
29
     * @var JailableDocument
30
     */
31
    private $object;
32
33
    /**
34
     * JailObject constructor.
35
     *
36
     * @param JailableDocument $object             The object that will be jailed
37
     * @param array            $whiteListFunctions A list of function names that can be called
38
     * @param array            $jailedFunctions
39
     */
40 55
    public function __construct(&$object, array $whiteListFunctions, array $jailedFunctions = array())
41
    {
42 55
        if (!($object instanceof JailableDocument) &&
43 55
            !($object instanceof \ArrayAccess) &&
44 55
            !($object instanceof \IteratorAggregate))
45
        {
46
            throw new \InvalidArgumentException('Must implement the ArrayAccess and Jailable interfaces');
47
        }
48
49 55
        $this->object = &$object;
50 55
        $this->whiteListFunctions = $whiteListFunctions;
51 55
        $this->jailedFunctions = $jailedFunctions;
52 55
    }
53
54 11
    public function __call($name, $arguments)
55
    {
56
        // White listed functions will always be getter functions, so somehow get the name of a possible getter function
57
        // name.
58 11
        $lcName = lcfirst($name);
59 11
        $getFxnCall = ($lcName[0] === 'g' && strpos($lcName, 'get') === 0) ? $lcName : sprintf('get%s', ucfirst($name));
60
61
        // Check if our function call is a jailed call, meaning the function should be mapped to special "jailed"
62
        // jailed version of the function call.
63 11
        if (array_key_exists($getFxnCall, $this->jailedFunctions))
64
        {
65 4
            return call_user_func_array(array($this->object, $this->jailedFunctions[$getFxnCall]), $arguments);
66
        }
67
68
        // Otherwise, test to see if the function call is in our white list and call it
69 8
        if (in_array($getFxnCall, $this->whiteListFunctions))
70
        {
71 7
            return call_user_func_array(array($this->object, $getFxnCall), $arguments);
72
        }
73
74 1
        throw new \BadMethodCallException();
75
    }
76
77
    public function coreInstanceOf($class)
78
    {
79
        return is_subclass_of($this->object, $class);
80
    }
81
82
    //
83
    // ArrayAccess Implementation
84
    //
85
86
    /**
87
     * {@inheritdoc}
88
     */
89 22
    public function offsetExists($offset)
90
    {
91 22
        return $this->object->offsetExists($offset);
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97 32
    public function offsetGet($offset)
98
    {
99 32
        return $this->object->offsetGet($offset);
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105
    public function offsetSet($offset, $value)
106
    {
107
        return $this->object->offsetSet($offset, $value);
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113
    public function offsetUnset($offset)
114
    {
115
        return $this->object->offsetUnset($offset);
116
    }
117
118
    //
119
    // IteratorAggregate implementation
120
    //
121
122
    /**
123
     * {@inheritdoc}
124
     */
125 19
    public function getIterator()
126
    {
127 19
        return $this->object->getIterator();
128
    }
129
}
130