DbRefArrayDecorator   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 7

Test Coverage

Coverage 87.04%

Importance

Changes 0
Metric Value
wmc 19
lcom 0
cbo 7
dl 0
loc 131
ccs 47
cts 54
cp 0.8704
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
D read() 0 97 14
A write() 0 28 5
1
<?php
2
3
/**
4
 * This software package is licensed under AGPL or Commercial license.
5
 *
6
 * @package maslosoft/mangan
7
 * @licence AGPL or Commercial
8
 * @copyright Copyright (c) Piotr Masełkowski <[email protected]>
9
 * @copyright Copyright (c) Maslosoft
10
 * @copyright Copyright (c) Others as mentioned in code
11
 * @link https://maslosoft.com/mangan/
12
 */
13
14
namespace Maslosoft\Mangan\Decorators;
15
16
use Maslosoft\Mangan\Helpers\DbRefManager;
17
use Maslosoft\Mangan\Helpers\PkManager;
18
use Maslosoft\Mangan\Helpers\RawFinder;
19
use Maslosoft\Mangan\Interfaces\Decorators\Property\DecoratorInterface;
20
use Maslosoft\Mangan\Interfaces\Transformators\TransformatorInterface;
21
use Maslosoft\Mangan\Meta\ManganMeta;
22
use Maslosoft\Mangan\Model\DbRef;
23
24
/**
25
 * DbRefArray
26
 *
27
 * @author Piotr Maselkowski <pmaselkowski at gmail.com>
28
 */
29
class DbRefArrayDecorator implements DecoratorInterface
30
{
31
32 5
	public function read($model, $name, &$dbValues, $transformatorClass = TransformatorInterface::class)
33
	{
34 5
		if (!$dbValues)
35
		{
36 2
			$fieldMeta = ManganMeta::create($model)->field($name);
37 2
			$model->$name = $fieldMeta->default;
38 2
			return;
39
		}
40
		/**
41
		 * NOTE: Documents must be sorted as $dbRefs,
42
		 * however mongo does not guarantee sorting by list of id's.
43
		 * This require sorting in php.
44
		 * If document has composite key this must be taken care too
45
		 * while comparision for sorting is made.
46
		 */
47 5
		$refs = [];
48 5
		$unsortedRefs = [];
49 5
		$pks = [];
50 5
		$sort = [];
51
52
		// Collect primary keys
53 5
		foreach ($dbValues as $key => $dbValue)
54
		{
55 5
			$dbValue['_class'] = DbRef::class;
56 5
			$dbRef = $transformatorClass::toModel($dbValue);
57
58 5
			DbRefDecorator::ensureClass($model, $name, $dbRef);
59
60
			// Collect keys separately for each type
61 5
			$pks[$dbRef->class][$key] = $dbRef->pk;
62 5
			$sort[$key] = $dbRef->pk;
63
		}
64
65
		// Fetch all types of db ref's en masse
66 5
		$i = 0;
67 5
		$unsortedPks = [];
68 5
		foreach ($pks as $referenced => $pkValues)
69
		{
70 5
			if (empty($referenced))
71
			{
72
				continue;
73
			}
74
			// Find all referenced documents
75 5
			$refModel = new $referenced;
76 5
			$found = (new RawFinder($refModel))->findAllByPk($pkValues);
77
78 5
			if (!$found)
79
			{
80
				continue;
81
			}
82 5
			foreach ($found as $document)
83
			{
84
				// Collect unsorted documents
85 5
				$unsortedRefs[$i] = $document;
86
87
				// Collect pk's
88 5
				$unsortedPks[$i] = PkManager::getFromArray($document, $refModel);
89 5
				$i++;
90
			}
91
		}
92
93
		// Find existing documents
94 5
		$existing = [];
95 5
		foreach ($model->$name as $key => $document)
96
		{
97
			foreach ($sort as $i => $pk)
98
			{
99
				if (PkManager::compare($pk, $document))
100
				{
101
					// Set existing document with key same as in sort
102
					$existing[$i] = $document;
103
				}
104
			}
105
		}
106
107
		// Sort as stored ref
108 5
		foreach ($sort as $key => $pk)
109
		{
110 5
			foreach ($unsortedRefs as $i => $document)
111
			{
112 5
				if (PkManager::compare($pk, $unsortedPks[$i]))
113
				{
114 5
					if (array_key_exists($key, $existing))
115
					{
116
						// Update existing instance
117
						$refs[$key] = $transformatorClass::toModel($document, $existing[$key], $existing[$key]);
118
					}
119
					else
120
					{
121
						// Create new instance
122 5
						$refs[$key] = $transformatorClass::toModel($document);
123
					}
124
				}
125
			}
126
		}
127 5
		$model->$name = $refs;
128 5
	}
129
130 5
	public function write($model, $name, &$dbValue, $transformatorClass = TransformatorInterface::class)
131
	{
132 5
		$fieldMeta = ManganMeta::create($model)->field($name);
133 5
		$dbValue[$name] = $fieldMeta->default;
134
135
		// Empty
136 5
		if (!$model->$name)
137
		{
138 2
			return;
139
		}
140
141
		// Bogus data
142 5
		if (!is_array($model->$name))
143
		{
144
			return;
145
		}
146
147
		// Store DbRefs and optionally referenced model
148 5
		foreach ($model->$name as $key => $referenced)
149
		{
150 5
			$dbRef = DbRefManager::extractRef($model, $name, $referenced);
151 5
			if ($fieldMeta->dbRef->updatable)
152
			{
153 5
				DbRefManager::save($referenced, $dbRef);
154
			}
155 5
			$dbValue[$name][$key] = $transformatorClass::fromModel($dbRef, false);
156
		}
157 5
	}
158
159
}
160