1 | <?php |
||
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) |
|
168 | |||
169 | } |
||
170 |