AbstractSnapshot   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 12
Bugs 2 Features 1
Metric Value
wmc 22
c 12
b 2
f 1
lcom 1
cbo 3
dl 0
loc 168
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
A setSetClass() 0 10 3
A diff() 0 11 2
A getRawData() 0 4 1
A getComparableData() 0 8 2
A getDataKeys() 0 4 1
A __clone() 0 3 1
A offsetExists() 0 4 1
A offsetGet() 0 4 1
A offsetSet() 0 4 1
A offsetUnset() 0 4 1
A isComparable() 0 8 2
B normalize() 0 27 6
1
<?php
2
/**
3
 * This file is part of the Totem package
4
 *
5
 * For the full copyright and license information, please view the LICENSE file
6
 * that was distributed with this source code.
7
 *
8
 * @copyright Baptiste Clavié <[email protected]>
9
 * @license   http://www.opensource.org/licenses/MIT-License MIT License
10
 */
11
12
namespace Totem;
13
14
use ArrayAccess;
15
use ReflectionClass;
16
17
use BadMethodCallException;
18
use InvalidArgumentException;
19
20
use Totem\Exception\IncomparableDataException;
21
22
/**
23
 * Base class for a Snapshot
24
 *
25
 * Represent the data fixed at a given time
26
 *
27
 * @author Baptiste Clavié <[email protected]>
28
 */
29
abstract class AbstractSnapshot implements ArrayAccess
30
{
31
    /** @var array data stored in an array */
32
    protected $data = [];
33
34
    /** @var mixed raw data stored */
35
    protected $raw;
36
37
    /** @var string Set class to use */
38
    private $setClass = 'Totem\\Set';
39
40
    public function setSetClass($class)
41
    {
42
        $reflection = new ReflectionClass($class);
43
44
        if (!$reflection->isInstantiable() || !$reflection->implementsInterface('Totem\\SetInterface')) {
45
            throw new InvalidArgumentException('A Set Class should be instantiable and implement Totem\\SetInterface');
46
        }
47
48
        $this->setClass = $class;
49
    }
50
51
    /**
52
     * Calculate the diff between two snapshots
53
     *
54
     * @param AbstractSnapshot $snapshot Snapshot to compare this one to
55
     *
56
     * @return Set Changeset between the two snapshots
57
     * @throws IncomparableDataException If the two snapshots are not comparable
58
     */
59
    public function diff(AbstractSnapshot $snapshot)
60
    {
61
        if (!$this->isComparable($snapshot)) {
62
            throw new IncomparableDataException;
63
        }
64
65
        $set = new $this->setClass;
66
        $set->compute($this, $snapshot);
67
68
        return $set;
69
    }
70
71
    /**
72
     * Get the raw data fed to this snapshot
73
     *
74
     * @return mixed
75
     */
76
    final public function getRawData()
77
    {
78
        return $this->raw;
79
    }
80
81
    /**
82
     * Get the computed data, transformed into an array by this constructor
83
     *
84
     * @return SnapshotInterface[]
85
     * @throws InvalidArgumentException If the data is not an array
86
     */
87
    final public function getComparableData()
88
    {
89
        if (!is_array($this->data)) {
90
            throw new InvalidArgumentException('The computed data is not an array, "' . gettype($this->data) . '" given');
91
        }
92
93
        return $this->data;
94
    }
95
96
    /**
97
     * Returns the keys of the data
98
     *
99
     * @return array
100
     * @throws InvalidArgumentException If the frozen data is not an array
101
     */
102
    final public function getDataKeys()
103
    {
104
        return array_keys($this->getComparableData());
105
    }
106
107
    /**
108
     * Clone this object
109
     *
110
     * @codeCoverageIgnore
111
     */
112
    final private function __clone()
113
    {
114
    }
115
116
    /** {@inheritDoc} */
117
    final public function offsetExists($offset)
118
    {
119
        return in_array($offset, $this->getDataKeys());
120
    }
121
122
    /** {@inheritDoc} */
123
    final public function offsetGet($offset)
124
    {
125
        return $this->getComparableData()[$offset];
126
    }
127
128
    /**
129
     * {@inheritDoc}
130
     *
131
     * @throws BadMethodCallException if a unset is tried on a snapshot property
132
     */
133
    final public function offsetSet($offset, $value)
134
    {
135
        throw new BadMethodCallException('A snapshot is frozen by nature');
136
    }
137
138
    /**
139
     * {@inheritDoc}
140
     *
141
     * @throws BadMethodCallException if a unset is tried on a snapshot property
142
     */
143
    final public function offsetUnset($offset)
144
    {
145
        throw new BadMethodCallException('A snapshot is frozen by nature');
146
    }
147
148
    /**
149
     * Check if the two snapshots are comparable
150
     *
151
     * @param AbstractSnapshot $snapshot Snapshot to be compared with
152
     *
153
     * @return boolean true if the two snapshots can be processed in a diff, false otherwise
154
     */
155
    public function isComparable(AbstractSnapshot $snapshot)
156
    {
157
        if (!$snapshot instanceof static) {
158
            return false;
159
        }
160
161
        return gettype($snapshot->raw) === gettype($this->raw);
162
    }
163
164
    /**
165
     * Finish data initialization
166
     *
167
     * To be called by child classes *after* the data has been initialized
168
     */
169
    protected function normalize()
170
    {
171
        if (!is_array($this->data)) {
172
            throw new InvalidArgumentException('The computed data is not an array, "' . gettype($this->data) . '" given');
173
        }
174
175
        foreach ($this->data as &$value) {
176
            // If the value is already an instance of a snapshot, we do not need to check if we have to snapshot it
177
            if ($value instanceof self) {
178
                continue;
179
            }
180
181
            switch (gettype($value)) {
182
                case 'object':
183
                    $value = new Snapshot\ObjectSnapshot($value);
184
                    $value->setClass = $this->setClass;
185
186
                    break;
187
188
                case 'array':
189
                    $value = new Snapshot\ArraySnapshot($value);
190
                    $value->setClass = $this->setClass;
191
192
                    break;
193
            }
194
        }
195
    }
196
}
197
198