Completed
Pull Request — 16.x (#167)
by Jitendra
05:11
created

OkFileAwareFileResolver   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 259
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 43.42%

Importance

Changes 0
Metric Value
wmc 31
lcom 1
cbo 4
dl 0
loc 259
ccs 33
cts 76
cp 0.4342
rs 9.92
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A removeLineFromFile() 0 4 1
A isEqualFilename() 0 4 1
A stripSuffix() 0 4 1
A prepareOkFilename() 0 4 1
A getOkFilenames() 0 25 4
B shouldBeHandled() 0 52 9
B loadFiles() 0 34 6
B cleanUpOkFile() 0 59 8
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\Exceptions\LineNotFoundException;
24
use TechDivision\Import\Exceptions\MissingOkFileException;
25
26
/**
27
 * Plugin that processes the subjects.
28
 *
29
 * @author    Tim Wagner <[email protected]>
30
 * @copyright 2016 TechDivision GmbH <[email protected]>
31
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
32
 * @link      https://github.com/techdivision/import
33
 * @link      http://www.techdivision.com
34
 */
35
class OkFileAwareFileResolver extends SimpleFileResolver implements OkFileAwareFileResolverInterface
36
{
37
38
    /**
39
     * Remove's the passed line from the file with the passed name.
40
     *
41
     * @param string $line     The line to be removed
42
     * @param string $filename The name of the file the line has to be removed
43
     *
44
     * @return void
45
     * @throws \Exception Is thrown, if the file doesn't exists, the line is not found or can not be removed
46
     */
47
    protected function removeLineFromFile($line, $filename)
48
    {
49
        $this->getApplication()->removeLineFromFile($line, $filename);
50
    }
51
52
    /**
53
     * Query whether or not the basename, without suffix, of the passed filenames are equal.
54
     *
55
     * @param string $filename1 The first filename to compare
56
     * @param string $filename2 The second filename to compare
57
     *
58
     * @return boolean TRUE if the passed files basename are equal, else FALSE
59
     */
60 1
    protected function isEqualFilename($filename1, $filename2)
61
    {
62 1
        return $this->stripSuffix($filename1, $this->getSuffix()) === $this->stripSuffix($filename2, $this->getOkFileSuffix());
63
    }
64
65
    /**
66
     * Strips the passed suffix, including the (.), from the filename and returns it.
67
     *
68
     * @param string $filename The filename to return the suffix from
69
     * @param string $suffix   The suffix to return
70
     *
71
     * @return string The filname without the suffix
72
     */
73 1
    protected function stripSuffix($filename, $suffix)
74
    {
75 1
        return basename($filename, sprintf('.%s', $suffix));
76
    }
77
78
    /**
79
     * Prepares and returns an OK filename from the passed parts.
80
     *
81
     * @param array $parts The parts to concatenate the OK filename from
82
     *
83
     * @return string The OK filename
84
     */
85 1
    protected function prepareOkFilename(array $parts)
86
    {
87 1
        return sprintf('%s/%s.%s', $this->getSourceDir(), implode($this->getElementSeparator(), $parts), $this->getOkFileSuffix());
88
    }
89
90
    /**
91
     * Return's an array with the names of the expected OK files for the actual subject.
92
     *
93
     * @return array The array with the expected OK filenames
94
     */
95 1
    protected function getOkFilenames()
96
    {
97
98
        // initialize the array for the available okFilenames
99 1
        $okFilenames = array();
100
101
        // prepare the OK filenames based on the found CSV file information
102 1
        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...
103
            // intialize the array for the parts of the names (prefix, filename + counter)
104 1
            $parts = array();
105
            // load the parts from the matches
106 1
            for ($z = 0; $z < $i; $z++) {
107
                // append the part
108 1
                $parts[] = $this->getMatch($patternKeys[$z]);
109
            }
110
111
            // query whether or not, the OK file exists, if yes append it
112 1
            if (file_exists($okFilename = $this->prepareOkFilename($parts))) {
113 1
                $okFilenames[] = $okFilename;
114
            }
115
        }
116
117
        // prepare and return the pattern for the OK file
118 1
        return $okFilenames;
119
    }
120
121
    /**
122
     * Queries whether or not, the passed filename should be handled by the subject.
123
     *
124
     * @param string $filename The filename to query for
125
     *
126
     * @return boolean TRUE if the file should be handled, else FALSE
127
     */
128 1
    public function shouldBeHandled($filename)
129
    {
130
131
        // update the matches, if the pattern matches
132 1
        $result = parent::shouldBeHandled($filename);
133
134
        // initialize the flag: we assume that the file is in an OK file
135 1
        $inOkFile = true;
136
137
        // query whether or not the subject requests an OK file
138 1
        if ($this->getSubjectConfiguration()->isOkFileNeeded()) {
139
            // try to load the expected OK filenames
140 1
            if (sizeof($okFilenames = $this->getOkFilenames()) === 0) {
141
                // stop processing, because the needed OK file is NOT available
142
                return false;
143
            }
144
145
            // reset the flag: assumption from initialization is invalid now
146 1
            $inOkFile = false;
147
148
            // iterate over the found OK filenames (should usually be only one, but could be more)
149 1
            foreach ($okFilenames as $okFilename) {
150
                // if the OK filename matches the CSV filename AND the OK file is empty
151 1
                if ($this->isEqualFilename($filename, $okFilename) && filesize($okFilename) === 0) {
152
                    $inOkFile = true;
153
                    break;
154
                }
155
156
                // load the OK file content
157 1
                $okFileLines = file($okFilename);
158
159
                // remove line breaks
160 1
                array_walk($okFileLines, function (&$line) {
161 1
                    $line = trim($line, PHP_EOL);
162 1
                });
163
164
                // query whether or not the OK file contains the filename
165 1
                if (in_array(basename($filename), $okFileLines)) {
166 1
                    $inOkFile = true;
167 1
                    break;
168
                }
169
            }
170
171
            // reset the matches because we've a new bunch
172 1
            if ($inOkFile === false) {
173 1
                $this->reset();
174
            }
175
        }
176
177
        // stop processing, because the filename doesn't match the subjects pattern
178 1
        return $result && $inOkFile;
179
    }
180
181
    /**
182
     * Query whether or not, the passed CSV filename is in the OK file. If the filename was found,
183
     * the OK file will be cleaned-up.
184
     *
185
     * @param string $filename The filename to be cleaned-up
186
     *
187
     * @return void
188
     * @throws \Exception Is thrown, if the passed filename is NOT in the OK file or the OK can not be cleaned-up
189
     */
190
    public function cleanUpOkFile($filename)
191
    {
192
193
        // query whether or not the subject needs an OK file, if yes remove the filename from the file
194
        if ($this->getSubjectConfiguration()->isOkFileNeeded() === false) {
195
            return;
196
        }
197
198
        try {
199
            // try to load the expected OK filenames
200
            if (sizeof($okFilenames = $this->getOkFilenames()) === 0) {
201
                throw new MissingOkFileException(sprintf('Can\'t find a OK filename for file %s', $filename));
202
            }
203
204
            // iterate over the found OK filenames (should usually be only one, but could be more)
205
            foreach ($okFilenames as $okFilename) {
206
                // clear the filecache
207
                \clearstatcache();
208
                // if the OK filename matches the CSV filename AND the OK file is empty
209
                if ($this->isEqualFilename($filename, $okFilename) && filesize($okFilename) === 0) {
210
                    unlink($okFilename);
211
                    return;
212
                }
213
214
                // else, remove the CSV filename from the OK file
215
                $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...
216
                fclose($fh);
217
218
                // if the OK file is empty, delete the file
219
                if (filesize($okFilename) === 0) {
220
                    unlink($okFilename);
221
                }
222
223
                // return immediately
224
                return;
225
            }
226
227
            // throw an exception if either no OK file has been found,
228
            // or the CSV file is not in one of the OK files
229
            throw new \Exception(
230
                sprintf(
231
                    'Can\'t found filename %s in one of the expected OK files: %s',
232
                    $filename,
233
                    implode(', ', $okFilenames)
234
                )
235
            );
236
        } catch (LineNotFoundException $lne) {
237
            // wrap and re-throw the exception
238
            throw new \Exception(
239
                sprintf(
240
                    'Can\'t remove filename %s from OK file: %s',
241
                    $filename,
242
                    $okFilename
243
                ),
244
                null,
245
                $lne
246
            );
247
        }
248
    }
249
250
    /**
251
     * Loads the files from the source directory and return's them sorted.
252
     *
253
     * @param string $serial The unique identifier of the actual import process
254
     *
255
     * @return array The array with the files matching the subjects suffix
256
     * @throws \Exception Is thrown, when the source directory is NOT available
257
     * @throws \TechDivision\Import\Exceptions\MissingOkFileException Is thrown, if files to be processed are available but the mandatory OK file is missing
258
     */
259
    public function loadFiles($serial)
260
    {
261
262
        // initialize the array with the files that has to be handled
263
        $filesToHandle = array();
264
265
        // load the files that match the regular expressiong
266
        $files = parent::loadFiles($serial);
267
268
        // query whether or not the file has to be handled
269
        foreach ($files as $file) {
270
            // query whether or not the file has to be handled
271
            if ($this->shouldBeHandled($file)) {
272
                // clean-up the OK file
273
                $this->cleanUpOkFile($file);
274
                // append the file to the list of files that has to be handled
275
                $filesToHandle[] = $file;
276
            }
277
        }
278
279
        // stop processing, if files ARE available, an OK file IS mandatory, but
280
        // NO file will be processed (because of a missing/not matching OK file)
281
        if ($this->getSubjectConfiguration()->isOkFileNeeded() && sizeof($files) > 0 && sizeof($filesToHandle) === 0) {
282
            throw new MissingOkFileException(
283
                sprintf(
284
                    'Stop processing, because can\'t find the mandatory OK file to process at least one of %s',
285
                    implode(', ', $files)
286
                )
287
            );
288
        }
289
290
        // return the array with the files that has to be handled
291
        return $filesToHandle;
292
    }
293
}
294