Completed
Push — master ( c8f19a...ddbfd2 )
by Peter
72:09 queued 69:12
created

Transformer::getMeta()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
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 135
	public static function fromModel(AnnotatedInterface $model, $fields = [])
42
	{
43 135
		$meta = static::getMeta($model);
44 135
		$calledClass = get_called_class();
45 135
		$decorator = new Decorator($model, $calledClass, $meta);
46 135
		$md = new ModelDecorator($model, $calledClass, $meta);
47 135
		$sanitizer = new Sanitizer($model, $calledClass, $meta);
48 135
		$filter = new Filter($model, $calledClass, $meta);
49 135
		$arr = [];
50 135
		foreach ($meta->fields() as $name => $fieldMeta)
51
		{
52 135
			if (!empty($fields) && !in_array($name, $fields))
53 135
			{
54 98
				continue;
55
			}
56 135
			if (!$filter->fromModel($model, $fieldMeta))
57 135
			{
58 42
				continue;
59
			}
60 135
			$model->$name = $sanitizer->write($name, $model->$name);
61 135
			$decorator->write($name, $arr);
62 135
			$model->$name = $sanitizer->read($name, $model->$name);
63 135
		}
64 135
		$md->write($arr);
65 135
		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 96
	public static function toModel($data, $className = null, AnnotatedInterface $instance = null)
78
	{
79 96
		$data = (array) $data;
80 96
		if (is_object($className))
81 96
		{
82 79
			$className = get_class($className);
83 79
		}
84 96
		if (!$className)
85 96
		{
86 42
			if (array_key_exists('_class', $data))
87 42
			{
88 40
				$className = $data['_class'];
89 40
			}
90
			else
91
			{
92 2
				if (null !== $instance)
93 2
				{
94 2
					$className = get_class($instance);
95 2
				}
96
				else
97
				{
98
					throw new TransformatorException('Could not determine document type');
99
				}
100
			}
101 42
		}
102
		if ($instance)
103 96
		{
104 8
			$model = $instance;
105 8
		}
106
		else
107
		{
108 92
			$model = new $className;
109
		}
110 96
		$meta = static::getMeta($model);
111 96
		$calledClass = get_called_class();
112 96
		$decorator = new Decorator($model, $calledClass, $meta);
113 96
		$md = new ModelDecorator($model, $calledClass, $meta);
114 96
		$sanitizer = new Sanitizer($model, $calledClass, $meta);
115 96
		$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 96
		$fieldsMeta = (array) $meta->fields();
121 96
		$pks = (array)PkManager::getPkKeys($model);
122 96
		foreach($pks as $key)
123
		{
124 96
			if(!array_key_exists($key, $fieldsMeta))
125 96
			{
126 17
				continue;
127
			}
128 95
			$pkMeta = $fieldsMeta[$key];
129 95
			unset($fieldsMeta[$key]);
130 95
			$fieldsMeta = array_merge([$key => $pkMeta], $fieldsMeta);
131 96
		}
132
133 96
		foreach ($fieldsMeta as $name => $fieldMeta)
134
		{
135
			/* @var $fieldMeta DocumentPropertyMeta */
136 96
			if (array_key_exists($name, $data))
137 96
			{
138
				// Value is available in passed data
139 96
				$value = $data[$name];
140 96
			}
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 5
			}
147
			else
148
			{
149
				// As a last resort set to default
150 19
				$value = $fieldMeta->default;
151
			}
152 96
			if (!$filter->toModel($model, $fieldMeta))
153 96
			{
154 27
				continue;
155
			}
156 96
			$decorator->read($name, $value);
157 96
			$model->$name = $sanitizer->read($name, $model->$name);
158 96
		}
159 96
		$md->read($data);
160
161 96
		return FinalizingManager::toModel(static::class, $model);
162
	}
163
164 151
	protected static function getMeta(AnnotatedInterface $model)
165
	{
166 151
		return ManganMeta::create($model);
167
	}
168
169
}
170