diff --git a/.travis.yml b/.travis.yml index 30e62386..80452372 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,7 @@ before_script: - (cd tests/Application && bin/console doctrine:database:create --env=test -vvv) - (cd tests/Application && bin/console doctrine:schema:create --env=test -vvv) - (cd tests/Application && bin/console assets:install web --env=test -vvv) + - (cd tests/Application && bin/console cache:warmup --env=dev -vvv) - (cd tests/Application && yarn run gulp) # Configure display @@ -65,10 +66,9 @@ before_script: script: - composer validate --strict - - bin/phpstan.phar analyse -c phpstan.neon -l max src/ + - bin/phpstan analyse -c phpstan.neon -l max src/ - bin/ecs check src/ spec/ tests/Behat/ -# - bin/phpunit - bin/phpspec run - bin/behat features/ --strict -vvv --no-interaction || bin/behat features/ --strict -vvv --no-interaction --rerun diff --git a/composer.json b/composer.json index 900f4a24..fef370c3 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,8 @@ "friends-of-behat/variadic-extension": "^1.0", "lakion/mink-debug-extension": "^1.2.3", "phpspec/phpspec": "^3.2", - "phpstan/phpstan-shim": "^0.9.2", + "phpstan/phpstan-symfony": "^0.10.0", + "phpstan/phpstan-webmozart-assert": "^0.10.0", "phpunit/phpunit": "^5.6", "portphp/csv": "^1.1.0", "portphp/excel": "^1.1.0", diff --git a/composer.lock b/composer.lock index f9538833..249a12a1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "872aea1950d60d71f59941aed6f2929c", + "content-hash": "e85bc9b443a1039506c8ddff0e5f1634", "packages": [ { "name": "behat/transliterator", @@ -8654,6 +8654,151 @@ ], "time": "2018-05-29T17:25:09+00:00" }, + { + "name": "nette/bootstrap", + "version": "v2.4.6", + "source": { + "type": "git", + "url": "https://github.com/nette/bootstrap.git", + "reference": "268816e3f1bb7426c3a4ceec2bd38a036b532543" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/bootstrap/zipball/268816e3f1bb7426c3a4ceec2bd38a036b532543", + "reference": "268816e3f1bb7426c3a4ceec2bd38a036b532543", + "shasum": "" + }, + "require": { + "nette/di": "~2.4.7", + "nette/utils": "~2.4", + "php": ">=5.6.0" + }, + "conflict": { + "nette/nette": "<2.2" + }, + "require-dev": { + "latte/latte": "~2.2", + "nette/application": "~2.3", + "nette/caching": "~2.3", + "nette/database": "~2.3", + "nette/forms": "~2.3", + "nette/http": "~2.4.0", + "nette/mail": "~2.3", + "nette/robot-loader": "^2.4.2 || ^3.0", + "nette/safe-stream": "~2.2", + "nette/security": "~2.3", + "nette/tester": "~2.0", + "tracy/tracy": "^2.4.1" + }, + "suggest": { + "nette/robot-loader": "to use Configurator::createRobotLoader()", + "tracy/tracy": "to use Configurator::enableTracy()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "๐Ÿ…ฑ Nette Bootstrap: the simple way to configure and bootstrap your Nette application.", + "homepage": "https://nette.org", + "keywords": [ + "bootstrapping", + "configurator", + "nette" + ], + "time": "2018-05-17T12:52:20+00:00" + }, + { + "name": "nette/di", + "version": "v2.4.13", + "source": { + "type": "git", + "url": "https://github.com/nette/di.git", + "reference": "3f8f212b02d5c17feb97a7e0a39ab306f40c06ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/di/zipball/3f8f212b02d5c17feb97a7e0a39ab306f40c06ca", + "reference": "3f8f212b02d5c17feb97a7e0a39ab306f40c06ca", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "nette/neon": "^2.3.3 || ~3.0.0", + "nette/php-generator": "^2.6.1 || ~3.0.0", + "nette/utils": "^2.4.3 || ~3.0.0", + "php": ">=5.6.0" + }, + "conflict": { + "nette/bootstrap": "<2.4", + "nette/nette": "<2.2" + }, + "require-dev": { + "nette/tester": "^2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "๐Ÿ’Ž Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP 7.1 features.", + "homepage": "https://nette.org", + "keywords": [ + "compiled", + "di", + "dic", + "factory", + "ioc", + "nette", + "static" + ], + "time": "2018-06-11T08:46:01+00:00" + }, { "name": "nette/finder", "version": "v2.4.2", @@ -8716,6 +8861,129 @@ ], "time": "2018-06-28T11:49:23+00:00" }, + { + "name": "nette/neon", + "version": "v2.4.3", + "source": { + "type": "git", + "url": "https://github.com/nette/neon.git", + "reference": "5e72b1dd3e2d34f0863c5561139a19df6a1ef398" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/neon/zipball/5e72b1dd3e2d34f0863c5561139a19df6a1ef398", + "reference": "5e72b1dd3e2d34f0863c5561139a19df6a1ef398", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "ext-json": "*", + "php": ">=5.6.0" + }, + "require-dev": { + "nette/tester": "~2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "๐Ÿธ Nette NEON: encodes and decodes NEON file format.", + "homepage": "http://ne-on.org", + "keywords": [ + "export", + "import", + "neon", + "nette", + "yaml" + ], + "time": "2018-03-21T12:12:21+00:00" + }, + { + "name": "nette/php-generator", + "version": "v3.0.4", + "source": { + "type": "git", + "url": "https://github.com/nette/php-generator.git", + "reference": "b381ecacbf5a0b5f99cc0b303d5b0578d409f446" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/php-generator/zipball/b381ecacbf5a0b5f99cc0b303d5b0578d409f446", + "reference": "b381ecacbf5a0b5f99cc0b303d5b0578d409f446", + "shasum": "" + }, + "require": { + "nette/utils": "^2.4.2 || ~3.0.0", + "php": ">=7.0" + }, + "conflict": { + "nette/nette": "<2.2" + }, + "require-dev": { + "nette/tester": "^2.0", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0", + "GPL-3.0" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "๐Ÿ˜ Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.2 features.", + "homepage": "https://nette.org", + "keywords": [ + "code", + "nette", + "php", + "scaffolding" + ], + "time": "2018-04-26T16:48:20+00:00" + }, { "name": "nette/robot-loader", "version": "v3.0.4", @@ -8863,6 +9131,57 @@ ], "time": "2018-05-02T17:16:08+00:00" }, + { + "name": "nikic/php-parser", + "version": "v4.0.3", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "bd088dc940a418f09cda079a9b5c7c478890fb8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bd088dc940a418f09cda079a9b5c7c478890fb8d", + "reference": "bd088dc940a418f09cda079a9b5c7c478890fb8d", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.5 || ^7.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2018-07-15T17:25:16+00:00" + }, { "name": "php-cs-fixer/diff", "version": "v1.3.0", @@ -9354,41 +9673,181 @@ "time": "2018-06-20T17:48:01+00:00" }, { - "name": "phpstan/phpstan-shim", - "version": "0.9.2", + "name": "phpstan/phpstan", + "version": "0.10.2", "source": { "type": "git", - "url": "https://github.com/phpstan/phpstan-shim.git", - "reference": "e4720fb2916be05de02869780072253e7e0e8a75" + "url": "https://github.com/phpstan/phpstan.git", + "reference": "d69658794514e57ad9f247e623513397038f362f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-shim/zipball/e4720fb2916be05de02869780072253e7e0e8a75", - "reference": "e4720fb2916be05de02869780072253e7e0e8a75", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d69658794514e57ad9f247e623513397038f362f", + "reference": "d69658794514e57ad9f247e623513397038f362f", "shasum": "" }, "require": { - "php": "~7.0" - }, - "replace": { - "phpstan/phpstan": "self.version" + "composer/xdebug-handler": "^1.0", + "jean85/pretty-package-versions": "^1.0.3", + "nette/bootstrap": "^2.4 || ^3.0", + "nette/di": "^2.4.7 || ^3.0", + "nette/robot-loader": "^3.0.1", + "nette/utils": "^2.4.5 || ^3.0", + "nikic/php-parser": "^4.0.2", + "php": "~7.1", + "phpstan/phpdoc-parser": "^0.3", + "symfony/console": "~3.2 || ~4.0", + "symfony/finder": "~3.2 || ~4.0" + }, + "require-dev": { + "brianium/paratest": "^2.0", + "consistence/coding-standard": "^3.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "ext-gd": "*", + "ext-intl": "*", + "ext-mysqli": "*", + "ext-zip": "*", + "jakub-onderka/php-parallel-lint": "^1.0", + "localheinz/composer-normalize": "~0.8.0", + "phing/phing": "^2.16.0", + "phpstan/phpstan-deprecation-rules": "^0.10.2", + "phpstan/phpstan-php-parser": "^0.10", + "phpstan/phpstan-phpunit": "^0.10", + "phpstan/phpstan-strict-rules": "^0.10", + "phpunit/phpunit": "^7.0", + "slevomat/coding-standard": "^4.6.2" }, "bin": [ - "phpstan", - "phpstan.phar" + "bin/phpstan" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.10-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": [ + "src/", + "build/PHPStan" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "time": "2018-07-22T17:55:11+00:00" + }, + { + "name": "phpstan/phpstan-symfony", + "version": "0.10", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-symfony.git", + "reference": "34b1940a678768ba1b957ca550f99bf7c81f6222" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/34b1940a678768ba1b957ca550f99bf7c81f6222", + "reference": "34b1940a678768ba1b957ca550f99bf7c81f6222", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "nikic/php-parser": "^4.0", + "php": "^7.1", + "phpstan/phpstan": "^0.10" + }, + "conflict": { + "symfony/framework-bundle": "<3.0" + }, + "require-dev": { + "consistence/coding-standard": "^3.0.1", + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "jakub-onderka/php-parallel-lint": "^1.0", + "phing/phing": "^2.16.0", + "phpstan/phpstan-phpunit": "^0.10", + "phpstan/phpstan-strict-rules": "^0.10", + "phpunit/phpunit": "^7.0", + "satooshi/php-coveralls": "^1.0", + "slevomat/coding-standard": "^4.5.2", + "symfony/framework-bundle": "^3.0 || ^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.10-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lukรกลก Unger", + "email": "looky.msc@gmail.com", + "homepage": "https://lookyman.net" + } ], + "description": "Symfony Framework extensions and rules for PHPStan", + "time": "2018-06-21T12:00:50+00:00" + }, + { + "name": "phpstan/phpstan-webmozart-assert", + "version": "0.10", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-webmozart-assert.git", + "reference": "5954bb88827ae8e4b45ee5db4f430c1ced69818a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-webmozart-assert/zipball/5954bb88827ae8e4b45ee5db4f430c1ced69818a", + "reference": "5954bb88827ae8e4b45ee5db4f430c1ced69818a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.0", + "php": "~7.1", + "phpstan/phpstan": "^0.10" + }, + "require-dev": { + "consistence/coding-standard": "^3.0.1", + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", + "jakub-onderka/php-parallel-lint": "^1.0", + "phing/phing": "^2.16.0", + "phpstan/phpstan-phpunit": "^0.10", + "phpstan/phpstan-strict-rules": "^0.10", + "phpunit/phpunit": "^7.1.3", + "slevomat/coding-standard": "^4.5.2", + "webmozart/assert": "^1.3.0" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.9-dev" + "dev-master": "0.10-dev" + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "PHPStan Phar distribution", - "time": "2018-01-28T14:29:27+00:00" + "description": "PHPStan webmozart/assert extension", + "time": "2018-06-23T17:24:59+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/phpstan.neon b/phpstan.neon index 1cbc5e8d..a933d7a7 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,11 @@ +includes: + - vendor/phpstan/phpstan-symfony/extension.neon + - vendor/phpstan/phpstan-webmozart-assert/extension.neon + parameters: + symfony: + container_xml_path: tests/Application/var/cache/dev/appDevDebugProjectContainer.xml + excludes_analyse: # Makes PHPStan crash - 'src/DependencyInjection/Configuration.php' diff --git a/src/Controller/ImportDataController.php b/src/Controller/ImportDataController.php index cbc317ca..36ef6cc1 100644 --- a/src/Controller/ImportDataController.php +++ b/src/Controller/ImportDataController.php @@ -4,6 +4,7 @@ namespace FriendsOfSylius\SyliusImportExportPlugin\Controller; +use FriendsOfSylius\SyliusImportExportPlugin\Exception\ImporterException; use FriendsOfSylius\SyliusImportExportPlugin\Form\ImportType; use FriendsOfSylius\SyliusImportExportPlugin\Importer\ImporterInterface; use FriendsOfSylius\SyliusImportExportPlugin\Importer\ImporterRegistry; @@ -79,7 +80,7 @@ public function importAction(Request $request): RedirectResponse if ($form->isSubmitted() && $form->isValid()) { $this->importData($importer, $form); } - $referer = (string) $request->headers->get('referer'); + $referer = $request->headers->get('referer'); return new RedirectResponse($referer); } @@ -102,7 +103,11 @@ private function importData(string $importer, FormInterface $form): void $file = $form->get('import-data')->getData(); /** @var ImporterInterface $service */ $service = $this->registry->get($name); - $result = $service->import($file->getRealPath()); + $path = $file->getRealPath(); + if (false === $path) { + throw new ImporterException(sprintf('File %s could not be loaded', $file->getClientOriginalName())); + } + $result = $service->import($path); $message = sprintf( 'Imported via %s importer (Time taken in ms: %s, Imported %s, Skipped %s, Failed %s)', diff --git a/src/Exporter/JsonResourceExporter.php b/src/Exporter/JsonResourceExporter.php index d9d5a554..7ecde63b 100644 --- a/src/Exporter/JsonResourceExporter.php +++ b/src/Exporter/JsonResourceExporter.php @@ -50,7 +50,7 @@ public function export(array $idsToExport): void */ public function getExportedData(): string { - return json_encode($this->data); + return json_encode($this->data) ?: ''; } /** diff --git a/src/Exporter/MqItemWriter.php b/src/Exporter/MqItemWriter.php index b2d815c0..2ce5e194 100644 --- a/src/Exporter/MqItemWriter.php +++ b/src/Exporter/MqItemWriter.php @@ -50,7 +50,7 @@ public function write(array $items): void { foreach ($items as $item) { $message = $this->redisContext->createMessage( - json_encode($item), + json_encode($item) ?: '', [], ['recordedOn' => (new \DateTime())->format('Y-m-d H:i:s')] ); diff --git a/src/Importer/JsonResourceImporter.php b/src/Importer/JsonResourceImporter.php index b12a185f..79a5dd0a 100644 --- a/src/Importer/JsonResourceImporter.php +++ b/src/Importer/JsonResourceImporter.php @@ -5,6 +5,7 @@ namespace FriendsOfSylius\SyliusImportExportPlugin\Importer; use Doctrine\Common\Persistence\ObjectManager; +use FriendsOfSylius\SyliusImportExportPlugin\Exception\ImporterException; use FriendsOfSylius\SyliusImportExportPlugin\Processor\ResourceProcessorInterface; final class JsonResourceImporter extends ResourceImporter implements SingleDataArrayImporterInterface @@ -32,9 +33,12 @@ public function import(string $fileName): ImporterResultInterface { $this->result->start(); - $dataAsArray = json_decode(file_get_contents($fileName), true); + $contents = file_get_contents($fileName); + if (false === $contents) { + throw new ImporterException(sprintf('File %s could not be loaded', $fileName)); + } - foreach ($dataAsArray as $i => $row) { + foreach (json_decode($contents, true) as $i => $row) { if ($this->importData($i, $row)) { break; } diff --git a/src/Importer/ResourceImporter.php b/src/Importer/ResourceImporter.php index 7f0c80f9..aab0bf64 100644 --- a/src/Importer/ResourceImporter.php +++ b/src/Importer/ResourceImporter.php @@ -50,7 +50,7 @@ class ResourceImporter implements ImporterInterface /** * @var int */ - private $batchCount; + private $batchCount = 0; public function __construct( ReaderFactory $readerFactory, @@ -76,9 +76,8 @@ public function import(string $fileName): ImporterResultInterface $this->result->start(); - $this->batchCount = 0; foreach ($reader as $i => $row) { - if ($this->importData($i, $row)) { + if ($this->importData((int) $i, $row)) { break; } } diff --git a/src/Writer/CsvWriter.php b/src/Writer/CsvWriter.php index ceab46ab..6e58b447 100644 --- a/src/Writer/CsvWriter.php +++ b/src/Writer/CsvWriter.php @@ -4,6 +4,7 @@ namespace FriendsOfSylius\SyliusImportExportPlugin\Writer; +use FriendsOfSylius\SyliusImportExportPlugin\Exception\ExporterException; use Port\Csv\CsvWriter as PortCsvWriter; class CsvWriter implements WriterInterface @@ -42,6 +43,9 @@ public function getFileContent(): string rewind($this->writer->getStream()); $contents = stream_get_contents($this->writer->getStream()); + if (false === $contents) { + throw new ExporterException(sprintf('Data stream could not be opened')); + } $this->finish(); diff --git a/src/Writer/ExcelWriter.php b/src/Writer/ExcelWriter.php index dd121388..5a752c20 100644 --- a/src/Writer/ExcelWriter.php +++ b/src/Writer/ExcelWriter.php @@ -4,6 +4,7 @@ namespace FriendsOfSylius\SyliusImportExportPlugin\Writer; +use FriendsOfSylius\SyliusImportExportPlugin\Exception\ExporterException; use FriendsOfSylius\SyliusImportExportPlugin\Exception\InvalidOrderException; use Port\Excel\ExcelWriter as PortExcelWriter; @@ -59,6 +60,9 @@ public function getFileContent(): string $this->finish(); $contents = file_get_contents($this->filename); + if (false === $contents) { + throw new ExporterException(sprintf('File %s could not be loaded', $this->filename)); + } unlink($this->filename); @@ -68,7 +72,11 @@ public function getFileContent(): string private function prepare(): void { if (null === $this->filename) { - $this->filename = tempnam($this->temporaryFolder, 'exp'); + $tmp = tempnam($this->temporaryFolder, 'exp'); + if (false === $tmp) { + throw new ExporterException(sprintf('Could not create temporary file in "%s"', $this->temporaryFolder)); + } + $this->filename = $tmp; } if (null === $this->writer) { diff --git a/tests/Application/app/AppKernel.php b/tests/Application/app/AppKernel.php index b84745b3..2846ca67 100644 --- a/tests/Application/app/AppKernel.php +++ b/tests/Application/app/AppKernel.php @@ -30,20 +30,4 @@ public function registerContainerConfiguration(LoaderInterface $loader): void { $loader->load($this->getRootDir() . '/config/config.yml'); } - - /** - * {@inheritdoc} - */ - public function getCacheDir(): string - { - return sprintf('%s/%s/cache', sys_get_temp_dir(), md5(__DIR__)); - } - - /** - * {@inheritdoc} - */ - public function getLogDir(): string - { - return sprintf('%s/%s/logs', sys_get_temp_dir(), md5(__DIR__)); - } }