1: <?php
2:
3: namespace PHPixie\ORM\Data\Types\Document;
4:
5: class Diffable extends \PHPixie\ORM\Data\Types\Document implements \PHPixie\ORM\Data\Type\Diffable
6: {
7: protected $dataBuilder;
8: protected $originalData;
9:
10: public function __construct($dataBuilder, $document)
11: {
12: $this->dataBuilder = $dataBuilder;
13: parent::__construct($document);
14: $this->setCurrentAsOriginal();
15: }
16:
17: public function originalData()
18: {
19: return $this->originalData;
20: }
21:
22: public function setCurrentAsOriginal()
23: {
24: $this->originalData = $this->data();
25: }
26:
27: public function diff()
28: {
29: if (($originalData = $this->originalData) === null)
30: $originalData = new \stdClass;
31:
32: list($set, $unset) = $this->objectDiff($this->data(), $this->originalData);
33: return $this->dataBuilder->removingDiff((object) $set, $unset);
34: }
35:
36: protected function objectDiff($new, $old)
37: {
38: $newData = get_object_vars($new);
39: $oldData = get_object_vars($old);
40: $unset = array_values(array_diff(array_keys($oldData), array_keys($newData)));
41:
42: $set = array();
43: foreach ($newData as $key => $value) {
44: if (!array_key_exists($key, $oldData)) {
45: $set[$key] = $value;
46: continue;
47: }
48:
49: $oldValue = $oldData[$key];
50:
51: if (is_object($value) && is_object($oldValue)) {
52: $prefix = $key.'.';
53:
54: list($subSet, $subUnset) = $this->objectDiff($value, $oldValue);
55: foreach ($subSet as $subKey => $subValue) {
56: $set[$prefix.$subKey] = $subValue;
57: }
58:
59: foreach ($subUnset as $subValue) {
60: $unset[] = $prefix.$subValue;
61: }
62: continue;
63: }
64:
65: if (!$this->isEqual($value, $oldValue))
66: $set[$key] = $value;
67: }
68:
69: return array($set, $unset);
70: }
71:
72: protected function isArrayEqual($new, $old)
73: {
74: if(array_keys($new) !== array_keys($old))
75:
76: return false;
77:
78: foreach($new as $key => $value)
79: if(!$this->isEqual($value, $old[$key]))
80:
81: return false;
82:
83: return true;
84: }
85:
86: protected function isObjectEqual($new, $old)
87: {
88: $newData = get_object_vars($new);
89: $oldData = get_object_vars($old);
90:
91: return $this->isArrayEqual($newData, $oldData);
92: }
93:
94: protected function isEqual($new, $old)
95: {
96: $type = gettype($new);
97:
98: if($type !== gettype($old))
99:
100: return false;
101:
102: if($type === 'array')
103:
104: return $this->isArrayEqual($new, $old);
105:
106: if ($type === 'object')
107: return $this->isObjectEqual($new, $old);
108:
109: return $new === $old;
110: }
111: }