diff --git a/app/config.php b/app/config.php index e59ea364..3eaf630a 100644 --- a/app/config.php +++ b/app/config.php @@ -4,6 +4,8 @@ use Colors\Color; use PhpSchool\PhpWorkshop\Listener\InitialCodeListener; +use PhpSchool\PhpWorkshop\Logger\Logger; +use Psr\Log\LoggerInterface; use function DI\create; use function DI\factory; use Kadet\Highlighter\KeyLighter; @@ -84,7 +86,17 @@ return [ 'appName' => basename($_SERVER['argv'][0]), + 'phpschoolGlobalDir' => sprintf('%s/.php-school', getenv('HOME')), + 'currentWorkingDirectory' => function (ContainerInterface $c) { + return getcwd(); + }, WorkshopType::class => WorkshopType::STANDARD(), + Psr\Log\LoggerInterface::class => function (ContainerInterface $c) { + $appName = $c->get('appName'); + $globalDir = $c->get('phpschoolGlobalDir'); + + return new Logger("$globalDir/logs/$appName.log"); + }, ExerciseDispatcher::class => function (ContainerInterface $c) { return new ExerciseDispatcher( $c->get(RunnerManager::class), @@ -203,7 +215,7 @@ //Listeners InitialCodeListener::class => function (ContainerInterface $c) { - return new InitialCodeListener(getcwd()); + return new InitialCodeListener($c->get('currentWorkingDirectory'), $c->get(LoggerInterface::class)); }, PrepareSolutionListener::class => create(), CodePatchListener::class => function (ContainerInterface $c) { diff --git a/composer.json b/composer.json index ae208848..c78f1610 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ "myclabs/php-enum": "^1.4", "php-school/keylighter": "^0.8.4", "nikic/php-parser": "^4.0", - "guzzlehttp/guzzle": "^7.2" + "guzzlehttp/guzzle": "^7.2", + "psr/log": "^1.1" }, "require-dev": { "composer/composer": "^2.0", diff --git a/composer.lock b/composer.lock index c5b721d0..30605d08 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": "606957d19b5a81a4a205f70f5bba7e0d", + "content-hash": "6e4610d7ae7b3985bfd98c08d1231f90", "packages": [ { "name": "aydin-hassan/cli-md-renderer", @@ -56,32 +56,31 @@ }, { "name": "beberlei/assert", - "version": "v3.2.7", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/beberlei/assert.git", - "reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf" + "reference": "5367e3895976b49704ae671f75bc5f0ba1b986ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/d63a6943fc4fd1a2aedb65994e3548715105abcf", - "reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf", + "url": "https://api.github.com/repos/beberlei/assert/zipball/5367e3895976b49704ae671f75bc5f0ba1b986ab", + "reference": "5367e3895976b49704ae671f75bc5f0ba1b986ab", "shasum": "" }, "require": { "ext-ctype": "*", + "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", "ext-simplexml": "*", - "php": "^7" + "php": "^7.0 || ^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", - "phpstan/phpstan-shim": "*", - "phpunit/phpunit": ">=6.0.0 <8" - }, - "suggest": { - "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" + "phpstan/phpstan": "*", + "phpunit/phpunit": ">=6.0.0", + "yoast/phpunit-polyfills": "^0.1.0" }, "type": "library", "autoload": { @@ -116,22 +115,22 @@ ], "support": { "issues": "https://github.com/beberlei/assert/issues", - "source": "https://github.com/beberlei/assert/tree/v3" + "source": "https://github.com/beberlei/assert/tree/v3.3.0" }, - "time": "2019-12-19T17:51:41+00:00" + "time": "2020-11-13T20:02:54+00:00" }, { "name": "fakerphp/faker", - "version": "v1.10.1", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "f2713a5016faaf6ffc60e9d456dedb5ebf0efcae" + "reference": "9aa6c9e289860951e6b4d010c7a841802d015cd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/f2713a5016faaf6ffc60e9d456dedb5ebf0efcae", - "reference": "f2713a5016faaf6ffc60e9d456dedb5ebf0efcae", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/9aa6c9e289860951e6b4d010c7a841802d015cd8", + "reference": "9aa6c9e289860951e6b4d010c7a841802d015cd8", "shasum": "" }, "require": { @@ -141,6 +140,7 @@ "fzaninotto/faker": "*" }, "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", "ext-intl": "*", "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.4.2" }, @@ -167,9 +167,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.10.1" + "source": "https://github.com/FakerPHP/Faker/tree/v1.12.0" }, - "time": "2020-10-28T09:32:46+00:00" + "time": "2020-11-23T09:33:08+00:00" }, { "name": "guzzlehttp/guzzle", @@ -561,16 +561,16 @@ }, { "name": "myclabs/php-enum", - "version": "1.7.6", + "version": "1.7.7", "source": { "type": "git", "url": "https://github.com/myclabs/php-enum.git", - "reference": "5f36467c7a87e20fbdc51e524fd8f9d1de80187c" + "reference": "d178027d1e679832db9f38248fcc7200647dc2b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/php-enum/zipball/5f36467c7a87e20fbdc51e524fd8f9d1de80187c", - "reference": "5f36467c7a87e20fbdc51e524fd8f9d1de80187c", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/d178027d1e679832db9f38248fcc7200647dc2b7", + "reference": "d178027d1e679832db9f38248fcc7200647dc2b7", "shasum": "" }, "require": { @@ -605,22 +605,32 @@ ], "support": { "issues": "https://github.com/myclabs/php-enum/issues", - "source": "https://github.com/myclabs/php-enum/tree/master" + "source": "https://github.com/myclabs/php-enum/tree/1.7.7" }, - "time": "2020-02-14T08:15:52+00:00" + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum", + "type": "tidelift" + } + ], + "time": "2020-11-14T18:14:52+00:00" }, { "name": "nikic/php-parser", - "version": "v4.10.2", + "version": "v4.10.3", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "658f1be311a230e0907f5dfe0213742aff0596de" + "reference": "dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/658f1be311a230e0907f5dfe0213742aff0596de", - "reference": "658f1be311a230e0907f5dfe0213742aff0596de", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984", + "reference": "dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984", "shasum": "" }, "require": { @@ -661,22 +671,22 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.3" }, - "time": "2020-09-26T10:30:38+00:00" + "time": "2020-12-03T17:45:45+00:00" }, { "name": "opis/closure", - "version": "3.6.0", + "version": "3.6.1", "source": { "type": "git", "url": "https://github.com/opis/closure.git", - "reference": "c547f8262a5fa9ff507bd06cc394067b83a75085" + "reference": "943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/c547f8262a5fa9ff507bd06cc394067b83a75085", - "reference": "c547f8262a5fa9ff507bd06cc394067b83a75085", + "url": "https://api.github.com/repos/opis/closure/zipball/943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5", + "reference": "943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5", "shasum": "" }, "require": { @@ -726,9 +736,9 @@ ], "support": { "issues": "https://github.com/opis/closure/issues", - "source": "https://github.com/opis/closure/tree/3.6.0" + "source": "https://github.com/opis/closure/tree/3.6.1" }, - "time": "2020-10-11T21:42:15+00:00" + "time": "2020-11-07T02:01:34+00:00" }, { "name": "php-di/invoker", @@ -1234,6 +1244,56 @@ }, "time": "2016-08-06T14:39:51+00:00" }, + { + "name": "psr/log", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.3" + }, + "time": "2020-03-23T09:12:05+00:00" + }, { "name": "ralouphie/getallheaders", "version": "3.0.3", @@ -1280,16 +1340,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.1.8", + "version": "v5.2.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "df08650ea7aee2d925380069c131a66124d79177" + "reference": "bb92ba7f38b037e531908590a858a04d85c0e238" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/df08650ea7aee2d925380069c131a66124d79177", - "reference": "df08650ea7aee2d925380069c131a66124d79177", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/bb92ba7f38b037e531908590a858a04d85c0e238", + "reference": "bb92ba7f38b037e531908590a858a04d85c0e238", "shasum": "" }, "require": { @@ -1322,7 +1382,7 @@ "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.1.8" + "source": "https://github.com/symfony/filesystem/tree/v5.2.0" }, "funding": [ { @@ -1338,7 +1398,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-11-12T09:58:18+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1504,16 +1564,16 @@ }, { "name": "symfony/process", - "version": "v5.1.8", + "version": "v5.2.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "f00872c3f6804150d6a0f73b4151daab96248101" + "reference": "240e74140d4d956265048f3025c0aecbbc302d54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/f00872c3f6804150d6a0f73b4151daab96248101", - "reference": "f00872c3f6804150d6a0f73b4151daab96248101", + "url": "https://api.github.com/repos/symfony/process/zipball/240e74140d4d956265048f3025c0aecbbc302d54", + "reference": "240e74140d4d956265048f3025c0aecbbc302d54", "shasum": "" }, "require": { @@ -1546,7 +1606,7 @@ "description": "Symfony Process Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.1.8" + "source": "https://github.com/symfony/process/tree/v5.2.0" }, "funding": [ { @@ -1562,7 +1622,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-11-02T15:47:15+00:00" } ], "packages-dev": [ @@ -1643,16 +1703,16 @@ }, { "name": "composer/composer", - "version": "2.0.4", + "version": "2.0.8", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "4053eab90a7cdf0b81dd93073dc6c18c15d487fd" + "reference": "62139b2806178adb979d76bd3437534a1a9fd490" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/4053eab90a7cdf0b81dd93073dc6c18c15d487fd", - "reference": "4053eab90a7cdf0b81dd93073dc6c18c15d487fd", + "url": "https://api.github.com/repos/composer/composer/zipball/62139b2806178adb979d76bd3437534a1a9fd490", + "reference": "62139b2806178adb979d76bd3437534a1a9fd490", "shasum": "" }, "require": { @@ -1720,7 +1780,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/2.0.4" + "source": "https://github.com/composer/composer/tree/2.0.8" }, "funding": [ { @@ -1736,27 +1796,27 @@ "type": "tidelift" } ], - "time": "2020-10-30T21:39:11+00:00" + "time": "2020-12-03T16:20:39+00:00" }, { "name": "composer/semver", - "version": "3.2.2", + "version": "3.2.4", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "4089fddb67bcf6bf860d91b979e95be303835002" + "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/4089fddb67bcf6bf860d91b979e95be303835002", - "reference": "4089fddb67bcf6bf860d91b979e95be303835002", + "url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", + "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.19", + "phpstan/phpstan": "^0.12.54", "symfony/phpunit-bridge": "^4.2 || ^5" }, "type": "library", @@ -1801,7 +1861,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.2" + "source": "https://github.com/composer/semver/tree/3.2.4" }, "funding": [ { @@ -1817,20 +1877,20 @@ "type": "tidelift" } ], - "time": "2020-10-14T08:51:15+00:00" + "time": "2020-11-13T08:59:24+00:00" }, { "name": "composer/spdx-licenses", - "version": "1.5.4", + "version": "1.5.5", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "6946f785871e2314c60b4524851f3702ea4f2223" + "reference": "de30328a7af8680efdc03e396aad24befd513200" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/6946f785871e2314c60b4524851f3702ea4f2223", - "reference": "6946f785871e2314c60b4524851f3702ea4f2223", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/de30328a7af8680efdc03e396aad24befd513200", + "reference": "de30328a7af8680efdc03e396aad24befd513200", "shasum": "" }, "require": { @@ -1842,7 +1902,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -1880,7 +1940,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/spdx-licenses/issues", - "source": "https://github.com/composer/spdx-licenses/tree/1.5.4" + "source": "https://github.com/composer/spdx-licenses/tree/1.5.5" }, "funding": [ { @@ -1896,20 +1956,20 @@ "type": "tidelift" } ], - "time": "2020-07-15T15:35:07+00:00" + "time": "2020-12-03T16:04:16+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.4.4", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "6e076a124f7ee146f2487554a94b6a19a74887ba" + "reference": "f28d44c286812c714741478d968104c5e604a1d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6e076a124f7ee146f2487554a94b6a19a74887ba", - "reference": "6e076a124f7ee146f2487554a94b6a19a74887ba", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f28d44c286812c714741478d968104c5e604a1d4", + "reference": "f28d44c286812c714741478d968104c5e604a1d4", "shasum": "" }, "require": { @@ -1943,7 +2003,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/1.4.4" + "source": "https://github.com/composer/xdebug-handler/tree/1.4.5" }, "funding": [ { @@ -1959,7 +2019,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:39:10+00:00" + "time": "2020-11-13T08:04:11+00:00" }, { "name": "justinrainbow/json-schema", @@ -2082,16 +2142,16 @@ }, { "name": "phpstan/phpstan", - "version": "0.12.53", + "version": "0.12.58", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "dbbdb0d7c2434ecd5289f6114d16473e694caa67" + "reference": "2a4847df6047b30af28854ed9dc95304cdb56ae5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dbbdb0d7c2434ecd5289f6114d16473e694caa67", - "reference": "dbbdb0d7c2434ecd5289f6114d16473e694caa67", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2a4847df6047b30af28854ed9dc95304cdb56ae5", + "reference": "2a4847df6047b30af28854ed9dc95304cdb56ae5", "shasum": "" }, "require": { @@ -2122,7 +2182,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.53" + "source": "https://github.com/phpstan/phpstan/tree/0.12.58" }, "funding": [ { @@ -2138,7 +2198,7 @@ "type": "tidelift" } ], - "time": "2020-11-01T14:51:50+00:00" + "time": "2020-11-29T13:32:03+00:00" }, { "name": "phpstan/phpstan-symfony", @@ -2214,56 +2274,6 @@ }, "time": "2020-10-30T09:50:09+00:00" }, - { - "name": "psr/log", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/1.1.3" - }, - "time": "2020-03-23T09:12:05+00:00" - }, { "name": "react/promise", "version": "v2.8.0", @@ -2316,16 +2326,16 @@ }, { "name": "seld/jsonlint", - "version": "1.8.2", + "version": "1.8.3", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "590cfec960b77fd55e39b7d9246659e95dd6d337" + "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/590cfec960b77fd55e39b7d9246659e95dd6d337", - "reference": "590cfec960b77fd55e39b7d9246659e95dd6d337", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9ad6ce79c342fbd44df10ea95511a1b24dee5b57", + "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57", "shasum": "" }, "require": { @@ -2363,7 +2373,7 @@ ], "support": { "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/master" + "source": "https://github.com/Seldaek/jsonlint/tree/1.8.3" }, "funding": [ { @@ -2375,7 +2385,7 @@ "type": "tidelift" } ], - "time": "2020-08-25T06:56:57+00:00" + "time": "2020-11-11T09:19:24+00:00" }, { "name": "seld/phar-utils", @@ -2483,16 +2493,16 @@ }, { "name": "symfony/console", - "version": "v5.1.8", + "version": "v5.2.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "e0b2c29c0fa6a69089209bbe8fcff4df2a313d0e" + "reference": "3e0564fb08d44a98bd5f1960204c958e57bd586b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/e0b2c29c0fa6a69089209bbe8fcff4df2a313d0e", - "reference": "e0b2c29c0fa6a69089209bbe8fcff4df2a313d0e", + "url": "https://api.github.com/repos/symfony/console/zipball/3e0564fb08d44a98bd5f1960204c958e57bd586b", + "reference": "3e0564fb08d44a98bd5f1960204c958e57bd586b", "shasum": "" }, "require": { @@ -2553,8 +2563,14 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], "support": { - "source": "https://github.com/symfony/console/tree/v5.1.8" + "source": "https://github.com/symfony/console/tree/v5.2.0" }, "funding": [ { @@ -2570,20 +2586,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-11-28T11:24:18+00:00" }, { "name": "symfony/finder", - "version": "v5.1.8", + "version": "v5.2.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "e70eb5a69c2ff61ea135a13d2266e8914a67b3a0" + "reference": "fd8305521692f27eae3263895d1ef1571c71a78d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/e70eb5a69c2ff61ea135a13d2266e8914a67b3a0", - "reference": "e70eb5a69c2ff61ea135a13d2266e8914a67b3a0", + "url": "https://api.github.com/repos/symfony/finder/zipball/fd8305521692f27eae3263895d1ef1571c71a78d", + "reference": "fd8305521692f27eae3263895d1ef1571c71a78d", "shasum": "" }, "require": { @@ -2615,7 +2631,7 @@ "description": "Symfony Finder Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.1.8" + "source": "https://github.com/symfony/finder/tree/v5.2.0" }, "funding": [ { @@ -2631,20 +2647,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-11-18T09:42:36+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v5.1.8", + "version": "v5.2.0", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "61744927348cd391ac12f7c6b70544991275845c" + "reference": "92a76ca5e64effd41ce111b8f476144dfa29f1f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/61744927348cd391ac12f7c6b70544991275845c", - "reference": "61744927348cd391ac12f7c6b70544991275845c", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/92a76ca5e64effd41ce111b8f476144dfa29f1f0", + "reference": "92a76ca5e64effd41ce111b8f476144dfa29f1f0", "shasum": "" }, "require": { @@ -2654,7 +2670,8 @@ "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0|9.1.2" }, "require-dev": { - "symfony/deprecation-contracts": "^2.1" + "symfony/deprecation-contracts": "^2.1", + "symfony/error-handler": "^4.4|^5.0" }, "suggest": { "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" @@ -2697,7 +2714,7 @@ "description": "Symfony PHPUnit Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v5.1.8" + "source": "https://github.com/symfony/phpunit-bridge/tree/v5.2.0" }, "funding": [ { @@ -2713,7 +2730,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T15:53:55+00:00" + "time": "2020-11-27T00:39:34+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -3120,16 +3137,16 @@ }, { "name": "symfony/string", - "version": "v5.1.8", + "version": "v5.2.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "a97573e960303db71be0dd8fda9be3bca5e0feea" + "reference": "40e975edadd4e32cd16f3753b3bad65d9ac48242" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/a97573e960303db71be0dd8fda9be3bca5e0feea", - "reference": "a97573e960303db71be0dd8fda9be3bca5e0feea", + "url": "https://api.github.com/repos/symfony/string/zipball/40e975edadd4e32cd16f3753b3bad65d9ac48242", + "reference": "40e975edadd4e32cd16f3753b3bad65d9ac48242", "shasum": "" }, "require": { @@ -3183,7 +3200,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.1.8" + "source": "https://github.com/symfony/string/tree/v5.2.0" }, "funding": [ { @@ -3199,7 +3216,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:01:57+00:00" + "time": "2020-10-24T12:08:07+00:00" } ], "aliases": [], diff --git a/src/Listener/InitialCodeListener.php b/src/Listener/InitialCodeListener.php index 93e1cadd..cfb4500e 100644 --- a/src/Listener/InitialCodeListener.php +++ b/src/Listener/InitialCodeListener.php @@ -5,8 +5,10 @@ namespace PhpSchool\PhpWorkshop\Listener; use PhpSchool\PhpWorkshop\Event\Event; +use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface; use PhpSchool\PhpWorkshop\Exercise\ProvidesInitialCode; use PhpSchool\PhpWorkshop\Solution\SolutionFile; +use Psr\Log\LoggerInterface; /** * Copy over any initial files for this exercise when @@ -22,9 +24,15 @@ class InitialCodeListener */ private $workingDirectory; - public function __construct(string $workingDirectory) + /** + * @var LoggerInterface + */ + private $logger; + + public function __construct(string $workingDirectory, LoggerInterface $logger) { $this->workingDirectory = $workingDirectory; + $this->logger = $logger; } /** @@ -32,6 +40,7 @@ public function __construct(string $workingDirectory) */ public function __invoke(Event $event): void { + /** @var ExerciseInterface $exercise */ $exercise = $event->getParameter('exercise'); if (!$exercise instanceof ProvidesInitialCode) { @@ -42,7 +51,19 @@ public function __invoke(Event $event): void /** @var SolutionFile $file */ if (!file_exists($this->workingDirectory . '/' . $file->getRelativePath())) { copy($file->getAbsolutePath(), $this->workingDirectory . '/' . $file->getRelativePath()); + $message = 'File successfully copied to working directory'; + } else { + $message = 'File not copied. File with same name already exists in working directory'; } + + $this->logger->debug( + $message, + [ + 'exercise' => $exercise->getName(), + 'workingDir' => $this->workingDirectory, + 'file' => $file->getAbsolutePath() + ] + ); } } } diff --git a/src/Logger/Logger.php b/src/Logger/Logger.php new file mode 100644 index 00000000..98c03e37 --- /dev/null +++ b/src/Logger/Logger.php @@ -0,0 +1,42 @@ +filePath = $filePath; + } + + public function log($level, $message, array $context = []): void + { + if (!file_exists($this->filePath)) { + if (!mkdir($concurrentDirectory = dirname($this->filePath), 0777, true) && !is_dir($concurrentDirectory)) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory)); + } + } + + file_put_contents( + $this->filePath, + sprintf( + "Time: %s, Level: %s, Message: %s, Context: %s\n\n", + (new \DateTime())->format('d-m-y H:i:s'), + $level, + $message, + json_encode($context) + ), + FILE_APPEND + ); + } +} diff --git a/test/Asset/ExerciseWithInitialCode.php b/test/Asset/ExerciseWithInitialCode.php index e32a9467..398b3785 100644 --- a/test/Asset/ExerciseWithInitialCode.php +++ b/test/Asset/ExerciseWithInitialCode.php @@ -13,7 +13,7 @@ class ExerciseWithInitialCode implements ExerciseInterface, ProvidesInitialCode { public function getName(): string { - // TODO: Implement getName() method. + return 'exercise-with-initial-code'; } public function getDescription(): string diff --git a/test/BaseTest.php b/test/BaseTest.php new file mode 100644 index 00000000..207f35f4 --- /dev/null +++ b/test/BaseTest.php @@ -0,0 +1,32 @@ +tempDirectory) { + $tempDirectory = sprintf('%s/%s', realpath(sys_get_temp_dir()), $this->getName()); + mkdir($tempDirectory, 0777, true); + + $this->tempDirectory = realpath($tempDirectory); + } + + return $this->tempDirectory; + } + + public function tearDown(): void + { + if ($this->tempDirectory) { + (new Filesystem())->remove($this->tempDirectory); + } + } +} diff --git a/test/ContainerAwareTest.php b/test/ContainerAwareTest.php new file mode 100644 index 00000000..c54e5573 --- /dev/null +++ b/test/ContainerAwareTest.php @@ -0,0 +1,82 @@ +addDefinitions(require $containerConfig); + + $containerBuilder->useAutowiring(false); + $containerBuilder->useAnnotations(false); + + $this->container = $containerBuilder->build(); + } + + public function mockLogger(): void + { + $this->container->set(LoggerInterface::class, new MockLogger()); + } + + public function mockCurrentWorkingDirectory(): void + { + $this->currentWorkingDirectory = $this->getTemporaryDirectory(); + $this->container->set('currentWorkingDirectory', $this->currentWorkingDirectory); + } + + public function getCurrentWorkingDirectory(): ?string + { + return $this->currentWorkingDirectory; + } + + /** + * @param array}> $messages + * @throws ExpectationFailedException + */ + public function assertLoggerHasMessages(array $messages): void + { + $logged = $this->container->get(LoggerInterface::class)->messages; + + foreach ($messages as $message) { + $this->assertContains( + [ + 'level' => $message['level'], + 'message' => $message['message'], + 'context' => $message['context'] + ], + $logged + ); + } + } + + public function tearDown(): void + { + if ($this->currentWorkingDirectory) { + (new Filesystem())->remove($this->currentWorkingDirectory); + } + + parent::tearDown(); + } +} diff --git a/test/Listener/InitialCodeListenerTest.php b/test/Listener/InitialCodeListenerTest.php index 18a55671..2faf1723 100644 --- a/test/Listener/InitialCodeListenerTest.php +++ b/test/Listener/InitialCodeListenerTest.php @@ -8,27 +8,16 @@ use PhpSchool\PhpWorkshop\Listener\InitialCodeListener; use PhpSchool\PhpWorkshopTest\Asset\CliExerciseImpl; use PhpSchool\PhpWorkshopTest\Asset\ExerciseWithInitialCode; -use PHPUnit\Framework\TestCase; -use Symfony\Component\Filesystem\Filesystem; +use PhpSchool\PhpWorkshopTest\ContainerAwareTest; -class InitialCodeListenerTest extends TestCase +class InitialCodeListenerTest extends ContainerAwareTest { - /** - * @var Filesystem - */ - private $filesystem; - - /** - * @var string - */ - private $cwd; - public function setUp(): void { - $this->filesystem = new Filesystem(); + parent::setUp(); - $this->cwd = sprintf('%s/%s', str_replace('\\', '/', sys_get_temp_dir()), $this->getName()); - mkdir($this->cwd, 0775, true); + $this->mockCurrentWorkingDirectory(); + $this->mockLogger(); } public function testExerciseCodeIsCopiedIfExerciseProvidesInitialCode(): void @@ -37,30 +26,67 @@ public function testExerciseCodeIsCopiedIfExerciseProvidesInitialCode(): void $event = new Event('exercise.selected', ['exercise' => $exercise]); - $listener = new InitialCodeListener($this->cwd); + $listener = $this->container->get(InitialCodeListener::class); $listener->__invoke($event); - $this->assertFileExists($this->cwd . '/init-solution.php'); + $this->assertFileExists($this->getCurrentWorkingDirectory() . '/init-solution.php'); $this->assertFileEquals( $exercise->getInitialCode()->getFiles()[0]->getAbsolutePath(), - $this->cwd . '/init-solution.php' + $this->getCurrentWorkingDirectory() . '/init-solution.php' + ); + + $this->assertLoggerHasMessages( + [ + [ + 'level' => 'debug', + 'message' => 'File successfully copied to working directory', + 'context' => [ + 'exercise' => 'exercise-with-initial-code', + 'workingDir' => $this->getCurrentWorkingDirectory(), + 'file' => $exercise->getInitialCode()->getFiles()[0]->getAbsolutePath() + ] + ] + ] ); } - public function testExerciseCodeIsNotCopiedIfExerciseDoesNotProvideInitialCode(): void + public function testExerciseCodeIsNotCopiedIfFileWithSameNameExistsInWorkingDirectory(): void { - $exercise = new CliExerciseImpl(); + $exercise = new ExerciseWithInitialCode(); $event = new Event('exercise.selected', ['exercise' => $exercise]); - $listener = new InitialCodeListener($this->cwd); + touch($this->getCurrentWorkingDirectory() . '/init-solution.php'); + + $listener = $this->container->get(InitialCodeListener::class); $listener->__invoke($event); - $this->assertEmpty(array_diff(scandir($this->cwd), ['.', '..'])); + $this->assertFileExists($this->getCurrentWorkingDirectory() . '/init-solution.php'); + + $this->assertLoggerHasMessages( + [ + [ + 'level' => 'debug', + 'message' => 'File not copied. File with same name already exists in working directory', + 'context' => [ + 'exercise' => 'exercise-with-initial-code', + 'workingDir' => $this->getCurrentWorkingDirectory(), + 'file' => $exercise->getInitialCode()->getFiles()[0]->getAbsolutePath() + ] + ] + ] + ); } - public function tearDown(): void + public function testExerciseCodeIsNotCopiedIfExerciseDoesNotProvideInitialCode(): void { - $this->filesystem->remove($this->cwd); + $exercise = new CliExerciseImpl(); + + $event = new Event('exercise.selected', ['exercise' => $exercise]); + + $listener = $this->container->get(InitialCodeListener::class); + $listener->__invoke($event); + + $this->assertEmpty(array_diff(scandir($this->getCurrentWorkingDirectory()), ['.', '..'])); } } diff --git a/test/Logger/LoggerTest.php b/test/Logger/LoggerTest.php new file mode 100644 index 00000000..cdfc26b9 --- /dev/null +++ b/test/Logger/LoggerTest.php @@ -0,0 +1,103 @@ +container->set('phpschoolGlobalDir', $this->getTemporaryDirectory()); + $this->container->set('appName', 'my-workshop'); + } + + public function testLoggerDoesNotCreateFileIfNoMessageIsLogged(): void + { + $expectedFileName = sprintf("%s/logs/my-workshop.log", $this->getTemporaryDirectory()); + + $logger = $this->container->get(LoggerInterface::class); + + $this->assertFileDoesNotExist($expectedFileName); + } + + public function testLoggerCreatesFileWhenMessageIsLogged(): void + { + $expectedFileName = sprintf("%s/logs/my-workshop.log", $this->getTemporaryDirectory()); + + $logger = $this->container->get(LoggerInterface::class); + $logger->critical('Failed to copy file'); + + $this->assertFileExists($expectedFileName); + $match = '/Time\: \d{2}\-\d{2}\-\d{2} \d{2}\:\d{2}\:\d{2}, Level\: critical, Message\: Failed to copy file,'; + $match .= ' Context\: \[\]' . "\n\n/"; + + $this->assertMatchesRegularExpression( + $match, + file_get_contents($expectedFileName) + ); + } + + public function testLoggerAppendsToFileWhenSecondMessageIsLogged(): void + { + $expectedFileName = sprintf("%s/logs/my-workshop.log", $this->getTemporaryDirectory()); + + $logger = $this->container->get(LoggerInterface::class); + $logger->critical('Failed to copy file'); + $logger->emergency('Second error'); + + $this->assertFileExists($expectedFileName); + $match = '/Time\: \d{2}\-\d{2}\-\d{2} \d{2}\:\d{2}\:\d{2}, Level\: critical, Message\: Failed to copy file,'; + $match .= ' Context\: \[\]' . "\n\n"; + $match .= 'Time\: \d{2}\-\d{2}\-\d{2} \d{2}\:\d{2}\:\d{2}, Level\: emergency, Message\: Second error,'; + $match .= ' Context\: \[\]' . "\n\n/"; + + $this->assertMatchesRegularExpression( + $match, + file_get_contents($expectedFileName) + ); + } + + public function testLoggerAppendsToFileWhenItAlreadyExists(): void + { + $expectedFileName = sprintf("%s/logs/my-workshop.log", $this->getTemporaryDirectory()); + + mkdir(dirname($expectedFileName), 0777, true); + file_put_contents($expectedFileName, "Please do not overwrite me\n\n"); + + $logger = $this->container->get(LoggerInterface::class); + $logger->emergency('Second error'); + + $this->assertFileExists($expectedFileName); + $match = '/Please do not overwrite me' . "\n\n"; + $match .= 'Time\: \d{2}\-\d{2}\-\d{2} \d{2}\:\d{2}\:\d{2}, Level\: emergency, Message\: Second error,'; + $match .= ' Context\: \[\]' . "\n\n/"; + + $this->assertMatchesRegularExpression( + $match, + file_get_contents($expectedFileName) + ); + } + + public function testLoggerWithContextIsEncoded(): void + { + $expectedFileName = sprintf("%s/logs/my-workshop.log", $this->getTemporaryDirectory()); + + $logger = $this->container->get(LoggerInterface::class); + $logger->critical('Failed to copy file', ['exercise' => 'my-exercise']); + + $this->assertFileExists($expectedFileName); + + $match = '/Time\: \d{2}\-\d{2}\-\d{2} \d{2}\:\d{2}\:\d{2}, Level\: critical, Message\: Failed to copy file, '; + $match .= 'Context\: {"exercise":"my-exercise"}/'; + $this->assertMatchesRegularExpression( + $match, + file_get_contents($expectedFileName) + ); + } +} diff --git a/test/MockLogger.php b/test/MockLogger.php new file mode 100644 index 00000000..2c908414 --- /dev/null +++ b/test/MockLogger.php @@ -0,0 +1,33 @@ +}> + */ + public $messages = []; + + public function log($level, $message, array $context = []): void + { + $this->messages[] = [ + 'level' => $level, + 'message' => $message, + 'context' => $context + ]; + } + + /** + * @return array}> + */ + public function getLastMessage(): array + { + return $this->messages[count($this->messages) - 1]; + } +}