FileController   A
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 396
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 37
eloc 224
c 4
b 0
f 0
dl 0
loc 396
ccs 0
cts 252
cp 0
rs 9.44

8 Methods

Rating   Name   Duplication   Size   Complexity  
A importCsvApi8() 0 33 5
B importCsvApi9() 0 31 6
A actionExportStatistics() 0 9 2
A actionDisplayErrors() 0 39 2
A actionExportRedirects() 0 9 2
A exportCsvFile() 0 24 3
B actionImportCsv() 0 73 7
C actionImportCsvColumns() 0 62 10
1
<?php
2
/**
3
 * Retour plugin for Craft CMS
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\errors\MissingComponentException;
17
use craft\helpers\ArrayHelper;
18
use craft\helpers\UrlHelper;
19
use craft\web\Controller;
20
use League\Csv\AbstractCsv;
21
use League\Csv\Exception;
22
use League\Csv\Reader;
23
use League\Csv\Statement;
24
use League\Csv\Writer;
25
use nystudio107\retour\assetbundles\retour\RetourImportAsset;
26
use nystudio107\retour\helpers\FileLog;
27
use nystudio107\retour\helpers\MultiSite as MultiSiteHelper;
28
use nystudio107\retour\helpers\Permission as PermissionHelper;
29
use nystudio107\retour\helpers\Version as VersionHelper;
30
use nystudio107\retour\Retour;
31
use SplTempFileObject;
32
use yii\base\InvalidConfigException;
33
use yii\web\BadRequestHttpException;
34
use yii\web\ForbiddenHttpException;
35
use yii\web\NotFoundHttpException;
36
use yii\web\Response;
37
use yii\web\UploadedFile;
38
39
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
40
 * @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...
41
 * @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...
42
 * @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...
43
 */
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...
44
class FileController extends Controller
45
{
46
    // Constants
47
    // =========================================================================
48
49
    const DOCUMENTATION_URL = 'https://github.com/nystudio107/craft-retour/';
50
51
    const LOG_FILE_NAME = 'retour-csv-import-errors';
52
53
    const EXPORT_REDIRECTS_CSV_FIELDS = [
54
        'redirectSrcUrl' => 'Legacy URL Pattern',
55
        'redirectDestUrl' => 'Redirect To',
56
        'redirectMatchType' => 'Match Type',
57
        'redirectHttpCode' => 'HTTP Status',
58
        'siteId' => 'Site ID',
59
        'redirectSrcMatch' => 'Legacy URL Match Type',
60
        'hitCount' => 'Hits',
61
        'associatedElementId' => 'Short Link Element ID',
62
        'hitLastTime' => 'Last Hit',
63
        'priority' => 'Priority',
64
    ];
65
66
    const EXPORT_STATISTICS_CSV_FIELDS = [
67
        'redirectSrcUrl' => '404 File Not Found URL',
68
        'referrerUrl' => 'Last Referrer URL',
69
        'remoteIp' => 'Remote IP',
70
        'hitCount' => 'Hits',
71
        'hitLastTime' => 'Last Hit',
72
        'handledByRetour' => 'Handled',
73
        'siteId' => 'Site ID',
74
    ];
75
76
    const IMPORT_REDIRECTS_CSV_FIELDS = [
77
        'redirectSrcUrl',
78
        'redirectDestUrl',
79
        'redirectMatchType',
80
        'redirectHttpCode',
81
        'siteId',
82
        'redirectSrcMatch',
83
        'hitCount',
84
        'associatedElementId',
85
        'priority',
86
    ];
87
88
    // Protected Properties
89
    // =========================================================================
90
91
    protected $allowAnonymous = [];
92
93
    // Public Methods
94
    // =========================================================================
95
96
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
97
     * @throws BadRequestHttpException
98
     * @throws ForbiddenHttpException
99
     * @throws MissingComponentException
100
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
101
    public function actionImportCsvColumns()
102
    {
103
        PermissionHelper::controllerPermissionCheck('retour:redirects');
104
        // If your CSV document was created or is read on a Macintosh computer,
105
        // add the following lines before using the library to help PHP detect line ending in Mac OS X
106
        if (!ini_get('auto_detect_line_endings')) {
107
            ini_set('auto_detect_line_endings', '1');
108
        }
109
        $csv = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $csv is dead and can be removed.
Loading history...
110
        $this->requirePostRequest();
111
        $filename = Craft::$app->getRequest()->getRequiredBodyParam('filename');
112
        $columns = Craft::$app->getRequest()->getRequiredBodyParam('columns');
113
        $headers = null;
114
        // Log the import
115
        Filelog::delete(self::LOG_FILE_NAME);
116
        FileLog::create(self::LOG_FILE_NAME, 'nystudio107\retour\*');
117
        try {
118
            $csv = Reader::createFromPath($filename);
119
            $csv->setDelimiter(Retour::$settings->csvColumnDelimiter);
120
            $headers = array_flip($csv->fetchOne(0));
121
        } catch (\Exception $e) {
122
            // If this throws an exception, try to read the CSV file from the data cache
123
            // This can happen on load balancer setups where the Craft temp directory isn't shared
124
            $cache = Craft::$app->getCache();
125
            $cachedFile = $cache->get($filename);
126
            if ($cachedFile !== false) {
127
                $csv = Reader::createFromString($cachedFile);
128
                try {
129
                    $csv->setDelimiter(Retour::$settings->csvColumnDelimiter);
130
                } catch (Exception $e) {
131
                    Craft::error($e, __METHOD__);
132
                }
133
                $headers = array_flip($csv->fetchOne(0));
134
                $cache->delete($filename);
135
            } else {
136
                Craft::error("Could not import ${$filename} from the file system, or the cache.", __METHOD__);
137
            }
138
        }
139
        $hasErrors = false;
140
        // If we have headers, then we have a file, so parse it
141
        if ($csv && $headers) {
142
            switch (VersionHelper::getLeagueCsvVersion()) {
143
                case 8:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
144
                    $hasErrors = $this->importCsvApi8($csv, $columns, $headers);
145
                    break;
146
                case 9:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
147
                    $hasErrors = $this->importCsvApi9($csv, $columns, $headers);
148
                    break;
149
                default:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
150
                    Craft::$app->getSession()->setNotice(Craft::t('retour', 'Unknown league/csv package API version'));
151
                    break;
152
            }
153
            @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

153
            /** @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...
154
            Retour::$plugin->clearAllCaches();
155
            Craft::$app->getSession()->setNotice(Craft::t('retour', 'Redirects imported from CSV file.'));
156
        } else {
157
            Craft::$app->getSession()->setError(Craft::t('retour', 'Redirects could not be imported.'));
158
        }
159
        if ($hasErrors) {
160
            $this->redirect(UrlHelper::actionUrl('retour/file/display-errors'));
161
        } else {
162
            $this->redirect('retour/redirects');
163
        }
164
    }
165
166
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
167
     * @param string|null $siteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
168
     *
169
     * @return Response
170
     * @throws ForbiddenHttpException
171
     * @throws NotFoundHttpException
172
     */
173
    public function actionImportCsv(string $siteHandle = null): Response
174
    {
175
        $variables = [];
176
        PermissionHelper::controllerPermissionCheck('retour:redirects');
177
        // If your CSV document was created or is read on a Macintosh computer,
178
        // add the following lines before using the library to help PHP detect line ending in Mac OS X
179
        if (!ini_get('auto_detect_line_endings')) {
180
            ini_set('auto_detect_line_endings', '1');
181
        }
182
        // Get the site to edit
183
        $siteId = MultiSiteHelper::getSiteIdFromHandle($siteHandle);
184
        $pluginName = Retour::$settings->pluginName;
185
        $templateTitle = Craft::t('retour', 'Import CSV File');
186
        $view = Craft::$app->getView();
187
        // Asset bundle
188
        try {
189
            $view->registerAssetBundle(RetourImportAsset::class);
190
        } catch (InvalidConfigException $e) {
191
            Craft::error($e->getMessage(), __METHOD__);
192
        }
193
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
194
            '@nystudio107/retour/web/assets/dist',
195
            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

195
        /** @scrutinizer ignore-call */ 
196
        $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...
196
        );
197
        // Enabled sites
198
        MultiSiteHelper::setMultiSiteVariables($siteHandle, $siteId, $variables);
199
        $variables['controllerHandle'] = 'file';
200
201
        // Basic variables
202
        $variables['fullPageForm'] = true;
203
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
204
        $variables['pluginName'] = $pluginName;
205
        $variables['title'] = $templateTitle;
206
        $siteHandleUri = Craft::$app->isMultiSite ? '/' . $siteHandle : '';
207
        $variables['crumbs'] = [
208
            [
209
                'label' => $pluginName,
210
                'url' => UrlHelper::cpUrl('retour'),
211
            ],
212
            [
213
                'label' => 'Redirects',
214
                'url' => UrlHelper::cpUrl('retour/redirects' . $siteHandleUri),
215
            ],
216
        ];
217
        $variables['docTitle'] = "{$pluginName} - Redirects - {$templateTitle}";
218
        $variables['selectedSubnavItem'] = 'redirects';
219
220
        // The CSV file
221
        $file = UploadedFile::getInstanceByName('file');
222
        if ($file !== null) {
223
            $filename = uniqid($file->name, true);
224
            $filePath = Craft::$app->getPath()->getTempPath() . DIRECTORY_SEPARATOR . $filename;
225
            $file->saveAs($filePath, false);
226
            // Also save the file to the cache as a backup way to access it
227
            $fileContents = @file_get_contents($filePath);
228
            if ($fileContents) {
229
                Craft::$app->getCache()->set($filePath, $fileContents);
230
            }
231
            // Read in the headers
232
            $csv = Reader::createFromPath($file->tempName);
233
            try {
234
                $csv->setDelimiter(Retour::$settings->csvColumnDelimiter);
235
            } catch (Exception $e) {
236
                Craft::error($e, __METHOD__);
237
            }
238
            $headers = $csv->fetchOne(0);
239
            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

239
            Craft::info(/** @scrutinizer ignore-type */ print_r($headers, true), __METHOD__);
Loading history...
240
            $variables['headers'] = $headers;
241
            $variables['filename'] = $filePath;
242
        }
243
244
        // Render the template
245
        return $this->renderTemplate('retour/import/index', $variables);
246
    }
247
248
    /**
249
     * Display the error log if something went wrong
250
     *
251
     * @return Response
252
     * @throws ForbiddenHttpException
253
     */
254
    public function actionDisplayErrors(): Response
255
    {
256
        $variables = [];
257
        PermissionHelper::controllerPermissionCheck('retour:redirects');
258
        $pluginName = Retour::$settings->pluginName;
259
        $templateTitle = Craft::t('retour', 'CSV File Import Errors');
260
        $view = Craft::$app->getView();
261
        // Asset bundle
262
        try {
263
            $view->registerAssetBundle(RetourImportAsset::class);
264
        } catch (InvalidConfigException $e) {
265
            Craft::error($e->getMessage(), __METHOD__);
266
        }
267
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
268
            '@nystudio107/retour/web/assets/dist',
269
            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

269
        /** @scrutinizer ignore-call */ 
270
        $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...
270
        );
271
        // Basic variables
272
        $variables['fullPageForm'] = true;
273
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
274
        $variables['pluginName'] = $pluginName;
275
        $variables['title'] = $templateTitle;
276
        $variables['crumbs'] = [
277
            [
278
                'label' => $pluginName,
279
                'url' => UrlHelper::cpUrl('retour'),
280
            ],
281
            [
282
                'label' => 'Redirects',
283
                'url' => UrlHelper::cpUrl('retour/redirects'),
284
            ],
285
        ];
286
        $variables['docTitle'] = "{$pluginName} - Redirects - {$templateTitle}";
287
        $variables['selectedSubnavItem'] = 'redirects';
288
        // The error log
289
        $variables['errorLogContents'] = FileLog::getContents(self::LOG_FILE_NAME);
290
291
        // Render the template
292
        return $this->renderTemplate('retour/import/errors', $variables);
293
    }
294
295
    /**
296
     * Export the statistics table as a CSV file
297
     *
298
     * @throws ForbiddenHttpException
299
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
300
    public function actionExportStatistics()
301
    {
302
        PermissionHelper::controllerPermissionCheck('retour:redirects');
303
        //Allow the fields to be localized
304
        $fields = self::EXPORT_STATISTICS_CSV_FIELDS;
305
        foreach ($fields as $key => $field) {
306
            $fields[$key] = Craft::t('retour', $field);
307
        }
308
        $this->exportCsvFile('retour-statistics', '{{%retour_stats}}', $fields);
309
    }
310
311
    /**
312
     * Export the redirects table as a CSV file
313
     *
314
     * @throws ForbiddenHttpException
315
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
316
    public function actionExportRedirects()
317
    {
318
        PermissionHelper::controllerPermissionCheck('retour:redirects');
319
        //Allow the fields to be localized
320
        $fields = self::EXPORT_REDIRECTS_CSV_FIELDS;
321
        foreach ($fields as $key => $field) {
322
            $fields[$key] = Craft::t('retour', $field);
323
        }
324
        $this->exportCsvFile('retour-redirects', '{{%retour_static_redirects}}', $fields);
325
    }
326
327
    // Public Methods
328
    // =========================================================================
329
330
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
331
     * @param string $filename
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
332
     * @param string $table
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
333
     * @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...
334
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
335
    protected function exportCsvFile(string $filename, string $table, array $columns)
336
    {
337
        // If your CSV document was created or is read on a Macintosh computer,
338
        // add the following lines before using the library to help PHP detect line ending in Mac OS X
339
        if (!ini_get('auto_detect_line_endings')) {
340
            ini_set('auto_detect_line_endings', '1');
341
        }
342
        // Query the db table
343
        $data = (new Query())
344
            ->from([$table])
345
            ->select(array_keys($columns))
346
            ->orderBy('hitCount DESC')
347
            ->all();
348
        // Create our CSV file writer
349
        $csv = Writer::createFromFileObject(new SplTempFileObject());
350
        try {
351
            $csv->setDelimiter(Retour::$settings->csvColumnDelimiter);
352
        } catch (Exception $e) {
353
            Craft::error($e, __METHOD__);
354
        }
355
        $csv->insertOne(array_values($columns));
356
        $csv->insertAll($data);
357
        $csv->output($filename . '.csv');
358
        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...
359
    }
360
361
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
362
     * @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...
363
     * @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...
364
     * @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...
365
     * @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...
366
     */
367
    protected function importCsvApi8(AbstractCsv $csv, array $columns, array $headers): bool
368
    {
369
        $hasErrors = false;
370
        /** @phpstan-ignore-next-line */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
371
        $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

371
        $csv->/** @scrutinizer ignore-call */ 
372
              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...
372
        $columns = ArrayHelper::filterEmptyStringsFromArray($columns);
373
        $rowIndex = 1;
374
        /** @phpstan-ignore-next-line */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
375
        $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

375
        $csv->/** @scrutinizer ignore-call */ 
376
              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...
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
376
            $redirectConfig = [
377
                'id' => 0,
378
            ];
379
            $index = 0;
380
            foreach (self::IMPORT_REDIRECTS_CSV_FIELDS as $importField) {
381
                if (isset($columns[$index], $headers[$columns[$index]])) {
382
                    $redirectConfig[$importField] = empty($row[$headers[$columns[$index]]])
383
                        ? null
384
                        : $row[$headers[$columns[$index]]];
385
                }
386
                $index++;
387
            }
388
            $redirectDump = print_r($redirectConfig, true);
389
            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

389
            Craft::debug("-> ROW #$rowIndex contents: " . /** @scrutinizer ignore-type */ $redirectDump, __METHOD__);
Loading history...
390
            if (!Retour::$plugin->redirects->saveRedirect($redirectConfig)) {
391
                Craft::info("-> ROW #$rowIndex contents: " . $redirectDump, __METHOD__);
392
                $hasErrors = true;
393
            }
394
            $rowIndex++;
395
396
            return true;
397
        });
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...
398
399
        return $hasErrors;
400
    }
401
402
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
403
     * @param Reader $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...
404
     * @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...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
405
     * @param array $headers
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...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
406
     * @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...
407
     * @throws Exception
0 ignored issues
show
Coding Style introduced by
Tag @throws cannot be grouped with parameter tags in a doc comment
Loading history...
408
     */
409
    protected function importCsvApi9(Reader $csv, array $columns, array $headers): bool
410
    {
411
        $hasErrors = false;
412
        $stmt = (new Statement())
413
            ->offset(1);
414
        $rows = $stmt->process($csv);
415
        $columns = ArrayHelper::filterEmptyStringsFromArray($columns);
416
        $rowIndex = 1;
417
        foreach ($rows as $row) {
418
            $redirectConfig = [
419
                'id' => 0,
420
            ];
421
            $index = 0;
422
            foreach (self::IMPORT_REDIRECTS_CSV_FIELDS as $importField) {
423
                if (isset($columns[$index], $headers[$columns[$index]])) {
424
                    $redirectConfig[$importField] = empty($row[$headers[$columns[$index]]])
425
                        ? null
426
                        : $row[$headers[$columns[$index]]];
427
                }
428
                $index++;
429
            }
430
            $redirectDump = print_r($redirectConfig, true);
431
            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

431
            Craft::debug("-> ROW #$rowIndex contents: " . /** @scrutinizer ignore-type */ $redirectDump, __METHOD__);
Loading history...
432
            if (!Retour::$plugin->redirects->saveRedirect($redirectConfig)) {
433
                Craft::info("-> ROW #$rowIndex contents: " . $redirectDump, __METHOD__);
434
                $hasErrors = true;
435
            }
436
            $rowIndex++;
437
        }
438
439
        return $hasErrors;
440
    }
441
}
442