Completed
Pull Request — master (#48)
by Vladimir
02:34
created

DataItem::getIterator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/**
4
 * @copyright 2017 Vladimir Jimenez
5
 * @license   https://github.com/allejo/stakx/blob/master/LICENSE.md MIT
6
 */
7
8
namespace allejo\stakx\Document;
9
10
use allejo\stakx\Exception\DependencyMissingException;
11
use allejo\stakx\Exception\UnsupportedDataTypeException;
12
use allejo\stakx\System\Filesystem;
13
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
14
use Symfony\Component\Finder\SplFileInfo;
15
use Symfony\Component\Yaml\Yaml;
16
17
class DataItem implements
18
    \ArrayAccess,
19
    \IteratorAggregate,
20
    TwigDocumentInterface,
21
    JailedDocumentInterface
22
{
23
    protected $data;
24
25
    private $fileExtension;
26
    private $namespace;
27
    private $fileName;
28
    private $filePath;
29
    private $fs;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $fs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
30
31
    public function __construct($filePath)
32
    {
33
        $this->fs = new Filesystem();
34
35
        if (!$this->fs->exists($filePath))
36
        {
37
            throw new FileNotFoundException("The following file could not be found: ${filePath}");
38
        }
39
40
        $this->fileExtension = strtolower($this->fs->getExtension($filePath));
41
        $this->fileName = $this->fs->getBaseName($filePath);
42
        $this->filePath = $filePath;
43
        $this->namespace = '';
44
45
        $this->refreshFileContent();
46
    }
47
48
    public function getIterator()
49
    {
50
        return new \ArrayIterator($this->data);
51
    }
52
53
    ///
54
    // Jailed Document implementation
55
    ///
56
57
    /**
58
     * {@inheritdoc}
59
     */
60
    public function createJail()
61
    {
62
        return new JailedDocument($this, array(
63
            'getExtension', 'getFilePath', 'getName', 'getRelativeFilePath'
64
        ));
65
    }
66
67
    ///
68
    // ArrayAccess implementation
69
    ///
70
71
    /**
72
     * {@inheritdoc}
73
     */
74
    public function offsetExists($offset)
75
    {
76
        return isset($this->data[$offset]);
77
    }
78
79
    /**
80
     * {@inheritdoc}
81
     */
82
    public function offsetGet($offset)
83
    {
84
        return $this->data[$offset];
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    public function offsetSet($offset, $value)
91
    {
92
        $this->data[$offset] = $value;
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98
    public function offsetUnset($offset)
99
    {
100
        unset($this->data[$offset]);
101
    }
102
103
    ///
104
    // Twig Document implementation
105
    ///
106
107
    public function getNamespace()
108
    {
109
        return $this->namespace;
110
    }
111
112
    public function setNamespace($namespace)
113
    {
114
        $this->namespace = $namespace;
115
    }
116
117
    public function getExtension()
118
    {
119
        return $this->fileExtension;
120
    }
121
122
    public function getFilePath()
123
    {
124
        return $this->filePath;
125
    }
126
127
    public function getName()
128
    {
129
        return $this->fileName;
130
    }
131
132
    public function getRelativeFilePath()
133
    {
134
        if ($this->filePath instanceof SplFileInfo)
135
        {
136
            return $this->filePath->getRelativePathname();
137
        }
138
139
        // TODO ensure that we always get SplFileInfo objects, even when handling VFS documents
140
        return $this->fs->getRelativePath($this->filePath);
141
    }
142
143
    public function refreshFileContent()
144
    {
145
        // This function can be called after the initial object was created and the file may have been deleted since the
146
        // creation of the object.
147 View Code Duplication
        if (!$this->fs->exists($this->filePath))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148
        {
149
            throw new FileNotFoundException(null, 0, null, $this->filePath);
150
        }
151
152
        $content = file_get_contents($this->getFilePath());
153
        $fxnName = 'from' . ucfirst($this->getExtension());
154
155
        if (method_exists(get_called_class(), $fxnName))
156
        {
157
            $this->data = (null !== ($c = $this->$fxnName($content))) ? $c : array();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $c. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
158
159
            return;
160
        }
161
162
        throw new UnsupportedDataTypeException($this->getExtension(), "There is no support to handle this file extension.");
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal There is no support to handle this file extension. does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
163
    }
164
165
    ///
166
    // File parsing helpers
167
    ///
168
169
    /**
170
     * Convert from CSV into an associative array.
171
     *
172
     * @param string $content CSV formatted text
173
     *
174
     * @return array
175
     */
176
    private function fromCsv($content)
177
    {
178
        $rows = array_map('str_getcsv', explode("\n", trim($content)));
179
        $columns = array_shift($rows);
180
        $csv = array();
181
182
        foreach ($rows as $row)
183
        {
184
            $csv[] = array_combine($columns, $row);
185
        }
186
187
        return $csv;
188
    }
189
190
    /**
191
     * Convert from JSON into an associative array.
192
     *
193
     * @param string $content JSON formatted text
194
     *
195
     * @return array
196
     */
197
    private function fromJson($content)
198
    {
199
        return json_decode($content, true);
200
    }
201
202
    /**
203
     * Convert from XML into an associative array.
204
     *
205
     * @param string $content XML formatted text
206
     *
207
     * @return array
208
     */
209
    private function fromXml($content)
210
    {
211
        return json_decode(json_encode(simplexml_load_string($content)), true);
212
    }
213
214
    /**
215
     * Convert from YAML into an associative array.
216
     *
217
     * @param string $content YAML formatted text
218
     *
219
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be string|array|\stdClass?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
220
     */
221
    private function fromYaml($content)
222
    {
223
        return Yaml::parse($content, Yaml::PARSE_DATETIME);
224
    }
225
226
    /**
227
     * An alias for handling `*.yml` files.
228
     *
229
     * @param string $content YAML formatted text
230
     *
231
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be string|array|\stdClass?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
232
     */
233
    private function fromYml($content)
234
    {
235
        return $this->fromYaml($content);
236
    }
237
238
    /**
239
     * @param string $extension
240
     *
241
     * @todo 0.1.0 Create a help page on the main stakx website for this topic and link to it
242
     *
243
     * @throws DependencyMissingException
244
     */
245
    private function handleDependencies($extension)
246
    {
247
        if ($extension === 'xml' && !function_exists('simplexml_load_string'))
248
        {
249
            throw new DependencyMissingException('XML', 'XML support is not available with the current PHP installation.');
250
        }
251
    }
252
}
253