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
![]() |
|||||||
9 | * @copyright Copyright (c) 2018 nystudio107 |
||||||
0 ignored issues
–
show
|
|||||||
10 | */ |
||||||
0 ignored issues
–
show
|
|||||||
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\MethodNotAllowedHttpException; |
||||||
36 | use yii\web\NotFoundHttpException; |
||||||
37 | use yii\web\Response; |
||||||
38 | use yii\web\UploadedFile; |
||||||
39 | |||||||
40 | /** |
||||||
0 ignored issues
–
show
|
|||||||
41 | * @author nystudio107 |
||||||
0 ignored issues
–
show
Content of the @author tag must be in the form "Display Name <[email protected]>"
![]() |
|||||||
42 | * @package Retour |
||||||
0 ignored issues
–
show
|
|||||||
43 | * @since 3.0.0 |
||||||
0 ignored issues
–
show
|
|||||||
44 | */ |
||||||
0 ignored issues
–
show
|
|||||||
45 | class FileController extends Controller |
||||||
46 | { |
||||||
47 | // Constants |
||||||
48 | // ========================================================================= |
||||||
49 | |||||||
50 | protected const DOCUMENTATION_URL = 'https://github.com/nystudio107/craft-retour/'; |
||||||
51 | |||||||
52 | public const LOG_FILE_NAME = 'retour-csv-import-errors'; |
||||||
53 | |||||||
54 | protected const EXPORT_REDIRECTS_CSV_FIELDS = [ |
||||||
55 | 'redirectSrcUrl' => 'Legacy URL Pattern', |
||||||
56 | 'redirectDestUrl' => 'Redirect To', |
||||||
57 | 'redirectMatchType' => 'Match Type', |
||||||
58 | 'redirectHttpCode' => 'HTTP Status', |
||||||
59 | 'siteId' => 'Site ID', |
||||||
60 | 'redirectSrcMatch' => 'Legacy URL Match Type', |
||||||
61 | 'hitCount' => 'Hits', |
||||||
62 | 'associatedElementId' => 'Short Link Element ID', |
||||||
63 | 'hitLastTime' => 'Last Hit', |
||||||
64 | 'priority' => 'Priority', |
||||||
65 | ]; |
||||||
66 | |||||||
67 | protected const EXPORT_STATISTICS_CSV_FIELDS = [ |
||||||
68 | 'redirectSrcUrl' => '404 File Not Found URL', |
||||||
69 | 'referrerUrl' => 'Last Referrer URL', |
||||||
70 | 'remoteIp' => 'Remote IP', |
||||||
71 | 'hitCount' => 'Hits', |
||||||
72 | 'hitLastTime' => 'Last Hit', |
||||||
73 | 'handledByRetour' => 'Handled', |
||||||
74 | 'siteId' => 'Site ID', |
||||||
75 | ]; |
||||||
76 | |||||||
77 | protected const IMPORT_REDIRECTS_CSV_FIELDS = [ |
||||||
78 | 'redirectSrcUrl', |
||||||
79 | 'redirectDestUrl', |
||||||
80 | 'redirectMatchType', |
||||||
81 | 'redirectHttpCode', |
||||||
82 | 'siteId', |
||||||
83 | 'redirectSrcMatch', |
||||||
84 | 'hitCount', |
||||||
85 | 'associatedElementId', |
||||||
86 | 'priority', |
||||||
87 | ]; |
||||||
88 | |||||||
89 | // Protected Properties |
||||||
90 | // ========================================================================= |
||||||
91 | |||||||
92 | protected array|bool|int $allowAnonymous = []; |
||||||
93 | |||||||
94 | // Public Methods |
||||||
95 | // ========================================================================= |
||||||
96 | |||||||
97 | /** |
||||||
0 ignored issues
–
show
|
|||||||
98 | * @throws BadRequestHttpException |
||||||
99 | * @throws Exception |
||||||
100 | * @throws ForbiddenHttpException |
||||||
101 | * @throws MissingComponentException |
||||||
102 | * @throws MethodNotAllowedHttpException |
||||||
103 | */ |
||||||
0 ignored issues
–
show
|
|||||||
104 | public function actionImportCsvColumns(): void |
||||||
105 | { |
||||||
106 | PermissionHelper::controllerPermissionCheck('retour:redirects'); |
||||||
107 | // If your CSV document was created or is read on a Macintosh computer, |
||||||
108 | // add the following lines before using the library to help PHP detect line ending in Mac OS X |
||||||
109 | if (!ini_get('auto_detect_line_endings')) { |
||||||
110 | ini_set('auto_detect_line_endings', '1'); |
||||||
111 | } |
||||||
112 | $csv = null; |
||||||
0 ignored issues
–
show
|
|||||||
113 | $this->requirePostRequest(); |
||||||
114 | $filename = Craft::$app->getRequest()->getRequiredBodyParam('filename'); |
||||||
115 | $columns = Craft::$app->getRequest()->getRequiredBodyParam('columns'); |
||||||
116 | $headers = null; |
||||||
117 | // Log the import |
||||||
118 | Filelog::delete(self::LOG_FILE_NAME); |
||||||
119 | FileLog::create(self::LOG_FILE_NAME, 'nystudio107\retour\*'); |
||||||
120 | try { |
||||||
121 | $csv = Reader::createFromPath($filename); |
||||||
122 | $csv->setDelimiter(Retour::$settings->csvColumnDelimiter ?? ','); |
||||||
123 | $headers = array_flip($csv->fetchOne(0)); |
||||||
0 ignored issues
–
show
The function
League\Csv\Reader::fetchOne() has been deprecated: since version 9.9.0
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
124 | } catch (\Exception $e) { |
||||||
125 | // If this throws an exception, try to read the CSV file from the data cache |
||||||
126 | // This can happen on load balancer setups where the Craft temp directory isn't shared |
||||||
127 | $cache = Craft::$app->getCache(); |
||||||
128 | $cachedFile = $cache->get($filename); |
||||||
129 | if ($cachedFile !== false) { |
||||||
130 | $csv = Reader::createFromString($cachedFile); |
||||||
131 | try { |
||||||
132 | $csv->setDelimiter(Retour::$settings->csvColumnDelimiter ?? ','); |
||||||
133 | } catch (Exception $e) { |
||||||
134 | Craft::error($e, __METHOD__); |
||||||
135 | } |
||||||
136 | $headers = array_flip($csv->fetchOne(0)); |
||||||
0 ignored issues
–
show
The function
League\Csv\Reader::fetchOne() has been deprecated: since version 9.9.0
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
137 | $cache->delete($filename); |
||||||
138 | } else { |
||||||
139 | Craft::error("Could not import ${$filename} from the file system, or the cache.", __METHOD__); |
||||||
140 | } |
||||||
141 | } |
||||||
142 | $hasErrors = false; |
||||||
143 | // If we have headers, then we have a file, so parse it |
||||||
144 | if ($csv && $headers) { |
||||||
145 | switch (VersionHelper::getLeagueCsvVersion()) { |
||||||
146 | case 8: |
||||||
0 ignored issues
–
show
|
|||||||
147 | $hasErrors = $this->importCsvApi8($csv, $columns, $headers); |
||||||
148 | break; |
||||||
149 | case 9: |
||||||
0 ignored issues
–
show
|
|||||||
150 | $hasErrors = $this->importCsvApi9($csv, $columns, $headers); |
||||||
151 | break; |
||||||
152 | default: |
||||||
0 ignored issues
–
show
|
|||||||
153 | Craft::$app->getSession()->setNotice(Craft::t('retour', 'Unknown league/csv package API version')); |
||||||
154 | break; |
||||||
155 | } |
||||||
156 | @unlink($filename); |
||||||
0 ignored issues
–
show
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
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.');
}
![]() |
|||||||
157 | Retour::$plugin->clearAllCaches(); |
||||||
0 ignored issues
–
show
The method
clearAllCaches() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
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. ![]() |
|||||||
158 | Craft::$app->getSession()->setNotice(Craft::t('retour', 'Redirects imported from CSV file.')); |
||||||
159 | } else { |
||||||
160 | Craft::$app->getSession()->setError(Craft::t('retour', 'Redirects could not be imported.')); |
||||||
161 | } |
||||||
162 | if ($hasErrors) { |
||||||
163 | $this->redirect(UrlHelper::actionUrl('retour/file/display-errors')); |
||||||
164 | } else { |
||||||
165 | $this->redirect('retour/redirects'); |
||||||
166 | } |
||||||
167 | } |
||||||
168 | |||||||
169 | /** |
||||||
0 ignored issues
–
show
|
|||||||
170 | * @param string|null $siteHandle |
||||||
0 ignored issues
–
show
|
|||||||
171 | * |
||||||
172 | * @return Response |
||||||
173 | * @throws ForbiddenHttpException |
||||||
174 | * @throws NotFoundHttpException |
||||||
175 | */ |
||||||
176 | public function actionImportCsv(string $siteHandle = null): Response |
||||||
177 | { |
||||||
178 | $variables = []; |
||||||
179 | PermissionHelper::controllerPermissionCheck('retour:redirects'); |
||||||
180 | // If your CSV document was created or is read on a Macintosh computer, |
||||||
181 | // add the following lines before using the library to help PHP detect line ending in Mac OS X |
||||||
182 | if (!ini_get('auto_detect_line_endings')) { |
||||||
183 | ini_set('auto_detect_line_endings', '1'); |
||||||
184 | } |
||||||
185 | // Get the site to edit |
||||||
186 | $siteId = MultiSiteHelper::getSiteIdFromHandle($siteHandle); |
||||||
187 | $pluginName = Retour::$settings->pluginName; |
||||||
188 | $templateTitle = Craft::t('retour', 'Import CSV File'); |
||||||
189 | $view = Craft::$app->getView(); |
||||||
190 | // Asset bundle |
||||||
191 | try { |
||||||
192 | $view->registerAssetBundle(RetourImportAsset::class); |
||||||
193 | } catch (InvalidConfigException $e) { |
||||||
194 | Craft::error($e->getMessage(), __METHOD__); |
||||||
195 | } |
||||||
196 | $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl( |
||||||
197 | '@nystudio107/retour/web/assets/dist', |
||||||
198 | true |
||||||
0 ignored issues
–
show
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
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. ![]() |
|||||||
199 | ); |
||||||
200 | // Enabled sites |
||||||
201 | MultiSiteHelper::setMultiSiteVariables($siteHandle, $siteId, $variables); |
||||||
202 | $variables['controllerHandle'] = 'file'; |
||||||
203 | |||||||
204 | // Basic variables |
||||||
205 | $variables['fullPageForm'] = true; |
||||||
206 | $variables['docsUrl'] = self::DOCUMENTATION_URL; |
||||||
207 | $variables['pluginName'] = $pluginName; |
||||||
208 | $variables['title'] = $templateTitle; |
||||||
209 | $siteHandleUri = Craft::$app->isMultiSite ? '/' . $siteHandle : ''; |
||||||
210 | $variables['crumbs'] = [ |
||||||
211 | [ |
||||||
212 | 'label' => $pluginName, |
||||||
213 | 'url' => UrlHelper::cpUrl('retour'), |
||||||
214 | ], |
||||||
215 | [ |
||||||
216 | 'label' => 'Redirects', |
||||||
217 | 'url' => UrlHelper::cpUrl('retour/redirects' . $siteHandleUri), |
||||||
218 | ], |
||||||
219 | ]; |
||||||
220 | $variables['docTitle'] = "{$pluginName} - Redirects - {$templateTitle}"; |
||||||
221 | $variables['selectedSubnavItem'] = 'redirects'; |
||||||
222 | |||||||
223 | // The CSV file |
||||||
224 | $file = UploadedFile::getInstanceByName('file'); |
||||||
225 | if ($file !== null) { |
||||||
226 | $filename = uniqid($file->name, true); |
||||||
227 | $filePath = Craft::$app->getPath()->getTempPath() . DIRECTORY_SEPARATOR . $filename; |
||||||
228 | $file->saveAs($filePath, false); |
||||||
229 | // Also save the file to the cache as a backup way to access it |
||||||
230 | $fileContents = @file_get_contents($filePath); |
||||||
231 | if ($fileContents) { |
||||||
232 | Craft::$app->getCache()->set($filePath, $fileContents); |
||||||
233 | } |
||||||
234 | // Read in the headers |
||||||
235 | $csv = Reader::createFromPath($file->tempName); |
||||||
236 | try { |
||||||
237 | $csv->setDelimiter(Retour::$settings->csvColumnDelimiter ?? ','); |
||||||
238 | } catch (Exception $e) { |
||||||
239 | Craft::error($e, __METHOD__); |
||||||
240 | } |
||||||
241 | $headers = $csv->fetchOne(0); |
||||||
0 ignored issues
–
show
The function
League\Csv\Reader::fetchOne() has been deprecated: since version 9.9.0
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
242 | Craft::info(print_r($headers, true), __METHOD__); |
||||||
0 ignored issues
–
show
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
![]() |
|||||||
243 | $variables['headers'] = $headers; |
||||||
244 | $variables['filename'] = $filePath; |
||||||
245 | } |
||||||
246 | |||||||
247 | // Render the template |
||||||
248 | return $this->renderTemplate('retour/import/index', $variables); |
||||||
249 | } |
||||||
250 | |||||||
251 | /** |
||||||
252 | * Display the error log if something went wrong |
||||||
253 | * |
||||||
254 | * @return Response |
||||||
255 | * @throws \yii\web\ForbiddenHttpException |
||||||
256 | */ |
||||||
257 | public function actionDisplayErrors(): Response |
||||||
258 | { |
||||||
259 | $variables = []; |
||||||
260 | PermissionHelper::controllerPermissionCheck('retour:redirects'); |
||||||
261 | $pluginName = Retour::$settings->pluginName; |
||||||
262 | $templateTitle = Craft::t('retour', 'CSV File Import Errors'); |
||||||
263 | $view = Craft::$app->getView(); |
||||||
264 | // Asset bundle |
||||||
265 | try { |
||||||
266 | $view->registerAssetBundle(RetourImportAsset::class); |
||||||
267 | } catch (InvalidConfigException $e) { |
||||||
268 | Craft::error($e->getMessage(), __METHOD__); |
||||||
269 | } |
||||||
270 | $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl( |
||||||
271 | '@nystudio107/retour/web/assets/dist', |
||||||
272 | true |
||||||
0 ignored issues
–
show
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
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. ![]() |
|||||||
273 | ); |
||||||
274 | // Basic variables |
||||||
275 | $variables['fullPageForm'] = true; |
||||||
276 | $variables['docsUrl'] = self::DOCUMENTATION_URL; |
||||||
277 | $variables['pluginName'] = $pluginName; |
||||||
278 | $variables['title'] = $templateTitle; |
||||||
279 | $variables['crumbs'] = [ |
||||||
280 | [ |
||||||
281 | 'label' => $pluginName, |
||||||
282 | 'url' => UrlHelper::cpUrl('retour'), |
||||||
283 | ], |
||||||
284 | [ |
||||||
285 | 'label' => 'Redirects', |
||||||
286 | 'url' => UrlHelper::cpUrl('retour/redirects'), |
||||||
287 | ], |
||||||
288 | ]; |
||||||
289 | $variables['docTitle'] = "{$pluginName} - Redirects - {$templateTitle}"; |
||||||
290 | $variables['selectedSubnavItem'] = 'redirects'; |
||||||
291 | // The error log |
||||||
292 | $variables['errorLogContents'] = FileLog::getContents(self::LOG_FILE_NAME); |
||||||
293 | |||||||
294 | // Render the template |
||||||
295 | return $this->renderTemplate('retour/import/errors', $variables); |
||||||
296 | } |
||||||
297 | |||||||
298 | /** |
||||||
299 | * Export the statistics table as a CSV file |
||||||
300 | * |
||||||
301 | * @throws ForbiddenHttpException |
||||||
302 | */ |
||||||
0 ignored issues
–
show
|
|||||||
303 | public function actionExportStatistics(): void |
||||||
304 | { |
||||||
305 | PermissionHelper::controllerPermissionCheck('retour:redirects'); |
||||||
306 | //Allow the fields to be localized |
||||||
307 | $fields = self::EXPORT_STATISTICS_CSV_FIELDS; |
||||||
308 | foreach ($fields as $key => $field) { |
||||||
309 | $fields[$key] = Craft::t('retour', $field); |
||||||
310 | } |
||||||
311 | $this->exportCsvFile('retour-statistics', '{{%retour_stats}}', $fields); |
||||||
312 | } |
||||||
313 | |||||||
314 | /** |
||||||
315 | * Export the redirects table as a CSV file |
||||||
316 | * |
||||||
317 | * @throws ForbiddenHttpException |
||||||
318 | */ |
||||||
0 ignored issues
–
show
|
|||||||
319 | public function actionExportRedirects(): void |
||||||
320 | { |
||||||
321 | PermissionHelper::controllerPermissionCheck('retour:redirects'); |
||||||
322 | //Allow the fields to be localized |
||||||
323 | $fields = self::EXPORT_REDIRECTS_CSV_FIELDS; |
||||||
324 | foreach ($fields as $key => $field) { |
||||||
325 | $fields[$key] = Craft::t('retour', $field); |
||||||
326 | } |
||||||
327 | $this->exportCsvFile('retour-redirects', '{{%retour_static_redirects}}', $fields); |
||||||
328 | } |
||||||
329 | |||||||
330 | |||||||
331 | // Public Methods |
||||||
332 | // ========================================================================= |
||||||
333 | |||||||
334 | /** |
||||||
0 ignored issues
–
show
|
|||||||
335 | * @param AbstractCsv $csv |
||||||
0 ignored issues
–
show
|
|||||||
336 | * @param array $columns |
||||||
0 ignored issues
–
show
|
|||||||
337 | * @param array $headers |
||||||
0 ignored issues
–
show
|
|||||||
338 | * @return bool whether the import has any errors |
||||||
0 ignored issues
–
show
|
|||||||
339 | */ |
||||||
340 | protected function importCsvApi8(AbstractCsv $csv, array $columns, array $headers): bool |
||||||
341 | { |
||||||
342 | $hasErrors = false; |
||||||
343 | /** @phpstan-ignore-next-line */ |
||||||
0 ignored issues
–
show
|
|||||||
344 | $csv->setOffset(1); |
||||||
0 ignored issues
–
show
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
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. ![]() |
|||||||
345 | $columns = ArrayHelper::filterEmptyStringsFromArray($columns); |
||||||
346 | $rowIndex = 1; |
||||||
347 | /** @phpstan-ignore-next-line */ |
||||||
0 ignored issues
–
show
|
|||||||
348 | $csv->each(function($row) use ($headers, $columns, &$rowIndex, &$hasErrors) { |
||||||
0 ignored issues
–
show
The method
each() does not exist on League\Csv\AbstractCsv . It seems like you code against a sub-type of League\Csv\AbstractCsv such as League\Csv\Reader .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
349 | $redirectConfig = [ |
||||||
350 | 'id' => 0, |
||||||
351 | ]; |
||||||
352 | $index = 0; |
||||||
353 | foreach (self::IMPORT_REDIRECTS_CSV_FIELDS as $importField) { |
||||||
354 | if (isset($columns[$index], $headers[$columns[$index]])) { |
||||||
355 | $redirectConfig[$importField] = empty($row[$headers[$columns[$index]]]) |
||||||
356 | ? null |
||||||
357 | : $row[$headers[$columns[$index]]]; |
||||||
358 | } |
||||||
359 | $index++; |
||||||
360 | } |
||||||
361 | $redirectDump = print_r($redirectConfig, true); |
||||||
362 | Craft::debug("-> ROW #$rowIndex contents: " . $redirectDump, __METHOD__); |
||||||
0 ignored issues
–
show
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
![]() |
|||||||
363 | if (!Retour::$plugin->redirects->saveRedirect($redirectConfig)) { |
||||||
0 ignored issues
–
show
The method
saveRedirect() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
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. ![]() |
|||||||
364 | Craft::info("-> ROW #$rowIndex contents: " . $redirectDump, __METHOD__); |
||||||
365 | $hasErrors = true; |
||||||
366 | } |
||||||
367 | $rowIndex++; |
||||||
368 | |||||||
369 | return true; |
||||||
370 | }); |
||||||
0 ignored issues
–
show
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.
![]() |
|||||||
371 | |||||||
372 | return $hasErrors; |
||||||
373 | } |
||||||
374 | |||||||
375 | /** |
||||||
0 ignored issues
–
show
|
|||||||
376 | * @param Reader $csv |
||||||
0 ignored issues
–
show
|
|||||||
377 | * @param array $columns |
||||||
0 ignored issues
–
show
|
|||||||
378 | * @param array $headers |
||||||
0 ignored issues
–
show
|
|||||||
379 | * @return bool whether the import has any errors |
||||||
0 ignored issues
–
show
|
|||||||
380 | * @throws Exception |
||||||
0 ignored issues
–
show
|
|||||||
381 | */ |
||||||
382 | protected function importCsvApi9(Reader $csv, array $columns, array $headers): bool |
||||||
383 | { |
||||||
384 | $hasErrors = false; |
||||||
385 | $stmt = (new Statement()) |
||||||
386 | ->offset(1); |
||||||
387 | $rows = $stmt->process($csv); |
||||||
388 | $columns = ArrayHelper::filterEmptyStringsFromArray($columns); |
||||||
389 | $rowIndex = 1; |
||||||
390 | foreach ($rows as $row) { |
||||||
391 | $redirectConfig = [ |
||||||
392 | 'id' => 0, |
||||||
393 | ]; |
||||||
394 | $index = 0; |
||||||
395 | foreach (self::IMPORT_REDIRECTS_CSV_FIELDS as $importField) { |
||||||
396 | if (isset($columns[$index], $headers[$columns[$index]])) { |
||||||
397 | $redirectConfig[$importField] = empty($row[$headers[$columns[$index]]]) |
||||||
398 | ? null |
||||||
399 | : $row[$headers[$columns[$index]]]; |
||||||
400 | } |
||||||
401 | $index++; |
||||||
402 | } |
||||||
403 | $redirectDump = print_r($redirectConfig, true); |
||||||
404 | Craft::debug("-> ROW #$rowIndex contents: " . $redirectDump, __METHOD__); |
||||||
0 ignored issues
–
show
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
![]() |
|||||||
405 | if (!Retour::$plugin->redirects->saveRedirect($redirectConfig)) { |
||||||
406 | Craft::info("-> ROW #$rowIndex contents: " . $redirectDump, __METHOD__); |
||||||
407 | $hasErrors = true; |
||||||
408 | } |
||||||
409 | $rowIndex++; |
||||||
410 | } |
||||||
411 | |||||||
412 | return $hasErrors; |
||||||
413 | } |
||||||
414 | |||||||
415 | /** |
||||||
0 ignored issues
–
show
|
|||||||
416 | * @param string $filename |
||||||
0 ignored issues
–
show
|
|||||||
417 | * @param string $table |
||||||
0 ignored issues
–
show
|
|||||||
418 | * @param array $columns |
||||||
0 ignored issues
–
show
|
|||||||
419 | */ |
||||||
0 ignored issues
–
show
|
|||||||
420 | protected function exportCsvFile(string $filename, string $table, array $columns): void |
||||||
421 | { |
||||||
422 | // If your CSV document was created or is read on a Macintosh computer, |
||||||
423 | // add the following lines before using the library to help PHP detect line ending in Mac OS X |
||||||
424 | if (!ini_get('auto_detect_line_endings')) { |
||||||
425 | ini_set('auto_detect_line_endings', '1'); |
||||||
426 | } |
||||||
427 | // Query the db table |
||||||
428 | $data = (new Query()) |
||||||
429 | ->from([$table]) |
||||||
430 | ->select(array_keys($columns)) |
||||||
431 | ->orderBy('hitCount DESC') |
||||||
432 | ->all(); |
||||||
433 | // Create our CSV file writer |
||||||
434 | $csv = Writer::createFromFileObject(new SplTempFileObject()); |
||||||
435 | try { |
||||||
436 | $csv->setDelimiter(Retour::$settings->csvColumnDelimiter ?? ','); |
||||||
437 | } catch (Exception $e) { |
||||||
438 | Craft::error($e, __METHOD__); |
||||||
439 | } |
||||||
440 | $csv->insertOne(array_values($columns)); |
||||||
441 | $csv->insertAll($data); |
||||||
442 | $csv->output($filename . '.csv'); |
||||||
0 ignored issues
–
show
The function
League\Csv\AbstractCsv::output() has been deprecated: since version 9.18.0
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
443 | exit(0); |
||||||
0 ignored issues
–
show
|
|||||||
444 | } |
||||||
445 | } |
||||||
446 |