Passed
Branch v3 (3b6795)
by Andrew
07:36
created

FileController::actionDisplayErrors()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 39
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 25
c 0
b 0
f 0
dl 0
loc 39
ccs 0
cts 34
cp 0
rs 9.52
cc 2
nc 2
nop 0
crap 6
1
<?php
2
/**
3
 * Retour plugin for Craft CMS 3.x
4
 *
5
 * Retour allows you to intelligently redirect legacy URLs, so that you don't
6
 * lose SEO value when rebuilding & restructuring a website
7
 *
8
 * @link      https://nystudio107.com/
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
9
 * @copyright Copyright (c) 2018 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
10
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
11
12
namespace nystudio107\retour\controllers;
13
14
use Craft;
15
use craft\db\Query;
16
use craft\helpers\ArrayHelper;
17
use craft\helpers\UrlHelper;
18
use craft\web\Controller;
19
use League\Csv\AbstractCsv;
20
use League\Csv\Exception;
21
use League\Csv\Reader;
22
use League\Csv\Statement;
23
use League\Csv\Writer;
24
use nystudio107\retour\assetbundles\retour\RetourImportAsset;
25
use nystudio107\retour\helpers\FileLog;
26
use nystudio107\retour\helpers\MultiSite as MultiSiteHelper;
27
use nystudio107\retour\helpers\Permission as PermissionHelper;
28
use nystudio107\retour\helpers\Version as VersionHelper;
29
use nystudio107\retour\Retour;
30
use yii\base\InvalidConfigException;
31
use yii\web\Response;
32
use yii\web\UploadedFile;
33
34
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
35
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
36
 * @package   Retour
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
37
 * @since     3.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
38
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
39
class FileController extends Controller
40
{
41
    // Constants
42
    // =========================================================================
43
44
    const DOCUMENTATION_URL = 'https://github.com/nystudio107/craft-retour/';
45
46
    const LOG_FILE_NAME = 'retour-csv-import-errors';
47
48
    const EXPORT_REDIRECTS_CSV_FIELDS = [
49
        'redirectSrcUrl' => 'Legacy URL Pattern',
50
        'redirectDestUrl' => 'Redirect To',
51
        'redirectMatchType' => 'Match Type',
52
        'redirectHttpCode' => 'HTTP Status',
53
        'siteId' => 'Site ID',
54
        'redirectSrcMatch' => 'Legacy URL Match Type',
55
        'hitCount' => 'Hits',
56
        'hitLastTime' => 'Last Hit',
57
    ];
58
59
    const EXPORT_STATISTICS_CSV_FIELDS = [
60
        'redirectSrcUrl' => '404 File Not Found URL',
61
        'referrerUrl' => 'Last Referrer URL',
62
        'remoteIp' => 'Remote IP',
63
        'hitCount' => 'Hits',
64
        'hitLastTime' => 'Last Hit',
65
        'handledByRetour' => 'Handled',
66
        'siteId' => 'Site ID',
67
    ];
68
69
    const IMPORT_REDIRECTS_CSV_FIELDS = [
70
        'redirectSrcUrl',
71
        'redirectDestUrl',
72
        'redirectMatchType',
73
        'redirectHttpCode',
74
        'siteId',
75
        'redirectSrcMatch',
76
        'hitCount'
77
    ];
78
79
    // Protected Properties
80
    // =========================================================================
81
82
    protected $allowAnonymous = [];
83
84
    // Public Methods
85
    // =========================================================================
86
87
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
88
     * @throws \yii\web\BadRequestHttpException
89
     * @throws \yii\web\ForbiddenHttpException
90
     * @throws \craft\errors\MissingComponentException
91
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
92
    public function actionImportCsvColumns()
93
    {
94
        PermissionHelper::controllerPermissionCheck('retour:redirects');
95
        // If your CSV document was created or is read on a Macintosh computer,
96
        // add the following lines before using the library to help PHP detect line ending in Mac OS X
97
        if (!ini_get('auto_detect_line_endings')) {
98
            ini_set('auto_detect_line_endings', '1');
99
        }
100
        $this->requirePostRequest();
101
        $filename = Craft::$app->getRequest()->getRequiredBodyParam('filename');
102
        $columns = Craft::$app->getRequest()->getRequiredBodyParam('columns');
103
        $headers = null;
104
        // Log the import
105
        Filelog::delete(self::LOG_FILE_NAME);
106
        FileLog::create(self::LOG_FILE_NAME, 'nystudio107\retour\*');
107
        try {
108
            $csv = Reader::createFromPath($filename);
109
            $csv->setDelimiter(Retour::$settings->csvColumnDelimiter ?? ',');
110
            $headers = array_flip($csv->fetchOne(0));
111
        } catch (\Exception $e) {
112
            // If this throws an exception, try to read the CSV file from the data cache
113
            // This can happen on load balancer setups where the Craft temp directory isn't shared
114
            $cache = Craft::$app->getCache();
115
            $cachedFile = $cache->get($filename);
116
            if ($cachedFile !== false) {
117
                $csv = Reader::createFromString($cachedFile);
118
                try {
119
                    $csv->setDelimiter(Retour::$settings->csvColumnDelimiter ?? ',');
120
                } catch (Exception $e) {
121
                    Craft::error($e, __METHOD__);
122
                }
123
                $headers = array_flip($csv->fetchOne(0));
124
                $cache->delete($filename);
125
            } else {
126
                Craft::error("Could not import ${$filename} from the file system, or the cache.", __METHOD__);
127
            }
128
        }
129
        $hasErrors = false;
130
        // If we have headers, then we have a file, so parse it
131
        if ($headers !== null) {
132
            switch (VersionHelper::getLeagueCsvVersion()) {
133
                case 8:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
134
                    $hasErrors = $this->importCsvApi8($csv, $columns, $headers);
135
                    break;
136
                case 9:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
137
                    $hasErrors = $this->importCsvApi9($csv, $columns, $headers);
138
                    break;
139
                default:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
140
                    Craft::$app->getSession()->setNotice(Craft::t('retour', 'Unknown league/csv package API version'));
141
                    break;
142
            }
143
            @unlink($filename);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

143
            /** @scrutinizer ignore-unhandled */ @unlink($filename);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
144
            Retour::$plugin->clearAllCaches();
145
            Craft::$app->getSession()->setNotice(Craft::t('retour', 'Redirects imported from CSV file.'));
146
        } else {
147
            Craft::$app->getSession()->setError(Craft::t('retour', 'Redirects could not be imported.'));
148
        }
149
        if ($hasErrors) {
150
            $this->redirect(UrlHelper::actionUrl('retour/file/display-errors'));
151
        } else {
152
            $this->redirect('retour/redirects');
153
        }
154
    }
155
156
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
157
     * @param string|null $siteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
158
     *
159
     * @return Response
160
     * @throws \yii\web\ForbiddenHttpException
161
     * @throws \yii\web\NotFoundHttpException
162
     */
163
    public function actionImportCsv(string $siteHandle = null): Response
164
    {
165
        $variables = [];
166
        PermissionHelper::controllerPermissionCheck('retour:redirects');
167
        // If your CSV document was created or is read on a Macintosh computer,
168
        // add the following lines before using the library to help PHP detect line ending in Mac OS X
169
        if (!ini_get('auto_detect_line_endings')) {
170
            ini_set('auto_detect_line_endings', '1');
171
        }
172
        // Get the site to edit
173
        $siteId = MultiSiteHelper::getSiteIdFromHandle($siteHandle);
174
        $pluginName = Retour::$settings->pluginName;
175
        $templateTitle = Craft::t('retour', 'Import CSV File');
176
        $view = Craft::$app->getView();
177
        // Asset bundle
178
        try {
179
            $view->registerAssetBundle(RetourImportAsset::class);
180
        } catch (InvalidConfigException $e) {
181
            Craft::error($e->getMessage(), __METHOD__);
182
        }
183
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
184
            '@nystudio107/retour/web/assets/dist',
185
            true
0 ignored issues
show
Unused Code introduced by
The call to yii\web\AssetManager::getPublishedUrl() has too many arguments starting with true. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

185
        /** @scrutinizer ignore-call */ 
186
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
186
        );
187
        // Enabled sites
188
        MultiSiteHelper::setMultiSiteVariables($siteHandle, $siteId, $variables);
189
        $variables['controllerHandle'] = 'file';
190
191
        // Basic variables
192
        $variables['fullPageForm'] = true;
193
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
194
        $variables['pluginName'] = $pluginName;
195
        $variables['title'] = $templateTitle;
196
        $siteHandleUri = Craft::$app->isMultiSite ? '/' . $siteHandle : '';
197
        $variables['crumbs'] = [
198
            [
199
                'label' => $pluginName,
200
                'url' => UrlHelper::cpUrl('retour'),
201
            ],
202
            [
203
                'label' => 'Redirects',
204
                'url' => UrlHelper::cpUrl('retour/redirects' . $siteHandleUri),
205
            ],
206
        ];
207
        $variables['docTitle'] = "{$pluginName} - Redirects - {$templateTitle}";
208
        $variables['selectedSubnavItem'] = 'redirects';
209
210
        // The CSV file
211
        $file = UploadedFile::getInstanceByName('file');
212
        if ($file !== null) {
213
            $filename = uniqid($file->name, true);
214
            $filePath = Craft::$app->getPath()->getTempPath() . DIRECTORY_SEPARATOR . $filename;
215
            $file->saveAs($filePath, false);
216
            // Also save the file to the cache as a backup way to access it
217
            $cache = Craft::$app->getCache();
218
            $fileHandle = fopen($filePath, 'r');
219
            if ($fileHandle) {
0 ignored issues
show
introduced by
$fileHandle is of type resource, thus it always evaluated to false.
Loading history...
220
                $fileContents = fgets($fileHandle);
221
                if ($fileContents) {
222
                    $cache->set($filePath, $fileContents);
223
                }
224
                fclose($fileHandle);
225
            }
226
            // Read in the headers
227
            $csv = Reader::createFromPath($file->tempName);
228
            try {
229
                $csv->setDelimiter(Retour::$settings->csvColumnDelimiter ?? ',');
230
            } catch (Exception $e) {
231
                Craft::error($e, __METHOD__);
232
            }
233
            $headers = $csv->fetchOne(0);
234
            Craft::info(print_r($headers, true), __METHOD__);
0 ignored issues
show
Bug introduced by
It seems like print_r($headers, true) can also be of type true; however, parameter $message of yii\BaseYii::info() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

234
            Craft::info(/** @scrutinizer ignore-type */ print_r($headers, true), __METHOD__);
Loading history...
235
            $variables['headers'] = $headers;
236
            $variables['filename'] = $filePath;
237
        }
238
239
        // Render the template
240
        return $this->renderTemplate('retour/import/index', $variables);
241
    }
242
243
    /**
244
     * Display the error log if something went wrong
245
     *
246
     * @return Response
247
     * @throws \yii\web\ForbiddenHttpException
248
     */
249
    public function actionDisplayErrors(): Response
250
    {
251
        $variables = [];
252
        PermissionHelper::controllerPermissionCheck('retour:redirects');
253
        $pluginName = Retour::$settings->pluginName;
254
        $templateTitle = Craft::t('retour', 'CSV File Import Errors');
255
        $view = Craft::$app->getView();
256
        // Asset bundle
257
        try {
258
            $view->registerAssetBundle(RetourImportAsset::class);
259
        } catch (InvalidConfigException $e) {
260
            Craft::error($e->getMessage(), __METHOD__);
261
        }
262
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
263
            '@nystudio107/retour/web/assets/dist',
264
            true
0 ignored issues
show
Unused Code introduced by
The call to yii\web\AssetManager::getPublishedUrl() has too many arguments starting with true. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

264
        /** @scrutinizer ignore-call */ 
265
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
265
        );
266
        // Basic variables
267
        $variables['fullPageForm'] = true;
268
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
269
        $variables['pluginName'] = $pluginName;
270
        $variables['title'] = $templateTitle;
271
        $variables['crumbs'] = [
272
            [
273
                'label' => $pluginName,
274
                'url' => UrlHelper::cpUrl('retour'),
275
            ],
276
            [
277
                'label' => 'Redirects',
278
                'url' => UrlHelper::cpUrl('retour/redirects'),
279
            ],
280
        ];
281
        $variables['docTitle'] = "{$pluginName} - Redirects - {$templateTitle}";
282
        $variables['selectedSubnavItem'] = 'redirects';
283
        // The error log
284
        $variables['errorLogContents'] = FileLog::getContents(self::LOG_FILE_NAME);
285
286
        // Render the template
287
        return $this->renderTemplate('retour/import/errors', $variables);
288
    }
289
290
    /**
291
     * Export the statistics table as a CSV file
292
     *
293
     * @throws \yii\web\ForbiddenHttpException
294
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
295
    public function actionExportStatistics()
296
    {
297
        PermissionHelper::controllerPermissionCheck('retour:redirects');
298
        $this->exportCsvFile('retour-statistics', '{{%retour_stats}}', self::EXPORT_STATISTICS_CSV_FIELDS);
299
    }
300
301
    /**
302
     * Export the redirects table as a CSV file
303
     *
304
     * @throws \yii\web\ForbiddenHttpException
305
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
306
    public function actionExportRedirects()
307
    {
308
        PermissionHelper::controllerPermissionCheck('retour:redirects');
309
        $this->exportCsvFile('retour-redirects', '{{%retour_static_redirects}}', self::EXPORT_REDIRECTS_CSV_FIELDS);
310
    }
311
312
    // Public Methods
313
    // =========================================================================
314
315
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
316
     * @param string $filename
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
317
     * @param string $table
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
318
     * @param array $columns
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
319
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
320
    protected function exportCsvFile(string $filename, string $table, array $columns)
321
    {
322
        // If your CSV document was created or is read on a Macintosh computer,
323
        // add the following lines before using the library to help PHP detect line ending in Mac OS X
324
        if (!ini_get('auto_detect_line_endings')) {
325
            ini_set('auto_detect_line_endings', '1');
326
        }
327
        // Query the db table
328
        $data = (new Query())
329
            ->from([$table])
330
            ->select(array_keys($columns))
331
            ->orderBy('hitCount DESC')
332
            ->all();
333
        // Create our CSV file writer
334
        $csv = Writer::createFromFileObject(new \SplTempFileObject());
335
        try {
336
            $csv->setDelimiter(Retour::$settings->csvColumnDelimiter ?? ',');
337
        } catch (Exception $e) {
338
            Craft::error($e, __METHOD__);
339
        }
340
        $csv->insertOne(array_values($columns));
341
        $csv->insertAll($data);
342
        $csv->output($filename . '.csv');
343
        exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
344
    }
345
346
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
347
     * @param AbstractCsv $csv
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
348
     * @param array $columns
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 7 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
349
     * @param array $headers
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 7 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
350
     * @return bool whether the import has any errors
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
351
     */
352
    protected function importCsvApi8(AbstractCsv $csv, array $columns, array $headers): bool
353
    {
354
        $hasErrors = false;
355
        $csv->setOffset(1);
0 ignored issues
show
Bug introduced by
The method setOffset() does not exist on League\Csv\AbstractCsv. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

355
        $csv->/** @scrutinizer ignore-call */ 
356
              setOffset(1);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
356
        $columns = ArrayHelper::filterEmptyStringsFromArray($columns);
357
        $rowIndex = 1;
358
        $csv->each(function ($row) use ($headers, $columns, &$rowIndex, &$hasErrors) {
0 ignored issues
show
Bug introduced by
The method each() does not exist on League\Csv\AbstractCsv. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

358
        $csv->/** @scrutinizer ignore-call */ 
359
              each(function ($row) use ($headers, $columns, &$rowIndex, &$hasErrors) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
359
            $redirectConfig = [
360
                'id' => 0,
361
            ];
362
            $index = 0;
363
            foreach (self::IMPORT_REDIRECTS_CSV_FIELDS as $importField) {
364
                if (isset($columns[$index], $headers[$columns[$index]])) {
365
                    $redirectConfig[$importField] = empty($row[$headers[$columns[$index]]])
366
                        ? null
367
                        : $row[$headers[$columns[$index]]];
368
                }
369
                $index++;
370
            }
371
            $redirectDump = print_r($redirectConfig, true);
372
            Craft::debug("-> ROW #$rowIndex contents: " . $redirectDump, __METHOD__);
0 ignored issues
show
Bug introduced by
Are you sure $redirectDump of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

372
            Craft::debug("-> ROW #$rowIndex contents: " . /** @scrutinizer ignore-type */ $redirectDump, __METHOD__);
Loading history...
373
            if (!Retour::$plugin->redirects->saveRedirect($redirectConfig)) {
374
                Craft::info("-> ROW #$rowIndex contents: " . $redirectDump, __METHOD__);
375
                $hasErrors = true;
376
            }
377
            $rowIndex++;
378
379
            return true;
380
        });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
381
382
        return $hasErrors;
383
    }
384
385
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
386
     * @param AbstractCsv $csv
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
387
     * @param array $columns
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 7 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
388
     * @param array $headers
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 7 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
389
     * @return bool whether the import has any errors
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
390
     * @throws Exception
0 ignored issues
show
Coding Style introduced by
Tag @throws cannot be grouped with parameter tags in a doc comment
Loading history...
391
     */
392
    protected function importCsvApi9(AbstractCsv $csv, array $columns, array $headers): bool
393
    {
394
        $hasErrors = false;
395
        $stmt = (new Statement())
396
            ->offset(1);
397
        $rows = $stmt->process($csv);
0 ignored issues
show
Bug introduced by
$csv of type League\Csv\AbstractCsv is incompatible with the type League\Csv\TabularDataReader expected by parameter $tabular_data of League\Csv\Statement::process(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

397
        $rows = $stmt->process(/** @scrutinizer ignore-type */ $csv);
Loading history...
398
        $columns = ArrayHelper::filterEmptyStringsFromArray($columns);
399
        $rowIndex = 1;
400
        foreach ($rows as $row) {
401
            $redirectConfig = [
402
                'id' => 0,
403
            ];
404
            $index = 0;
405
            foreach (self::IMPORT_REDIRECTS_CSV_FIELDS as $importField) {
406
                if (isset($columns[$index], $headers[$columns[$index]])) {
407
                    $redirectConfig[$importField] = empty($row[$headers[$columns[$index]]])
408
                        ? null
409
                        : $row[$headers[$columns[$index]]];
410
                }
411
                $index++;
412
            }
413
            $redirectDump = print_r($redirectConfig, true);
414
            Craft::debug("-> ROW #$rowIndex contents: " . $redirectDump, __METHOD__);
0 ignored issues
show
Bug introduced by
Are you sure $redirectDump of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

414
            Craft::debug("-> ROW #$rowIndex contents: " . /** @scrutinizer ignore-type */ $redirectDump, __METHOD__);
Loading history...
415
            if (!Retour::$plugin->redirects->saveRedirect($redirectConfig)) {
416
                Craft::info("-> ROW #$rowIndex contents: " . $redirectDump, __METHOD__);
417
                $hasErrors = true;
418
            }
419
            $rowIndex++;
420
        }
421
422
        return $hasErrors;
423
    }
424
}
425