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

DataItem::refreshFileContent()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 9

Duplication

Lines 4
Ratio 20 %

Importance

Changes 0
Metric Value
dl 4
loc 20
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 9
nc 3
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
    TwigDocumentInterface,
20
    JailedDocumentInterface
21
{
22
    protected $data;
23
24
    private $fileExtension;
25
    private $namespace;
26
    private $fileName;
27
    private $filePath;
28
    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...
29
30
    public function __construct($filePath)
31
    {
32
        $this->fs = new Filesystem();
33
34
        if (!$this->fs->exists($filePath))
35
        {
36
            throw new FileNotFoundException("The following file could not be found: ${filePath}");
37
        }
38
39
        $this->fileExtension = strtolower($this->fs->getExtension($filePath));
40
        $this->fileName = $this->fs->getBaseName($filePath);
41
        $this->filePath = $filePath;
42
        $this->namespace = '';
43
44
        $this->refreshFileContent();
45
    }
46
47
    ///
48
    // Jailed Document implementation
49
    ///
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function createJail()
55
    {
56
        return new JailedDocument($this, array(
57
            'getExtension', 'getFilePath', 'getName', 'getRelativeFilePath'
58
        ));
59
    }
60
61
    ///
62
    // ArrayAccess implementation
63
    ///
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    public function offsetExists($offset)
69
    {
70
        return isset($this->data[$offset]);
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76
    public function offsetGet($offset)
77
    {
78
        return $this->data[$offset];
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84
    public function offsetSet($offset, $value)
85
    {
86
        $this->data[$offset] = $value;
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function offsetUnset($offset)
93
    {
94
        unset($this->data[$offset]);
95
    }
96
97
    ///
98
    // Twig Document implementation
99
    ///
100
101
    public function getNamespace()
102
    {
103
        return $this->namespace;
104
    }
105
106
    public function setNamespace($namespace)
107
    {
108
        $this->namespace = $namespace;
109
    }
110
111
    public function getExtension()
112
    {
113
        return $this->fileExtension;
114
    }
115
116
    public function getFilePath()
117
    {
118
        return $this->filePath;
119
    }
120
121
    public function getName()
122
    {
123
        return $this->fileName;
124
    }
125
126
    public function getRelativeFilePath()
127
    {
128
        if ($this->filePath instanceof SplFileInfo)
129
        {
130
            return $this->filePath->getRelativePathname();
131
        }
132
133
        // TODO ensure that we always get SplFileInfo objects, even when handling VFS documents
134
        return $this->fs->getRelativePath($this->filePath);
135
    }
136
137
    public function refreshFileContent()
138
    {
139
        // This function can be called after the initial object was created and the file may have been deleted since the
140
        // creation of the object.
141 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...
142
        {
143
            throw new FileNotFoundException(null, 0, null, $this->filePath);
144
        }
145
146
        $content = file_get_contents($this->getFilePath());
147
        $fxnName = 'from' . ucfirst($this->getExtension());
148
149
        if (method_exists(get_called_class(), $fxnName))
150
        {
151
            $this->data = $this->$fxnName($content);
152
            return;
153
        }
154
155
        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...
156
    }
157
158
    ///
159
    // File parsing helpers
160
    ///
161
162
    /**
163
     * Convert from CSV into an associative array.
164
     *
165
     * @param string $content CSV formatted text
166
     *
167
     * @return array
168
     */
169
    private function fromCsv($content)
170
    {
171
        $rows = array_map('str_getcsv', explode("\n", trim($content)));
172
        $columns = array_shift($rows);
173
        $csv = array();
174
175
        foreach ($rows as $row)
176
        {
177
            $csv[] = array_combine($columns, $row);
178
        }
179
180
        return $csv;
181
    }
182
183
    /**
184
     * Convert from JSON into an associative array.
185
     *
186
     * @param string $content JSON formatted text
187
     *
188
     * @return array
189
     */
190
    private function fromJson($content)
191
    {
192
        return json_decode($content, true);
193
    }
194
195
    /**
196
     * Convert from XML into an associative array.
197
     *
198
     * @param string $content XML formatted text
199
     *
200
     * @return array
201
     */
202
    private function fromXml($content)
203
    {
204
        return json_decode(json_encode(simplexml_load_string($content)), true);
205
    }
206
207
    /**
208
     * Convert from YAML into an associative array.
209
     *
210
     * @param string $content YAML formatted text
211
     *
212
     * @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...
213
     */
214
    private function fromYaml($content)
215
    {
216
        return Yaml::parse($content, Yaml::PARSE_DATETIME);
217
    }
218
219
    /**
220
     * An alias for handling `*.yml` files.
221
     *
222
     * @param string $content YAML formatted text
223
     *
224
     * @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...
225
     */
226
    private function fromYml($content)
227
    {
228
        return $this->fromYaml($content);
229
    }
230
231
    /**
232
     * @param string $extension
233
     *
234
     * @todo 0.1.0 Create a help page on the main stakx website for this topic and link to it
235
     *
236
     * @throws DependencyMissingException
237
     */
238
    private function handleDependencies($extension)
239
    {
240
        if ($extension === 'xml' && !function_exists('simplexml_load_string'))
241
        {
242
            throw new DependencyMissingException('XML', 'XML support is not available with the current PHP installation.');
243
        }
244
    }
245
}
246