Completed
Push — 8.x ( 824af6 )
by Tim
09:11
created

SimpleFileResolver::cleanUpOkFile()   B

Complexity

Conditions 8
Paths 13

Size

Total Lines 57

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
dl 0
loc 57
c 0
b 0
f 0
ccs 0
cts 27
cp 0
rs 7.6937
cc 8
nc 13
nop 1
crap 72

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
 * TechDivision\Import\Subjects\FileResolver\BunchFileResolver
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2016 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/techdivision/import
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Subjects\FileResolver;
22
23
use TechDivision\Import\Utils\BunchKeys;
24
use TechDivision\Import\Exceptions\LineNotFoundException;
25
use TechDivision\Import\Exceptions\MissingOkFileException;
26
27
/**
28
 * Plugin that processes the subjects.
29
 *
30
 * @author    Tim Wagner <[email protected]>
31
 * @copyright 2016 TechDivision GmbH <[email protected]>
32
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
33
 * @link      https://github.com/techdivision/import
34
 * @link      http://www.techdivision.com
35
 */
36
class SimpleFileResolver extends AbstractFileResolver
37
{
38
39
    /**
40
     * The regular expression used to load the files with.
41
     *
42
     * @var string
43
     */
44
    private $regex = '/^.*\/%s\\.%s$/';
45
46
    /**
47
     * The matches for the last processed CSV filename.
48
     *
49
     * @var array
50
     */
51
    private $matches = array();
52
53
    /**
54
     * Returns the regular expression used to load the files with.
55
     *
56
     * @return string The regular expression
57
     */
58 2
    protected function getRegex()
59
    {
60 2
        return $this->regex;
61
    }
62
63
    /**
64
     * Returns the number of matches found.
65
     *
66
     * @return integer The number of matches
67
     */
68 2
    protected function countMatches()
69
    {
70 2
        return sizeof($this->matches);
71
    }
72
73
    /**
74
     * Adds the passed match to the array with the matches.
75
     *
76
     * @param string $name  The name of the match
77
     * @param string $match The match itself
78
     *
79
     * @return void
80
     */
81 2
    protected function addMatch($name, $match)
82
    {
83 2
        $this->matches[strtolower($name)] = $match;
84 2
    }
85
86
    /**
87
     * Returns the match with the passed name.
88
     *
89
     * @param string $name The name of the match to return
90
     *
91
     * @return string|null The match itself
92
     */
93 2
    protected function getMatch($name)
94
    {
95 2
        if (isset($this->matches[$name])) {
96 2
            return $this->matches[$name];
97
        }
98
    }
99
100
    /**
101
     * Returns the elements the filenames consists of, converted to lowercase.
102
     *
103
     * @return array The array with the filename elements
104
     */
105 2
    protected function getPatternKeys()
106
    {
107
108
        // load the pattern keys from the configuration
109 2
        $patternKeys = $this->getPatternElements();
110
111
        // make sure that they are all lowercase
112 2
        array_walk($patternKeys, function (&$value) {
113 2
            $value = strtolower($value);
114 2
        });
115
116
        // return the pattern keys
117 2
        return $patternKeys;
118
    }
119
120
    /**
121
     * Remove's the passed line from the file with the passed name.
122
     *
123
     * @param string $line     The line to be removed
124
     * @param string $filename The name of the file the line has to be removed
125
     *
126
     * @return void
127
     * @throws \Exception Is thrown, if the file doesn't exists, the line is not found or can not be removed
128
     */
129
    protected function removeLineFromFile($line, $filename)
130
    {
131
        $this->getApplication()->removeLineFromFile($line, $filename);
132
    }
133
134
    /**
135
     * Returns the values to create the regex pattern from.
136
     *
137
     * @return array The array with the pattern values
138
     */
139 2
    protected function resolvePatternValues()
140
    {
141
142
        // initialize the array
143 2
        $elements = array();
144
145
        // prepare the pattern values
146 2
        foreach ($this->getPatternKeys() as $element) {
147 2
            $elements[] = sprintf('(?<%s>%s)', $element, $this->resolvePatternValue($element));
148
        }
149
150
        // return the pattern values
151 2
        return $elements;
152
    }
153
154
    /**
155
     * Resolves the pattern value for the given element name.
156
     *
157
     * @param string $element The element name to resolve the pattern value for
158
     *
159
     * @return string|null The resolved pattern value
160
     */
161 2
    protected function resolvePatternValue($element)
162
    {
163
164
        // query whether or not matches has been found OR the counter element has been passed
165 2
        if ($this->countMatches() === 0 || BunchKeys::COUNTER === $element) {
166
            // prepare the method name for the callback to load the pattern value with
167 2
            $methodName = sprintf('get%s', ucfirst($element));
168
169
            // load the pattern value
170 2
            if (in_array($methodName, get_class_methods($this->getFileResolverConfiguration()))) {
171 2
                return call_user_func(array($this->getFileResolverConfiguration(), $methodName));
172
            }
173
174
            // stop processing
175
            return;
176
        }
177
178
        // try to load the pattern value from the matches
179 2
        return $this->getMatch($element);
180
    }
181
182
    /**
183
     * Prepares and returns the pattern for the regex to load the files from the
184
     * source directory for the passed subject.
185
     *
186
     * @return string The prepared regex pattern
187
     */
188 2
    protected function preparePattern()
189
    {
190 2
        return sprintf($this->getRegex(), implode($this->getElementSeparator(), $this->resolvePatternValues()), $this->getSuffix());
191
    }
192
193
    /**
194
     * Prepares and returns an OK filename from the passed parts.
195
     *
196
     * @param array $parts The parts to concatenate the OK filename from
197
     *
198
     * @return string The OK filename
199
     */
200
    protected function prepareOkFilename(array $parts)
201
    {
202
        return sprintf('%s/%s.%s', $this->getSourceDir(), implode($this->getElementSeparator(), $parts), $this->getOkFileSuffix());
203
    }
204
205
    /**
206
     * Query whether or not the basename, without suffix, of the passed filenames are equal.
207
     *
208
     * @param string $filename1 The first filename to compare
209
     * @param string $filename2 The second filename to compare
210
     *
211
     * @return boolean TRUE if the passed files basename are equal, else FALSE
212
     */
213
    protected function isEqualFilename($filename1, $filename2)
214
    {
215
        return $this->stripSuffix($filename1, $this->getSuffix()) === $this->stripSuffix($filename2, $this->getOkFileSuffix());
216
    }
217
218
    /**
219
     * Strips the passed suffix, including the (.), from the filename and returns it.
220
     *
221
     * @param string $filename The filename to return the suffix from
222
     * @param string $suffix   The suffix to return
223
     *
224
     * @return string The filname without the suffix
225
     */
226
    protected function stripSuffix($filename, $suffix)
227
    {
228
        return basename($filename, sprintf('.%s', $suffix));
229
    }
230
231
    /**
232
     * Return's an array with the names of the expected OK files for the actual subject.
233
     *
234
     * @return array The array with the expected OK filenames
235
     */
236
    protected function getOkFilenames()
237
    {
238
239
        // initialize the array for the available okFilenames
240
        $okFilenames = array();
241
242
        // prepare the OK filenames based on the found CSV file information
243
        for ($i = 1; $i <= sizeof($patternKeys = $this->getPatternKeys()); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
244
            // intialize the array for the parts of the names (prefix, filename + counter)
245
            $parts = array();
246
            // load the parts from the matches
247
            for ($z = 0; $z < $i; $z++) {
248
                // append the part
249
                $parts[] = $this->getMatch($patternKeys[$z]);
250
            }
251
252
            // query whether or not, the OK file exists, if yes append it
253
            if (file_exists($okFilename = $this->prepareOkFilename($parts))) {
254
                $okFilenames[] = $okFilename;
255
            }
256
        }
257
258
        // prepare and return the pattern for the OK file
259
        return $okFilenames;
260
    }
261
262
    /**
263
     * Resets the file resolver to parse another source directory for new files.
264
     *
265
     * @return void
266
     */
267
    public function reset()
268
    {
269
        $this->matches = array();
270
    }
271
272
    /**
273
     * Returns the matches.
274
     *
275
     * @return array The array with the matches
276
     */
277
    public function getMatches()
278
    {
279
        return array_merge(array(BunchKeys::FILENAME => date('Ymd-His'), BunchKeys::COUNTER => 1), $this->matches);
280
    }
281
282
    /**
283
     * Queries whether or not, the passed filename should be handled by the subject.
284
     *
285
     * @param string $filename The filename to query for
286
     *
287
     * @return boolean TRUE if the file should be handled, else FALSE
288
     */
289 2
    public function shouldBeHandled($filename)
290
    {
291
292
        // initialize the array with the matches
293 2
        $matches = array();
294
295
        // update the matches, if the pattern matches
296 2
        if ($result = preg_match($this->preparePattern(), $filename, $matches)) {
297 2
            foreach ($matches as $name => $match) {
298 2
                $this->addMatch($name, $match);
299
            }
300
        }
301
302
        // stop processing, if the filename doesn't match
303 2
        return (boolean) $result;
304
    }
305
306
    /**
307
     * Query whether or not, the passed CSV filename is in the OK file. If the filename was found,
308
     * the OK file will be cleaned-up.
309
     *
310
     * @param string $filename The filename to be cleaned-up
311
     *
312
     * @return void
313
     * @throws \Exception Is thrown, if the passed filename is NOT in the OK file or the OK can not be cleaned-up
314
     */
315
    public function cleanUpOkFile($filename)
316
    {
317
318
        // query whether or not the subject needs an OK file, if yes remove the filename from the file
319
        if ($this->getSubjectConfiguration()->isOkFileNeeded() === false) {
320
            return;
321
        }
322
323
        try {
324
            // try to load the expected OK filenames
325
            if (sizeof($okFilenames = $this->getOkFilenames()) === 0) {
326
                throw new MissingOkFileException(sprintf('Can\'t find a OK filename for file %s', $filename));
327
            }
328
329
            // iterate over the found OK filenames (should usually be only one, but could be more)
330
            foreach ($okFilenames as $okFilename) {
331
                // if the OK filename matches the CSV filename AND the OK file is empty
332
                if ($this->isEqualFilename($filename, $okFilename) && filesize($okFilename) === 0) {
333
                    unlink($okFilename);
334
                    return;
335
                }
336
337
                // else, remove the CSV filename from the OK file
338
                $this->removeLineFromFile(basename($filename), $fh = fopen($okFilename, 'r+'));
0 ignored issues
show
Documentation introduced by
$fh = fopen($okFilename, 'r+') is of type resource, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
339
                fclose($fh);
340
341
                // if the OK file is empty, delete the file
342
                if (filesize($okFilename) === 0) {
343
                    unlink($okFilename);
344
                }
345
346
                // return immediately
347
                return;
348
            }
349
350
            // throw an exception if either no OK file has been found,
351
            // or the CSV file is not in one of the OK files
352
            throw new \Exception(
353
                sprintf(
354
                    'Can\'t found filename %s in one of the expected OK files: %s',
355
                    $filename,
356
                    implode(', ', $okFilenames)
357
                )
358
            );
359
        } catch (LineNotFoundException $lne) {
360
            // wrap and re-throw the exception
361
            throw new \Exception(
362
                sprintf(
363
                    'Can\'t remove filename %s from OK file: %s',
364
                    $filename,
365
                    $okFilename
366
                ),
367
                null,
368
                $lne
369
            );
370
        }
371
    }
372
}
373