Completed
Push — master ( 427d35...72a5e8 )
by Peter
06:31
created

Transformer::toModel()   F

Complexity

Conditions 12
Paths 254

Size

Total Lines 86
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 12.0024

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 86
ccs 38
cts 39
cp 0.9744
rs 3.7956
cc 12
eloc 43
nc 254
nop 3
crap 12.0024

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Transformers;
15
16
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
17
use Maslosoft\Mangan\Exceptions\TransformatorException;
18
use Maslosoft\Mangan\Helpers\Decorator\Decorator;
19
use Maslosoft\Mangan\Helpers\Decorator\ModelDecorator;
20
use Maslosoft\Mangan\Helpers\Finalizer\FinalizingManager;
21
use Maslosoft\Mangan\Helpers\PkManager;
22
use Maslosoft\Mangan\Helpers\PropertyFilter\Filter;
23
use Maslosoft\Mangan\Helpers\Sanitizer\Sanitizer;
24
use Maslosoft\Mangan\Meta\DocumentPropertyMeta;
25
use Maslosoft\Mangan\Meta\ManganMeta;
26
27
/**
28
 * Transformer
29
 *
30
 * @author Piotr Maselkowski <pmaselkowski at gmail.com>
31
 */
32
abstract class Transformer
33
{
34
35
	/**
36
	 * Returns the given object as an associative array
37
	 * @param AnnotatedInterface|object $model
38
	 * @param string[] $fields Fields to transform
39
	 * @return array an associative array of the contents of this object
40
	 */
41 121
	public static function fromModel(AnnotatedInterface $model, $fields = [])
42
	{
43 121
		$meta = static::getMeta($model);
44 121
		$calledClass = get_called_class();
45 121
		$decorator = new Decorator($model, $calledClass, $meta);
46 121
		$md = new ModelDecorator($model, $calledClass, $meta);
47 121
		$sanitizer = new Sanitizer($model, $calledClass, $meta);
48 121
		$filter = new Filter($model, $calledClass, $meta);
49 121
		$arr = [];
50 121
		foreach ($meta->fields() as $name => $fieldMeta)
51
		{
52 121
			if (!empty($fields) && !in_array($name, $fields))
53
			{
54 82
				continue;
55
			}
56 121
			if (!$filter->fromModel($model, $fieldMeta))
57
			{
58 39
				continue;
59
			}
60 121
			$model->$name = $sanitizer->write($name, $model->$name);
61 121
			$decorator->write($name, $arr);
62 121
			$model->$name = $sanitizer->read($name, $model->$name);
63
		}
64 121
		$md->write($arr);
65 121
		return FinalizingManager::fromModel($arr, static::class, $model);
66
	}
67
68
	/**
69
	 * Create document from array
70
	 *
71
	 * @param mixed[] $data
72
	 * @param string|object $className
73
	 * @param AnnotatedInterface $instance
74
	 * @return AnnotatedInterface
75
	 * @throws TransformatorException
76
	 */
77 94
	public static function toModel($data, $className = null, AnnotatedInterface $instance = null)
78
	{
79 94
		$data = (array) $data;
80 94
		if (is_object($className))
81
		{
82 75
			$className = get_class($className);
83
		}
84 94
		if (!$className)
85
		{
86 44
			if (array_key_exists('_class', $data))
87
			{
88 42
				$className = $data['_class'];
89
			}
90
			else
91
			{
92 2
				if (null !== $instance)
93
				{
94 2
					$className = get_class($instance);
95
				}
96
				else
97
				{
98
					throw new TransformatorException('Could not determine document type');
99
				}
100
			}
101
		}
102 94
		if ($instance)
103
		{
104 8
			$model = $instance;
105
		}
106
		else
107
		{
108 90
			$model = new $className;
109
		}
110 94
		$meta = static::getMeta($model);
111 94
		$calledClass = get_called_class();
112 94
		$decorator = new Decorator($model, $calledClass, $meta);
113 94
		$md = new ModelDecorator($model, $calledClass, $meta);
114 94
		$sanitizer = new Sanitizer($model, $calledClass, $meta);
115 94
		$filter = new Filter($model, $calledClass, $meta);
116
117
		// Ensure that primary keys are processed first,
118
		// as in some cases those could be processed *after* related
119
		// document(s), which results in wrong _id (or pk) being passed.
120 94
		$fieldsMeta = (array) $meta->fields();
121 94
		$pks = (array)PkManager::getPkKeys($model);
122 94
		foreach($pks as $key)
123
		{
124 94
			if(!array_key_exists($key, $fieldsMeta))
125
			{
126 18
				continue;
127
			}
128 93
			$pkMeta = $fieldsMeta[$key];
129 93
			unset($fieldsMeta[$key]);
130 93
			$fieldsMeta = array_merge([$key => $pkMeta], $fieldsMeta);
131
		}
132
133 94
		foreach ($fieldsMeta as $name => $fieldMeta)
134
		{
135
			/* @var $fieldMeta DocumentPropertyMeta */
136 94
			if (array_key_exists($name, $data))
137
			{
138
				// Value is available in passed data
139 94
				$value = $data[$name];
140
			}
141 23
			elseif (!empty($instance))
142
			{
143
				// Take value from existing instance
144
				// NOTE: We could `continue` here but value should be sanitized anyway
145 5
				$value = $model->$name;
146
			}
147
			else
148
			{
149
				// As a last resort set to default
150 19
				$value = $fieldMeta->default;
151
			}
152 94
			if (!$filter->toModel($model, $fieldMeta))
153
			{
154 26
				continue;
155
			}
156 94
			$decorator->read($name, $value);
157 94
			$model->$name = $sanitizer->read($name, $model->$name);
158
		}
159 94
		$md->read($data);
160
161 94
		return FinalizingManager::toModel(static::class, $model);
162
	}
163
164 137
	protected static function getMeta(AnnotatedInterface $model)
165
	{
166 137
		return ManganMeta::create($model);
167
	}
168
169
}
170