Passed
Pull Request — dev (#118)
by Marcin
02:36
created
src/Converter.php 1 patch
Indentation   +175 added lines, -175 removed lines patch added patch discarded remove patch
@@ -23,179 +23,179 @@
 block discarded – undo
23 23
  */
24 24
 class Converter
25 25
 {
26
-    /**
27
-     * @var array
28
-     */
29
-    protected $classes = [];
30
-
31
-    /**
32
-     * Converter constructor.
33
-     *
34
-     * @throws \RuntimeException
35
-     */
36
-    public function __construct()
37
-    {
38
-        $classes = static::getClassesMapping() ?? [];
39
-        if (!is_array($classes)) {
40
-            throw new \RuntimeException(
41
-                sprintf('CONFIG: "classes" mapping must be an array (%s given)', gettype($classes)));
42
-        }
43
-
44
-        $this->classes = $classes;
45
-    }
46
-
47
-    /**
48
-     * Returns local copy of configuration mapping for the classes.
49
-     *
50
-     * @return array
51
-     */
52
-    public function getClasses(): array
53
-    {
54
-        return $this->classes;
55
-    }
56
-
57
-    /**
58
-     * Checks if we have "classes" mapping configured for $data object class.
59
-     * Returns @true if there's valid config for this class.
60
-     * Throws \RuntimeException if there's no config "classes" mapping entry for this object configured.
61
-     * Throws \InvalidArgumentException if No data conversion mapping configured for given class.
62
-     *
63
-     * @param object $data Object to check mapping for.
64
-     *
65
-     * @return array
66
-     *
67
-     * @throws \InvalidArgumentException
68
-     */
69
-    protected function getClassMappingConfigOrThrow(object $data): array
70
-    {
71
-        $result = null;
72
-
73
-        // check for exact class name match...
74
-        $cls = get_class($data);
75
-        if (array_key_exists($cls, $this->classes)) {
76
-            $result = $this->classes[ $cls ];
77
-        } else {
78
-            // no exact match, then lets try with `instanceof`
79
-            foreach (array_keys($this->classes) as $class_name) {
80
-                if ($data instanceof $class_name) {
81
-                    $result = $this->classes[ $class_name ];
82
-                    break;
83
-                }
84
-            }
85
-        }
86
-
87
-        if ($result === null) {
88
-            throw new \InvalidArgumentException(sprintf('No data conversion mapping configured for "%s" class.', $cls));
89
-        }
90
-
91
-        return $result;
92
-    }
93
-
94
-    /**
95
-     * We need to prepare source data
96
-     *
97
-     * @param object|array|null $data
98
-     *
99
-     * @return array|null
100
-     *
101
-     * @throws \InvalidArgumentException
102
-     */
103
-    public function convert($data = null): ?array
104
-    {
105
-        if ($data === null) {
106
-            return null;
107
-        }
108
-
109
-        if (is_object($data)) {
110
-            $cfg = $this->getClassMappingConfigOrThrow($data);
111
-            $data = [$cfg[ ResponseBuilder::KEY_KEY ] => $data->{$cfg[ ResponseBuilder::KEY_METHOD ]}()];
112
-        } elseif (!is_array($data)) {
113
-            throw new \InvalidArgumentException(
114
-                sprintf('Payload must be null, array or object with mapping ("%s" given).', gettype($data)));
115
-        }
116
-
117
-        return $this->convertArray($data);
118
-    }
119
-
120
-    /**
121
-     * Recursively walks $data array and converts all known objects if found. Note
122
-     * $data array is passed by reference so source $data array may be modified.
123
-     *
124
-     * @param array $data array to recursively convert known elements of
125
-     *
126
-     * @return array
127
-     *
128
-     * @throws \RuntimeException
129
-     */
130
-    protected function convertArray(array $data): array
131
-    {
132
-        // This is to ensure that we either have array with user provided keys i.e. ['foo'=>'bar'], which will then
133
-        // be turned into JSON object or array without user specified keys (['bar']) which we would return as JSON
134
-        // array. But you can't mix these two as the final JSON would not produce predictable results.
135
-        $string_keys_cnt = 0;
136
-        $int_keys_cnt = 0;
137
-        foreach ($data as $key => $val) {
138
-            if (is_int($key)) {
139
-                $int_keys_cnt++;
140
-            } else {
141
-                $string_keys_cnt++;
142
-            }
143
-
144
-            if (($string_keys_cnt > 0) && ($int_keys_cnt > 0)) {
145
-                throw new \RuntimeException(
146
-                    'Invalid data array. Either set own keys for all the items or do not specify any keys at all. ' .
147
-                    'Arrays with mixed keys are not supported by design.');
148
-            }
149
-        }
150
-
151
-        foreach ($data as $key => $val) {
152
-            if (is_array($val)) {
153
-                $data[ $key ] = $this->convertArray($val);
154
-            } elseif (is_object($val)) {
155
-                $cls = get_class($val);
156
-                if (array_key_exists($cls, $this->classes)) {
157
-                    $conversion_method = $this->classes[ $cls ][ ResponseBuilder::KEY_METHOD ];
158
-                    $converted_data = $val->$conversion_method();
159
-                    $data[ $key ] = $converted_data;
160
-                }
161
-            }
162
-        }
163
-
164
-        return $data;
165
-    }
166
-
167
-    /**
168
-     * Reads and validates "classes" config mapping
169
-     *
170
-     * @return array Classes mapping as specified in configuration or empty array if configuration found
171
-     *
172
-     * @throws \RuntimeException if "classes" mapping is technically invalid (i.e. not array etc).
173
-     */
174
-    protected static function getClassesMapping(): ?array
175
-    {
176
-        $classes = Config::get(ResponseBuilder::CONF_KEY_CLASSES);
177
-
178
-        if ($classes !== null) {
179
-            if (!is_array($classes)) {
180
-                throw new \RuntimeException(
181
-                    sprintf('CONFIG: "classes" mapping must be an array (%s given)', gettype($classes)));
182
-            }
183
-
184
-            $mandatory_keys = [
185
-                ResponseBuilder::KEY_KEY,
186
-                ResponseBuilder::KEY_METHOD,
187
-            ];
188
-            foreach ($classes as $class_name => $class_config) {
189
-                foreach ($mandatory_keys as $key_name) {
190
-                    if (!array_key_exists($key_name, $class_config)) {
191
-                        throw new \RuntimeException("CONFIG: Missing '{$key_name}' for '{$class_name}' class mapping");
192
-                    }
193
-                }
194
-            }
195
-        } else {
196
-            $classes = [];
197
-        }
198
-
199
-        return $classes;
200
-    }
26
+	/**
27
+	 * @var array
28
+	 */
29
+	protected $classes = [];
30
+
31
+	/**
32
+	 * Converter constructor.
33
+	 *
34
+	 * @throws \RuntimeException
35
+	 */
36
+	public function __construct()
37
+	{
38
+		$classes = static::getClassesMapping() ?? [];
39
+		if (!is_array($classes)) {
40
+			throw new \RuntimeException(
41
+				sprintf('CONFIG: "classes" mapping must be an array (%s given)', gettype($classes)));
42
+		}
43
+
44
+		$this->classes = $classes;
45
+	}
46
+
47
+	/**
48
+	 * Returns local copy of configuration mapping for the classes.
49
+	 *
50
+	 * @return array
51
+	 */
52
+	public function getClasses(): array
53
+	{
54
+		return $this->classes;
55
+	}
56
+
57
+	/**
58
+	 * Checks if we have "classes" mapping configured for $data object class.
59
+	 * Returns @true if there's valid config for this class.
60
+	 * Throws \RuntimeException if there's no config "classes" mapping entry for this object configured.
61
+	 * Throws \InvalidArgumentException if No data conversion mapping configured for given class.
62
+	 *
63
+	 * @param object $data Object to check mapping for.
64
+	 *
65
+	 * @return array
66
+	 *
67
+	 * @throws \InvalidArgumentException
68
+	 */
69
+	protected function getClassMappingConfigOrThrow(object $data): array
70
+	{
71
+		$result = null;
72
+
73
+		// check for exact class name match...
74
+		$cls = get_class($data);
75
+		if (array_key_exists($cls, $this->classes)) {
76
+			$result = $this->classes[ $cls ];
77
+		} else {
78
+			// no exact match, then lets try with `instanceof`
79
+			foreach (array_keys($this->classes) as $class_name) {
80
+				if ($data instanceof $class_name) {
81
+					$result = $this->classes[ $class_name ];
82
+					break;
83
+				}
84
+			}
85
+		}
86
+
87
+		if ($result === null) {
88
+			throw new \InvalidArgumentException(sprintf('No data conversion mapping configured for "%s" class.', $cls));
89
+		}
90
+
91
+		return $result;
92
+	}
93
+
94
+	/**
95
+	 * We need to prepare source data
96
+	 *
97
+	 * @param object|array|null $data
98
+	 *
99
+	 * @return array|null
100
+	 *
101
+	 * @throws \InvalidArgumentException
102
+	 */
103
+	public function convert($data = null): ?array
104
+	{
105
+		if ($data === null) {
106
+			return null;
107
+		}
108
+
109
+		if (is_object($data)) {
110
+			$cfg = $this->getClassMappingConfigOrThrow($data);
111
+			$data = [$cfg[ ResponseBuilder::KEY_KEY ] => $data->{$cfg[ ResponseBuilder::KEY_METHOD ]}()];
112
+		} elseif (!is_array($data)) {
113
+			throw new \InvalidArgumentException(
114
+				sprintf('Payload must be null, array or object with mapping ("%s" given).', gettype($data)));
115
+		}
116
+
117
+		return $this->convertArray($data);
118
+	}
119
+
120
+	/**
121
+	 * Recursively walks $data array and converts all known objects if found. Note
122
+	 * $data array is passed by reference so source $data array may be modified.
123
+	 *
124
+	 * @param array $data array to recursively convert known elements of
125
+	 *
126
+	 * @return array
127
+	 *
128
+	 * @throws \RuntimeException
129
+	 */
130
+	protected function convertArray(array $data): array
131
+	{
132
+		// This is to ensure that we either have array with user provided keys i.e. ['foo'=>'bar'], which will then
133
+		// be turned into JSON object or array without user specified keys (['bar']) which we would return as JSON
134
+		// array. But you can't mix these two as the final JSON would not produce predictable results.
135
+		$string_keys_cnt = 0;
136
+		$int_keys_cnt = 0;
137
+		foreach ($data as $key => $val) {
138
+			if (is_int($key)) {
139
+				$int_keys_cnt++;
140
+			} else {
141
+				$string_keys_cnt++;
142
+			}
143
+
144
+			if (($string_keys_cnt > 0) && ($int_keys_cnt > 0)) {
145
+				throw new \RuntimeException(
146
+					'Invalid data array. Either set own keys for all the items or do not specify any keys at all. ' .
147
+					'Arrays with mixed keys are not supported by design.');
148
+			}
149
+		}
150
+
151
+		foreach ($data as $key => $val) {
152
+			if (is_array($val)) {
153
+				$data[ $key ] = $this->convertArray($val);
154
+			} elseif (is_object($val)) {
155
+				$cls = get_class($val);
156
+				if (array_key_exists($cls, $this->classes)) {
157
+					$conversion_method = $this->classes[ $cls ][ ResponseBuilder::KEY_METHOD ];
158
+					$converted_data = $val->$conversion_method();
159
+					$data[ $key ] = $converted_data;
160
+				}
161
+			}
162
+		}
163
+
164
+		return $data;
165
+	}
166
+
167
+	/**
168
+	 * Reads and validates "classes" config mapping
169
+	 *
170
+	 * @return array Classes mapping as specified in configuration or empty array if configuration found
171
+	 *
172
+	 * @throws \RuntimeException if "classes" mapping is technically invalid (i.e. not array etc).
173
+	 */
174
+	protected static function getClassesMapping(): ?array
175
+	{
176
+		$classes = Config::get(ResponseBuilder::CONF_KEY_CLASSES);
177
+
178
+		if ($classes !== null) {
179
+			if (!is_array($classes)) {
180
+				throw new \RuntimeException(
181
+					sprintf('CONFIG: "classes" mapping must be an array (%s given)', gettype($classes)));
182
+			}
183
+
184
+			$mandatory_keys = [
185
+				ResponseBuilder::KEY_KEY,
186
+				ResponseBuilder::KEY_METHOD,
187
+			];
188
+			foreach ($classes as $class_name => $class_config) {
189
+				foreach ($mandatory_keys as $key_name) {
190
+					if (!array_key_exists($key_name, $class_config)) {
191
+						throw new \RuntimeException("CONFIG: Missing '{$key_name}' for '{$class_name}' class mapping");
192
+					}
193
+				}
194
+			}
195
+		} else {
196
+			$classes = [];
197
+		}
198
+
199
+		return $classes;
200
+	}
201 201
 }
Please login to merge, or discard this patch.