Base::_format()   B
last analyzed

Complexity

Conditions 8
Paths 25

Size

Total Lines 61
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 24
nc 25
nop 4
dl 0
loc 61
rs 7.0047
c 0
b 0
f 0

How to fix   Long Method   

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
 * Provides XML file handling for known schemas
5
 *
6
 * PHP Version 5
7
 *
8
 * @category  Core
9
 * @package   XML
10
 * @author    Hans-Joachim Piepereit <[email protected]>
11
 * @copyright 2013 cSphere Team
12
 * @license   http://opensource.org/licenses/bsd-license Simplified BSD License
13
 * @link      http://www.csphere.eu
14
 **/
15
16
namespace csphere\core\xml;
17
18
/**
19
 * Provides XML file handling for known schemas
20
 *
21
 * @category  Core
22
 * @package   XML
23
 * @author    Hans-Joachim Piepereit <[email protected]>
24
 * @copyright 2013 cSphere Team
25
 * @license   http://opensource.org/licenses/bsd-license Simplified BSD License
26
 * @link      http://www.csphere.eu
27
 **/
28
29
abstract class Base extends \csphere\core\service\Drivers
30
{
31
    /**
32
     * Stores the cache object
33
     **/
34
    protected $cache = null;
35
36
    /**
37
     * Stores the local path
38
     **/
39
    protected $path = '';
40
41
    /**
42
     * Stores the local path
43
     **/
44
    private static $_count = [];
45
46
    /**
47
     * Creates the XML handler object
48
     *
49
     * @param array $config Configuration details as an array
50
     *
51
     * @return \csphere\core\xml\Base
52
     **/
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
53
54
    public function __construct(array $config)
55
    {
56
        parent::__construct($config);
57
58
        $this->path = \csphere\core\init\path();
59
60
        $this->cache = $this->loader->load('cache');
61
    }
62
63
    /**
64
     * Try to find a source inside the cache or as a file
65
     *
66
     * @param string  $type  Type of target, e.g. plugin
67
     * @param string  $name  Directory name of the target
68
     * @param string  $lang  Language if more than one is possible
69
     * @param boolean $empty Return empty array if file is missing
70
     *
71
     * @throws \Exception
72
     *
73
     * @return array
74
     **/
0 ignored issues
show
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
75
76
    public function source($type, $name, $lang = 'en', $empty = false)
77
    {
78
        // Set key here to not let drivers accidently overcut something
79
        $key = 'xml_' . $this->driver() . '_' . $type . '_' . $name . '_' . $lang;
80
81
        // Try to fetch key from cache or load file otherwise
82
        $string = $this->cache->load($key);
83
84
        if ($string == false) {
85
86
            $file = $this->path . $this->file($type, $name, $lang);
87
88
            // Check if file exists
89
            if (file_exists($file)) {
90
91
                $string = file_get_contents($file);
92
93
                // Parse XML to array structure and format it
94
                $string = $this->_structure($string);
95
96
                // Apply driver specific changes
97
                $string = $this->change($string);
98
99
                // Save to cache for later usage
100
                $this->cache->save($key, $string);
101
102
            } elseif ($empty === true) {
103
104
                // In some cases it is not relevant if the file exists
105
                $string = [];
106
107
            } else {
108
109
                throw new \Exception('XML file not found: ' . $file);
110
            }
111
        }
112
113
        return $string;
114
    }
115
116
    /**
117
     * Transforms the given string to a driver specific array
118
     *
119
     * @param string $string String containing the XML content
120
     *
121
     * @return array
122
     **/
0 ignored issues
show
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
123
124
    public function transform($string)
125
    {
126
        // Parse XML to array structure and format it
127
        $string = $this->_structure($string);
128
129
        // Apply driver specific changes
130
        $string = $this->change($string);
131
132
        return $string;
133
    }
134
135
    /**
136
     * Converts a valid XML data string into arrays
137
     *
138
     * @param string $string The XML data string to use
139
     *
140
     * @throws \Exception
141
     *
142
     * @return array
143
     **/
0 ignored issues
show
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
144
145
    private function _structure($string)
146
    {
147
        // @TODO: Set XSD for validation
148
        // Could be possible with xmlreader extension
149
150
        // Create the parser
151
        $parser = xml_parser_create('UTF-8');
152
153
        // Disable uppercase usage and blank entries
154
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
155
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
156
157
        // Split data into values and index arrays
158
        $struct = xml_parse_into_struct($parser, $string, $values, $index);
159
160
        // Check for errors and free parser
161
        $code = xml_get_error_code($parser);
162
163
        xml_parser_free($parser);
164
165
        if ($struct == 0 || $code != 0) {
166
167
            $error = xml_error_string($code);
168
169
            throw new \Exception($error);
170
        }
171
172
        // Format result set for later usage
173
        self::$_count = [];
174
        $end          = (count($values) - 2);
175
        $result       = $this->_format($values, (array)$index, 1, $end);
176
177
        return $result;
178
    }
179
180
    /**
181
     * Format data as an usable array
182
     *
183
     * @param array   $values Array with value data
184
     * @param array   $index  Array with index data
185
     * @param integer $start  Start point of data loop
186
     * @param integer $end    End point of data loop
187
     *
188
     * @return array
189
     **/
0 ignored issues
show
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
190
191
    private function _format(array $values, array $index, $start, $end)
192
    {
193
        $result = [];
194
195
        // Loop through every values array entry from start to end
196
        for ($i = $start; $i < $end; $i++) {
197
198
            // Prepare data for result set content
199
            $tag = $values[$i]['tag'];
200
201
            // Add attributes if there are any
202
            $attr = [];
203
204
            if (isset($values[$i]['attributes'])) {
205
206
                $attr = $values[$i]['attributes'];
207
            }
208
209
            // Add value if there is one
210
            if (isset($values[$i]['value'])) {
211
212
                $attr['value'] = $values[$i]['value'];
213
            }
214
215
            // Type open creates a sub loop with additional details
216
            if ($values[$i]['type'] == 'complete') {
217
218
                $result[$tag][] = $attr;
219
220
            } elseif ($values[$i]['type'] == 'open') {
221
222
                // Determine the end point for the sub loop
223
                if (isset(self::$_count[$tag])) {
224
225
                    self::$_count[$tag] = (self::$_count[$tag] + 2);
226
227
                } else {
228
229
                    self::$_count[$tag] = 1;
230
                }
231
232
                $stop = $index[$tag][(self::$_count[$tag])];
233
234
                // Add nested elements to result array
235
                $open = $this->_format($values, $index, ($i + 1), $stop);
236
237
                if ($attr != []) {
238
239
                    $attr = ['attr' => [$attr]];
240
                    $open = array_merge($attr, $open);
241
                }
242
243
                $result[$tag][] = $open;
244
245
                // Skip some steps here to not use data twice
246
                $i = $stop;
247
            }
248
        }
249
250
        return $result;
251
    }
252
253
    /**
254
     * Move attributes up to data array in a loop
255
     *
256
     * @param array $array Array to convert
257
     *
258
     * @return array
259
     **/
0 ignored issues
show
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
260
261
    protected function loopattr(array $array)
262
    {
263
        $new = [];
264
265
        foreach ($array AS $row) {
266
267
            $attr = isset($row['attr'][0]) ? $row['attr'][0] : [];
268
269
            unset($row['attr']);
270
271
            $new[] = array_merge($attr, $row);
272
        }
273
274
        return $new;
275
    }
276
277
    /**
278
     * Change array depth for common settings
279
     *
280
     * @param array $array Array to convert
281
     *
282
     * @return array
283
     **/
0 ignored issues
show
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
284
285
    protected function common(array $array)
286
    {
287
        // Shorten array depth for simple elements
288
        $array['vendor']    = $array['vendor'][0]['value'];
289
        $array['version']   = $array['version'][0]['value'];
290
        $array['published'] = $array['published'][0]['value'];
291
        $array['copyright'] = $array['copyright'][0]['value'];
292
        $array['license']   = $array['license'][0]['value'];
293
        $array['name']      = $array['name'][0]['value'];
294
        $array['info']      = $array['info'][0]['value'];
295
        $array['engine']    = $array['engine'][0];
296
        $array['icon']      = $array['icon'][0];
297
        $array['authors']   = $array['authors'][0];
298
        $array['contact']   = $array['contact'][0];
299
300
        // Check for optional version_max
301
        if (empty($array['engine']['version_max'])) {
302
303
            $array['engine']['version_max'] = '';
304
        }
305
306
        return $array;
307
    }
308
309
    /**
310
     * Determine the driver specific source file
311
     *
312
     * @param string $type Type of target, e.g. plugin
313
     * @param string $name Directory name of the target
314
     * @param string $lang Language if more than one is possible
315
     *
316
     * @return string
317
     **/
0 ignored issues
show
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
318
319
    abstract protected function file($type, $name, $lang);
320
321
    /**
322
     * Change data array for easier usage
323
     *
324
     * @param array $array Formated array generated earlier
325
     *
326
     * @return array
327
     **/
0 ignored issues
show
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
328
329
    abstract protected function change(array $array);
330
}
331