From ed69eb5d7b120f2a747c7e9f598476a2f19f5523 Mon Sep 17 00:00:00 2001 From: hide_d Date: Tue, 28 Jan 2020 00:22:43 +0900 Subject: [PATCH] composer package update --- composer.json | 4 +- composer.lock | 318 +- composer.phar | Bin 1849094 -> 1936666 bytes vendor/bin/pscss | 12 +- vendor/bin/pscss.bat | 2 +- vendor/catfan/medoo/.github/FUNDING.yml | 3 + .../.github/ISSUE_TEMPLATE/bug_report.md | 19 + vendor/catfan/medoo/LICENSE.md | 2 +- vendor/catfan/medoo/README.md | 10 +- vendor/catfan/medoo/composer.json | 8 +- vendor/catfan/medoo/src/Medoo.php | 712 +++- vendor/composer/ClassLoader.php | 4 +- vendor/composer/autoload_classmap.php | 37 +- vendor/composer/autoload_files.php | 1 + vendor/composer/autoload_psr4.php | 2 +- vendor/composer/autoload_static.php | 48 +- vendor/composer/installed.json | 338 +- vendor/ezyang/htmlpurifier/INSTALL | 36 +- vendor/ezyang/htmlpurifier/INSTALL.fr.utf8 | 2 +- vendor/ezyang/htmlpurifier/NEWS | 34 + vendor/ezyang/htmlpurifier/README.md | 2 +- vendor/ezyang/htmlpurifier/VERSION | 2 +- vendor/ezyang/htmlpurifier/WHATSNEW | 15 +- vendor/ezyang/htmlpurifier/composer.json | 4 +- .../library/HTMLPurifier.includes.php | 2 +- .../htmlpurifier/library/HTMLPurifier.php | 16 +- .../HTMLPurifier/AttrDef/HTML/Bool.php | 4 +- .../library/HTMLPurifier/AttrDef/URI/Host.php | 6 +- .../library/HTMLPurifier/CSSDefinition.php | 52 +- .../library/HTMLPurifier/ChildDef/Custom.php | 2 +- .../library/HTMLPurifier/Config.php | 4 +- .../library/HTMLPurifier/ConfigSchema.php | 2 +- .../HTMLPurifier/ConfigSchema/schema.ser | Bin 15923 -> 24124 bytes .../AutoFormat.RemoveEmpty.RemoveNbsp.txt | 2 +- .../schema/Core.AllowParseManyTags.txt | 12 + .../schema/Core.ColorKeywords.txt | 159 +- .../library/HTMLPurifier/Encoder.php | 2 +- .../library/HTMLPurifier/EntityParser.php | 2 +- .../library/HTMLPurifier/HTMLModule.php | 4 +- .../HTMLPurifier/HTMLModule/SafeScripting.php | 4 +- .../Language/messages/en-x-test.php | 2 + .../Language/messages/en-x-testmini.php | 2 + .../library/HTMLPurifier/Lexer/DOMLex.php | 24 +- .../HTMLPurifier/Printer/ConfigForm.php | 4 +- .../HTMLPurifier/TagTransform/Font.php | 2 +- .../library/HTMLPurifier/VarParser.php | 32 +- .../HTMLPurifier/VarParser/Flexible.php | 10 +- .../ezyang/htmlpurifier/maintenance/.htaccess | 8 +- .../ezyang/htmlpurifier/maintenance/flush.php | 30 - .../ezyang/htmlpurifier/maintenance/flush.sh | 8 + .../maintenance/update-config.php | 34 - .../plugins/phorum/config.default.php | 1 + vendor/ezyang/htmlpurifier/release2-tag.php | 22 - ...release1-update.php => update-for-release} | 2 +- vendor/guzzlehttp/guzzle/.php_cs | 23 + vendor/guzzlehttp/guzzle/CHANGELOG.md | 35 + vendor/guzzlehttp/guzzle/Dockerfile | 18 + vendor/guzzlehttp/guzzle/README.md | 23 +- vendor/guzzlehttp/guzzle/composer.json | 43 +- vendor/guzzlehttp/guzzle/src/Client.php | 101 +- .../guzzlehttp/guzzle/src/ClientInterface.php | 7 +- .../guzzle/src/Cookie/CookieJar.php | 8 +- .../guzzle/src/Cookie/CookieJarInterface.php | 6 +- .../guzzle/src/Cookie/FileCookieJar.php | 3 +- .../guzzle/src/Cookie/SessionCookieJar.php | 1 + .../guzzle/src/Cookie/SetCookie.php | 4 +- .../guzzle/src/Exception/ClientException.php | 4 +- .../guzzle/src/Exception/GuzzleException.php | 30 +- .../Exception/InvalidArgumentException.php | 7 + .../guzzle/src/Exception/RequestException.php | 35 +- .../guzzle/src/Exception/ServerException.php | 4 +- .../Exception/TooManyRedirectsException.php | 4 +- .../src/Exception/TransferException.php | 4 +- .../guzzle/src/Handler/CurlFactory.php | 44 +- .../guzzle/src/Handler/CurlMultiHandler.php | 34 +- .../guzzle/src/Handler/MockHandler.php | 10 +- .../guzzle/src/Handler/StreamHandler.php | 24 +- vendor/guzzlehttp/guzzle/src/HandlerStack.php | 14 +- .../guzzle/src/MessageFormatter.php | 5 + vendor/guzzlehttp/guzzle/src/Middleware.php | 7 +- vendor/guzzlehttp/guzzle/src/Pool.php | 15 +- .../guzzle/src/PrepareBodyMiddleware.php | 5 + .../guzzle/src/RedirectMiddleware.php | 28 +- .../guzzlehttp/guzzle/src/RequestOptions.php | 10 +- .../guzzlehttp/guzzle/src/RetryMiddleware.php | 22 +- .../guzzlehttp/guzzle/src/TransferStats.php | 12 +- vendor/guzzlehttp/guzzle/src/functions.php | 73 +- vendor/guzzlehttp/psr7/CHANGELOG.md | 252 +- vendor/guzzlehttp/psr7/README.md | 8 +- vendor/guzzlehttp/psr7/composer.json | 18 +- vendor/guzzlehttp/psr7/src/AppendStream.php | 16 +- vendor/guzzlehttp/psr7/src/FnStream.php | 9 + vendor/guzzlehttp/psr7/src/InflateStream.php | 2 +- vendor/guzzlehttp/psr7/src/LimitStream.php | 2 +- vendor/guzzlehttp/psr7/src/MessageTrait.php | 60 +- vendor/guzzlehttp/psr7/src/Request.php | 13 +- vendor/guzzlehttp/psr7/src/Response.php | 26 +- vendor/guzzlehttp/psr7/src/Rfc7230.php | 18 + vendor/guzzlehttp/psr7/src/ServerRequest.php | 34 +- vendor/guzzlehttp/psr7/src/Stream.php | 68 +- vendor/guzzlehttp/psr7/src/StreamWrapper.php | 46 +- vendor/guzzlehttp/psr7/src/Uri.php | 124 +- vendor/guzzlehttp/psr7/src/functions.php | 133 +- vendor/leafo/scssphp/composer.json | 41 - vendor/leafo/scssphp/src/Formatter/Nested.php | 201 - .../src/SourceMap/Base64VLQEncoder.php | 217 - vendor/monolog/monolog/.php_cs | 59 - vendor/monolog/monolog/CHANGELOG.md | 62 + vendor/monolog/monolog/README.md | 3 +- vendor/monolog/monolog/composer.json | 2 +- vendor/monolog/monolog/doc/01-usage.md | 231 -- .../doc/02-handlers-formatters-processors.md | 157 - vendor/monolog/monolog/doc/03-utilities.md | 13 - vendor/monolog/monolog/doc/04-extending.md | 76 - vendor/monolog/monolog/doc/sockets.md | 39 - vendor/monolog/monolog/phpunit.xml.dist | 19 - .../monolog/src/Monolog/ErrorHandler.php | 13 +- .../Monolog/Formatter/FluentdFormatter.php | 5 +- .../src/Monolog/Formatter/HtmlFormatter.php | 7 +- .../src/Monolog/Formatter/JsonFormatter.php | 32 +- .../src/Monolog/Formatter/LineFormatter.php | 10 +- .../Monolog/Formatter/MongoDBFormatter.php | 8 +- .../Monolog/Formatter/NormalizerFormatter.php | 153 +- .../Monolog/Formatter/WildfireFormatter.php | 4 +- .../src/Monolog/Handler/AbstractHandler.php | 26 +- .../Handler/AbstractProcessingHandler.php | 2 + .../Monolog/Handler/AbstractSyslogHandler.php | 6 +- .../Monolog/Handler/BrowserConsoleHandler.php | 59 +- .../src/Monolog/Handler/BufferHandler.php | 35 +- .../src/Monolog/Handler/ChromePHPHandler.php | 19 +- .../src/Monolog/Handler/CubeHandler.php | 5 +- .../Monolog/Handler/DeduplicationHandler.php | 2 +- .../Monolog/Handler/ElasticSearchHandler.php | 8 +- .../src/Monolog/Handler/ErrorLogHandler.php | 8 +- .../src/Monolog/Handler/FilterHandler.php | 58 +- .../ActivationStrategyInterface.php | 2 +- .../Monolog/Handler/FingersCrossedHandler.php | 98 +- .../src/Monolog/Handler/FirePHPHandler.php | 2 +- .../src/Monolog/Handler/FlowdockHandler.php | 3 +- .../Handler/FormattableHandlerInterface.php | 39 + .../Handler/FormattableHandlerTrait.php | 63 + .../src/Monolog/Handler/GelfHandler.php | 8 - .../src/Monolog/Handler/GroupHandler.php | 19 +- .../src/Monolog/Handler/HandlerInterface.php | 4 +- .../src/Monolog/Handler/HandlerWrapper.php | 10 +- .../src/Monolog/Handler/HipChatHandler.php | 17 + .../src/Monolog/Handler/IFTTTHandler.php | 11 +- .../src/Monolog/Handler/InsightOpsHandler.php | 62 + .../src/Monolog/Handler/LogEntriesHandler.php | 4 +- .../src/Monolog/Handler/MandrillHandler.php | 2 +- .../src/Monolog/Handler/NewRelicHandler.php | 7 +- .../src/Monolog/Handler/PHPConsoleHandler.php | 3 +- .../Handler/ProcessableHandlerInterface.php | 40 + .../Handler/ProcessableHandlerTrait.php | 73 + .../src/Monolog/Handler/PsrHandler.php | 2 +- .../src/Monolog/Handler/PushoverHandler.php | 6 +- .../src/Monolog/Handler/RavenHandler.php | 14 +- .../src/Monolog/Handler/RedisHandler.php | 3 +- .../src/Monolog/Handler/RollbarHandler.php | 12 + .../Monolog/Handler/RotatingFileHandler.php | 18 +- .../src/Monolog/Handler/SamplingHandler.php | 53 +- .../src/Monolog/Handler/Slack/SlackRecord.php | 19 +- .../src/Monolog/Handler/SlackHandler.php | 8 +- .../Monolog/Handler/SlackWebhookHandler.php | 8 +- .../src/Monolog/Handler/SlackbotHandler.php | 8 +- .../src/Monolog/Handler/SocketHandler.php | 47 +- .../src/Monolog/Handler/StreamHandler.php | 7 +- .../Monolog/Handler/SwiftMailerHandler.php | 16 +- .../src/Monolog/Handler/SyslogHandler.php | 10 +- .../src/Monolog/Handler/SyslogUdpHandler.php | 49 +- .../src/Monolog/Handler/TestHandler.php | 29 +- .../Handler/WhatFailureGroupHandler.php | 11 + .../Monolog/Handler/ZendMonitorHandler.php | 46 +- vendor/monolog/monolog/src/Monolog/Logger.php | 250 +- .../src/Monolog/Processor/GitProcessor.php | 2 +- .../Processor/IntrospectionProcessor.php | 2 +- .../src/Monolog/Processor/MemoryProcessor.php | 6 +- .../Monolog/Processor/MercurialProcessor.php | 2 +- .../Monolog/Processor/ProcessIdProcessor.php | 2 +- .../Monolog/Processor/ProcessorInterface.php | 25 + .../Processor/PsrLogMessageProcessor.php | 6 +- .../src/Monolog/Processor/TagProcessor.php | 2 +- .../src/Monolog/Processor/UidProcessor.php | 17 +- .../src/Monolog/Processor/WebProcessor.php | 2 +- .../src/Monolog/ResettableInterface.php | 31 + .../monolog/src/Monolog/SignalHandler.php | 115 + vendor/monolog/monolog/src/Monolog/Utils.php | 159 + .../tests/Monolog/ErrorHandlerTest.php | 31 - .../Formatter/ChromePHPFormatterTest.php | 158 - .../Formatter/ElasticaFormatterTest.php | 79 - .../Formatter/FlowdockFormatterTest.php | 55 - .../Formatter/FluentdFormatterTest.php | 62 - .../Formatter/GelfMessageFormatterTest.php | 258 -- .../Monolog/Formatter/JsonFormatterTest.php | 183 - .../Monolog/Formatter/LineFormatterTest.php | 222 - .../Monolog/Formatter/LogglyFormatterTest.php | 40 - .../Formatter/LogstashFormatterTest.php | 333 -- .../Formatter/MongoDBFormatterTest.php | 262 -- .../Formatter/NormalizerFormatterTest.php | 423 -- .../Monolog/Formatter/ScalarFormatterTest.php | 110 - .../Formatter/WildfireFormatterTest.php | 142 - .../Monolog/Handler/AbstractHandlerTest.php | 115 - .../Handler/AbstractProcessingHandlerTest.php | 80 - .../tests/Monolog/Handler/AmqpHandlerTest.php | 136 - .../Handler/BrowserConsoleHandlerTest.php | 130 - .../Monolog/Handler/BufferHandlerTest.php | 158 - .../Monolog/Handler/ChromePHPHandlerTest.php | 156 - .../Monolog/Handler/CouchDBHandlerTest.php | 31 - .../Handler/DeduplicationHandlerTest.php | 165 - .../Handler/DoctrineCouchDBHandlerTest.php | 52 - .../Monolog/Handler/DynamoDbHandlerTest.php | 82 - .../Handler/ElasticSearchHandlerTest.php | 239 -- .../Monolog/Handler/ErrorLogHandlerTest.php | 66 - .../Monolog/Handler/FilterHandlerTest.php | 170 - .../Handler/FingersCrossedHandlerTest.php | 279 -- .../Monolog/Handler/FirePHPHandlerTest.php | 96 - .../tests/Monolog/Handler/Fixtures/.gitkeep | 0 .../Monolog/Handler/FleepHookHandlerTest.php | 85 - .../Monolog/Handler/FlowdockHandlerTest.php | 88 - .../Monolog/Handler/GelfHandlerLegacyTest.php | 95 - .../tests/Monolog/Handler/GelfHandlerTest.php | 117 - .../Handler/GelfMockMessagePublisher.php | 25 - .../Monolog/Handler/GroupHandlerTest.php | 112 - .../Monolog/Handler/HandlerWrapperTest.php | 130 - .../Monolog/Handler/HipChatHandlerTest.php | 279 -- .../Monolog/Handler/LogEntriesHandlerTest.php | 84 - .../tests/Monolog/Handler/MailHandlerTest.php | 75 - .../tests/Monolog/Handler/MockRavenClient.php | 27 - .../Monolog/Handler/MongoDBHandlerTest.php | 65 - .../Handler/NativeMailerHandlerTest.php | 111 - .../Monolog/Handler/NewRelicHandlerTest.php | 200 - .../tests/Monolog/Handler/NullHandlerTest.php | 33 - .../Monolog/Handler/PHPConsoleHandlerTest.php | 273 -- .../tests/Monolog/Handler/PsrHandlerTest.php | 50 - .../Monolog/Handler/PushoverHandlerTest.php | 141 - .../Monolog/Handler/RavenHandlerTest.php | 255 -- .../Monolog/Handler/RedisHandlerTest.php | 127 - .../Monolog/Handler/RollbarHandlerTest.php | 84 - .../Handler/RotatingFileHandlerTest.php | 211 - .../Monolog/Handler/SamplingHandlerTest.php | 33 - .../Monolog/Handler/Slack/SlackRecordTest.php | 387 -- .../Monolog/Handler/SlackHandlerTest.php | 155 - .../Handler/SlackWebhookHandlerTest.php | 107 - .../Monolog/Handler/SlackbotHandlerTest.php | 47 - .../Monolog/Handler/SocketHandlerTest.php | 309 -- .../Monolog/Handler/StreamHandlerTest.php | 184 - .../Handler/SwiftMailerHandlerTest.php | 113 - .../Monolog/Handler/SyslogHandlerTest.php | 44 - .../Monolog/Handler/SyslogUdpHandlerTest.php | 76 - .../tests/Monolog/Handler/TestHandlerTest.php | 70 - .../tests/Monolog/Handler/UdpSocketTest.php | 64 - .../Handler/WhatFailureGroupHandlerTest.php | 121 - .../Handler/ZendMonitorHandlerTest.php | 69 - .../monolog/tests/Monolog/LoggerTest.php | 548 --- .../Monolog/Processor/GitProcessorTest.php | 29 - .../Processor/IntrospectionProcessorTest.php | 123 - .../MemoryPeakUsageProcessorTest.php | 42 - .../Processor/MemoryUsageProcessorTest.php | 42 - .../Processor/MercurialProcessorTest.php | 41 - .../Processor/ProcessIdProcessorTest.php | 30 - .../Processor/PsrLogMessageProcessorTest.php | 43 - .../Monolog/Processor/TagProcessorTest.php | 49 - .../Monolog/Processor/UidProcessorTest.php | 33 - .../Monolog/Processor/WebProcessorTest.php | 113 - .../tests/Monolog/PsrLogCompatTest.php | 47 - .../monolog/tests/Monolog/RegistryTest.php | 153 - .../monolog/tests/Monolog/TestCase.php | 58 - vendor/psr/log/Psr/Log/LoggerInterface.php | 2 + vendor/psr/log/Psr/Log/LoggerTrait.php | 2 + vendor/psr/log/Psr/Log/NullLogger.php | 2 + .../log/Psr/Log/Test/LoggerInterfaceTest.php | 8 +- vendor/psr/log/Psr/Log/Test/TestLogger.php | 147 + vendor/psr/log/README.md | 13 + vendor/psr/log/composer.json | 2 +- vendor/ralouphie/getallheaders/LICENSE | 21 + vendor/ralouphie/getallheaders/README.md | 27 + vendor/ralouphie/getallheaders/composer.json | 26 + .../getallheaders/src/getallheaders.php | 46 + vendor/{leafo => scssphp}/scssphp/LICENSE.md | 2 +- vendor/{leafo => scssphp}/scssphp/README.md | 8 +- vendor/{leafo => scssphp}/scssphp/bin/pscss | 46 +- vendor/scssphp/scssphp/composer.json | 51 + .../scssphp/example/Server.php | 70 +- .../{leafo => scssphp}/scssphp/scss.inc.php | 10 +- .../scssphp/src/Base/Range.php | 6 +- .../{leafo => scssphp}/scssphp/src/Block.php | 13 +- vendor/scssphp/scssphp/src/Cache.php | 239 ++ .../{leafo => scssphp}/scssphp/src/Colors.php | 75 +- .../scssphp/src/Compiler.php | 3621 +++++++++++++---- .../scssphp/src/Compiler/Environment.php | 15 +- .../src/Exception/CompilerException.php | 6 +- .../scssphp/src/Exception/ParserException.php | 6 +- .../scssphp/src/Exception/RangeException.php | 6 +- .../scssphp/src/Exception/ServerException.php | 6 +- .../scssphp/src/Formatter.php | 114 +- .../scssphp/src/Formatter/Compact.php | 8 +- .../scssphp/src/Formatter/Compressed.php | 29 +- .../scssphp/src/Formatter/Crunched.php | 29 +- .../scssphp/src/Formatter/Debug.php | 10 +- .../scssphp/src/Formatter/Expanded.php | 12 +- .../scssphp/scssphp/src/Formatter/Nested.php | 228 ++ .../scssphp/src/Formatter/OutputBlock.php | 8 +- .../{leafo => scssphp}/scssphp/src/Node.php | 6 +- .../scssphp/src/Node/Number.php | 30 +- .../{leafo => scssphp}/scssphp/src/Parser.php | 1392 +++++-- .../scssphp/scssphp/src/SourceMap/Base64.php | 184 + .../scssphp/src/SourceMap/Base64VLQ.php | 146 + .../src/SourceMap/SourceMapGenerator.php | 80 +- .../{leafo => scssphp}/scssphp/src/Type.php | 6 +- .../{leafo => scssphp}/scssphp/src/Util.php | 16 +- .../scssphp/src/Version.php | 8 +- vendor/symfony/lock/.gitattributes | 3 + vendor/symfony/lock/.gitignore | 3 - .../symfony/lock/BlockingStoreInterface.php | 27 + vendor/symfony/lock/CHANGELOG.md | 16 + .../lock/Exception/ExceptionInterface.php | 2 +- .../lock/Exception/InvalidTtlException.php | 19 + vendor/symfony/lock/Factory.php | 10 +- vendor/symfony/lock/Key.php | 13 +- vendor/symfony/lock/LICENSE | 2 +- vendor/symfony/lock/Lock.php | 68 +- vendor/symfony/lock/LockFactory.php | 33 + .../symfony/lock/PersistingStoreInterface.php | 53 + vendor/symfony/lock/Store/CombinedStore.php | 50 +- .../symfony/lock/Store/ExpiringStoreTrait.php | 30 + vendor/symfony/lock/Store/FlockStore.php | 9 +- vendor/symfony/lock/Store/MemcachedStore.php | 51 +- vendor/symfony/lock/Store/PdoStore.php | 363 ++ vendor/symfony/lock/Store/RedisStore.php | 68 +- .../symfony/lock/Store/RetryTillSaveStore.php | 15 +- vendor/symfony/lock/Store/SemaphoreStore.php | 13 +- vendor/symfony/lock/Store/StoreFactory.php | 76 +- vendor/symfony/lock/Store/ZookeeperStore.php | 176 + vendor/symfony/lock/StoreInterface.php | 35 +- vendor/symfony/lock/Tests/FactoryTest.php | 36 - vendor/symfony/lock/Tests/LockTest.php | 268 -- .../Tests/Store/AbstractRedisStoreTest.php | 45 - .../lock/Tests/Store/AbstractStoreTest.php | 115 - .../Tests/Store/BlockingStoreTestTrait.php | 92 - .../lock/Tests/Store/CombinedStoreTest.php | 356 -- .../Tests/Store/ExpiringStoreTestTrait.php | 107 - .../lock/Tests/Store/FlockStoreTest.php | 78 - .../lock/Tests/Store/MemcachedStoreTest.php | 60 - .../lock/Tests/Store/PredisStoreTest.php | 36 - .../lock/Tests/Store/RedisArrayStoreTest.php | 38 - .../lock/Tests/Store/RedisStoreTest.php | 36 - .../Tests/Store/RetryTillSaveStoreTest.php | 35 - .../lock/Tests/Store/SemaphoreStoreTest.php | 60 - .../Tests/Strategy/ConsensusStrategyTest.php | 89 - .../Tests/Strategy/UnanimousStrategyTest.php | 89 - vendor/symfony/lock/composer.json | 7 +- vendor/symfony/lock/phpunit.xml.dist | 32 - vendor/vlucas/valitron/.github/FUNDING.yml | 1 + vendor/vlucas/valitron/README.md | 948 ++++- vendor/vlucas/valitron/composer.json | 4 +- vendor/vlucas/valitron/lang/ar.php | 1 + vendor/vlucas/valitron/lang/az.php | 1 + vendor/vlucas/valitron/lang/bg.php | 1 + vendor/vlucas/valitron/lang/de.php | 1 + vendor/vlucas/valitron/lang/el.php | 1 + vendor/vlucas/valitron/lang/en.php | 68 +- vendor/vlucas/valitron/lang/es.php | 63 +- vendor/vlucas/valitron/lang/fi.php | 1 + vendor/vlucas/valitron/lang/fr.php | 1 + vendor/vlucas/valitron/lang/id.php | 1 + vendor/vlucas/valitron/lang/it.php | 1 + vendor/vlucas/valitron/lang/ja.php | 1 + vendor/vlucas/valitron/lang/ko.php | 1 + vendor/vlucas/valitron/lang/lt.php | 7 +- vendor/vlucas/valitron/lang/lv.php | 1 + vendor/vlucas/valitron/lang/nb.php | 39 + vendor/vlucas/valitron/lang/nl.php | 1 + vendor/vlucas/valitron/lang/nn.php | 35 + vendor/vlucas/valitron/lang/no.php | 33 +- vendor/vlucas/valitron/lang/pl.php | 1 + vendor/vlucas/valitron/lang/pt-br.php | 65 +- vendor/vlucas/valitron/lang/ro.php | 1 + vendor/vlucas/valitron/lang/ru.php | 65 +- vendor/vlucas/valitron/lang/sk.php | 1 + vendor/vlucas/valitron/lang/sv.php | 1 + vendor/vlucas/valitron/lang/th.php | 1 + vendor/vlucas/valitron/lang/tr.php | 1 + vendor/vlucas/valitron/lang/uk.php | 1 + vendor/vlucas/valitron/lang/vi.php | 1 + vendor/vlucas/valitron/lang/zh-cn.php | 1 + vendor/vlucas/valitron/lang/zh-tw.php | 1 + .../valitron/src/Valitron/Validator.php | 511 ++- vendor/xemlock/htmlpurifier-html5/README.md | 32 +- .../xemlock/htmlpurifier-html5/composer.json | 10 +- .../library/HTMLPurifier/AttrDef/Float.php | 116 + .../HTMLPurifier/AttrDef/HTML5/ARel.php | 148 + .../HTMLPurifier/AttrDef/HTML5/Datetime.php | 360 ++ .../HTMLPurifier/AttrDef/HTML5/Duration.php | 173 + .../HTMLPurifier/AttrDef/HTML5/Week.php | 47 + .../AttrDef/HTML5/YearlessDate.php | 41 + .../library/HTMLPurifier/AttrDef/Regexp.php | 48 - .../AttrTransform/HTML5/Dialog.php | 19 + .../AttrTransform/HTML5/Progress.php | 38 + .../AttrTransform/HTML5/Script.php | 23 + .../HTMLPurifier/ChildDef/HTML5/Abstract.php | 70 + .../ChildDef/{ => HTML5}/Details.php | 45 +- .../HTMLPurifier/ChildDef/HTML5/Fieldset.php | 77 + .../ChildDef/{ => HTML5}/Figure.php | 25 +- .../ChildDef/{ => HTML5}/Media.php | 4 +- .../ChildDef/{ => HTML5}/Picture.php | 8 +- .../HTMLPurifier/ChildDef/HTML5/Script.php | 81 + .../HTMLPurifier/ChildDef/HTML5/Time.php | 68 + .../library/HTMLPurifier/HTML5Config.php | 45 +- .../library/HTMLPurifier/HTML5Definition.php | 128 +- .../HTMLPurifier/HTMLModule/HTML5/Bdo.php | 44 + .../HTMLPurifier/HTMLModule/HTML5/Edit.php | 32 + .../HTMLPurifier/HTMLModule/HTML5/Forms.php | 69 + .../HTMLModule/HTML5/Hypertext.php | 31 + .../HTMLPurifier/HTMLModule/HTML5/Iframe.php | 60 + .../HTMLModule/HTML5/Interactive.php | 34 + .../HTMLPurifier/HTMLModule/HTML5/List.php | 30 + .../HTMLPurifier/HTMLModule/HTML5/Media.php | 71 + .../HTMLPurifier/HTMLModule/HTML5/Ruby.php | 36 + .../HTMLModule/HTML5/SafeScripting.php | 46 + .../HTMLModule/HTML5/Scripting.php | 49 + .../HTMLPurifier/HTMLModule/HTML5/Text.php | 91 + 421 files changed, 13998 insertions(+), 16264 deletions(-) create mode 100644 vendor/catfan/medoo/.github/FUNDING.yml create mode 100644 vendor/catfan/medoo/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt delete mode 100644 vendor/ezyang/htmlpurifier/maintenance/flush.php create mode 100644 vendor/ezyang/htmlpurifier/maintenance/flush.sh delete mode 100644 vendor/ezyang/htmlpurifier/maintenance/update-config.php delete mode 100644 vendor/ezyang/htmlpurifier/release2-tag.php rename vendor/ezyang/htmlpurifier/{release1-update.php => update-for-release} (98%) create mode 100644 vendor/guzzlehttp/guzzle/.php_cs create mode 100644 vendor/guzzlehttp/guzzle/Dockerfile create mode 100644 vendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php create mode 100644 vendor/guzzlehttp/psr7/src/Rfc7230.php delete mode 100644 vendor/leafo/scssphp/composer.json delete mode 100644 vendor/leafo/scssphp/src/Formatter/Nested.php delete mode 100644 vendor/leafo/scssphp/src/SourceMap/Base64VLQEncoder.php delete mode 100644 vendor/monolog/monolog/.php_cs delete mode 100644 vendor/monolog/monolog/doc/01-usage.md delete mode 100644 vendor/monolog/monolog/doc/02-handlers-formatters-processors.md delete mode 100644 vendor/monolog/monolog/doc/03-utilities.md delete mode 100644 vendor/monolog/monolog/doc/04-extending.md delete mode 100644 vendor/monolog/monolog/doc/sockets.md delete mode 100644 vendor/monolog/monolog/phpunit.xml.dist create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php create mode 100644 vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php create mode 100644 vendor/monolog/monolog/src/Monolog/ResettableInterface.php create mode 100644 vendor/monolog/monolog/src/Monolog/SignalHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Utils.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/FluentdFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/MongoDBFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/DeduplicationHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/Fixtures/.gitkeep delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/FleepHookHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/GelfMockMessagePublisher.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/HandlerWrapperTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/PHPConsoleHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/PsrHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/RollbarHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/SamplingHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/Slack/SlackRecordTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/SlackHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/SlackWebhookHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/SlackbotHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/SwiftMailerHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/LoggerTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/MercurialProcessorTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/PsrLogMessageProcessorTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/RegistryTest.php delete mode 100644 vendor/monolog/monolog/tests/Monolog/TestCase.php create mode 100644 vendor/psr/log/Psr/Log/Test/TestLogger.php create mode 100644 vendor/ralouphie/getallheaders/LICENSE create mode 100644 vendor/ralouphie/getallheaders/README.md create mode 100644 vendor/ralouphie/getallheaders/composer.json create mode 100644 vendor/ralouphie/getallheaders/src/getallheaders.php rename vendor/{leafo => scssphp}/scssphp/LICENSE.md (93%) rename vendor/{leafo => scssphp}/scssphp/README.md (81%) rename vendor/{leafo => scssphp}/scssphp/bin/pscss (73%) create mode 100644 vendor/scssphp/scssphp/composer.json rename vendor/{leafo => scssphp}/scssphp/example/Server.php (90%) rename vendor/{leafo => scssphp}/scssphp/scss.inc.php (80%) rename vendor/{leafo => scssphp}/scssphp/src/Base/Range.php (85%) rename vendor/{leafo => scssphp}/scssphp/src/Block.php (75%) create mode 100644 vendor/scssphp/scssphp/src/Cache.php rename vendor/{leafo => scssphp}/scssphp/src/Colors.php (74%) rename vendor/{leafo => scssphp}/scssphp/src/Compiler.php (52%) rename vendor/{leafo => scssphp}/scssphp/src/Compiler/Environment.php (58%) rename vendor/{leafo => scssphp}/scssphp/src/Exception/CompilerException.php (65%) rename vendor/{leafo => scssphp}/scssphp/src/Exception/ParserException.php (64%) rename vendor/{leafo => scssphp}/scssphp/src/Exception/RangeException.php (64%) rename vendor/{leafo => scssphp}/scssphp/src/Exception/ServerException.php (64%) rename vendor/{leafo => scssphp}/scssphp/src/Formatter.php (63%) rename vendor/{leafo => scssphp}/scssphp/src/Formatter/Compact.php (81%) rename vendor/{leafo => scssphp}/scssphp/src/Formatter/Compressed.php (64%) rename vendor/{leafo => scssphp}/scssphp/src/Formatter/Crunched.php (61%) rename vendor/{leafo => scssphp}/scssphp/src/Formatter/Debug.php (92%) rename vendor/{leafo => scssphp}/scssphp/src/Formatter/Expanded.php (81%) create mode 100644 vendor/scssphp/scssphp/src/Formatter/Nested.php rename vendor/{leafo => scssphp}/scssphp/src/Formatter/OutputBlock.php (80%) rename vendor/{leafo => scssphp}/scssphp/src/Node.php (79%) rename vendor/{leafo => scssphp}/scssphp/src/Node/Number.php (93%) rename vendor/{leafo => scssphp}/scssphp/src/Parser.php (57%) create mode 100644 vendor/scssphp/scssphp/src/SourceMap/Base64.php create mode 100644 vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php rename vendor/{leafo => scssphp}/scssphp/src/SourceMap/SourceMapGenerator.php (83%) rename vendor/{leafo => scssphp}/scssphp/src/Type.php (94%) rename vendor/{leafo => scssphp}/scssphp/src/Util.php (78%) rename vendor/{leafo => scssphp}/scssphp/src/Version.php (56%) create mode 100644 vendor/symfony/lock/.gitattributes delete mode 100644 vendor/symfony/lock/.gitignore create mode 100644 vendor/symfony/lock/BlockingStoreInterface.php create mode 100644 vendor/symfony/lock/Exception/InvalidTtlException.php create mode 100644 vendor/symfony/lock/LockFactory.php create mode 100644 vendor/symfony/lock/PersistingStoreInterface.php create mode 100644 vendor/symfony/lock/Store/ExpiringStoreTrait.php create mode 100644 vendor/symfony/lock/Store/PdoStore.php create mode 100644 vendor/symfony/lock/Store/ZookeeperStore.php delete mode 100644 vendor/symfony/lock/Tests/FactoryTest.php delete mode 100644 vendor/symfony/lock/Tests/LockTest.php delete mode 100644 vendor/symfony/lock/Tests/Store/AbstractRedisStoreTest.php delete mode 100644 vendor/symfony/lock/Tests/Store/AbstractStoreTest.php delete mode 100644 vendor/symfony/lock/Tests/Store/BlockingStoreTestTrait.php delete mode 100644 vendor/symfony/lock/Tests/Store/CombinedStoreTest.php delete mode 100644 vendor/symfony/lock/Tests/Store/ExpiringStoreTestTrait.php delete mode 100644 vendor/symfony/lock/Tests/Store/FlockStoreTest.php delete mode 100644 vendor/symfony/lock/Tests/Store/MemcachedStoreTest.php delete mode 100644 vendor/symfony/lock/Tests/Store/PredisStoreTest.php delete mode 100644 vendor/symfony/lock/Tests/Store/RedisArrayStoreTest.php delete mode 100644 vendor/symfony/lock/Tests/Store/RedisStoreTest.php delete mode 100644 vendor/symfony/lock/Tests/Store/RetryTillSaveStoreTest.php delete mode 100644 vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php delete mode 100644 vendor/symfony/lock/Tests/Strategy/ConsensusStrategyTest.php delete mode 100644 vendor/symfony/lock/Tests/Strategy/UnanimousStrategyTest.php delete mode 100644 vendor/symfony/lock/phpunit.xml.dist create mode 100644 vendor/vlucas/valitron/.github/FUNDING.yml create mode 100644 vendor/vlucas/valitron/lang/nb.php create mode 100644 vendor/vlucas/valitron/lang/nn.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Float.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/ARel.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/Datetime.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/Duration.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/Week.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/YearlessDate.php delete mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Regexp.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrTransform/HTML5/Dialog.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrTransform/HTML5/Progress.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrTransform/HTML5/Script.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Abstract.php rename vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/{ => HTML5}/Details.php (65%) create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Fieldset.php rename vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/{ => HTML5}/Figure.php (69%) rename vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/{ => HTML5}/Media.php (96%) rename vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/{ => HTML5}/Picture.php (83%) create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Script.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Time.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Bdo.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Edit.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Forms.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Hypertext.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Iframe.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Interactive.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/List.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Media.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Ruby.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/SafeScripting.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Scripting.php create mode 100644 vendor/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Text.php diff --git a/composer.json b/composer.json index abac4455..89f435c9 100644 --- a/composer.json +++ b/composer.json @@ -11,14 +11,14 @@ "sergeytsalkov/meekrodb": "^2.3", "league/plates": "^3.3", "guzzlehttp/guzzle": "^6.3", - "leafo/scssphp": "^0.7.5", + "scssphp/scssphp": "^1.0", "monolog/monolog": "^1.23", "firephp/firephp-core": "^0.4.0", "vlucas/valitron": "^1.4", "php-extended/php-tail": "^2.1", "pguardiario/phpuri": "^1.0", "symfony/lock": "^4.1", - "ezyang/htmlpurifier": "^4.10", + "ezyang/htmlpurifier": "^4.12", "xemlock/htmlpurifier-html5": "^0.1.7", "catfan/medoo": "^1.5" }, diff --git a/composer.lock b/composer.lock index 38688521..40782c04 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3fceaf3c2925068c7e757ab12036e29e", + "content-hash": "b3449508d08a0a23e0b942d060b5b5b1", "packages": [ { "name": "brandonwamboldt/utilphp", @@ -54,16 +54,16 @@ }, { "name": "catfan/medoo", - "version": "v1.5.7", + "version": "v1.7.8", "source": { "type": "git", "url": "https://github.com/catfan/Medoo.git", - "reference": "8d90cba0e8ff176028847527d0ea76fe41a06ecf" + "reference": "dd9d570584cfb1e09ec470608479b86e41d5b60d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/catfan/Medoo/zipball/8d90cba0e8ff176028847527d0ea76fe41a06ecf", - "reference": "8d90cba0e8ff176028847527d0ea76fe41a06ecf", + "url": "https://api.github.com/repos/catfan/Medoo/zipball/dd9d570584cfb1e09ec470608479b86e41d5b60d", + "reference": "dd9d570584cfb1e09ec470608479b86e41d5b60d", "shasum": "" }, "require": { @@ -77,7 +77,7 @@ "ext-pdo_oci8": "For Oracle version 8 database", "ext-pdo_pqsql": "For PostgreSQL database", "ext-pdo_sqlite": "For SQLite database", - "ext-pdo_sqlsrv": "For MSSQL database" + "ext-pdo_sqlsrv": "For MSSQL database on both Window/Liunx platform" }, "type": "framework", "autoload": { @@ -95,10 +95,11 @@ "email": "angel@catfan.me" } ], - "description": "The lightest PHP database framework to accelerate development", + "description": "The lightweight PHP database framework to accelerate development", "homepage": "https://medoo.in", "keywords": [ "database", + "database library", "lightweight", "mariadb", "mssql", @@ -109,27 +110,27 @@ "sql", "sqlite" ], - "time": "2018-06-14T18:59:08+00:00" + "time": "2019-12-19T05:04:34+00:00" }, { "name": "ezyang/htmlpurifier", - "version": "v4.10.0", + "version": "v4.12.0", "source": { "type": "git", "url": "https://github.com/ezyang/htmlpurifier.git", - "reference": "d85d39da4576a6934b72480be6978fb10c860021" + "reference": "a617e55bc62a87eec73bd456d146d134ad716f03" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021", - "reference": "d85d39da4576a6934b72480be6978fb10c860021", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/a617e55bc62a87eec73bd456d146d134ad716f03", + "reference": "a617e55bc62a87eec73bd456d146d134ad716f03", "shasum": "" }, "require": { "php": ">=5.2" }, "require-dev": { - "simpletest/simpletest": "^1.1" + "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" }, "type": "library", "autoload": { @@ -142,7 +143,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL" + "LGPL-2.1-or-later" ], "authors": [ { @@ -156,7 +157,7 @@ "keywords": [ "html" ], - "time": "2018-02-23T01:58:20+00:00" + "time": "2019-10-28T03:44:26+00:00" }, { "name": "firephp/firephp-core", @@ -196,44 +197,46 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.3.3", + "version": "6.5.2", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82", + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82", "shasum": "" }, "require": { + "ext-json": "*", "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.4", + "guzzlehttp/psr7": "^1.6.1", "php": ">=5.5" }, "require-dev": { "ext-curl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.0" + "psr/log": "^1.1" }, "suggest": { + "ext-intl": "Required for Internationalized Domain Name (IDN) support", "psr/log": "Required for using the Log middleware" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.3-dev" + "dev-master": "6.5-dev" } }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { "GuzzleHttp\\": "src/" - } + }, + "files": [ + "src/functions_include.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -257,7 +260,7 @@ "rest", "web service" ], - "time": "2018-04-22T15:46:56+00:00" + "time": "2019-12-23T11:57:10+00:00" }, { "name": "guzzlehttp/promises", @@ -312,32 +315,37 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.4.2", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", "shasum": "" }, "require": { "php": ">=5.4.0", - "psr/http-message": "~1.0" + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -367,65 +375,14 @@ "keywords": [ "http", "message", + "psr-7", "request", "response", "stream", "uri", "url" ], - "time": "2017-03-20T17:10:46+00:00" - }, - { - "name": "leafo/scssphp", - "version": "v0.7.7", - "source": { - "type": "git", - "url": "https://github.com/leafo/scssphp.git", - "reference": "1d656f8c02a3a69404bba6b28ec4e06edddf0f49" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/leafo/scssphp/zipball/1d656f8c02a3a69404bba6b28ec4e06edddf0f49", - "reference": "1d656f8c02a3a69404bba6b28ec4e06edddf0f49", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.6", - "squizlabs/php_codesniffer": "~2.5" - }, - "bin": [ - "bin/pscss" - ], - "type": "library", - "autoload": { - "psr-4": { - "Leafo\\ScssPhp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Leaf Corcoran", - "email": "leafot@gmail.com", - "homepage": "http://leafo.net" - } - ], - "description": "scssphp is a compiler for SCSS written in PHP.", - "homepage": "http://leafo.github.io/scssphp/", - "keywords": [ - "css", - "less", - "sass", - "scss", - "stylesheet" - ], - "time": "2018-07-22T01:22:08+00:00" + "time": "2019-07-01T23:21:34+00:00" }, { "name": "league/plates", @@ -484,16 +441,16 @@ }, { "name": "monolog/monolog", - "version": "1.23.0", + "version": "1.25.3", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", - "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fa82921994db851a8becaf3787a9e73c5976b6f1", + "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1", "shasum": "" }, "require": { @@ -558,7 +515,7 @@ "logging", "psr-3" ], - "time": "2017-06-19T01:22:40+00:00" + "time": "2019-12-20T14:15:16+00:00" }, { "name": "pguardiario/phpuri", @@ -720,16 +677,16 @@ }, { "name": "psr/log", - "version": "1.0.2", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", "shasum": "" }, "require": { @@ -738,7 +695,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -763,7 +720,108 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2019-11-01T11:05:21+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "scssphp/scssphp", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/scssphp/scssphp.git", + "reference": "5b3c9d704950d8f9637f5110c36c281ec47dc13c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/scssphp/scssphp/zipball/5b3c9d704950d8f9637f5110c36c281ec47dc13c", + "reference": "5b3c9d704950d8f9637f5110c36c281ec47dc13c", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3", + "squizlabs/php_codesniffer": "~2.5", + "twbs/bootstrap": "~4.3", + "zurb/foundation": "~6.5" + }, + "bin": [ + "bin/pscss" + ], + "type": "library", + "autoload": { + "psr-4": { + "ScssPhp\\ScssPhp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthon Pang", + "email": "apang@softwaredevelopment.ca", + "homepage": "https://github.com/robocoder" + }, + { + "name": "Cédric Morin", + "email": "cedric@yterium.com", + "homepage": "https://github.com/Cerdic" + } + ], + "description": "scssphp is a compiler for SCSS written in PHP.", + "homepage": "http://scssphp.github.io/scssphp/", + "keywords": [ + "css", + "less", + "sass", + "scss", + "stylesheet" + ], + "time": "2019-12-12T05:00:52+00:00" }, { "name": "sergeytsalkov/meekrodb", @@ -810,29 +868,34 @@ }, { "name": "symfony/lock", - "version": "v4.1.1", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/lock.git", - "reference": "d508b5dd92272cb74300396ecaadde969d0f7976" + "reference": "6c4f5b620871cfef5b004fc57f2ca74572ae03b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/lock/zipball/d508b5dd92272cb74300396ecaadde969d0f7976", - "reference": "d508b5dd92272cb74300396ecaadde969d0f7976", + "url": "https://api.github.com/repos/symfony/lock/zipball/6c4f5b620871cfef5b004fc57f2ca74572ae03b3", + "reference": "6c4f5b620871cfef5b004fc57f2ca74572ae03b3", "shasum": "" }, "require": { "php": "^7.1.3", "psr/log": "~1.0" }, + "conflict": { + "doctrine/dbal": "<2.5" + }, "require-dev": { + "doctrine/dbal": "~2.5", + "mongodb/mongodb": "~1.1", "predis/predis": "~1.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -848,13 +911,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Jérémy Derussé", "email": "jeremy@derusse.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Lock Component", @@ -867,20 +930,20 @@ "redlock", "semaphore" ], - "time": "2018-06-21T11:15:46+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "vlucas/valitron", - "version": "v1.4.3", + "version": "v1.4.7", "source": { "type": "git", "url": "https://github.com/vlucas/valitron.git", - "reference": "3c5463315bfa23b17f8949b100a960d035234e43" + "reference": "a03072bed1679660200766d134507a30193eaf6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/valitron/zipball/3c5463315bfa23b17f8949b100a960d035234e43", - "reference": "3c5463315bfa23b17f8949b100a960d035234e43", + "url": "https://api.github.com/repos/vlucas/valitron/zipball/a03072bed1679660200766d134507a30193eaf6d", + "reference": "a03072bed1679660200766d134507a30193eaf6d", "shasum": "" }, "require": { @@ -916,28 +979,29 @@ "validation", "validator" ], - "time": "2018-05-06T10:45:26+00:00" + "time": "2019-08-29T19:49:43+00:00" }, { "name": "xemlock/htmlpurifier-html5", - "version": "v0.1.7", + "version": "v0.1.11", "source": { "type": "git", "url": "https://github.com/xemlock/htmlpurifier-html5.git", - "reference": "b4b35e51ec75e0207c23035f7d9a354bdcdac359" + "reference": "f0d563f9fd4a82a3d759043483f9a94c0d8c2255" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/xemlock/htmlpurifier-html5/zipball/b4b35e51ec75e0207c23035f7d9a354bdcdac359", - "reference": "b4b35e51ec75e0207c23035f7d9a354bdcdac359", + "url": "https://api.github.com/repos/xemlock/htmlpurifier-html5/zipball/f0d563f9fd4a82a3d759043483f9a94c0d8c2255", + "reference": "f0d563f9fd4a82a3d759043483f9a94c0d8c2255", "shasum": "" }, "require": { - "ezyang/htmlpurifier": "^4.7", + "ezyang/htmlpurifier": "^4.8", "php": ">=5.2" }, "require-dev": { - "phpunit/phpunit": "4.7.*|5.7.*" + "php-coveralls/php-coveralls": "^1.1|^2.1", + "phpunit/phpunit": ">=4.7 <8.0" }, "type": "library", "autoload": { @@ -955,8 +1019,18 @@ "email": "xemlock@gmail.com" } ], - "description": "HTML Purifier definitions for HTML5 elements", - "time": "2018-06-07T14:30:17+00:00" + "description": "HTML5 element definitions for HTML Purifier", + "keywords": [ + "HTML5", + "Purifier", + "html", + "htmlpurifier", + "security", + "tidy", + "validator", + "xss" + ], + "time": "2019-08-07T17:19:21+00:00" } ], "packages-dev": [], diff --git a/composer.phar b/composer.phar index 4055d874a1a1f195c0a08966e4e0e9dbaaf0a5e0..57fce9576e23b4da0126bc16c90492bbb87ab6d3 100644 GIT binary patch delta 114705 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 I=5+3F00wzPF#rGn delta 54293 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 Kue~O)D*I1}B*(D; diff --git a/vendor/bin/pscss b/vendor/bin/pscss index 9539281c..2879dcb9 100644 --- a/vendor/bin/pscss +++ b/vendor/bin/pscss @@ -1,10 +1,14 @@ #!/usr/bin/env sh -dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../leafo/scssphp/bin" && pwd) +dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../scssphp/scssphp/bin" && pwd) -if [ -d /proc/cygdrive ] && [[ $(which php) == $(readlink -n /proc/cygdrive)/* ]]; then - # We are in Cgywin using Windows php, so the path must be translated - dir=$(cygpath -m "$dir"); +if [ -d /proc/cygdrive ]; then + case $(which php) in + $(readlink -n /proc/cygdrive)/*) + # We are in Cygwin using Windows php, so the path must be translated + dir=$(cygpath -m "$dir"); + ;; + esac fi "${dir}/pscss" "$@" diff --git a/vendor/bin/pscss.bat b/vendor/bin/pscss.bat index cadaeea9..1e368dc9 100644 --- a/vendor/bin/pscss.bat +++ b/vendor/bin/pscss.bat @@ -1,4 +1,4 @@ @ECHO OFF setlocal DISABLEDELAYEDEXPANSION -SET BIN_TARGET=%~dp0/../leafo/scssphp/bin/pscss +SET BIN_TARGET=%~dp0/../scssphp/scssphp/bin/pscss php "%BIN_TARGET%" %* diff --git a/vendor/catfan/medoo/.github/FUNDING.yml b/vendor/catfan/medoo/.github/FUNDING.yml new file mode 100644 index 00000000..d3400156 --- /dev/null +++ b/vendor/catfan/medoo/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +open_collective: medoo diff --git a/vendor/catfan/medoo/.github/ISSUE_TEMPLATE/bug_report.md b/vendor/catfan/medoo/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..160e7e0f --- /dev/null +++ b/vendor/catfan/medoo/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,19 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Information** +- Version of Medoo: +- Type of Database (MySQL, MSSQL, SQLite...): +- System (Liunx\Windows\Mac): + +**Detail Code** +The detail code causes the problem. + +**Expected output** +A clear and concise description of what output you expected. diff --git a/vendor/catfan/medoo/LICENSE.md b/vendor/catfan/medoo/LICENSE.md index a681c880..e63dae83 100644 --- a/vendor/catfan/medoo/LICENSE.md +++ b/vendor/catfan/medoo/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 Angel Lai +Copyright (c) 2019 Angel Lai Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/catfan/medoo/README.md b/vendor/catfan/medoo/README.md index f31e1d06..5288a756 100644 --- a/vendor/catfan/medoo/README.md +++ b/vendor/catfan/medoo/README.md @@ -6,9 +6,11 @@ Total Downloads Latest Stable Version License + Backers on Open Collective + Sponsors on Open Collective

-> The Lightest PHP database framework to accelerate development +> The lightweight PHP database framework to accelerate development ## Features @@ -26,7 +28,7 @@ ## Requirement -PHP 5.4+ and PDO extension installed +PHP 5.4+ and PDO extension installed, recommend PHP 7.0+ ## Get Started @@ -34,7 +36,7 @@ PHP 5.4+ and PDO extension installed Add Medoo to composer.json configuration file. ``` -$ composer require catfan/Medoo +$ composer require catfan/medoo ``` And update the composer @@ -43,7 +45,7 @@ $ composer update ``` ```php -// If you installed via composer, just use this code to requrie autoloader on the top of your projects. +// If you installed via composer, just use this code to require autoloader on the top of your projects. require 'vendor/autoload.php'; // Using Medoo namespace diff --git a/vendor/catfan/medoo/composer.json b/vendor/catfan/medoo/composer.json index 39c1a9de..2bb0d08f 100644 --- a/vendor/catfan/medoo/composer.json +++ b/vendor/catfan/medoo/composer.json @@ -1,8 +1,8 @@ { "name": "catfan/medoo", "type": "framework", - "description": "The lightest PHP database framework to accelerate development", - "keywords": ["database", "lightweight", "PHP framework", "SQL", "MySQL", "MSSQL", "SQLite", "PostgreSQL", "MariaDB", "Oracle"], + "description": "The lightweight PHP database framework to accelerate development", + "keywords": ["database", "database library", "lightweight", "PHP framework", "SQL", "MySQL", "MSSQL", "SQLite", "PostgreSQL", "MariaDB", "Oracle"], "homepage": "https://medoo.in", "license": "MIT", "support": { @@ -18,10 +18,10 @@ }, "suggest": { "ext-pdo_mysql": "For MySQL or MariaDB database", - "ext-pdo_sqlsrv": "For MSSQL database", + "ext-pdo_sqlsrv": "For MSSQL database on both Window/Liunx platform", "ext-pdo_dblib": "For MSSQL or Sybase database on Linux/UNIX platform", "ext-pdo_oci": "For Oracle database", - "ext-pdo_oci8": "For Oracle version 8 database", + "ext-pdo_oci8": "For Oracle version 8 database", "ext-pdo_pqsql": "For PostgreSQL database", "ext-pdo_sqlite": "For SQLite database" }, diff --git a/vendor/catfan/medoo/src/Medoo.php b/vendor/catfan/medoo/src/Medoo.php index b97b8b8c..ae3cf41e 100644 --- a/vendor/catfan/medoo/src/Medoo.php +++ b/vendor/catfan/medoo/src/Medoo.php @@ -2,9 +2,9 @@ /*! * Medoo database framework * https://medoo.in - * Version 1.5.7 + * Version 1.7.8 * - * Copyright 2018, Angel Lai + * Copyright 2019, Angel Lai * Released under the MIT license */ @@ -13,6 +13,7 @@ namespace Medoo; use PDO; use Exception; use PDOException; +use InvalidArgumentException; class Raw { public $map; @@ -29,7 +30,7 @@ class Medoo protected $statement; - protected $option = []; + protected $dsn; protected $logs = []; @@ -39,16 +40,18 @@ class Medoo protected $guid = 0; - public function __construct($options = null) - { - if (!is_array($options)) - { - return false; - } + protected $errorInfo = null; + public function __construct(array $options) + { if (isset($options[ 'database_type' ])) { $this->type = strtolower($options[ 'database_type' ]); + + if ($this->type === 'mariadb') + { + $this->type = 'mysql'; + } } if (isset($options[ 'prefix' ])) @@ -56,23 +59,47 @@ class Medoo $this->prefix = $options[ 'prefix' ]; } - if (isset($options[ 'option' ])) - { - $this->option = $options[ 'option' ]; - } - if (isset($options[ 'logging' ]) && is_bool($options[ 'logging' ])) { $this->logging = $options[ 'logging' ]; } - if (isset($options[ 'command' ]) && is_array($options[ 'command' ])) + $option = isset($options[ 'option' ]) ? $options[ 'option' ] : []; + $commands = (isset($options[ 'command' ]) && is_array($options[ 'command' ])) ? $options[ 'command' ] : []; + + switch ($this->type) { - $commands = $options[ 'command' ]; + case 'mysql': + // Make MySQL using standard quoted identifier + $commands[] = 'SET SQL_MODE=ANSI_QUOTES'; + + break; + + case 'mssql': + // Keep MSSQL QUOTED_IDENTIFIER is ON for standard quoting + $commands[] = 'SET QUOTED_IDENTIFIER ON'; + + // Make ANSI_NULLS is ON for NULL value + $commands[] = 'SET ANSI_NULLS ON'; + + break; } - else + + if (isset($options[ 'pdo' ])) { - $commands = []; + if (!$options[ 'pdo' ] instanceof PDO) + { + throw new InvalidArgumentException('Invalid PDO object supplied'); + } + + $this->pdo = $options[ 'pdo' ]; + + foreach ($commands as $value) + { + $this->pdo->exec($value); + } + + return; } if (isset($options[ 'dsn' ])) @@ -83,7 +110,7 @@ class Medoo } else { - return false; + throw new InvalidArgumentException('Invalid DSN option supplied'); } } else @@ -100,7 +127,6 @@ class Medoo switch ($this->type) { - case 'mariadb': case 'mysql': $attr = [ 'driver' => 'mysql', @@ -121,8 +147,6 @@ class Medoo } } - // Make MySQL using standard quoted identifier - $commands[] = 'SET SQL_MODE=ANSI_QUOTES'; break; case 'pgsql': @@ -176,6 +200,16 @@ class Medoo 'host' => $options[ 'server' ] . ($is_port ? ':' . $port : ''), 'dbname' => $options[ 'database_name' ] ]; + + if (isset($options[ 'appname' ])) + { + $attr[ 'appname' ] = $options[ 'appname' ]; + } + + if (isset($options[ 'charset' ])) + { + $attr[ 'charset' ] = $options[ 'charset' ]; + } } else { @@ -184,13 +218,46 @@ class Medoo 'Server' => $options[ 'server' ] . ($is_port ? ',' . $port : ''), 'Database' => $options[ 'database_name' ] ]; + + if (isset($options[ 'appname' ])) + { + $attr[ 'APP' ] = $options[ 'appname' ]; + } + + $config = [ + 'ApplicationIntent', + 'AttachDBFileName', + 'Authentication', + 'ColumnEncryption', + 'ConnectionPooling', + 'Encrypt', + 'Failover_Partner', + 'KeyStoreAuthentication', + 'KeyStorePrincipalId', + 'KeyStoreSecret', + 'LoginTimeout', + 'MultipleActiveResultSets', + 'MultiSubnetFailover', + 'Scrollable', + 'TraceFile', + 'TraceOn', + 'TransactionIsolation', + 'TransparentNetworkIPResolution', + 'TrustServerCertificate', + 'WSID', + ]; + + foreach ($config as $value) + { + $keyname = strtolower(preg_replace(['/([a-z\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $value)); + + if (isset($options[ $keyname ])) + { + $attr[ $value ] = $options[ $keyname ]; + } + } } - // Keep MSSQL QUOTED_IDENTIFIER is ON for standard quoting - $commands[] = 'SET QUOTED_IDENTIFIER ON'; - - // Make ANSI_NULLS is ON for NULL value - $commands[] = 'SET ANSI_NULLS ON'; break; case 'sqlite': @@ -203,8 +270,18 @@ class Medoo } } + if (!isset($attr)) + { + throw new InvalidArgumentException('Incorrect connection options'); + } + $driver = $attr[ 'driver' ]; + if (!in_array($driver, PDO::getAvailableDrivers())) + { + throw new InvalidArgumentException("Unsupported PDO driver: {$driver}"); + } + unset($attr[ 'driver' ]); $stack = []; @@ -214,22 +291,27 @@ class Medoo $stack[] = is_int($key) ? $value : $key . '=' . $value; } - $dsn = $driver . ':' . implode($stack, ';'); + $dsn = $driver . ':' . implode(';', $stack); if ( - in_array($this->type, ['mariadb', 'mysql', 'pgsql', 'sybase', 'mssql']) && + in_array($this->type, ['mysql', 'pgsql', 'sybase', 'mssql']) && isset($options[ 'charset' ]) ) { - $commands[] = "SET NAMES '" . $options[ 'charset' ] . "'"; + $commands[] = "SET NAMES '{$options[ 'charset' ]}'" . ( + $this->type === 'mysql' && isset($options[ 'collation' ]) ? + " COLLATE '{$options[ 'collation' ]}'" : '' + ); } + $this->dsn = $dsn; + try { $this->pdo = new PDO( $dsn, isset($options[ 'username' ]) ? $options[ 'username' ] : null, isset($options[ 'password' ]) ? $options[ 'password' ] : null, - $this->option + $option ); foreach ($commands as $value) @@ -242,18 +324,6 @@ class Medoo } } - public function __call($name, $arguments) - { - $aggregation = ['avg', 'count', 'max', 'min', 'sum']; - - if (in_array($name, $aggregation)) - { - array_unshift($arguments, $name); - - return call_user_func_array([$this, 'aggregate'], $arguments); - } - } - public function query($query, $map = []) { $raw = $this->raw($query, $map); @@ -265,6 +335,8 @@ class Medoo public function exec($query, $map = []) { + $this->statement = null; + if ($this->debug_mode) { echo $this->generate($query, $map); @@ -285,28 +357,37 @@ class Medoo $statement = $this->pdo->prepare($query); - if ($statement) + if (!$statement) { - foreach ($map as $key => $value) - { - $statement->bindValue($key, $value[ 0 ], $value[ 1 ]); - } + $this->errorInfo = $this->pdo->errorInfo(); + $this->statement = null; - $statement->execute(); - - $this->statement = $statement; - - return $statement; + return false; } - return false; + $this->statement = $statement; + + foreach ($map as $key => $value) + { + $statement->bindValue($key, $value[ 0 ], $value[ 1 ]); + } + + $execute = $statement->execute(); + + $this->errorInfo = $statement->errorInfo(); + + if (!$execute) + { + $this->statement = null; + } + + return $statement; } protected function generate($query, $map) { $identifier = [ 'mysql' => '`$1`', - 'mariadb' => '`$1`', 'mssql' => '[$1]' ]; @@ -396,6 +477,11 @@ class Medoo protected function tableQuote($table) { + if (!preg_match('/^[a-zA-Z0-9_]+$/i', $table)) + { + throw new InvalidArgumentException("Incorrect table name \"$table\""); + } + return '"' . $this->prefix . $table . '"'; } @@ -430,6 +516,11 @@ class Medoo protected function columnQuote($string) { + if (!preg_match('/^[a-zA-Z0-9_]+(\.?[a-zA-Z0-9_]+)?$/i', $string)) + { + throw new InvalidArgumentException("Incorrect column name \"$string\""); + } + if (strpos($string, '.') !== false) { return '"' . $this->prefix . str_replace('.', '"."', $string) . '"'; @@ -438,7 +529,7 @@ class Medoo return '"' . $string . '"'; } - protected function columnPush(&$columns, &$map) + protected function columnPush(&$columns, &$map, $root, $is_join = false) { if ($columns === '*') { @@ -454,23 +545,34 @@ class Medoo foreach ($columns as $key => $value) { - if (is_array($value)) + if (!is_int($key) && is_array($value) && $root && count(array_keys($columns)) === 1) { - $stack[] = $this->columnPush($value, $map); + $stack[] = $this->columnQuote($key); + + $stack[] = $this->columnPush($value, $map, false, $is_join); + } + elseif (is_array($value)) + { + $stack[] = $this->columnPush($value, $map, false, $is_join); } elseif (!is_int($key) && $raw = $this->buildRaw($value, $map)) { preg_match('/(?[a-zA-Z0-9_\.]+)(\s*\[(?(String|Bool|Int|Number))\])?/i', $key, $match); - $stack[] = $raw . ' AS ' . $this->columnQuote( $match[ 'column' ] ); + $stack[] = $raw . ' AS ' . $this->columnQuote($match[ 'column' ]); } elseif (is_int($key) && is_string($value)) { + if ($is_join && strpos($value, '*') !== false) + { + throw new InvalidArgumentException('Cannot use table.* to select all columns while joining table'); + } + preg_match('/(?[a-zA-Z0-9_\.]+)(?:\s*\((?[a-zA-Z0-9_]+)\))?(?:\s*\[(?(?:String|Bool|Int|Number|Object|JSON))\])?/i', $value, $match); if (!empty($match[ 'alias' ])) { - $stack[] = $this->columnQuote( $match[ 'column' ] ) . ' AS ' . $this->columnQuote( $match[ 'alias' ] ); + $stack[] = $this->columnQuote($match[ 'column' ]) . ' AS ' . $this->columnQuote($match[ 'alias' ]); $columns[ $key ] = $match[ 'alias' ]; @@ -481,12 +583,12 @@ class Medoo } else { - $stack[] = $this->columnQuote( $match[ 'column' ] ); + $stack[] = $this->columnQuote($match[ 'column' ]); } } } - return implode($stack, ','); + return implode(',', $stack); } protected function arrayQuote($array) @@ -498,7 +600,7 @@ class Medoo $stack[] = is_int($value) ? $value : $this->pdo->quote($value); } - return implode($stack, ','); + return implode(',', $stack); } protected function innerConjunct($data, $map, $conjunctor, $outer_conjunctor) @@ -560,7 +662,7 @@ class Medoo if (is_numeric($value)) { $condition .= $map_key; - $map[ $map_key ] = [$value, PDO::PARAM_INT]; + $map[ $map_key ] = [$value, is_float($value) ? PDO::PARAM_STR : PDO::PARAM_INT]; } elseif ($raw = $this->buildRaw($value, $map)) { @@ -587,8 +689,10 @@ class Medoo foreach ($value as $index => $item) { - $placeholders[] = $map_key . $index . '_i'; - $map[ $map_key . $index . '_i' ] = $this->typeMap($item, gettype($item)); + $stack_key = $map_key . $index . '_i'; + + $placeholders[] = $stack_key; + $map[ $stack_key ] = $this->typeMap($item, gettype($item)); } $stack[] = $column . ' NOT IN (' . implode(', ', $placeholders) . ')'; @@ -635,7 +739,7 @@ class Medoo { $item = strval($item); - if (!preg_match('/(\[.+\]|_|%.+|.+%)/', $item)) + if (!preg_match('/(\[.+\]|[\*\?\!\%#^-_]|%.+|.+%)/', $item)) { $item = '%' . $item . '%'; } @@ -682,8 +786,10 @@ class Medoo foreach ($value as $index => $item) { - $placeholders[] = $map_key . $index . '_i'; - $map[ $map_key . $index . '_i' ] = $this->typeMap($item, gettype($item)); + $stack_key = $map_key . $index . '_i'; + + $placeholders[] = $stack_key; + $map[ $stack_key ] = $this->typeMap($item, gettype($item)); } $stack[] = $column . ' IN (' . implode(', ', $placeholders) . ')'; @@ -728,7 +834,7 @@ class Medoo $where_clause = ' WHERE ' . $this->dataImplode($conditions, $map, ' AND'); } - if (isset($where[ 'MATCH' ])) + if (isset($where[ 'MATCH' ]) && $this->type === 'mysql') { $MATCH = $where[ 'MATCH' ]; @@ -748,7 +854,7 @@ class Medoo $mode = ' ' . $mode_array[ $MATCH[ 'mode' ] ]; } - $columns = implode(array_map([$this, 'columnQuote'], $MATCH[ 'columns' ]), ', '); + $columns = implode(', ', array_map([$this, 'columnQuote'], $MATCH[ 'columns' ])); $map_key = $this->mapKey(); $map[ $map_key ] = [$MATCH[ 'keyword' ], PDO::PARAM_STR]; @@ -769,7 +875,7 @@ class Medoo $stack[] = $this->columnQuote($value); } - $where_clause .= ' GROUP BY ' . implode($stack, ','); + $where_clause .= ' GROUP BY ' . implode(',', $stack); } elseif ($raw = $this->buildRaw($GROUP, $map)) { @@ -817,7 +923,7 @@ class Medoo } } - $where_clause .= ' ORDER BY ' . implode($stack, ','); + $where_clause .= ' ORDER BY ' . implode(',', $stack); } elseif ($raw = $this->buildRaw($ORDER, $map)) { @@ -894,6 +1000,7 @@ class Medoo $table_query = $table; } + $is_join = false; $join_key = is_array($join) ? array_keys($join) : null; if ( @@ -901,67 +1008,8 @@ class Medoo strpos($join_key[ 0 ], '[') === 0 ) { - $table_join = []; - - $join_array = [ - '>' => 'LEFT', - '<' => 'RIGHT', - '<>' => 'FULL', - '><' => 'INNER' - ]; - - foreach($join as $sub_table => $relation) - { - preg_match('/(\[(?\<\>?|\>\[a-zA-Z0-9_]+)\s?(\((?[a-zA-Z0-9_]+)\))?/', $sub_table, $match); - - if ($match[ 'join' ] !== '' && $match[ 'table' ] !== '') - { - if (is_string($relation)) - { - $relation = 'USING ("' . $relation . '")'; - } - - if (is_array($relation)) - { - // For ['column1', 'column2'] - if (isset($relation[ 0 ])) - { - $relation = 'USING ("' . implode($relation, '", "') . '")'; - } - else - { - $joins = []; - - foreach ($relation as $key => $value) - { - $joins[] = ( - strpos($key, '.') > 0 ? - // For ['tableB.column' => 'column'] - $this->columnQuote($key) : - - // For ['column1' => 'column2'] - $table . '."' . $key . '"' - ) . - ' = ' . - $this->tableQuote(isset($match[ 'alias' ]) ? $match[ 'alias' ] : $match[ 'table' ]) . '."' . $value . '"'; - } - - $relation = 'ON ' . implode($joins, ' AND '); - } - } - - $table_name = $this->tableQuote($match[ 'table' ]) . ' '; - - if (isset($match[ 'alias' ])) - { - $table_name .= 'AS ' . $this->tableQuote($match[ 'alias' ]) . ' '; - } - - $table_join[] = $join_array[ $match[ 'join' ] ] . ' JOIN ' . $table_name . $relation; - } - } - - $table_query .= ' ' . implode($table_join, ' '); + $is_join = true; + $table_query .= ' ' . $this->buildJoin($table, $join); } else { @@ -999,6 +1047,10 @@ class Medoo $where = $columns; } } + elseif ($raw = $this->buildRaw($column_fn, $map)) + { + $column = $raw; + } else { if (empty($columns) || $this->isRaw($columns)) @@ -1007,18 +1059,83 @@ class Medoo $where = $join; } - $column = $column_fn . '(' . $this->columnPush($columns, $map) . ')'; + $column = $column_fn . '(' . $this->columnPush($columns, $map, true) . ')'; } } else { - $column = $this->columnPush($columns, $map); + $column = $this->columnPush($columns, $map, true, $is_join); } return 'SELECT ' . $column . ' FROM ' . $table_query . $this->whereClause($where, $map); } - protected function columnMap($columns, &$stack) + protected function buildJoin($table, $join) + { + $table_join = []; + + $join_array = [ + '>' => 'LEFT', + '<' => 'RIGHT', + '<>' => 'FULL', + '><' => 'INNER' + ]; + + foreach($join as $sub_table => $relation) + { + preg_match('/(\[(?\<\>?|\>\[a-zA-Z0-9_]+)\s?(\((?[a-zA-Z0-9_]+)\))?/', $sub_table, $match); + + if ($match[ 'join' ] !== '' && $match[ 'table' ] !== '') + { + if (is_string($relation)) + { + $relation = 'USING ("' . $relation . '")'; + } + + if (is_array($relation)) + { + // For ['column1', 'column2'] + if (isset($relation[ 0 ])) + { + $relation = 'USING ("' . implode('", "', $relation) . '")'; + } + else + { + $joins = []; + + foreach ($relation as $key => $value) + { + $joins[] = ( + strpos($key, '.') > 0 ? + // For ['tableB.column' => 'column'] + $this->columnQuote($key) : + + // For ['column1' => 'column2'] + $table . '."' . $key . '"' + ) . + ' = ' . + $this->tableQuote(isset($match[ 'alias' ]) ? $match[ 'alias' ] : $match[ 'table' ]) . '."' . $value . '"'; + } + + $relation = 'ON ' . implode(' AND ', $joins); + } + } + + $table_name = $this->tableQuote($match[ 'table' ]) . ' '; + + if (isset($match[ 'alias' ])) + { + $table_name .= 'AS ' . $this->tableQuote($match[ 'alias' ]) . ' '; + } + + $table_join[] = $join_array[ $match[ 'join' ] ] . ' JOIN ' . $table_name . $relation; + } + } + + return implode(' ', $table_join); + } + + protected function columnMap($columns, &$stack, $root) { if ($columns === '*') { @@ -1061,15 +1178,52 @@ class Medoo } elseif (!is_int($key) && is_array($value)) { - $this->columnMap($value, $stack); + if ($root && count(array_keys($columns)) === 1) + { + $stack[ $key ] = [$key, 'String']; + } + + $this->columnMap($value, $stack, false); } } return $stack; } - protected function dataMap($data, $columns, $column_map, &$stack) + protected function dataMap($data, $columns, $column_map, &$stack, $root, &$result) { + if ($root) + { + $columns_key = array_keys($columns); + + if (count($columns_key) === 1 && is_array($columns[$columns_key[0]])) + { + $index_key = array_keys($columns)[0]; + $data_key = preg_replace("/^[a-zA-Z0-9_]+\./i", "", $index_key); + + $current_stack = []; + + foreach ($data as $item) + { + $this->dataMap($data, $columns[ $index_key ], $column_map, $current_stack, false, $result); + + $index = $data[ $data_key ]; + + $result[ $index ] = $current_stack; + } + } + else + { + $current_stack = []; + + $this->dataMap($data, $columns, $column_map, $current_stack, false, $result); + + $result[] = $current_stack; + } + + return; + } + foreach ($columns as $key => $value) { $isRaw = $this->isRaw($value); @@ -1080,7 +1234,7 @@ class Medoo $column_key = $map[ 0 ]; - $result = $data[ $column_key ]; + $item = $data[ $column_key ]; if (isset($map[ 1 ])) { @@ -1089,7 +1243,7 @@ class Medoo continue; } - if (is_null($result)) + if (is_null($item)) { $stack[ $column_key ] = null; continue; @@ -1098,50 +1252,103 @@ class Medoo switch ($map[ 1 ]) { case 'Number': - $stack[ $column_key ] = (double) $result; + $stack[ $column_key ] = (double) $item; break; case 'Int': - $stack[ $column_key ] = (int) $result; + $stack[ $column_key ] = (int) $item; break; case 'Bool': - $stack[ $column_key ] = (bool) $result; + $stack[ $column_key ] = (bool) $item; break; case 'Object': - $stack[ $column_key ] = unserialize($result); + $stack[ $column_key ] = unserialize($item); break; case 'JSON': - $stack[ $column_key ] = json_decode($result, true); + $stack[ $column_key ] = json_decode($item, true); break; case 'String': - $stack[ $column_key ] = $result; + $stack[ $column_key ] = $item; break; } } else { - $stack[ $column_key ] = $result; + $stack[ $column_key ] = $item; } } else { $current_stack = []; - $this->dataMap($data, $value, $column_map, $current_stack); + $this->dataMap($data, $value, $column_map, $current_stack, false, $result); $stack[ $key ] = $current_stack; } } } + public function create($table, $columns, $options = null) + { + $stack = []; + + $tableName = $this->prefix . $table; + + foreach ($columns as $name => $definition) + { + if (is_int($name)) + { + $stack[] = preg_replace('/\<([a-zA-Z0-9_]+)\>/i', '"$1"', $definition); + } + elseif (is_array($definition)) + { + $stack[] = $name . ' ' . implode(' ', $definition); + } + elseif (is_string($definition)) + { + $stack[] = $name . ' ' . $this->query($definition); + } + } + + $table_option = ''; + + if (is_array($options)) + { + $option_stack = []; + + foreach ($options as $key => $value) + { + if (is_string($value) || is_int($value)) + { + $option_stack[] = "$key = $value"; + } + } + + $table_option = ' ' . implode(', ', $option_stack); + } + elseif (is_string($options)) + { + $table_option = ' ' . $options; + } + + return $this->exec("CREATE TABLE IF NOT EXISTS $tableName (" . implode(', ', $stack) . ")$table_option"); + } + + public function drop($table) + { + $tableName = $this->prefix . $table; + + return $this->exec("DROP TABLE IF EXISTS $tableName"); + } + public function select($table, $join, $columns = null, $where = null) { $map = []; - $stack = []; + $result = []; $column_map = []; $index = 0; @@ -1152,9 +1359,9 @@ class Medoo $query = $this->exec($this->selectContext($table, $map, $join, $columns, $where), $map); - $this->columnMap($columns, $column_map); + $this->columnMap($columns, $column_map, true); - if (!$query) + if (!$this->statement) { return false; } @@ -1164,23 +1371,27 @@ class Medoo return $query->fetchAll(PDO::FETCH_ASSOC); } - if ($is_single) - { - return $query->fetchAll(PDO::FETCH_COLUMN); - } - while ($data = $query->fetch(PDO::FETCH_ASSOC)) { $current_stack = []; - $this->dataMap($data, $columns, $column_map, $current_stack); - - $stack[ $index ] = $current_stack; - - $index++; + $this->dataMap($data, $columns, $column_map, $current_stack, true, $result); } - return $stack; + if ($is_single) + { + $single_result = []; + $result_key = $column_map[ $column ][ 0 ]; + + foreach ($result as $item) + { + $single_result[] = $item[ $result_key ]; + } + + return $single_result; + } + + return $result; } public function insert($table, $datas) @@ -1217,7 +1428,7 @@ class Medoo continue; } - $map_key =$this->mapKey(); + $map_key = $this->mapKey(); $values[] = $map_key; @@ -1257,7 +1468,7 @@ class Medoo } } - $stack[] = '(' . implode($values, ', ') . ')'; + $stack[] = '(' . implode(', ', $values) . ')'; } foreach ($columns as $key) @@ -1373,8 +1584,9 @@ class Medoo public function get($table, $join = null, $columns = null, $where = null) { $map = []; - $stack = []; + $result = []; $column_map = []; + $current_stack = []; if ($where === null) { @@ -1391,33 +1603,31 @@ class Medoo $query = $this->exec($this->selectContext($table, $map, $join, $columns, $where) . ' LIMIT 1', $map); - if ($query) + if (!$this->statement) { - $data = $query->fetchAll(PDO::FETCH_ASSOC); - - if (isset($data[ 0 ])) - { - if ($column === '*') - { - return $data[ 0 ]; - } - - $this->columnMap($columns, $column_map); - - $this->dataMap($data[ 0 ], $columns, $column_map, $stack); - - if ($is_single) - { - return $stack[ $column_map[ $column ][ 0 ] ]; - } - - return $stack; - } - return false; } - return false; + $data = $query->fetchAll(PDO::FETCH_ASSOC); + + if (isset($data[ 0 ])) + { + if ($column === '*') + { + return $data[ 0 ]; + } + + $this->columnMap($columns, $column_map, true); + + $this->dataMap($data[ 0 ], $columns, $column_map, $current_stack, true, $result); + + if ($is_single) + { + return $result[ 0 ][ $column_map[ $column ][ 0 ] ]; + } + + return $result[ 0 ]; + } } public function has($table, $join, $where = null) @@ -1425,16 +1635,66 @@ class Medoo $map = []; $column = null; - $query = $this->exec('SELECT EXISTS(' . $this->selectContext($table, $map, $join, $column, $where, 1) . ')', $map); - - if ($query) + if ($this->type === 'mssql') { - $result = $query->fetchColumn(); - - return $result === '1' || $result === true; + $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, Medoo::raw('TOP 1 1')), $map); + } + else + { + $query = $this->exec('SELECT EXISTS(' . $this->selectContext($table, $map, $join, $column, $where, 1) . ')', $map); } - return false; + if (!$this->statement) + { + return false; + } + + $result = $query->fetchColumn(); + + return $result === '1' || $result === 1 || $result === true; + } + + public function rand($table, $join = null, $columns = null, $where = null) + { + $type = $this->type; + + $order = 'RANDOM()'; + + if ($type === 'mysql') + { + $order = 'RAND()'; + } + elseif ($type === 'mssql') + { + $order = 'NEWID()'; + } + + $order_raw = $this->raw($order); + + if ($where === null) + { + if ($columns === null) + { + $columns = [ + 'ORDER' => $order_raw + ]; + } + else + { + $column = $join; + unset($columns[ 'ORDER' ]); + + $columns[ 'ORDER' ] = $order_raw; + } + } + else + { + unset($where[ 'ORDER' ]); + + $where[ 'ORDER' ] = $order_raw; + } + + return $this->select($table, $join, $columns, $where); } private function aggregate($type, $table, $join = null, $column = null, $where = null) @@ -1443,14 +1703,39 @@ class Medoo $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, strtoupper($type)), $map); - if ($query) + if (!$this->statement) { - $number = $query->fetchColumn(); - - return is_numeric($number) ? $number + 0 : $number; + return false; } - return false; + $number = $query->fetchColumn(); + + return is_numeric($number) ? $number + 0 : $number; + } + + public function count($table, $join = null, $column = null, $where = null) + { + return $this->aggregate('count', $table, $join, $column, $where); + } + + public function avg($table, $join, $column = null, $where = null) + { + return $this->aggregate('avg', $table, $join, $column, $where); + } + + public function max($table, $join, $column = null, $where = null) + { + return $this->aggregate('max', $table, $join, $column, $where); + } + + public function min($table, $join, $column = null, $where = null) + { + return $this->aggregate('min', $table, $join, $column, $where); + } + + public function sum($table, $join, $column = null, $where = null) + { + return $this->aggregate('sum', $table, $join, $column, $where); } public function action($actions) @@ -1485,22 +1770,30 @@ class Medoo public function id() { + if ($this->statement == null) + { + return null; + } + $type = $this->type; if ($type === 'oracle') { return 0; } - elseif ($type === 'mssql') - { - return $this->pdo->query('SELECT SCOPE_IDENTITY()')->fetchColumn(); - } elseif ($type === 'pgsql') { return $this->pdo->query('SELECT LASTVAL()')->fetchColumn(); } - return $this->pdo->lastInsertId(); + $lastId = $this->pdo->lastInsertId(); + + if ($lastId != "0" && $lastId != "") + { + return $lastId; + } + + return null; } public function debug() @@ -1512,7 +1805,7 @@ class Medoo public function error() { - return $this->statement ? $this->statement->errorInfo() : null; + return $this->errorInfo; } public function last() @@ -1547,7 +1840,8 @@ class Medoo $output[ $key ] = @$this->pdo->getAttribute(constant('PDO::ATTR_' . $value)); } + $output[ 'dsn' ] = $this->dsn; + return $output; } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index dc02dfb1..fce8549f 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -279,7 +279,7 @@ class ClassLoader */ public function setApcuPrefix($apcuPrefix) { - $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; } /** @@ -377,7 +377,7 @@ class ClassLoader $subPath = $class; while (false !== $lastPos = strrpos($subPath, '\\')) { $subPath = substr($subPath, 0, $lastPos); - $search = $subPath.'\\'; + $search = $subPath . '\\'; if (isset($this->prefixDirsPsr4[$search])) { $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); foreach ($this->prefixDirsPsr4[$search] as $dir) { diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index f698c3fd..13991c13 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -11,19 +11,40 @@ return array( 'DBTransaction' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'FB' => $vendorDir . '/firephp/firephp-core/lib/FirePHPCore/fb.php', 'FirePHP' => $vendorDir . '/firephp/firephp-core/lib/FirePHPCore/FirePHP.class.php', + 'HTMLPurifier_AttrDef_Float' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Float.php', + 'HTMLPurifier_AttrDef_HTML5_ARel' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/ARel.php', + 'HTMLPurifier_AttrDef_HTML5_Datetime' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/Datetime.php', + 'HTMLPurifier_AttrDef_HTML5_Duration' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/Duration.php', + 'HTMLPurifier_AttrDef_HTML5_Week' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/Week.php', + 'HTMLPurifier_AttrDef_HTML5_YearlessDate' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/YearlessDate.php', 'HTMLPurifier_AttrDef_HTML_Bool2' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML/Bool2.php', - 'HTMLPurifier_AttrDef_Regexp' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Regexp.php', - 'HTMLPurifier_ChildDef_Details' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Details.php', - 'HTMLPurifier_ChildDef_Figure' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Figure.php', - 'HTMLPurifier_ChildDef_Media' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Media.php', - 'HTMLPurifier_ChildDef_Picture' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Picture.php', + 'HTMLPurifier_AttrTransform_HTML5_Dialog' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrTransform/HTML5/Dialog.php', + 'HTMLPurifier_AttrTransform_HTML5_Progress' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrTransform/HTML5/Progress.php', + 'HTMLPurifier_AttrTransform_HTML5_Script' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrTransform/HTML5/Script.php', + 'HTMLPurifier_ChildDef_HTML5_Abstract' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Abstract.php', + 'HTMLPurifier_ChildDef_HTML5_Details' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Details.php', + 'HTMLPurifier_ChildDef_HTML5_Fieldset' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Fieldset.php', + 'HTMLPurifier_ChildDef_HTML5_Figure' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Figure.php', + 'HTMLPurifier_ChildDef_HTML5_Media' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Media.php', + 'HTMLPurifier_ChildDef_HTML5_Picture' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Picture.php', + 'HTMLPurifier_ChildDef_HTML5_Script' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Script.php', + 'HTMLPurifier_ChildDef_HTML5_Time' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Time.php', 'HTMLPurifier_HTML5Config' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Config.php', 'HTMLPurifier_HTML5Definition' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Definition.php', + 'HTMLPurifier_HTMLModule_HTML5_Bdo' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Bdo.php', + 'HTMLPurifier_HTMLModule_HTML5_Edit' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Edit.php', + 'HTMLPurifier_HTMLModule_HTML5_Forms' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Forms.php', + 'HTMLPurifier_HTMLModule_HTML5_Hypertext' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Hypertext.php', + 'HTMLPurifier_HTMLModule_HTML5_Iframe' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Iframe.php', + 'HTMLPurifier_HTMLModule_HTML5_Interactive' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Interactive.php', + 'HTMLPurifier_HTMLModule_HTML5_List' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/List.php', + 'HTMLPurifier_HTMLModule_HTML5_Media' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Media.php', + 'HTMLPurifier_HTMLModule_HTML5_Ruby' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Ruby.php', + 'HTMLPurifier_HTMLModule_HTML5_SafeScripting' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/SafeScripting.php', + 'HTMLPurifier_HTMLModule_HTML5_Scripting' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Scripting.php', + 'HTMLPurifier_HTMLModule_HTML5_Text' => $vendorDir . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Text.php', 'MeekroDB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBEval' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBException' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'WhereClause' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', - 'kakao\\KakaoKey' => $baseDir . '/d_setting/KakaoKey.php', - 'sammo\\RootDB' => $baseDir . '/d_setting/RootDB.php', - 'sammo\\ServConfig' => $baseDir . '/d_setting/ServConfig.php', ); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index c61c1246..e8faaee3 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', '2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 9bd88669..9f668b24 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -10,6 +10,7 @@ return array( 'kakao\\' => array($baseDir . '/src/kakao'), 'Valitron\\' => array($vendorDir . '/vlucas/valitron/src/Valitron'), 'Symfony\\Component\\Lock\\' => array($vendorDir . '/symfony/lock'), + 'ScssPhp\\ScssPhp\\' => array($vendorDir . '/scssphp/scssphp/src'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), 'PhpExtended\\Tail\\' => array($vendorDir . '/php-extended/php-tail/src'), @@ -17,7 +18,6 @@ return array( 'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'), 'Medoo\\' => array($vendorDir . '/catfan/medoo/src'), 'League\\Plates\\' => array($vendorDir . '/league/plates/src'), - 'Leafo\\ScssPhp\\' => array($vendorDir . '/leafo/scssphp/src'), 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 85e66636..3f96f6c6 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -7,6 +7,7 @@ namespace Composer\Autoload; class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a { public static $files = array ( + '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', @@ -31,6 +32,7 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a 'S' => array ( 'Symfony\\Component\\Lock\\' => 23, + 'ScssPhp\\ScssPhp\\' => 16, ), 'P' => array ( @@ -47,7 +49,6 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a 'L' => array ( 'League\\Plates\\' => 14, - 'Leafo\\ScssPhp\\' => 14, ), 'G' => array ( @@ -74,6 +75,10 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a array ( 0 => __DIR__ . '/..' . '/symfony/lock', ), + 'ScssPhp\\ScssPhp\\' => + array ( + 0 => __DIR__ . '/..' . '/scssphp/scssphp/src', + ), 'Psr\\Log\\' => array ( 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', @@ -102,10 +107,6 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a array ( 0 => __DIR__ . '/..' . '/league/plates/src', ), - 'Leafo\\ScssPhp\\' => - array ( - 0 => __DIR__ . '/..' . '/leafo/scssphp/src', - ), 'GuzzleHttp\\Psr7\\' => array ( 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', @@ -143,21 +144,42 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a 'DBTransaction' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'FB' => __DIR__ . '/..' . '/firephp/firephp-core/lib/FirePHPCore/fb.php', 'FirePHP' => __DIR__ . '/..' . '/firephp/firephp-core/lib/FirePHPCore/FirePHP.class.php', + 'HTMLPurifier_AttrDef_Float' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Float.php', + 'HTMLPurifier_AttrDef_HTML5_ARel' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/ARel.php', + 'HTMLPurifier_AttrDef_HTML5_Datetime' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/Datetime.php', + 'HTMLPurifier_AttrDef_HTML5_Duration' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/Duration.php', + 'HTMLPurifier_AttrDef_HTML5_Week' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/Week.php', + 'HTMLPurifier_AttrDef_HTML5_YearlessDate' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML5/YearlessDate.php', 'HTMLPurifier_AttrDef_HTML_Bool2' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/HTML/Bool2.php', - 'HTMLPurifier_AttrDef_Regexp' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrDef/Regexp.php', - 'HTMLPurifier_ChildDef_Details' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Details.php', - 'HTMLPurifier_ChildDef_Figure' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Figure.php', - 'HTMLPurifier_ChildDef_Media' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Media.php', - 'HTMLPurifier_ChildDef_Picture' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/Picture.php', + 'HTMLPurifier_AttrTransform_HTML5_Dialog' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrTransform/HTML5/Dialog.php', + 'HTMLPurifier_AttrTransform_HTML5_Progress' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrTransform/HTML5/Progress.php', + 'HTMLPurifier_AttrTransform_HTML5_Script' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/AttrTransform/HTML5/Script.php', + 'HTMLPurifier_ChildDef_HTML5_Abstract' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Abstract.php', + 'HTMLPurifier_ChildDef_HTML5_Details' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Details.php', + 'HTMLPurifier_ChildDef_HTML5_Fieldset' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Fieldset.php', + 'HTMLPurifier_ChildDef_HTML5_Figure' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Figure.php', + 'HTMLPurifier_ChildDef_HTML5_Media' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Media.php', + 'HTMLPurifier_ChildDef_HTML5_Picture' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Picture.php', + 'HTMLPurifier_ChildDef_HTML5_Script' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Script.php', + 'HTMLPurifier_ChildDef_HTML5_Time' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/ChildDef/HTML5/Time.php', 'HTMLPurifier_HTML5Config' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Config.php', 'HTMLPurifier_HTML5Definition' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTML5Definition.php', + 'HTMLPurifier_HTMLModule_HTML5_Bdo' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Bdo.php', + 'HTMLPurifier_HTMLModule_HTML5_Edit' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Edit.php', + 'HTMLPurifier_HTMLModule_HTML5_Forms' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Forms.php', + 'HTMLPurifier_HTMLModule_HTML5_Hypertext' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Hypertext.php', + 'HTMLPurifier_HTMLModule_HTML5_Iframe' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Iframe.php', + 'HTMLPurifier_HTMLModule_HTML5_Interactive' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Interactive.php', + 'HTMLPurifier_HTMLModule_HTML5_List' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/List.php', + 'HTMLPurifier_HTMLModule_HTML5_Media' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Media.php', + 'HTMLPurifier_HTMLModule_HTML5_Ruby' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Ruby.php', + 'HTMLPurifier_HTMLModule_HTML5_SafeScripting' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/SafeScripting.php', + 'HTMLPurifier_HTMLModule_HTML5_Scripting' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Scripting.php', + 'HTMLPurifier_HTMLModule_HTML5_Text' => __DIR__ . '/..' . '/xemlock/htmlpurifier-html5/library/HTMLPurifier/HTMLModule/HTML5/Text.php', 'MeekroDB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBEval' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBException' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'WhereClause' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', - 'kakao\\KakaoKey' => __DIR__ . '/../..' . '/d_setting/KakaoKey.php', - 'sammo\\RootDB' => __DIR__ . '/../..' . '/d_setting/RootDB.php', - 'sammo\\ServConfig' => __DIR__ . '/../..' . '/d_setting/ServConfig.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 7b29a9ee..dd219e8c 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -49,17 +49,17 @@ }, { "name": "catfan/medoo", - "version": "v1.5.7", - "version_normalized": "1.5.7.0", + "version": "v1.7.8", + "version_normalized": "1.7.8.0", "source": { "type": "git", "url": "https://github.com/catfan/Medoo.git", - "reference": "8d90cba0e8ff176028847527d0ea76fe41a06ecf" + "reference": "dd9d570584cfb1e09ec470608479b86e41d5b60d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/catfan/Medoo/zipball/8d90cba0e8ff176028847527d0ea76fe41a06ecf", - "reference": "8d90cba0e8ff176028847527d0ea76fe41a06ecf", + "url": "https://api.github.com/repos/catfan/Medoo/zipball/dd9d570584cfb1e09ec470608479b86e41d5b60d", + "reference": "dd9d570584cfb1e09ec470608479b86e41d5b60d", "shasum": "" }, "require": { @@ -73,9 +73,9 @@ "ext-pdo_oci8": "For Oracle version 8 database", "ext-pdo_pqsql": "For PostgreSQL database", "ext-pdo_sqlite": "For SQLite database", - "ext-pdo_sqlsrv": "For MSSQL database" + "ext-pdo_sqlsrv": "For MSSQL database on both Window/Liunx platform" }, - "time": "2018-06-14T18:59:08+00:00", + "time": "2019-12-19T05:04:34+00:00", "type": "framework", "installation-source": "dist", "autoload": { @@ -93,10 +93,11 @@ "email": "angel@catfan.me" } ], - "description": "The lightest PHP database framework to accelerate development", + "description": "The lightweight PHP database framework to accelerate development", "homepage": "https://medoo.in", "keywords": [ "database", + "database library", "lightweight", "mariadb", "mssql", @@ -110,26 +111,26 @@ }, { "name": "ezyang/htmlpurifier", - "version": "v4.10.0", - "version_normalized": "4.10.0.0", + "version": "v4.12.0", + "version_normalized": "4.12.0.0", "source": { "type": "git", "url": "https://github.com/ezyang/htmlpurifier.git", - "reference": "d85d39da4576a6934b72480be6978fb10c860021" + "reference": "a617e55bc62a87eec73bd456d146d134ad716f03" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021", - "reference": "d85d39da4576a6934b72480be6978fb10c860021", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/a617e55bc62a87eec73bd456d146d134ad716f03", + "reference": "a617e55bc62a87eec73bd456d146d134ad716f03", "shasum": "" }, "require": { "php": ">=5.2" }, "require-dev": { - "simpletest/simpletest": "^1.1" + "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" }, - "time": "2018-02-23T01:58:20+00:00", + "time": "2019-10-28T03:44:26+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -142,7 +143,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL" + "LGPL-2.1-or-later" ], "authors": [ { @@ -197,47 +198,49 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.3.3", - "version_normalized": "6.3.3.0", + "version": "6.5.2", + "version_normalized": "6.5.2.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82", + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82", "shasum": "" }, "require": { + "ext-json": "*", "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.4", + "guzzlehttp/psr7": "^1.6.1", "php": ">=5.5" }, "require-dev": { "ext-curl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.0" + "psr/log": "^1.1" }, "suggest": { + "ext-intl": "Required for Internationalized Domain Name (IDN) support", "psr/log": "Required for using the Log middleware" }, - "time": "2018-04-22T15:46:56+00:00", + "time": "2019-12-23T11:57:10+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "6.3-dev" + "dev-master": "6.5-dev" } }, "installation-source": "dist", "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { "GuzzleHttp\\": "src/" - } + }, + "files": [ + "src/functions_include.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -317,34 +320,39 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.4.2", - "version_normalized": "1.4.2.0", + "version": "1.6.1", + "version_normalized": "1.6.1.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", "shasum": "" }, "require": { "php": ">=5.4.0", - "psr/http-message": "~1.0" + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" }, - "time": "2017-03-20T17:10:46+00:00", + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + }, + "time": "2019-07-01T23:21:34+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.6-dev" } }, "installation-source": "dist", @@ -375,6 +383,7 @@ "keywords": [ "http", "message", + "psr-7", "request", "response", "stream", @@ -382,60 +391,6 @@ "url" ] }, - { - "name": "leafo/scssphp", - "version": "v0.7.7", - "version_normalized": "0.7.7.0", - "source": { - "type": "git", - "url": "https://github.com/leafo/scssphp.git", - "reference": "1d656f8c02a3a69404bba6b28ec4e06edddf0f49" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/leafo/scssphp/zipball/1d656f8c02a3a69404bba6b28ec4e06edddf0f49", - "reference": "1d656f8c02a3a69404bba6b28ec4e06edddf0f49", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.6", - "squizlabs/php_codesniffer": "~2.5" - }, - "time": "2018-07-22T01:22:08+00:00", - "bin": [ - "bin/pscss" - ], - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Leafo\\ScssPhp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Leaf Corcoran", - "email": "leafot@gmail.com", - "homepage": "http://leafo.net" - } - ], - "description": "scssphp is a compiler for SCSS written in PHP.", - "homepage": "http://leafo.github.io/scssphp/", - "keywords": [ - "css", - "less", - "sass", - "scss", - "stylesheet" - ] - }, { "name": "league/plates", "version": "3.3.0", @@ -495,17 +450,17 @@ }, { "name": "monolog/monolog", - "version": "1.23.0", - "version_normalized": "1.23.0.0", + "version": "1.25.3", + "version_normalized": "1.25.3.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", - "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fa82921994db851a8becaf3787a9e73c5976b6f1", + "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1", "shasum": "" }, "require": { @@ -541,7 +496,7 @@ "ruflin/elastica": "Allow sending log messages to an Elastic Search server", "sentry/sentry": "Allow sending log messages to a Sentry server" }, - "time": "2017-06-19T01:22:40+00:00", + "time": "2019-12-20T14:15:16+00:00", "type": "library", "extra": { "branch-alias": { @@ -741,27 +696,27 @@ }, { "name": "psr/log", - "version": "1.0.2", - "version_normalized": "1.0.2.0", + "version": "1.1.2", + "version_normalized": "1.1.2.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", "shasum": "" }, "require": { "php": ">=5.3.0" }, - "time": "2016-10-10T12:19:37+00:00", + "time": "2019-11-01T11:05:21+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "installation-source": "dist", @@ -788,6 +743,111 @@ "psr-3" ] }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "version_normalized": "3.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "time": "2019-03-08T08:55:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders." + }, + { + "name": "scssphp/scssphp", + "version": "1.0.6", + "version_normalized": "1.0.6.0", + "source": { + "type": "git", + "url": "https://github.com/scssphp/scssphp.git", + "reference": "5b3c9d704950d8f9637f5110c36c281ec47dc13c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/scssphp/scssphp/zipball/5b3c9d704950d8f9637f5110c36c281ec47dc13c", + "reference": "5b3c9d704950d8f9637f5110c36c281ec47dc13c", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3", + "squizlabs/php_codesniffer": "~2.5", + "twbs/bootstrap": "~4.3", + "zurb/foundation": "~6.5" + }, + "time": "2019-12-12T05:00:52+00:00", + "bin": [ + "bin/pscss" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ScssPhp\\ScssPhp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthon Pang", + "email": "apang@softwaredevelopment.ca", + "homepage": "https://github.com/robocoder" + }, + { + "name": "Cédric Morin", + "email": "cedric@yterium.com", + "homepage": "https://github.com/Cerdic" + } + ], + "description": "scssphp is a compiler for SCSS written in PHP.", + "homepage": "http://scssphp.github.io/scssphp/", + "keywords": [ + "css", + "less", + "sass", + "scss", + "stylesheet" + ] + }, { "name": "sergeytsalkov/meekrodb", "version": "v2.3", @@ -835,31 +895,36 @@ }, { "name": "symfony/lock", - "version": "v4.1.1", - "version_normalized": "4.1.1.0", + "version": "v4.4.3", + "version_normalized": "4.4.3.0", "source": { "type": "git", "url": "https://github.com/symfony/lock.git", - "reference": "d508b5dd92272cb74300396ecaadde969d0f7976" + "reference": "6c4f5b620871cfef5b004fc57f2ca74572ae03b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/lock/zipball/d508b5dd92272cb74300396ecaadde969d0f7976", - "reference": "d508b5dd92272cb74300396ecaadde969d0f7976", + "url": "https://api.github.com/repos/symfony/lock/zipball/6c4f5b620871cfef5b004fc57f2ca74572ae03b3", + "reference": "6c4f5b620871cfef5b004fc57f2ca74572ae03b3", "shasum": "" }, "require": { "php": "^7.1.3", "psr/log": "~1.0" }, + "conflict": { + "doctrine/dbal": "<2.5" + }, "require-dev": { + "doctrine/dbal": "~2.5", + "mongodb/mongodb": "~1.1", "predis/predis": "~1.0" }, - "time": "2018-06-21T11:15:46+00:00", + "time": "2020-01-04T13:00:46+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.4-dev" } }, "installation-source": "dist", @@ -876,13 +941,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Jérémy Derussé", "email": "jeremy@derusse.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Lock Component", @@ -898,17 +963,17 @@ }, { "name": "vlucas/valitron", - "version": "v1.4.3", - "version_normalized": "1.4.3.0", + "version": "v1.4.7", + "version_normalized": "1.4.7.0", "source": { "type": "git", "url": "https://github.com/vlucas/valitron.git", - "reference": "3c5463315bfa23b17f8949b100a960d035234e43" + "reference": "a03072bed1679660200766d134507a30193eaf6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/valitron/zipball/3c5463315bfa23b17f8949b100a960d035234e43", - "reference": "3c5463315bfa23b17f8949b100a960d035234e43", + "url": "https://api.github.com/repos/vlucas/valitron/zipball/a03072bed1679660200766d134507a30193eaf6d", + "reference": "a03072bed1679660200766d134507a30193eaf6d", "shasum": "" }, "require": { @@ -920,7 +985,7 @@ "suggest": { "ext-mbstring": "It can support the multiple bytes string length." }, - "time": "2018-05-06T10:45:26+00:00", + "time": "2019-08-29T19:49:43+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -949,27 +1014,28 @@ }, { "name": "xemlock/htmlpurifier-html5", - "version": "v0.1.7", - "version_normalized": "0.1.7.0", + "version": "v0.1.11", + "version_normalized": "0.1.11.0", "source": { "type": "git", "url": "https://github.com/xemlock/htmlpurifier-html5.git", - "reference": "b4b35e51ec75e0207c23035f7d9a354bdcdac359" + "reference": "f0d563f9fd4a82a3d759043483f9a94c0d8c2255" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/xemlock/htmlpurifier-html5/zipball/b4b35e51ec75e0207c23035f7d9a354bdcdac359", - "reference": "b4b35e51ec75e0207c23035f7d9a354bdcdac359", + "url": "https://api.github.com/repos/xemlock/htmlpurifier-html5/zipball/f0d563f9fd4a82a3d759043483f9a94c0d8c2255", + "reference": "f0d563f9fd4a82a3d759043483f9a94c0d8c2255", "shasum": "" }, "require": { - "ezyang/htmlpurifier": "^4.7", + "ezyang/htmlpurifier": "^4.8", "php": ">=5.2" }, "require-dev": { - "phpunit/phpunit": "4.7.*|5.7.*" + "php-coveralls/php-coveralls": "^1.1|^2.1", + "phpunit/phpunit": ">=4.7 <8.0" }, - "time": "2018-06-07T14:30:17+00:00", + "time": "2019-08-07T17:19:21+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -987,6 +1053,16 @@ "email": "xemlock@gmail.com" } ], - "description": "HTML Purifier definitions for HTML5 elements" + "description": "HTML5 element definitions for HTML Purifier", + "keywords": [ + "HTML5", + "Purifier", + "html", + "htmlpurifier", + "security", + "tidy", + "validator", + "xss" + ] } ] diff --git a/vendor/ezyang/htmlpurifier/INSTALL b/vendor/ezyang/htmlpurifier/INSTALL index e6dd02af..5f6a965f 100644 --- a/vendor/ezyang/htmlpurifier/INSTALL +++ b/vendor/ezyang/htmlpurifier/INSTALL @@ -15,7 +15,7 @@ with these contents. --------------------------------------------------------------------------- 1. Compatibility -HTML Purifier is PHP 5 and PHP 7, and is actively tested from PHP 5.0.5 +HTML Purifier is PHP 5 and PHP 7, and is actively tested from PHP 5.3 and up. It has no core dependencies with other libraries. These optional extensions can enhance the capabilities of HTML Purifier: @@ -101,31 +101,6 @@ Autoload compatibility autoloader, but there are some cases where you will need to change your own code to accomodate HTML Purifier. These are those cases: - PHP VERSION IS LESS THAN 5.1.2, AND YOU'VE DEFINED __autoload - Because spl_autoload_register() doesn't exist in early versions - of PHP 5, HTML Purifier has no way of adding itself to the autoload - stack. Modify your __autoload function to test - HTMLPurifier_Bootstrap::autoload($class) - - For example, suppose your autoload function looks like this: - - function __autoload($class) { - require str_replace('_', '/', $class) . '.php'; - return true; - } - - A modified version with HTML Purifier would look like this: - - function __autoload($class) { - if (HTMLPurifier_Bootstrap::autoload($class)) return true; - require str_replace('_', '/', $class) . '.php'; - return true; - } - - Note that there *is* some custom behavior in our autoloader; the - original autoloader in our example would work for 99% of the time, - but would fail when including language files. - AN __autoload FUNCTION IS DECLARED AFTER OUR AUTOLOADER IS REGISTERED spl_autoload_register() has the curious behavior of disabling the existing __autoload() handler. Users need to explicitly @@ -138,11 +113,6 @@ Autoload compatibility spl_autoload_register('__autoload') - Users should also be on guard if they use a version of PHP previous - to 5.1.2 without an autoloader--HTML Purifier will define __autoload() - for you, which can collide with an autoloader that was added by *you* - later. - For better performance ---------------------- @@ -204,9 +174,7 @@ For advanced users HTMLPurifier.autoload.php Registers our autoload handler HTMLPurifier_Bootstrap::autoload($class). - You can do these operations by yourself--in fact, you must modify your own - autoload handler if you are using a version of PHP earlier than PHP 5.1.2 - (See "Autoload compatibility" above). + You can do these operations by yourself, if you like. --------------------------------------------------------------------------- diff --git a/vendor/ezyang/htmlpurifier/INSTALL.fr.utf8 b/vendor/ezyang/htmlpurifier/INSTALL.fr.utf8 index 95164abb..629387e2 100644 --- a/vendor/ezyang/htmlpurifier/INSTALL.fr.utf8 +++ b/vendor/ezyang/htmlpurifier/INSTALL.fr.utf8 @@ -11,7 +11,7 @@ pied de page, mais je recommande de lire le document. 1. Compatibilité -HTML Purifier fonctionne avec PHP 5. PHP 5.0.5 est la dernière version testée. +HTML Purifier fonctionne avec PHP 5. PHP 5.3 est la dernière version testée. Il ne dépend pas d'autres librairies. Les extensions optionnelles sont iconv (généralement déjà installée) et tidy diff --git a/vendor/ezyang/htmlpurifier/NEWS b/vendor/ezyang/htmlpurifier/NEWS index 9b6e1023..35283501 100644 --- a/vendor/ezyang/htmlpurifier/NEWS +++ b/vendor/ezyang/htmlpurifier/NEWS @@ -9,6 +9,40 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier . Internal change ========================== +4.12.0, released 2019-10-27 +! PHP 7.4 is supported, thank you Witold Wasiczko, Mateuz Turcza and + Edi Modrić +- PHPDocs for HTMLModule::addElement() and Bool attr are fixed (thanks + Mateusz) + +4.11.0, released 2019-07-14 +# SafeScripting now matches case-sensitively against its whitelist (previously it was + case-insensitive.) Thanks Dimitri Gritsajuk + for reporting. +! New directive %Core.AllowParseManyTags which allows parsing of many nested tags. + Thanks M. Suzuki for contributing the patch. +! purifyArray now supports multidimensional arrays. Thanks + Sandro Miguel Marques for contributing this patch. +! initial and inherit settings available for width, height, and the min-/max- + versions thereof. Thanks Michael Kliewe for contributing + this patch. +! More color names are supported. Thanks Daijobou for contributing. +- Compatibility fixes for PHP 7.3, including new CI for PHP 7.3 + (thank you Lukas Neumann ) and removal of + reserved words in our constants (thanks Darko Hrgovic +- Compatibility fixes for HHVM. Thanks Mateusz Turcza for contributing + this fix. +- HTML Purifier now never defines __autoload, fixing #196. Thanks + Michael Kliewe for reporting. +- In some situations, Config.php would report an undefined index: class + error; this has been fixed. Thanks DiLong Fa for contributing + this fix. +- We no longer produce '); + static::writeOutput(''); } elseif ($format === 'js') { - self::writeOutput(self::generateScript()); + static::writeOutput(static::generateScript()); } - self::reset(); + static::resetStatic(); } } + public function close() + { + self::resetStatic(); + } + + public function reset() + { + self::resetStatic(); + } + /** * Forget all logged records */ - public static function reset() + public static function resetStatic() { - self::$records = array(); + static::$records = array(); } /** @@ -133,18 +143,18 @@ class BrowserConsoleHandler extends AbstractProcessingHandler private static function generateScript() { $script = array(); - foreach (self::$records as $record) { - $context = self::dump('Context', $record['context']); - $extra = self::dump('Extra', $record['extra']); + foreach (static::$records as $record) { + $context = static::dump('Context', $record['context']); + $extra = static::dump('Extra', $record['extra']); if (empty($context) && empty($extra)) { - $script[] = self::call_array('log', self::handleStyles($record['formatted'])); + $script[] = static::call_array('log', static::handleStyles($record['formatted'])); } else { $script = array_merge($script, - array(self::call_array('groupCollapsed', self::handleStyles($record['formatted']))), + array(static::call_array('groupCollapsed', static::handleStyles($record['formatted']))), $context, $extra, - array(self::call('groupEnd')) + array(static::call('groupEnd')) ); } } @@ -154,21 +164,22 @@ class BrowserConsoleHandler extends AbstractProcessingHandler private static function handleStyles($formatted) { - $args = array(self::quote('font-weight: normal')); + $args = array(); $format = '%c' . $formatted; preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); foreach (array_reverse($matches) as $match) { - $args[] = self::quote(self::handleCustomStyles($match[2][0], $match[1][0])); $args[] = '"font-weight: normal"'; + $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0])); $pos = $match[0][1]; $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0])); } - array_unshift($args, self::quote($format)); + $args[] = static::quote('font-weight: normal'); + $args[] = static::quote($format); - return $args; + return array_reverse($args); } private static function handleCustomStyles($style, $string) @@ -198,13 +209,13 @@ class BrowserConsoleHandler extends AbstractProcessingHandler if (empty($dict)) { return $script; } - $script[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title)); + $script[] = static::call('log', static::quote('%c%s'), static::quote('font-weight: bold'), static::quote($title)); foreach ($dict as $key => $value) { $value = json_encode($value); if (empty($value)) { - $value = self::quote(''); + $value = static::quote(''); } - $script[] = self::call('log', self::quote('%s: %o'), self::quote($key), $value); + $script[] = static::call('log', static::quote('%s: %o'), static::quote($key), $value); } return $script; @@ -220,7 +231,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler $args = func_get_args(); $method = array_shift($args); - return self::call_array($method, $args); + return static::call_array($method, $args); } private static function call_array($method, array $args) diff --git a/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php index 72f89535..0957e558 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php @@ -12,6 +12,8 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\ResettableInterface; +use Monolog\Formatter\FormatterInterface; /** * Buffers all records until closing the handler and then pass them as batch. @@ -34,8 +36,8 @@ class BufferHandler extends AbstractHandler * @param HandlerInterface $handler Handler. * @param int $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param Boolean $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded */ public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false) { @@ -114,4 +116,33 @@ class BufferHandler extends AbstractHandler $this->bufferSize = 0; $this->buffer = array(); } + + public function reset() + { + $this->flush(); + + parent::reset(); + + if ($this->handler instanceof ResettableInterface) { + $this->handler->reset(); + } + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + $this->handler->setFormatter($formatter); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->handler->getFormatter(); + } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php index 785cb0c9..47120e54 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php @@ -13,6 +13,7 @@ namespace Monolog\Handler; use Monolog\Formatter\ChromePHPFormatter; use Monolog\Logger; +use Monolog\Utils; /** * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) @@ -32,7 +33,7 @@ class ChromePHPHandler extends AbstractProcessingHandler * Header name */ const HEADER_NAME = 'X-ChromeLogger-Data'; - + /** * Regular expression to detect supported browsers (matches any Chrome, or Firefox 43+) */ @@ -43,9 +44,9 @@ class ChromePHPHandler extends AbstractProcessingHandler /** * Tracks whether we sent too much data * - * Chrome limits the headers to 256KB, so when we sent 240KB we stop sending + * Chrome limits the headers to 4KB, so when we sent 3KB we stop sending * - * @var Boolean + * @var bool */ protected static $overflowed = false; @@ -58,8 +59,8 @@ class ChromePHPHandler extends AbstractProcessingHandler protected static $sendHeaders = true; /** - * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct($level = Logger::DEBUG, $bubble = true) { @@ -134,9 +135,9 @@ class ChromePHPHandler extends AbstractProcessingHandler self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; } - $json = @json_encode(self::$json); + $json = Utils::jsonEncode(self::$json, null, true); $data = base64_encode(utf8_encode($json)); - if (strlen($data) > 240 * 1024) { + if (strlen($data) > 3 * 1024) { self::$overflowed = true; $record = array( @@ -149,7 +150,7 @@ class ChromePHPHandler extends AbstractProcessingHandler 'extra' => array(), ); self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); - $json = @json_encode(self::$json); + $json = Utils::jsonEncode(self::$json, null, true); $data = base64_encode(utf8_encode($json)); } @@ -174,7 +175,7 @@ class ChromePHPHandler extends AbstractProcessingHandler /** * Verifies if the headers are accepted by the current user agent * - * @return Boolean + * @return bool */ protected function headersAccepted() { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php index 96b3ca0c..44928efb 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Logs to Cube. @@ -119,9 +120,9 @@ class CubeHandler extends AbstractProcessingHandler $data['data']['level'] = $record['level']; if ($this->scheme === 'http') { - $this->writeHttp(json_encode($data)); + $this->writeHttp(Utils::jsonEncode($data)); } else { - $this->writeUdp(json_encode($data)); + $this->writeUdp(Utils::jsonEncode($data)); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php index 7778c22a..35b55cb4 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php @@ -60,7 +60,7 @@ class DeduplicationHandler extends BufferHandler * @param string $deduplicationStore The file/path where the deduplication log should be kept * @param int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes * @param int $time The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $time = 60, $bubble = true) { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php index 81967406..bb0f83eb 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php @@ -46,10 +46,10 @@ class ElasticSearchHandler extends AbstractProcessingHandler protected $options = array(); /** - * @param Client $client Elastica Client object - * @param array $options Handler configuration - * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param Client $client Elastica Client object + * @param array $options Handler configuration + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true) { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php index 1447a584..b2986b0f 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php @@ -28,10 +28,10 @@ class ErrorLogHandler extends AbstractProcessingHandler protected $expandNewlines; /** - * @param int $messageType Says where the error should go. - * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param Boolean $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries + * @param int $messageType Says where the error should go. + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries */ public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true, $expandNewlines = false) { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php index 2a0f7fd1..949f2271 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; /** * Simple handler wrapper that filters records based on a list of levels @@ -40,15 +41,15 @@ class FilterHandler extends AbstractHandler /** * Whether the messages that are handled can bubble up the stack or not * - * @var Boolean + * @var bool */ protected $bubble; /** - * @param callable|HandlerInterface $handler Handler or factory callable($record, $this). + * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler). * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided * @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true) { @@ -104,21 +105,13 @@ class FilterHandler extends AbstractHandler return false; } - // The same logic as in FingersCrossedHandler - if (!$this->handler instanceof HandlerInterface) { - $this->handler = call_user_func($this->handler, $record, $this); - if (!$this->handler instanceof HandlerInterface) { - throw new \RuntimeException("The factory callable should return a HandlerInterface"); - } - } - if ($this->processors) { foreach ($this->processors as $processor) { $record = call_user_func($processor, $record); } } - $this->handler->handle($record); + $this->getHandler($record)->handle($record); return false === $this->bubble; } @@ -135,6 +128,45 @@ class FilterHandler extends AbstractHandler } } - $this->handler->handleBatch($filtered); + if (count($filtered) > 0) { + $this->getHandler($filtered[count($filtered) - 1])->handleBatch($filtered); + } + } + + /** + * Return the nested handler + * + * If the handler was provided as a factory callable, this will trigger the handler's instantiation. + * + * @return HandlerInterface + */ + public function getHandler(array $record = null) + { + if (!$this->handler instanceof HandlerInterface) { + $this->handler = call_user_func($this->handler, $record, $this); + if (!$this->handler instanceof HandlerInterface) { + throw new \RuntimeException("The factory callable should return a HandlerInterface"); + } + } + + return $this->handler; + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + $this->getHandler()->setFormatter($formatter); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->getHandler()->getFormatter(); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php index c3e42efe..aaca12cc 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -22,7 +22,7 @@ interface ActivationStrategyInterface * Returns whether the given record activates the handler. * * @param array $record - * @return Boolean + * @return bool */ public function isHandlerActivated(array $record); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php index d1dcaacf..cdabc445 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php @@ -14,6 +14,8 @@ namespace Monolog\Handler; use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; use Monolog\Logger; +use Monolog\ResettableInterface; +use Monolog\Formatter\FormatterInterface; /** * Buffers all records until a certain level is reached @@ -38,11 +40,11 @@ class FingersCrossedHandler extends AbstractHandler protected $passthruLevel; /** - * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler). + * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler). * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param Boolean $stopBuffering Whether the handler should stop buffering after being triggered (default true) + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $stopBuffering Whether the handler should stop buffering after being triggered (default true) * @param int $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered */ public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null) @@ -87,15 +89,7 @@ class FingersCrossedHandler extends AbstractHandler if ($this->stopBuffering) { $this->buffering = false; } - if (!$this->handler instanceof HandlerInterface) { - $record = end($this->buffer) ?: null; - - $this->handler = call_user_func($this->handler, $record, $this); - if (!$this->handler instanceof HandlerInterface) { - throw new \RuntimeException("The factory callable should return a HandlerInterface"); - } - } - $this->handler->handleBatch($this->buffer); + $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer); $this->buffer = array(); } @@ -119,7 +113,7 @@ class FingersCrossedHandler extends AbstractHandler $this->activate(); } } else { - $this->handler->handle($record); + $this->getHandler($record)->handle($record); } return false === $this->bubble; @@ -130,24 +124,18 @@ class FingersCrossedHandler extends AbstractHandler */ public function close() { - if (null !== $this->passthruLevel) { - $level = $this->passthruLevel; - $this->buffer = array_filter($this->buffer, function ($record) use ($level) { - return $record['level'] >= $level; - }); - if (count($this->buffer) > 0) { - $this->handler->handleBatch($this->buffer); - $this->buffer = array(); - } - } + $this->flushBuffer(); } - /** - * Resets the state of the handler. Stops forwarding records to the wrapped handler. - */ public function reset() { - $this->buffering = true; + $this->flushBuffer(); + + parent::reset(); + + if ($this->getHandler() instanceof ResettableInterface) { + $this->getHandler()->reset(); + } } /** @@ -160,4 +148,60 @@ class FingersCrossedHandler extends AbstractHandler $this->buffer = array(); $this->reset(); } + + /** + * Resets the state of the handler. Stops forwarding records to the wrapped handler. + */ + private function flushBuffer() + { + if (null !== $this->passthruLevel) { + $level = $this->passthruLevel; + $this->buffer = array_filter($this->buffer, function ($record) use ($level) { + return $record['level'] >= $level; + }); + if (count($this->buffer) > 0) { + $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer); + } + } + + $this->buffer = array(); + $this->buffering = true; + } + + /** + * Return the nested handler + * + * If the handler was provided as a factory callable, this will trigger the handler's instantiation. + * + * @return HandlerInterface + */ + public function getHandler(array $record = null) + { + if (!$this->handler instanceof HandlerInterface) { + $this->handler = call_user_func($this->handler, $record, $this); + if (!$this->handler instanceof HandlerInterface) { + throw new \RuntimeException("The factory callable should return a HandlerInterface"); + } + } + + return $this->handler; + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + $this->getHandler()->setFormatter($formatter); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->getHandler()->getFormatter(); + } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php index fee47950..c30b1843 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php @@ -158,7 +158,7 @@ class FirePHPHandler extends AbstractProcessingHandler /** * Verifies if the headers are accepted by the current user agent * - * @return Boolean + * @return bool */ protected function headersAccepted() { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php index dd9a361c..f0f010cb 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; use Monolog\Formatter\FlowdockFormatter; use Monolog\Formatter\FormatterInterface; @@ -105,7 +106,7 @@ class FlowdockHandler extends SocketHandler */ private function buildContent($record) { - return json_encode($record['formatted']['flowdock']); + return Utils::jsonEncode($record['formatted']['flowdock']); } /** diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php new file mode 100644 index 00000000..3e2f1b28 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\FormatterInterface; + +/** + * Interface to describe loggers that have a formatter + * + * This interface is present in monolog 1.x to ease forward compatibility. + * + * @author Jordi Boggiano + */ +interface FormattableHandlerInterface +{ + /** + * Sets the formatter. + * + * @param FormatterInterface $formatter + * @return HandlerInterface self + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface; + + /** + * Gets the formatter. + * + * @return FormatterInterface + */ + public function getFormatter(): FormatterInterface; +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php b/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php new file mode 100644 index 00000000..e9ec5e77 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; + +/** + * Helper trait for implementing FormattableInterface + * + * This trait is present in monolog 1.x to ease forward compatibility. + * + * @author Jordi Boggiano + */ +trait FormattableHandlerTrait +{ + /** + * @var FormatterInterface + */ + protected $formatter; + + /** + * {@inheritdoc} + * @suppress PhanTypeMismatchReturn + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + $this->formatter = $formatter; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter(): FormatterInterface + { + if (!$this->formatter) { + $this->formatter = $this->getDefaultFormatter(); + } + + return $this->formatter; + } + + /** + * Gets the default formatter. + * + * Overwrite this if the LineFormatter is not a good default for your handler. + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new LineFormatter(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php index d3847d82..71e46693 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php @@ -47,14 +47,6 @@ class GelfHandler extends AbstractProcessingHandler $this->publisher = $publisher; } - /** - * {@inheritdoc} - */ - public function close() - { - $this->publisher = null; - } - /** * {@inheritdoc} */ diff --git a/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php index 663f5a92..0d461f9c 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\FormatterInterface; +use Monolog\ResettableInterface; /** * Forwards records to multiple handlers @@ -23,8 +24,8 @@ class GroupHandler extends AbstractHandler protected $handlers; /** - * @param array $handlers Array of Handlers. - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param array $handlers Array of Handlers. + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(array $handlers, $bubble = true) { @@ -79,8 +80,9 @@ class GroupHandler extends AbstractHandler $processed = array(); foreach ($records as $record) { foreach ($this->processors as $processor) { - $processed[] = call_user_func($processor, $record); + $record = call_user_func($processor, $record); } + $processed[] = $record; } $records = $processed; } @@ -90,6 +92,17 @@ class GroupHandler extends AbstractHandler } } + public function reset() + { + parent::reset(); + + foreach ($this->handlers as $handler) { + if ($handler instanceof ResettableInterface) { + $handler->reset(); + } + } + } + /** * {@inheritdoc} */ diff --git a/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php index d920c4ba..8d5a4a09 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php @@ -31,7 +31,7 @@ interface HandlerInterface * * @param array $record Partial log record containing only a level key * - * @return Boolean + * @return bool */ public function isHandling(array $record); @@ -46,7 +46,7 @@ interface HandlerInterface * calling further handlers in the stack with a given log record. * * @param array $record The record to handle - * @return Boolean true means that this handler handled the record, and that bubbling is not permitted. + * @return bool true means that this handler handled the record, and that bubbling is not permitted. * false means the record was either not processed or that this handler allows bubbling. */ public function handle(array $record); diff --git a/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php b/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php index e540d80f..55e64986 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; /** @@ -30,7 +31,7 @@ use Monolog\Formatter\FormatterInterface; * * @author Alexey Karapetov */ -class HandlerWrapper implements HandlerInterface +class HandlerWrapper implements HandlerInterface, ResettableInterface { /** * @var HandlerInterface @@ -105,4 +106,11 @@ class HandlerWrapper implements HandlerInterface { return $this->handler->getFormatter(); } + + public function reset() + { + if ($this->handler instanceof ResettableInterface) { + return $this->handler->reset(); + } + } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php index 73049f36..179d6268 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php @@ -97,6 +97,8 @@ class HipChatHandler extends SocketHandler */ public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com', $version = self::API_V1) { + @trigger_error('The Monolog\Handler\HipChatHandler class is deprecated. You should migrate to Slack and the SlackWebhookHandler / SlackbotHandler, see https://www.atlassian.com/partnerships/slack', E_USER_DEPRECATED); + if ($version == self::API_V1 && !$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) { throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.'); } @@ -219,6 +221,21 @@ class HipChatHandler extends SocketHandler protected function write(array $record) { parent::write($record); + $this->finalizeWrite(); + } + + /** + * Finalizes the request by reading some bytes and then closing the socket + * + * If we do not read some but close the socket too early, hipchat sometimes + * drops the request entirely. + */ + protected function finalizeWrite() + { + $res = $this->getResource(); + if (is_resource($res)) { + @fread($res, 2048); + } $this->closeSocket(); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php index d60a3c82..f4d3b97e 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * IFTTTHandler uses cURL to trigger IFTTT Maker actions @@ -30,10 +31,10 @@ class IFTTTHandler extends AbstractProcessingHandler private $secretKey; /** - * @param string $eventName The name of the IFTTT Maker event that should be triggered - * @param string $secretKey A valid IFTTT secret key - * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param string $eventName The name of the IFTTT Maker event that should be triggered + * @param string $secretKey A valid IFTTT secret key + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct($eventName, $secretKey, $level = Logger::ERROR, $bubble = true) { @@ -53,7 +54,7 @@ class IFTTTHandler extends AbstractProcessingHandler "value2" => $record["level_name"], "value3" => $record["message"], ); - $postString = json_encode($postData); + $postString = Utils::jsonEncode($postData); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://maker.ifttt.com/trigger/" . $this->eventName . "/with/key/" . $this->secretKey); diff --git a/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php new file mode 100644 index 00000000..8f683dce --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + + namespace Monolog\Handler; + + use Monolog\Logger; + +/** + * Inspired on LogEntriesHandler. + * + * @author Robert Kaufmann III + * @author Gabriel Machado + */ +class InsightOpsHandler extends SocketHandler +{ + /** + * @var string + */ + protected $logToken; + + /** + * @param string $token Log token supplied by InsightOps + * @param string $region Region where InsightOps account is hosted. Could be 'us' or 'eu'. + * @param bool $useSSL Whether or not SSL encryption should be used + * @param int $level The minimum logging level to trigger this handler + * @param bool $bubble Whether or not messages that are handled should bubble up the stack. + * + * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing + */ + public function __construct($token, $region = 'us', $useSSL = true, $level = Logger::DEBUG, $bubble = true) + { + if ($useSSL && !extension_loaded('openssl')) { + throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for InsightOpsHandler'); + } + + $endpoint = $useSSL + ? 'ssl://' . $region . '.data.logs.insight.rapid7.com:443' + : $region . '.data.logs.insight.rapid7.com:80'; + + parent::__construct($endpoint, $level, $bubble); + $this->logToken = $token; + } + + /** + * {@inheritdoc} + * + * @param array $record + * @return string + */ + protected function generateDataStream($record) + { + return $this->logToken . ' ' . $record['formatted']; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php index 494c605b..ea89fb3e 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php @@ -31,13 +31,13 @@ class LogEntriesHandler extends SocketHandler * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ - public function __construct($token, $useSSL = true, $level = Logger::DEBUG, $bubble = true) + public function __construct($token, $useSSL = true, $level = Logger::DEBUG, $bubble = true, $host = 'data.logentries.com') { if ($useSSL && !extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); } - $endpoint = $useSSL ? 'ssl://data.logentries.com:443' : 'data.logentries.com:80'; + $endpoint = $useSSL ? 'ssl://' . $host . ':443' : $host . ':80'; parent::__construct($endpoint, $level, $bubble); $this->logToken = $token; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php index ab95924f..3f0956a9 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php @@ -27,7 +27,7 @@ class MandrillHandler extends MailHandler * @param string $apiKey A valid Mandrill API key * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct($apiKey, $message, $level = Logger::ERROR, $bubble = true) { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php index 6718e9e0..64dc1381 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php @@ -12,12 +12,15 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; use Monolog\Formatter\NormalizerFormatter; /** * Class to record a log on a NewRelic application. * Enabling New Relic High Security mode may prevent capture of useful information. * + * This handler requires a NormalizerFormatter to function and expects an array in $record['formatted'] + * * @see https://docs.newrelic.com/docs/agents/php-agent * @see https://docs.newrelic.com/docs/accounts-partnerships/accounts/security/high-security */ @@ -84,7 +87,7 @@ class NewRelicHandler extends AbstractProcessingHandler unset($record['formatted']['context']['transaction_name']); } - if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) { + if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) { newrelic_notice_error($record['message'], $record['context']['exception']); unset($record['formatted']['context']['exception']); } else { @@ -188,7 +191,7 @@ class NewRelicHandler extends AbstractProcessingHandler if (null === $value || is_scalar($value)) { newrelic_add_custom_parameter($key, $value); } else { - newrelic_add_custom_parameter($key, @json_encode($value)); + newrelic_add_custom_parameter($key, Utils::jsonEncode($value, null, true)); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php index 1f2076a4..d0a8b43e 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php @@ -14,6 +14,7 @@ namespace Monolog\Handler; use Exception; use Monolog\Formatter\LineFormatter; use Monolog\Logger; +use Monolog\Utils; use PhpConsole\Connector; use PhpConsole\Handler; use PhpConsole\Helper; @@ -188,7 +189,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler $tags = $this->getRecordTags($record); $message = $record['message']; if ($record['context']) { - $message .= ' ' . json_encode($this->connector->getDumper()->dump(array_filter($record['context']))); + $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($record['context'])), null, true); } $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php new file mode 100644 index 00000000..66a3d83a --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Processor\ProcessorInterface; + +/** + * Interface to describe loggers that have processors + * + * This interface is present in monolog 1.x to ease forward compatibility. + * + * @author Jordi Boggiano + */ +interface ProcessableHandlerInterface +{ + /** + * Adds a processor in the stack. + * + * @param ProcessorInterface|callable $callback + * @return HandlerInterface self + */ + public function pushProcessor($callback): HandlerInterface; + + /** + * Removes the processor on top of the stack and returns it. + * + * @throws \LogicException In case the processor stack is empty + * @return callable + */ + public function popProcessor(): callable; +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php b/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php new file mode 100644 index 00000000..09f32a12 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\ResettableInterface; + +/** + * Helper trait for implementing ProcessableInterface + * + * This trait is present in monolog 1.x to ease forward compatibility. + * + * @author Jordi Boggiano + */ +trait ProcessableHandlerTrait +{ + /** + * @var callable[] + */ + protected $processors = []; + + /** + * {@inheritdoc} + * @suppress PhanTypeMismatchReturn + */ + public function pushProcessor($callback): HandlerInterface + { + array_unshift($this->processors, $callback); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function popProcessor(): callable + { + if (!$this->processors) { + throw new \LogicException('You tried to pop from an empty processor stack.'); + } + + return array_shift($this->processors); + } + + /** + * Processes a record. + */ + protected function processRecord(array $record): array + { + foreach ($this->processors as $processor) { + $record = $processor($record); + } + + return $record; + } + + protected function resetProcessors(): void + { + foreach ($this->processors as $processor) { + if ($processor instanceof ResettableInterface) { + $processor->reset(); + } + } + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php index 1ae85845..a99e6ab7 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php @@ -31,7 +31,7 @@ class PsrHandler extends AbstractHandler /** * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, $bubble = true) { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php index bba72005..f27bb3da 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php @@ -69,8 +69,8 @@ class PushoverHandler extends SocketHandler * @param string|array $users Pushover user id or array of ids the message will be sent to * @param string $title Title sent to the Pushover API * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param Boolean $useSSL Whether to connect via SSL. Required when pushing messages to users that are not + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $useSSL Whether to connect via SSL. Required when pushing messages to users that are not * the pushover.net app owner. OpenSSL is required for this option. * @param int $highPriorityLevel The minimum logging level at which this handler will start * sending "high priority" requests to the Pushover API @@ -180,6 +180,6 @@ class PushoverHandler extends SocketHandler */ public function useFormattedMessage($value) { - $this->useFormattedMessage = (boolean) $value; + $this->useFormattedMessage = (bool) $value; } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php index 53a8b391..1929f25f 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php @@ -18,7 +18,7 @@ use Raven_Client; /** * Handler to send messages to a Sentry (https://github.com/getsentry/sentry) server - * using raven-php (https://github.com/getsentry/raven-php) + * using sentry-php (https://github.com/getsentry/sentry-php) * * @author Marc Abramowitz */ @@ -27,7 +27,7 @@ class RavenHandler extends AbstractProcessingHandler /** * Translates Monolog log levels to Raven log levels. */ - private $logLevels = array( + protected $logLevels = array( Logger::DEBUG => Raven_Client::DEBUG, Logger::INFO => Raven_Client::INFO, Logger::NOTICE => Raven_Client::INFO, @@ -42,7 +42,7 @@ class RavenHandler extends AbstractProcessingHandler * @var string should represent the current version of the calling * software. Can be any string (git commit, version number) */ - private $release; + protected $release; /** * @var Raven_Client the client object that sends the message to the server @@ -57,10 +57,12 @@ class RavenHandler extends AbstractProcessingHandler /** * @param Raven_Client $ravenClient * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true) { + @trigger_error('The Monolog\Handler\RavenHandler class is deprecated. You should rather upgrade to the sentry/sentry 2.x and use Sentry\Monolog\Handler, see https://github.com/getsentry/sentry-php/blob/master/src/Monolog/Handler.php', E_USER_DEPRECATED); + parent::__construct($level, $bubble); $this->ravenClient = $ravenClient; @@ -180,7 +182,7 @@ class RavenHandler extends AbstractProcessingHandler } if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) { - $options['extra']['message'] = $record['formatted']; + $options['message'] = $record['formatted']; $this->ravenClient->captureException($record['context']['exception'], $options); } else { $this->ravenClient->captureMessage($record['formatted'], array(), $options); @@ -216,7 +218,7 @@ class RavenHandler extends AbstractProcessingHandler */ protected function getExtraParameters() { - return array('checksum', 'release', 'event_id'); + return array('contexts', 'checksum', 'release', 'event_id'); } /** diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php index 590f9965..bb00db50 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php @@ -73,7 +73,8 @@ class RedisHandler extends AbstractProcessingHandler protected function writeCapped(array $record) { if ($this->redisClient instanceof \Redis) { - $this->redisClient->multi() + $mode = defined('\Redis::MULTI') ? \Redis::MULTI : 1; + $this->redisClient->multi($mode) ->rpush($this->redisKey, $record["formatted"]) ->ltrim($this->redisKey, -$this->capSize, -1) ->exec(); diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php index 6c8a3e3e..65073ffe 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php @@ -129,4 +129,16 @@ class RollbarHandler extends AbstractProcessingHandler { $this->flush(); } + + /** + * {@inheritdoc} + */ + public function reset() + { + $this->flush(); + + parent::reset(); + } + + } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php index 3b60b3d1..ae2309f8 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php @@ -39,9 +39,9 @@ class RotatingFileHandler extends StreamHandler * @param string $filename * @param int $maxFiles The maximal amount of files to keep (0 means unlimited) * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) - * @param Boolean $useLocking Try to lock log file before doing any writes + * @param bool $useLocking Try to lock log file before doing any writes */ public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false) { @@ -66,6 +66,18 @@ class RotatingFileHandler extends StreamHandler } } + /** + * {@inheritdoc} + */ + public function reset() + { + parent::reset(); + + if (true === $this->mustRotate) { + $this->rotate(); + } + } + public function setFilenameFormat($filenameFormat, $dateFormat) { if (!preg_match('{^Y(([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { @@ -166,7 +178,7 @@ class RotatingFileHandler extends StreamHandler $fileInfo = pathinfo($this->filename); $glob = str_replace( array('{filename}', '{date}'), - array($fileInfo['filename'], '*'), + array($fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'), $fileInfo['dirname'] . '/' . $this->filenameFormat ); if (!empty($fileInfo['extension'])) { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php index 9509ae37..b547ed7d 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\Formatter\FormatterInterface; + /** * Sampling handler * @@ -38,7 +40,7 @@ class SamplingHandler extends AbstractHandler protected $factor; /** - * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler). + * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler). * @param int $factor Sample factor */ public function __construct($handler, $factor) @@ -54,29 +56,58 @@ class SamplingHandler extends AbstractHandler public function isHandling(array $record) { - return $this->handler->isHandling($record); + return $this->getHandler($record)->isHandling($record); } public function handle(array $record) { if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) { - // The same logic as in FingersCrossedHandler - if (!$this->handler instanceof HandlerInterface) { - $this->handler = call_user_func($this->handler, $record, $this); - if (!$this->handler instanceof HandlerInterface) { - throw new \RuntimeException("The factory callable should return a HandlerInterface"); - } - } - if ($this->processors) { foreach ($this->processors as $processor) { $record = call_user_func($processor, $record); } } - $this->handler->handle($record); + $this->getHandler($record)->handle($record); } return false === $this->bubble; } + + /** + * Return the nested handler + * + * If the handler was provided as a factory callable, this will trigger the handler's instantiation. + * + * @return HandlerInterface + */ + public function getHandler(array $record = null) + { + if (!$this->handler instanceof HandlerInterface) { + $this->handler = call_user_func($this->handler, $record, $this); + if (!$this->handler instanceof HandlerInterface) { + throw new \RuntimeException("The factory callable should return a HandlerInterface"); + } + } + + return $this->handler; + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + $this->getHandler()->setFormatter($formatter); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->getHandler()->getFormatter(); + } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php b/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php index 38bc838a..39455501 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php @@ -12,6 +12,7 @@ namespace Monolog\Handler\Slack; use Monolog\Logger; +use Monolog\Utils; use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; @@ -146,7 +147,7 @@ class SlackRecord if ($this->useShortAttachment) { $attachment['fields'][] = $this->generateAttachmentField( - ucfirst($key), + $key, $record[$key] ); } else { @@ -207,13 +208,17 @@ class SlackRecord { $normalized = $this->normalizerFormatter->format($fields); $prettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128; + $flags = 0; + if (PHP_VERSION_ID >= 50400) { + $flags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; + } $hasSecondDimension = count(array_filter($normalized, 'is_array')); $hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric')); return $hasSecondDimension || $hasNonNumericKeys - ? json_encode($normalized, $prettyPrintFlag) - : json_encode($normalized); + ? Utils::jsonEncode($normalized, $prettyPrintFlag | $flags) + : Utils::jsonEncode($normalized, $flags); } /** @@ -229,8 +234,8 @@ class SlackRecord /** * Generates attachment field * - * @param string $title - * @param string|array $value\ + * @param string $title + * @param string|array $value * * @return array */ @@ -241,7 +246,7 @@ class SlackRecord : $value; return array( - 'title' => $title, + 'title' => ucfirst($title), 'value' => $value, 'short' => false ); @@ -257,7 +262,7 @@ class SlackRecord private function generateAttachmentFields(array $data) { $fields = array(); - foreach ($data as $key => $value) { + foreach ($this->normalizerFormatter->format($data) as $key => $value) { $fields[] = $this->generateAttachmentField($key, $value); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php index 3ac4d836..88c4c4d0 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php @@ -13,6 +13,7 @@ namespace Monolog\Handler; use Monolog\Formatter\FormatterInterface; use Monolog\Logger; +use Monolog\Utils; use Monolog\Handler\Slack\SlackRecord; /** @@ -75,6 +76,11 @@ class SlackHandler extends SocketHandler return $this->slackRecord; } + public function getToken() + { + return $this->token; + } + /** * {@inheritdoc} * @@ -113,7 +119,7 @@ class SlackHandler extends SocketHandler $dataArray['token'] = $this->token; if (!empty($dataArray['attachments'])) { - $dataArray['attachments'] = json_encode($dataArray['attachments']); + $dataArray['attachments'] = Utils::jsonEncode($dataArray['attachments']); } return $dataArray; diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php index 9a1bbb44..b87be99a 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php @@ -13,6 +13,7 @@ namespace Monolog\Handler; use Monolog\Formatter\FormatterInterface; use Monolog\Logger; +use Monolog\Utils; use Monolog\Handler\Slack\SlackRecord; /** @@ -70,6 +71,11 @@ class SlackWebhookHandler extends AbstractProcessingHandler return $this->slackRecord; } + public function getWebhookUrl() + { + return $this->webhookUrl; + } + /** * {@inheritdoc} * @@ -78,7 +84,7 @@ class SlackWebhookHandler extends AbstractProcessingHandler protected function write(array $record) { $postData = $this->slackRecord->getSlackData($record); - $postString = json_encode($postData); + $postString = Utils::jsonEncode($postData); $ch = curl_init(); $options = array( diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php index baead525..d3352ea0 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php @@ -16,8 +16,11 @@ use Monolog\Logger; /** * Sends notifications through Slack's Slackbot * - * @author Haralan Dobrev - * @see https://slack.com/apps/A0F81R8ET-slackbot + * @author Haralan Dobrev + * @see https://slack.com/apps/A0F81R8ET-slackbot + * @deprecated According to Slack the API used on this handler it is deprecated. + * Therefore this handler will be removed on 2.x + * Slack suggests to use webhooks instead. Please contact slack for more information. */ class SlackbotHandler extends AbstractProcessingHandler { @@ -48,6 +51,7 @@ class SlackbotHandler extends AbstractProcessingHandler */ public function __construct($slackTeam, $token, $channel, $level = Logger::CRITICAL, $bubble = true) { + @trigger_error('SlackbotHandler is deprecated and will be removed on 2.x', E_USER_DEPRECATED); parent::__construct($level, $bubble); $this->slackTeam = $slackTeam; diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php index 7a61bf4e..db50d97f 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php @@ -27,15 +27,16 @@ class SocketHandler extends AbstractProcessingHandler private $timeout = 0; private $writingTimeout = 10; private $lastSentBytes = null; + private $chunkSize = null; private $persistent = false; private $errno; private $errstr; private $lastWritingAt; /** - * @param string $connectionString Socket connection string - * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param string $connectionString Socket connection string + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true) { @@ -87,7 +88,7 @@ class SocketHandler extends AbstractProcessingHandler */ public function setPersistent($persistent) { - $this->persistent = (boolean) $persistent; + $this->persistent = (bool) $persistent; } /** @@ -127,6 +128,16 @@ class SocketHandler extends AbstractProcessingHandler $this->writingTimeout = (float) $seconds; } + /** + * Set chunk size. Only has effect during connection in the writing cycle. + * + * @param float $bytes + */ + public function setChunkSize($bytes) + { + $this->chunkSize = $bytes; + } + /** * Get current connection string * @@ -177,6 +188,16 @@ class SocketHandler extends AbstractProcessingHandler return $this->writingTimeout; } + /** + * Get current chunk size + * + * @return float + */ + public function getChunkSize() + { + return $this->chunkSize; + } + /** * Check to see if the socket is currently available. * @@ -219,6 +240,16 @@ class SocketHandler extends AbstractProcessingHandler return stream_set_timeout($this->resource, $seconds, $microseconds); } + /** + * Wrapper to allow mocking + * + * @see http://php.net/manual/en/function.stream-set-chunk-size.php + */ + protected function streamSetChunkSize() + { + return stream_set_chunk_size($this->resource, $this->chunkSize); + } + /** * Wrapper to allow mocking */ @@ -268,6 +299,7 @@ class SocketHandler extends AbstractProcessingHandler { $this->createSocketResource(); $this->setSocketTimeout(); + $this->setStreamChunkSize(); } private function createSocketResource() @@ -290,6 +322,13 @@ class SocketHandler extends AbstractProcessingHandler } } + private function setStreamChunkSize() + { + if ($this->chunkSize && !$this->streamSetChunkSize()) { + throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()"); + } + } + private function writeToSocket($data) { $length = strlen($data); diff --git a/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php index 09a15738..27d90e06 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php @@ -32,9 +32,9 @@ class StreamHandler extends AbstractProcessingHandler /** * @param resource|string $stream * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) - * @param Boolean $useLocking Try to lock log file before doing any writes + * @param bool $useLocking Try to lock log file before doing any writes * * @throws \Exception If a missing directory is not buildable * @throws \InvalidArgumentException If stream is not a resource or string @@ -63,6 +63,7 @@ class StreamHandler extends AbstractProcessingHandler fclose($this->stream); } $this->stream = null; + $this->dirCreated = null; } /** @@ -167,7 +168,7 @@ class StreamHandler extends AbstractProcessingHandler set_error_handler(array($this, 'customErrorHandler')); $status = mkdir($dir, 0777, true); restore_error_handler(); - if (false === $status) { + if (false === $status && !is_dir($dir)) { throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir)); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php index 72f44a53..ac7b16ff 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Swift; @@ -29,7 +30,7 @@ class SwiftMailerHandler extends MailHandler * @param \Swift_Mailer $mailer The mailer to use * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true) { @@ -47,6 +48,17 @@ class SwiftMailerHandler extends MailHandler $this->mailer->send($this->buildMessage($content, $records)); } + /** + * Gets the formatter for the Swift_Message subject. + * + * @param string $format The format of the subject + * @return FormatterInterface + */ + protected function getSubjectFormatter($format) + { + return new LineFormatter($format); + } + /** * Creates instance of Swift_Message to be sent * @@ -69,7 +81,7 @@ class SwiftMailerHandler extends MailHandler } if ($records) { - $subjectFormatter = new LineFormatter($message->getSubject()); + $subjectFormatter = $this->getSubjectFormatter($message->getSubject()); $message->setSubject($subjectFormatter->format($this->getHighestRecord($records))); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php index 376bc3b2..f770c802 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php @@ -32,11 +32,11 @@ class SyslogHandler extends AbstractSyslogHandler protected $logopts; /** - * @param string $ident - * @param mixed $facility - * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID + * @param string $ident + * @param mixed $facility + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID */ public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID) { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php index 4718711b..4dfd5f5e 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php @@ -18,25 +18,37 @@ use Monolog\Handler\SyslogUdp\UdpSocket; * A Handler for logging to a remote syslogd server. * * @author Jesper Skovgaard Nielsen + * @author Dominik Kukacka */ class SyslogUdpHandler extends AbstractSyslogHandler { + const RFC3164 = 0; + const RFC5424 = 1; + + private $dateFormats = array( + self::RFC3164 => 'M d H:i:s', + self::RFC5424 => \DateTime::RFC3339, + ); + protected $socket; protected $ident; + protected $rfc; /** - * @param string $host - * @param int $port - * @param mixed $facility - * @param int $level The minimum logging level at which this handler will be triggered - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param string $ident Program name or tag for each log message. + * @param string $host + * @param int $port + * @param mixed $facility + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param string $ident Program name or tag for each log message. + * @param int $rfc RFC to format the message for. */ - public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php') + public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php', $rfc = self::RFC5424) { parent::__construct($facility, $level, $bubble); $this->ident = $ident; + $this->rfc = $rfc; $this->socket = new UdpSocket($host, $port ?: 514); } @@ -67,7 +79,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler } /** - * Make common syslog header (see rfc5424) + * Make common syslog header (see rfc5424 or rfc3164) */ protected function makeCommonSyslogHeader($severity) { @@ -81,16 +93,25 @@ class SyslogUdpHandler extends AbstractSyslogHandler $hostname = '-'; } - return "<$priority>1 " . - $this->getDateTime() . " " . - $hostname . " " . - $this->ident . " " . - $pid . " - - "; + $date = $this->getDateTime(); + + if ($this->rfc === self::RFC3164) { + return "<$priority>" . + $date . " " . + $hostname . " " . + $this->ident . "[" . $pid . "]: "; + } else { + return "<$priority>1 " . + $date . " " . + $hostname . " " . + $this->ident . " " . + $pid . " - - "; + } } protected function getDateTime() { - return date(\DateTime::RFC3339); + return date($this->dateFormats[$this->rfc]); } /** diff --git a/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php index e39cfc66..478db0ac 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php @@ -67,6 +67,7 @@ class TestHandler extends AbstractProcessingHandler { protected $records = array(); protected $recordsByLevel = array(); + private $skipReset = false; public function getRecords() { @@ -79,19 +80,41 @@ class TestHandler extends AbstractProcessingHandler $this->recordsByLevel = array(); } + public function reset() + { + if (!$this->skipReset) { + $this->clear(); + } + } + + public function setSkipReset($skipReset) + { + $this->skipReset = $skipReset; + } + public function hasRecords($level) { return isset($this->recordsByLevel[$level]); } + /** + * @param string|array $record Either a message string or an array containing message and optionally context keys that will be checked against all records + * @param int $level Logger::LEVEL constant value + */ public function hasRecord($record, $level) { - if (is_array($record)) { - $record = $record['message']; + if (is_string($record)) { + $record = array('message' => $record); } return $this->hasRecordThatPasses(function ($rec) use ($record) { - return $rec['message'] === $record; + if ($rec['message'] !== $record['message']) { + return false; + } + if (isset($record['context']) && $rec['context'] !== $record['context']) { + return false; + } + return true; }, $level); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php index 2732ba3d..7d7622a3 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -48,6 +48,17 @@ class WhatFailureGroupHandler extends GroupHandler */ public function handleBatch(array $records) { + if ($this->processors) { + $processed = array(); + foreach ($records as $record) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + $processed[] = $record; + } + $records = $processed; + } + foreach ($this->handlers as $handler) { try { $handler->handleBatch($records); diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php index f22cf218..a20aeae0 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php @@ -17,6 +17,7 @@ use Monolog\Logger; * Handler sending logs to Zend Monitor * * @author Christian Bergau + * @author Jason Davis */ class ZendMonitorHandler extends AbstractProcessingHandler { @@ -25,16 +26,7 @@ class ZendMonitorHandler extends AbstractProcessingHandler * * @var array */ - protected $levelMap = array( - Logger::DEBUG => 1, - Logger::INFO => 2, - Logger::NOTICE => 3, - Logger::WARNING => 4, - Logger::ERROR => 5, - Logger::CRITICAL => 6, - Logger::ALERT => 7, - Logger::EMERGENCY => 0, - ); + protected $levelMap = array(); /** * Construct @@ -46,8 +38,21 @@ class ZendMonitorHandler extends AbstractProcessingHandler public function __construct($level = Logger::DEBUG, $bubble = true) { if (!function_exists('zend_monitor_custom_event')) { - throw new MissingExtensionException('You must have Zend Server installed in order to use this handler'); + throw new MissingExtensionException( + 'You must have Zend Server installed with Zend Monitor enabled in order to use this handler' + ); } + //zend monitor constants are not defined if zend monitor is not enabled. + $this->levelMap = array( + Logger::DEBUG => \ZEND_MONITOR_EVENT_SEVERITY_INFO, + Logger::INFO => \ZEND_MONITOR_EVENT_SEVERITY_INFO, + Logger::NOTICE => \ZEND_MONITOR_EVENT_SEVERITY_INFO, + Logger::WARNING => \ZEND_MONITOR_EVENT_SEVERITY_WARNING, + Logger::ERROR => \ZEND_MONITOR_EVENT_SEVERITY_ERROR, + Logger::CRITICAL => \ZEND_MONITOR_EVENT_SEVERITY_ERROR, + Logger::ALERT => \ZEND_MONITOR_EVENT_SEVERITY_ERROR, + Logger::EMERGENCY => \ZEND_MONITOR_EVENT_SEVERITY_ERROR, + ); parent::__construct($level, $bubble); } @@ -57,22 +62,23 @@ class ZendMonitorHandler extends AbstractProcessingHandler protected function write(array $record) { $this->writeZendMonitorCustomEvent( - $this->levelMap[$record['level']], + Logger::getLevelName($record['level']), $record['message'], - $record['formatted'] + $record['formatted'], + $this->levelMap[$record['level']] ); } /** - * Write a record to Zend Monitor - * - * @param int $level - * @param string $message - * @param array $formatted + * Write to Zend Monitor Events + * @param string $type Text displayed in "Class Name (custom)" field + * @param string $message Text displayed in "Error String" + * @param mixed $formatted Displayed in Custom Variables tab + * @param int $severity Set the event severity level (-1,0,1) */ - protected function writeZendMonitorCustomEvent($level, $message, $formatted) + protected function writeZendMonitorCustomEvent($type, $message, $formatted, $severity) { - zend_monitor_custom_event($level, $message, $formatted); + zend_monitor_custom_event($type, $message, $formatted, $severity); } /** diff --git a/vendor/monolog/monolog/src/Monolog/Logger.php b/vendor/monolog/monolog/src/Monolog/Logger.php index 49d00af1..e649af51 100644 --- a/vendor/monolog/monolog/src/Monolog/Logger.php +++ b/vendor/monolog/monolog/src/Monolog/Logger.php @@ -15,6 +15,7 @@ use Monolog\Handler\HandlerInterface; use Monolog\Handler\StreamHandler; use Psr\Log\LoggerInterface; use Psr\Log\InvalidArgumentException; +use Exception; /** * Monolog log channel @@ -24,7 +25,7 @@ use Psr\Log\InvalidArgumentException; * * @author Jordi Boggiano */ -class Logger implements LoggerInterface +class Logger implements LoggerInterface, ResettableInterface { /** * Detailed debug information @@ -133,6 +134,11 @@ class Logger implements LoggerInterface */ protected $microsecondTimestamps = true; + /** + * @var callable + */ + protected $exceptionHandler; + /** * @param string $name The logging channel * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc. @@ -141,7 +147,7 @@ class Logger implements LoggerInterface public function __construct($name, array $handlers = array(), array $processors = array()) { $this->name = $name; - $this->handlers = $handlers; + $this->setHandlers($handlers); $this->processors = $processors; } @@ -281,7 +287,7 @@ class Logger implements LoggerInterface * @param int $level The logging level * @param string $message The log message * @param array $context The log context - * @return Boolean Whether the record has been processed + * @return bool Whether the record has been processed */ public function addRecord($level, $message, array $context = array()) { @@ -329,27 +335,75 @@ class Logger implements LoggerInterface 'extra' => array(), ); - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } - - while ($handler = current($this->handlers)) { - if (true === $handler->handle($record)) { - break; + try { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); } - next($this->handlers); + while ($handler = current($this->handlers)) { + if (true === $handler->handle($record)) { + break; + } + + next($this->handlers); + } + } catch (Exception $e) { + $this->handleException($e, $record); } return true; } + /** + * Ends a log cycle and frees all resources used by handlers. + * + * Closing a Handler means flushing all buffers and freeing any open resources/handles. + * Handlers that have been closed should be able to accept log records again and re-open + * themselves on demand, but this may not always be possible depending on implementation. + * + * This is useful at the end of a request and will be called automatically on every handler + * when they get destructed. + */ + public function close() + { + foreach ($this->handlers as $handler) { + if (method_exists($handler, 'close')) { + $handler->close(); + } + } + } + + /** + * Ends a log cycle and resets all handlers and processors to their initial state. + * + * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal + * state, and getting it back to a state in which it can receive log records again. + * + * This is useful in case you want to avoid logs leaking between two requests or jobs when you + * have a long running process like a worker or an application server serving multiple requests + * in one process. + */ + public function reset() + { + foreach ($this->handlers as $handler) { + if ($handler instanceof ResettableInterface) { + $handler->reset(); + } + } + + foreach ($this->processors as $processor) { + if ($processor instanceof ResettableInterface) { + $processor->reset(); + } + } + } + /** * Adds a log record at the DEBUG level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addDebug($message, array $context = array()) { @@ -359,9 +413,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the INFO level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addInfo($message, array $context = array()) { @@ -371,9 +425,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the NOTICE level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addNotice($message, array $context = array()) { @@ -383,9 +437,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the WARNING level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addWarning($message, array $context = array()) { @@ -395,9 +449,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the ERROR level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addError($message, array $context = array()) { @@ -407,9 +461,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the CRITICAL level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addCritical($message, array $context = array()) { @@ -419,9 +473,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the ALERT level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addAlert($message, array $context = array()) { @@ -431,9 +485,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the EMERGENCY level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addEmergency($message, array $context = array()) { @@ -473,8 +527,13 @@ class Logger implements LoggerInterface */ public static function toMonologLevel($level) { - if (is_string($level) && defined(__CLASS__.'::'.strtoupper($level))) { - return constant(__CLASS__.'::'.strtoupper($level)); + if (is_string($level)) { + // Contains chars of all log levels and avoids using strtoupper() which may have + // strange results depending on locale (for example, "i" will become "İ") + $upper = strtr($level, 'abcdefgilmnortuwy', 'ABCDEFGILMNORTUWY'); + if (defined(__CLASS__.'::'.$upper)) { + return constant(__CLASS__ . '::' . $upper); + } } return $level; @@ -484,7 +543,7 @@ class Logger implements LoggerInterface * Checks whether the Logger has a handler that listens on the given level * * @param int $level - * @return Boolean + * @return bool */ public function isHandling($level) { @@ -501,15 +560,52 @@ class Logger implements LoggerInterface return false; } + /** + * Set a custom exception handler + * + * @param callable $callback + * @return $this + */ + public function setExceptionHandler($callback) + { + if (!is_callable($callback)) { + throw new \InvalidArgumentException('Exception handler must be valid callable (callback or object with an __invoke method), '.var_export($callback, true).' given'); + } + $this->exceptionHandler = $callback; + + return $this; + } + + /** + * @return callable + */ + public function getExceptionHandler() + { + return $this->exceptionHandler; + } + + /** + * Delegates exception management to the custom exception handler, + * or throws the exception if no custom handler is set. + */ + protected function handleException(Exception $e, array $record) + { + if (!$this->exceptionHandler) { + throw $e; + } + + call_user_func($this->exceptionHandler, $e, $record); + } + /** * Adds a log record at an arbitrary level. * * This method allows for compatibility with common interfaces. * * @param mixed $level The log level - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function log($level, $message, array $context = array()) { @@ -523,9 +619,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function debug($message, array $context = array()) { @@ -537,9 +633,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function info($message, array $context = array()) { @@ -551,9 +647,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function notice($message, array $context = array()) { @@ -565,9 +661,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function warn($message, array $context = array()) { @@ -579,9 +675,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function warning($message, array $context = array()) { @@ -593,9 +689,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function err($message, array $context = array()) { @@ -607,9 +703,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function error($message, array $context = array()) { @@ -621,9 +717,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function crit($message, array $context = array()) { @@ -635,9 +731,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function critical($message, array $context = array()) { @@ -649,9 +745,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function alert($message, array $context = array()) { @@ -663,9 +759,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function emerg($message, array $context = array()) { @@ -677,9 +773,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function emergency($message, array $context = array()) { diff --git a/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php index 1899400d..9fc3f50f 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php @@ -19,7 +19,7 @@ use Monolog\Logger; * @author Nick Otter * @author Jordi Boggiano */ -class GitProcessor +class GitProcessor implements ProcessorInterface { private $level; private static $cache; diff --git a/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php index 2c07caed..6ae192a2 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php @@ -24,7 +24,7 @@ use Monolog\Logger; * * @author Jordi Boggiano */ -class IntrospectionProcessor +class IntrospectionProcessor implements ProcessorInterface { private $level; diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php index 85f9dc5e..2a379a30 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php @@ -16,7 +16,7 @@ namespace Monolog\Processor; * * @author Rob Jensen */ -abstract class MemoryProcessor +abstract class MemoryProcessor implements ProcessorInterface { /** * @var bool If true, get the real size of memory allocated from system. Else, only the memory used by emalloc() is reported. @@ -34,8 +34,8 @@ abstract class MemoryProcessor */ public function __construct($realUsage = true, $useFormatting = true) { - $this->realUsage = (boolean) $realUsage; - $this->useFormatting = (boolean) $useFormatting; + $this->realUsage = (bool) $realUsage; + $this->useFormatting = (bool) $useFormatting; } /** diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php index 7c07a7e9..2f5b3265 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php @@ -18,7 +18,7 @@ use Monolog\Logger; * * @author Jonathan A. Schweder */ -class MercurialProcessor +class MercurialProcessor implements ProcessorInterface { private $level; private static $cache; diff --git a/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php index 9d3f5590..66b80fbb 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php @@ -16,7 +16,7 @@ namespace Monolog\Processor; * * @author Andreas Hörnicke */ -class ProcessIdProcessor +class ProcessIdProcessor implements ProcessorInterface { /** * @param array $record diff --git a/vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php b/vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php new file mode 100644 index 00000000..7e64d4df --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * An optional interface to allow labelling Monolog processors. + * + * @author Nicolas Grekas + */ +interface ProcessorInterface +{ + /** + * @return array The processed records + */ + public function __invoke(array $records); +} diff --git a/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php index c2686ce5..00885054 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\Utils; + /** * Processes a record's message according to PSR-3 rules * @@ -18,7 +20,7 @@ namespace Monolog\Processor; * * @author Jordi Boggiano */ -class PsrLogMessageProcessor +class PsrLogMessageProcessor implements ProcessorInterface { /** * @param array $record @@ -35,7 +37,7 @@ class PsrLogMessageProcessor if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) { $replacements['{'.$key.'}'] = $val; } elseif (is_object($val)) { - $replacements['{'.$key.'}'] = '[object '.get_class($val).']'; + $replacements['{'.$key.'}'] = '[object '.Utils::getClass($val).']'; } else { $replacements['{'.$key.'}'] = '['.gettype($val).']'; } diff --git a/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php index 7e2df2ac..615a4d99 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php @@ -16,7 +16,7 @@ namespace Monolog\Processor; * * @author Martijn Riemers */ -class TagProcessor +class TagProcessor implements ProcessorInterface { private $tags; diff --git a/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php index 812707cd..d1f708cf 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php @@ -11,12 +11,14 @@ namespace Monolog\Processor; +use Monolog\ResettableInterface; + /** * Adds a unique identifier into records * * @author Simon Mönch */ -class UidProcessor +class UidProcessor implements ProcessorInterface, ResettableInterface { private $uid; @@ -26,7 +28,8 @@ class UidProcessor throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32'); } - $this->uid = substr(hash('md5', uniqid('', true)), 0, $length); + + $this->uid = $this->generateUid($length); } public function __invoke(array $record) @@ -43,4 +46,14 @@ class UidProcessor { return $this->uid; } + + public function reset() + { + $this->uid = $this->generateUid(strlen($this->uid)); + } + + private function generateUid($length) + { + return substr(hash('md5', uniqid('', true)), 0, $length); + } } diff --git a/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php index ea1d8978..684188f6 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php @@ -16,7 +16,7 @@ namespace Monolog\Processor; * * @author Jordi Boggiano */ -class WebProcessor +class WebProcessor implements ProcessorInterface { /** * @var array|\ArrayAccess diff --git a/vendor/monolog/monolog/src/Monolog/ResettableInterface.php b/vendor/monolog/monolog/src/Monolog/ResettableInterface.php new file mode 100644 index 00000000..635bc77d --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/ResettableInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +/** + * Handler or Processor implementing this interface will be reset when Logger::reset() is called. + * + * Resetting ends a log cycle gets them back to their initial state. + * + * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal + * state, and getting it back to a state in which it can receive log records again. + * + * This is useful in case you want to avoid logs leaking between two requests or jobs when you + * have a long running process like a worker or an application server serving multiple requests + * in one process. + * + * @author Grégoire Pineau + */ +interface ResettableInterface +{ + public function reset(); +} diff --git a/vendor/monolog/monolog/src/Monolog/SignalHandler.php b/vendor/monolog/monolog/src/Monolog/SignalHandler.php new file mode 100644 index 00000000..d87018fe --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/SignalHandler.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use ReflectionExtension; + +/** + * Monolog POSIX signal handler + * + * @author Robert Gust-Bardon + */ +class SignalHandler +{ + private $logger; + + private $previousSignalHandler = array(); + private $signalLevelMap = array(); + private $signalRestartSyscalls = array(); + + public function __construct(LoggerInterface $logger) + { + $this->logger = $logger; + } + + public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, $callPrevious = true, $restartSyscalls = true, $async = true) + { + if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) { + return $this; + } + + if ($callPrevious) { + if (function_exists('pcntl_signal_get_handler')) { + $handler = pcntl_signal_get_handler($signo); + if ($handler === false) { + return $this; + } + $this->previousSignalHandler[$signo] = $handler; + } else { + $this->previousSignalHandler[$signo] = true; + } + } else { + unset($this->previousSignalHandler[$signo]); + } + $this->signalLevelMap[$signo] = $level; + $this->signalRestartSyscalls[$signo] = $restartSyscalls; + + if (function_exists('pcntl_async_signals') && $async !== null) { + pcntl_async_signals($async); + } + + pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); + + return $this; + } + + public function handleSignal($signo, array $siginfo = null) + { + static $signals = array(); + + if (!$signals && extension_loaded('pcntl')) { + $pcntl = new ReflectionExtension('pcntl'); + $constants = $pcntl->getConstants(); + if (!$constants) { + // HHVM 3.24.2 returns an empty array. + $constants = get_defined_constants(true); + $constants = $constants['Core']; + } + foreach ($constants as $name => $value) { + if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) { + $signals[$value] = $name; + } + } + unset($constants); + } + + $level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL; + $signal = isset($signals[$signo]) ? $signals[$signo] : $signo; + $context = isset($siginfo) ? $siginfo : array(); + $this->logger->log($level, sprintf('Program received signal %s', $signal), $context); + + if (!isset($this->previousSignalHandler[$signo])) { + return; + } + + if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) { + if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch') + && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) { + $restartSyscalls = isset($this->signalRestartSyscalls[$signo]) ? $this->signalRestartSyscalls[$signo] : true; + pcntl_signal($signo, SIG_DFL, $restartSyscalls); + pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset); + posix_kill(posix_getpid(), $signo); + pcntl_signal_dispatch(); + pcntl_sigprocmask(SIG_SETMASK, $oldset); + pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); + } + } elseif (is_callable($this->previousSignalHandler[$signo])) { + if (PHP_VERSION_ID >= 70100) { + $this->previousSignalHandler[$signo]($signo, $siginfo); + } else { + $this->previousSignalHandler[$signo]($signo); + } + } + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Utils.php b/vendor/monolog/monolog/src/Monolog/Utils.php new file mode 100644 index 00000000..180a159d --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Utils.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +class Utils +{ + /** + * @internal + */ + public static function getClass($object) + { + $class = \get_class($object); + + return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; + } + + /** + * Return the JSON representation of a value + * + * @param mixed $data + * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + * @param bool $ignoreErrors whether to ignore encoding errors or to throw on error, when ignored and the encoding fails, "null" is returned which is valid json for null + * @throws \RuntimeException if encoding fails and errors are not ignored + * @return string + */ + public static function jsonEncode($data, $encodeFlags = null, $ignoreErrors = false) + { + if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) { + $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; + } + + if ($ignoreErrors) { + $json = @json_encode($data, $encodeFlags); + if (false === $json) { + return 'null'; + } + + return $json; + } + + $json = json_encode($data, $encodeFlags); + if (false === $json) { + $json = self::handleJsonError(json_last_error(), $data); + } + + return $json; + } + + /** + * Handle a json_encode failure. + * + * If the failure is due to invalid string encoding, try to clean the + * input and encode again. If the second encoding attempt fails, the + * inital error is not encoding related or the input can't be cleaned then + * raise a descriptive exception. + * + * @param int $code return code of json_last_error function + * @param mixed $data data that was meant to be encoded + * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + * @throws \RuntimeException if failure can't be corrected + * @return string JSON encoded data after error correction + */ + public static function handleJsonError($code, $data, $encodeFlags = null) + { + if ($code !== JSON_ERROR_UTF8) { + self::throwEncodeError($code, $data); + } + + if (is_string($data)) { + self::detectAndCleanUtf8($data); + } elseif (is_array($data)) { + array_walk_recursive($data, array('Monolog\Utils', 'detectAndCleanUtf8')); + } else { + self::throwEncodeError($code, $data); + } + + if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) { + $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; + } + + $json = json_encode($data, $encodeFlags); + + if ($json === false) { + self::throwEncodeError(json_last_error(), $data); + } + + return $json; + } + + /** + * Throws an exception according to a given code with a customized message + * + * @param int $code return code of json_last_error function + * @param mixed $data data that was meant to be encoded + * @throws \RuntimeException + */ + private static function throwEncodeError($code, $data) + { + switch ($code) { + case JSON_ERROR_DEPTH: + $msg = 'Maximum stack depth exceeded'; + break; + case JSON_ERROR_STATE_MISMATCH: + $msg = 'Underflow or the modes mismatch'; + break; + case JSON_ERROR_CTRL_CHAR: + $msg = 'Unexpected control character found'; + break; + case JSON_ERROR_UTF8: + $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded'; + break; + default: + $msg = 'Unknown error'; + } + + throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true)); + } + + /** + * Detect invalid UTF-8 string characters and convert to valid UTF-8. + * + * Valid UTF-8 input will be left unmodified, but strings containing + * invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed + * original encoding of ISO-8859-15. This conversion may result in + * incorrect output if the actual encoding was not ISO-8859-15, but it + * will be clean UTF-8 output and will not rely on expensive and fragile + * detection algorithms. + * + * Function converts the input in place in the passed variable so that it + * can be used as a callback for array_walk_recursive. + * + * @param mixed &$data Input to check and convert if needed + * @private + */ + public static function detectAndCleanUtf8(&$data) + { + if (is_string($data) && !preg_match('//u', $data)) { + $data = preg_replace_callback( + '/[\x80-\xFF]+/', + function ($m) { return utf8_encode($m[0]); }, + $data + ); + $data = str_replace( + array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'), + array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'), + $data + ); + } + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php deleted file mode 100644 index a9a3f301..00000000 --- a/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog; - -use Monolog\Handler\TestHandler; - -class ErrorHandlerTest extends \PHPUnit_Framework_TestCase -{ - public function testHandleError() - { - $logger = new Logger('test', array($handler = new TestHandler)); - $errHandler = new ErrorHandler($logger); - - $errHandler->registerErrorHandler(array(E_USER_NOTICE => Logger::EMERGENCY), false); - trigger_error('Foo', E_USER_ERROR); - $this->assertCount(1, $handler->getRecords()); - $this->assertTrue($handler->hasErrorRecords()); - trigger_error('Foo', E_USER_NOTICE); - $this->assertCount(2, $handler->getRecords()); - $this->assertTrue($handler->hasEmergencyRecords()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php deleted file mode 100644 index 71c42046..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php +++ /dev/null @@ -1,158 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -use Monolog\Logger; - -class ChromePHPFormatterTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers Monolog\Formatter\ChromePHPFormatter::format - */ - public function testDefaultFormat() - { - $formatter = new ChromePHPFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('ip' => '127.0.0.1'), - 'message' => 'log', - ); - - $message = $formatter->format($record); - - $this->assertEquals( - array( - 'meh', - array( - 'message' => 'log', - 'context' => array('from' => 'logger'), - 'extra' => array('ip' => '127.0.0.1'), - ), - 'unknown', - 'error', - ), - $message - ); - } - - /** - * @covers Monolog\Formatter\ChromePHPFormatter::format - */ - public function testFormatWithFileAndLine() - { - $formatter = new ChromePHPFormatter(); - $record = array( - 'level' => Logger::CRITICAL, - 'level_name' => 'CRITICAL', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('ip' => '127.0.0.1', 'file' => 'test', 'line' => 14), - 'message' => 'log', - ); - - $message = $formatter->format($record); - - $this->assertEquals( - array( - 'meh', - array( - 'message' => 'log', - 'context' => array('from' => 'logger'), - 'extra' => array('ip' => '127.0.0.1'), - ), - 'test : 14', - 'error', - ), - $message - ); - } - - /** - * @covers Monolog\Formatter\ChromePHPFormatter::format - */ - public function testFormatWithoutContext() - { - $formatter = new ChromePHPFormatter(); - $record = array( - 'level' => Logger::DEBUG, - 'level_name' => 'DEBUG', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ); - - $message = $formatter->format($record); - - $this->assertEquals( - array( - 'meh', - 'log', - 'unknown', - 'log', - ), - $message - ); - } - - /** - * @covers Monolog\Formatter\ChromePHPFormatter::formatBatch - */ - public function testBatchFormatThrowException() - { - $formatter = new ChromePHPFormatter(); - $records = array( - array( - 'level' => Logger::INFO, - 'level_name' => 'INFO', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ), - array( - 'level' => Logger::WARNING, - 'level_name' => 'WARNING', - 'channel' => 'foo', - 'context' => array(), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log2', - ), - ); - - $this->assertEquals( - array( - array( - 'meh', - 'log', - 'unknown', - 'info', - ), - array( - 'foo', - 'log2', - 'unknown', - 'warn', - ), - ), - $formatter->formatBatch($records) - ); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php deleted file mode 100644 index 90cc48dd..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/ElasticaFormatterTest.php +++ /dev/null @@ -1,79 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -use Monolog\Logger; - -class ElasticaFormatterTest extends \PHPUnit_Framework_TestCase -{ - public function setUp() - { - if (!class_exists("Elastica\Document")) { - $this->markTestSkipped("ruflin/elastica not installed"); - } - } - - /** - * @covers Monolog\Formatter\ElasticaFormatter::__construct - * @covers Monolog\Formatter\ElasticaFormatter::format - * @covers Monolog\Formatter\ElasticaFormatter::getDocument - */ - public function testFormat() - { - // test log message - $msg = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ); - - // expected values - $expected = $msg; - $expected['datetime'] = '1970-01-01T00:00:00.000000+00:00'; - $expected['context'] = array( - 'class' => '[object] (stdClass: {})', - 'foo' => 7, - 0 => 'bar', - ); - - // format log message - $formatter = new ElasticaFormatter('my_index', 'doc_type'); - $doc = $formatter->format($msg); - $this->assertInstanceOf('Elastica\Document', $doc); - - // Document parameters - $params = $doc->getParams(); - $this->assertEquals('my_index', $params['_index']); - $this->assertEquals('doc_type', $params['_type']); - - // Document data values - $data = $doc->getData(); - foreach (array_keys($expected) as $key) { - $this->assertEquals($expected[$key], $data[$key]); - } - } - - /** - * @covers Monolog\Formatter\ElasticaFormatter::getIndex - * @covers Monolog\Formatter\ElasticaFormatter::getType - */ - public function testGetters() - { - $formatter = new ElasticaFormatter('my_index', 'doc_type'); - $this->assertEquals('my_index', $formatter->getIndex()); - $this->assertEquals('doc_type', $formatter->getType()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php deleted file mode 100644 index 1b2fd97a..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/FlowdockFormatterTest.php +++ /dev/null @@ -1,55 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -use Monolog\Logger; -use Monolog\TestCase; - -class FlowdockFormatterTest extends TestCase -{ - /** - * @covers Monolog\Formatter\FlowdockFormatter::format - */ - public function testFormat() - { - $formatter = new FlowdockFormatter('test_source', 'source@test.com'); - $record = $this->getRecord(); - - $expected = array( - 'source' => 'test_source', - 'from_address' => 'source@test.com', - 'subject' => 'in test_source: WARNING - test', - 'content' => 'test', - 'tags' => array('#logs', '#warning', '#test'), - 'project' => 'test_source', - ); - $formatted = $formatter->format($record); - - $this->assertEquals($expected, $formatted['flowdock']); - } - - /** - * @ covers Monolog\Formatter\FlowdockFormatter::formatBatch - */ - public function testFormatBatch() - { - $formatter = new FlowdockFormatter('test_source', 'source@test.com'); - $records = array( - $this->getRecord(Logger::WARNING), - $this->getRecord(Logger::DEBUG), - ); - $formatted = $formatter->formatBatch($records); - - $this->assertArrayHasKey('flowdock', $formatted[0]); - $this->assertArrayHasKey('flowdock', $formatted[1]); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/FluentdFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/FluentdFormatterTest.php deleted file mode 100644 index 622b2bae..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/FluentdFormatterTest.php +++ /dev/null @@ -1,62 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -use Monolog\Logger; -use Monolog\TestCase; - -class FluentdFormatterTest extends TestCase -{ - /** - * @covers Monolog\Formatter\FluentdFormatter::__construct - * @covers Monolog\Formatter\FluentdFormatter::isUsingLevelsInTag - */ - public function testConstruct() - { - $formatter = new FluentdFormatter(); - $this->assertEquals(false, $formatter->isUsingLevelsInTag()); - $formatter = new FluentdFormatter(false); - $this->assertEquals(false, $formatter->isUsingLevelsInTag()); - $formatter = new FluentdFormatter(true); - $this->assertEquals(true, $formatter->isUsingLevelsInTag()); - } - - /** - * @covers Monolog\Formatter\FluentdFormatter::format - */ - public function testFormat() - { - $record = $this->getRecord(Logger::WARNING); - $record['datetime'] = new \DateTime("@0"); - - $formatter = new FluentdFormatter(); - $this->assertEquals( - '["test",0,{"message":"test","extra":[],"level":300,"level_name":"WARNING"}]', - $formatter->format($record) - ); - } - - /** - * @covers Monolog\Formatter\FluentdFormatter::format - */ - public function testFormatWithTag() - { - $record = $this->getRecord(Logger::ERROR); - $record['datetime'] = new \DateTime("@0"); - - $formatter = new FluentdFormatter(true); - $this->assertEquals( - '["test.error",0,{"message":"test","extra":[]}]', - $formatter->format($record) - ); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php deleted file mode 100644 index 4a247616..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ /dev/null @@ -1,258 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -use Monolog\Logger; - -class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase -{ - public function setUp() - { - if (!class_exists('\Gelf\Message')) { - $this->markTestSkipped("graylog2/gelf-php or mlehner/gelf-php is not installed"); - } - } - - /** - * @covers Monolog\Formatter\GelfMessageFormatter::format - */ - public function testDefaultFormatter() - { - $formatter = new GelfMessageFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ); - - $message = $formatter->format($record); - - $this->assertInstanceOf('Gelf\Message', $message); - $this->assertEquals(0, $message->getTimestamp()); - $this->assertEquals('log', $message->getShortMessage()); - $this->assertEquals('meh', $message->getFacility()); - $this->assertEquals(null, $message->getLine()); - $this->assertEquals(null, $message->getFile()); - $this->assertEquals($this->isLegacy() ? 3 : 'error', $message->getLevel()); - $this->assertNotEmpty($message->getHost()); - - $formatter = new GelfMessageFormatter('mysystem'); - - $message = $formatter->format($record); - - $this->assertInstanceOf('Gelf\Message', $message); - $this->assertEquals('mysystem', $message->getHost()); - } - - /** - * @covers Monolog\Formatter\GelfMessageFormatter::format - */ - public function testFormatWithFileAndLine() - { - $formatter = new GelfMessageFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('file' => 'test', 'line' => 14), - 'message' => 'log', - ); - - $message = $formatter->format($record); - - $this->assertInstanceOf('Gelf\Message', $message); - $this->assertEquals('test', $message->getFile()); - $this->assertEquals(14, $message->getLine()); - } - - /** - * @covers Monolog\Formatter\GelfMessageFormatter::format - * @expectedException InvalidArgumentException - */ - public function testFormatInvalidFails() - { - $formatter = new GelfMessageFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - ); - - $formatter->format($record); - } - - /** - * @covers Monolog\Formatter\GelfMessageFormatter::format - */ - public function testFormatWithContext() - { - $formatter = new GelfMessageFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => 'pair'), - 'message' => 'log', - ); - - $message = $formatter->format($record); - - $this->assertInstanceOf('Gelf\Message', $message); - - $message_array = $message->toArray(); - - $this->assertArrayHasKey('_ctxt_from', $message_array); - $this->assertEquals('logger', $message_array['_ctxt_from']); - - // Test with extraPrefix - $formatter = new GelfMessageFormatter(null, null, 'CTX'); - $message = $formatter->format($record); - - $this->assertInstanceOf('Gelf\Message', $message); - - $message_array = $message->toArray(); - - $this->assertArrayHasKey('_CTXfrom', $message_array); - $this->assertEquals('logger', $message_array['_CTXfrom']); - } - - /** - * @covers Monolog\Formatter\GelfMessageFormatter::format - */ - public function testFormatWithContextContainingException() - { - $formatter = new GelfMessageFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger', 'exception' => array( - 'class' => '\Exception', - 'file' => '/some/file/in/dir.php:56', - 'trace' => array('/some/file/1.php:23', '/some/file/2.php:3'), - )), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ); - - $message = $formatter->format($record); - - $this->assertInstanceOf('Gelf\Message', $message); - - $this->assertEquals("/some/file/in/dir.php", $message->getFile()); - $this->assertEquals("56", $message->getLine()); - } - - /** - * @covers Monolog\Formatter\GelfMessageFormatter::format - */ - public function testFormatWithExtra() - { - $formatter = new GelfMessageFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => 'pair'), - 'message' => 'log', - ); - - $message = $formatter->format($record); - - $this->assertInstanceOf('Gelf\Message', $message); - - $message_array = $message->toArray(); - - $this->assertArrayHasKey('_key', $message_array); - $this->assertEquals('pair', $message_array['_key']); - - // Test with extraPrefix - $formatter = new GelfMessageFormatter(null, 'EXT'); - $message = $formatter->format($record); - - $this->assertInstanceOf('Gelf\Message', $message); - - $message_array = $message->toArray(); - - $this->assertArrayHasKey('_EXTkey', $message_array); - $this->assertEquals('pair', $message_array['_EXTkey']); - } - - public function testFormatWithLargeData() - { - $formatter = new GelfMessageFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('exception' => str_repeat(' ', 32767)), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => str_repeat(' ', 32767)), - 'message' => 'log' - ); - $message = $formatter->format($record); - $messageArray = $message->toArray(); - - // 200 for padding + metadata - $length = 200; - - foreach ($messageArray as $key => $value) { - if (!in_array($key, array('level', 'timestamp'))) { - $length += strlen($value); - } - } - - $this->assertLessThanOrEqual(65792, $length, 'The message length is no longer than the maximum allowed length'); - } - - public function testFormatWithUnlimitedLength() - { - $formatter = new GelfMessageFormatter('LONG_SYSTEM_NAME', null, 'ctxt_', PHP_INT_MAX); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('exception' => str_repeat(' ', 32767 * 2)), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => str_repeat(' ', 32767 * 2)), - 'message' => 'log' - ); - $message = $formatter->format($record); - $messageArray = $message->toArray(); - - // 200 for padding + metadata - $length = 200; - - foreach ($messageArray as $key => $value) { - if (!in_array($key, array('level', 'timestamp'))) { - $length += strlen($value); - } - } - - $this->assertGreaterThanOrEqual(131289, $length, 'The message should not be truncated'); - } - - private function isLegacy() - { - return interface_exists('\Gelf\IMessagePublisher'); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php deleted file mode 100644 index c9445f36..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php +++ /dev/null @@ -1,183 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -use Monolog\Logger; -use Monolog\TestCase; - -class JsonFormatterTest extends TestCase -{ - /** - * @covers Monolog\Formatter\JsonFormatter::__construct - * @covers Monolog\Formatter\JsonFormatter::getBatchMode - * @covers Monolog\Formatter\JsonFormatter::isAppendingNewlines - */ - public function testConstruct() - { - $formatter = new JsonFormatter(); - $this->assertEquals(JsonFormatter::BATCH_MODE_JSON, $formatter->getBatchMode()); - $this->assertEquals(true, $formatter->isAppendingNewlines()); - $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_NEWLINES, false); - $this->assertEquals(JsonFormatter::BATCH_MODE_NEWLINES, $formatter->getBatchMode()); - $this->assertEquals(false, $formatter->isAppendingNewlines()); - } - - /** - * @covers Monolog\Formatter\JsonFormatter::format - */ - public function testFormat() - { - $formatter = new JsonFormatter(); - $record = $this->getRecord(); - $this->assertEquals(json_encode($record)."\n", $formatter->format($record)); - - $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); - $record = $this->getRecord(); - $this->assertEquals(json_encode($record), $formatter->format($record)); - } - - /** - * @covers Monolog\Formatter\JsonFormatter::formatBatch - * @covers Monolog\Formatter\JsonFormatter::formatBatchJson - */ - public function testFormatBatch() - { - $formatter = new JsonFormatter(); - $records = array( - $this->getRecord(Logger::WARNING), - $this->getRecord(Logger::DEBUG), - ); - $this->assertEquals(json_encode($records), $formatter->formatBatch($records)); - } - - /** - * @covers Monolog\Formatter\JsonFormatter::formatBatch - * @covers Monolog\Formatter\JsonFormatter::formatBatchNewlines - */ - public function testFormatBatchNewlines() - { - $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_NEWLINES); - $records = $expected = array( - $this->getRecord(Logger::WARNING), - $this->getRecord(Logger::DEBUG), - ); - array_walk($expected, function (&$value, $key) { - $value = json_encode($value); - }); - $this->assertEquals(implode("\n", $expected), $formatter->formatBatch($records)); - } - - public function testDefFormatWithException() - { - $formatter = new JsonFormatter(); - $exception = new \RuntimeException('Foo'); - $formattedException = $this->formatException($exception); - - $message = $this->formatRecordWithExceptionInContext($formatter, $exception); - - $this->assertContextContainsFormattedException($formattedException, $message); - } - - public function testDefFormatWithPreviousException() - { - $formatter = new JsonFormatter(); - $exception = new \RuntimeException('Foo', 0, new \LogicException('Wut?')); - $formattedPrevException = $this->formatException($exception->getPrevious()); - $formattedException = $this->formatException($exception, $formattedPrevException); - - $message = $this->formatRecordWithExceptionInContext($formatter, $exception); - - $this->assertContextContainsFormattedException($formattedException, $message); - } - - public function testDefFormatWithThrowable() - { - if (!class_exists('Error') || !is_subclass_of('Error', 'Throwable')) { - $this->markTestSkipped('Requires PHP >=7'); - } - - $formatter = new JsonFormatter(); - $throwable = new \Error('Foo'); - $formattedThrowable = $this->formatException($throwable); - - $message = $this->formatRecordWithExceptionInContext($formatter, $throwable); - - $this->assertContextContainsFormattedException($formattedThrowable, $message); - } - - /** - * @param string $expected - * @param string $actual - * - * @internal param string $exception - */ - private function assertContextContainsFormattedException($expected, $actual) - { - $this->assertEquals( - '{"level_name":"CRITICAL","channel":"core","context":{"exception":'.$expected.'},"datetime":null,"extra":[],"message":"foobar"}'."\n", - $actual - ); - } - - /** - * @param JsonFormatter $formatter - * @param \Exception|\Throwable $exception - * - * @return string - */ - private function formatRecordWithExceptionInContext(JsonFormatter $formatter, $exception) - { - $message = $formatter->format(array( - 'level_name' => 'CRITICAL', - 'channel' => 'core', - 'context' => array('exception' => $exception), - 'datetime' => null, - 'extra' => array(), - 'message' => 'foobar', - )); - return $message; - } - - /** - * @param \Exception|\Throwable $exception - * - * @return string - */ - private function formatExceptionFilePathWithLine($exception) - { - $options = 0; - if (version_compare(PHP_VERSION, '5.4.0', '>=')) { - $options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; - } - $path = substr(json_encode($exception->getFile(), $options), 1, -1); - return $path . ':' . $exception->getLine(); - } - - /** - * @param \Exception|\Throwable $exception - * - * @param null|string $previous - * - * @return string - */ - private function formatException($exception, $previous = null) - { - $formattedException = - '{"class":"' . get_class($exception) . - '","message":"' . $exception->getMessage() . - '","code":' . $exception->getCode() . - ',"file":"' . $this->formatExceptionFilePathWithLine($exception) . - ($previous ? '","previous":' . $previous : '"') . - '}'; - return $formattedException; - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php deleted file mode 100644 index 310d93ca..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php +++ /dev/null @@ -1,222 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -/** - * @covers Monolog\Formatter\LineFormatter - */ -class LineFormatterTest extends \PHPUnit_Framework_TestCase -{ - public function testDefFormatWithString() - { - $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format(array( - 'level_name' => 'WARNING', - 'channel' => 'log', - 'context' => array(), - 'message' => 'foo', - 'datetime' => new \DateTime, - 'extra' => array(), - )); - $this->assertEquals('['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message); - } - - public function testDefFormatWithArrayContext() - { - $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format(array( - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'message' => 'foo', - 'datetime' => new \DateTime, - 'extra' => array(), - 'context' => array( - 'foo' => 'bar', - 'baz' => 'qux', - 'bool' => false, - 'null' => null, - ), - )); - $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foo {"foo":"bar","baz":"qux","bool":false,"null":null} []'."\n", $message); - } - - public function testDefFormatExtras() - { - $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format(array( - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime, - 'extra' => array('ip' => '127.0.0.1'), - 'message' => 'log', - )); - $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] {"ip":"127.0.0.1"}'."\n", $message); - } - - public function testFormatExtras() - { - $formatter = new LineFormatter("[%datetime%] %channel%.%level_name%: %message% %context% %extra.file% %extra%\n", 'Y-m-d'); - $message = $formatter->format(array( - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime, - 'extra' => array('ip' => '127.0.0.1', 'file' => 'test'), - 'message' => 'log', - )); - $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] test {"ip":"127.0.0.1"}'."\n", $message); - } - - public function testContextAndExtraOptionallyNotShownIfEmpty() - { - $formatter = new LineFormatter(null, 'Y-m-d', false, true); - $message = $formatter->format(array( - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime, - 'extra' => array(), - 'message' => 'log', - )); - $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log '."\n", $message); - } - - public function testContextAndExtraReplacement() - { - $formatter = new LineFormatter('%context.foo% => %extra.foo%'); - $message = $formatter->format(array( - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('foo' => 'bar'), - 'datetime' => new \DateTime, - 'extra' => array('foo' => 'xbar'), - 'message' => 'log', - )); - $this->assertEquals('bar => xbar', $message); - } - - public function testDefFormatWithObject() - { - $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format(array( - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime, - 'extra' => array('foo' => new TestFoo, 'bar' => new TestBar, 'baz' => array(), 'res' => fopen('php://memory', 'rb')), - 'message' => 'foobar', - )); - - $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foobar [] {"foo":"[object] (Monolog\\\\Formatter\\\\TestFoo: {\\"foo\\":\\"foo\\"})","bar":"[object] (Monolog\\\\Formatter\\\\TestBar: bar)","baz":[],"res":"[resource] (stream)"}'."\n", $message); - } - - public function testDefFormatWithException() - { - $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format(array( - 'level_name' => 'CRITICAL', - 'channel' => 'core', - 'context' => array('exception' => new \RuntimeException('Foo')), - 'datetime' => new \DateTime, - 'extra' => array(), - 'message' => 'foobar', - )); - - $path = str_replace('\\/', '/', json_encode(__FILE__)); - - $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__ - 8).')"} []'."\n", $message); - } - - public function testDefFormatWithPreviousException() - { - $formatter = new LineFormatter(null, 'Y-m-d'); - $previous = new \LogicException('Wut?'); - $message = $formatter->format(array( - 'level_name' => 'CRITICAL', - 'channel' => 'core', - 'context' => array('exception' => new \RuntimeException('Foo', 0, $previous)), - 'datetime' => new \DateTime, - 'extra' => array(), - 'message' => 'foobar', - )); - - $path = str_replace('\\/', '/', json_encode(__FILE__)); - - $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__ - 8).', LogicException(code: 0): Wut? at '.substr($path, 1, -1).':'.(__LINE__ - 12).')"} []'."\n", $message); - } - - public function testBatchFormat() - { - $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->formatBatch(array( - array( - 'level_name' => 'CRITICAL', - 'channel' => 'test', - 'message' => 'bar', - 'context' => array(), - 'datetime' => new \DateTime, - 'extra' => array(), - ), - array( - 'level_name' => 'WARNING', - 'channel' => 'log', - 'message' => 'foo', - 'context' => array(), - 'datetime' => new \DateTime, - 'extra' => array(), - ), - )); - $this->assertEquals('['.date('Y-m-d').'] test.CRITICAL: bar [] []'."\n".'['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message); - } - - public function testFormatShouldStripInlineLineBreaks() - { - $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format( - array( - 'message' => "foo\nbar", - 'context' => array(), - 'extra' => array(), - ) - ); - - $this->assertRegExp('/foo bar/', $message); - } - - public function testFormatShouldNotStripInlineLineBreaksWhenFlagIsSet() - { - $formatter = new LineFormatter(null, 'Y-m-d', true); - $message = $formatter->format( - array( - 'message' => "foo\nbar", - 'context' => array(), - 'extra' => array(), - ) - ); - - $this->assertRegExp('/foo\nbar/', $message); - } -} - -class TestFoo -{ - public $foo = 'foo'; -} - -class TestBar -{ - public function __toString() - { - return 'bar'; - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php deleted file mode 100644 index 6d59b3f3..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/LogglyFormatterTest.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -use Monolog\TestCase; - -class LogglyFormatterTest extends TestCase -{ - /** - * @covers Monolog\Formatter\LogglyFormatter::__construct - */ - public function testConstruct() - { - $formatter = new LogglyFormatter(); - $this->assertEquals(LogglyFormatter::BATCH_MODE_NEWLINES, $formatter->getBatchMode()); - $formatter = new LogglyFormatter(LogglyFormatter::BATCH_MODE_JSON); - $this->assertEquals(LogglyFormatter::BATCH_MODE_JSON, $formatter->getBatchMode()); - } - - /** - * @covers Monolog\Formatter\LogglyFormatter::format - */ - public function testFormat() - { - $formatter = new LogglyFormatter(); - $record = $this->getRecord(); - $formatted_decoded = json_decode($formatter->format($record), true); - $this->assertArrayHasKey("timestamp", $formatted_decoded); - $this->assertEquals(new \DateTime($formatted_decoded["timestamp"]), $record["datetime"]); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php deleted file mode 100644 index 9f6b1cc4..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php +++ /dev/null @@ -1,333 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -use Monolog\Logger; - -class LogstashFormatterTest extends \PHPUnit_Framework_TestCase -{ - public function tearDown() - { - \PHPUnit_Framework_Error_Warning::$enabled = true; - - return parent::tearDown(); - } - - /** - * @covers Monolog\Formatter\LogstashFormatter::format - */ - public function testDefaultFormatter() - { - $formatter = new LogstashFormatter('test', 'hostname'); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $this->assertEquals("1970-01-01T00:00:00.000000+00:00", $message['@timestamp']); - $this->assertEquals('log', $message['@message']); - $this->assertEquals('meh', $message['@fields']['channel']); - $this->assertContains('meh', $message['@tags']); - $this->assertEquals(Logger::ERROR, $message['@fields']['level']); - $this->assertEquals('test', $message['@type']); - $this->assertEquals('hostname', $message['@source']); - - $formatter = new LogstashFormatter('mysystem'); - - $message = json_decode($formatter->format($record), true); - - $this->assertEquals('mysystem', $message['@type']); - } - - /** - * @covers Monolog\Formatter\LogstashFormatter::format - */ - public function testFormatWithFileAndLine() - { - $formatter = new LogstashFormatter('test'); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('file' => 'test', 'line' => 14), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $this->assertEquals('test', $message['@fields']['file']); - $this->assertEquals(14, $message['@fields']['line']); - } - - /** - * @covers Monolog\Formatter\LogstashFormatter::format - */ - public function testFormatWithContext() - { - $formatter = new LogstashFormatter('test'); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => 'pair'), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $message_array = $message['@fields']; - - $this->assertArrayHasKey('ctxt_from', $message_array); - $this->assertEquals('logger', $message_array['ctxt_from']); - - // Test with extraPrefix - $formatter = new LogstashFormatter('test', null, null, 'CTX'); - $message = json_decode($formatter->format($record), true); - - $message_array = $message['@fields']; - - $this->assertArrayHasKey('CTXfrom', $message_array); - $this->assertEquals('logger', $message_array['CTXfrom']); - } - - /** - * @covers Monolog\Formatter\LogstashFormatter::format - */ - public function testFormatWithExtra() - { - $formatter = new LogstashFormatter('test'); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => 'pair'), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $message_array = $message['@fields']; - - $this->assertArrayHasKey('key', $message_array); - $this->assertEquals('pair', $message_array['key']); - - // Test with extraPrefix - $formatter = new LogstashFormatter('test', null, 'EXT'); - $message = json_decode($formatter->format($record), true); - - $message_array = $message['@fields']; - - $this->assertArrayHasKey('EXTkey', $message_array); - $this->assertEquals('pair', $message_array['EXTkey']); - } - - public function testFormatWithApplicationName() - { - $formatter = new LogstashFormatter('app', 'test'); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => 'pair'), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $this->assertArrayHasKey('@type', $message); - $this->assertEquals('app', $message['@type']); - } - - /** - * @covers Monolog\Formatter\LogstashFormatter::format - */ - public function testDefaultFormatterV1() - { - $formatter = new LogstashFormatter('test', 'hostname', null, 'ctxt_', LogstashFormatter::V1); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $this->assertEquals("1970-01-01T00:00:00.000000+00:00", $message['@timestamp']); - $this->assertEquals("1", $message['@version']); - $this->assertEquals('log', $message['message']); - $this->assertEquals('meh', $message['channel']); - $this->assertEquals('ERROR', $message['level']); - $this->assertEquals('test', $message['type']); - $this->assertEquals('hostname', $message['host']); - - $formatter = new LogstashFormatter('mysystem', null, null, 'ctxt_', LogstashFormatter::V1); - - $message = json_decode($formatter->format($record), true); - - $this->assertEquals('mysystem', $message['type']); - } - - /** - * @covers Monolog\Formatter\LogstashFormatter::format - */ - public function testFormatWithFileAndLineV1() - { - $formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('file' => 'test', 'line' => 14), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $this->assertEquals('test', $message['file']); - $this->assertEquals(14, $message['line']); - } - - /** - * @covers Monolog\Formatter\LogstashFormatter::format - */ - public function testFormatWithContextV1() - { - $formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => 'pair'), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $this->assertArrayHasKey('ctxt_from', $message); - $this->assertEquals('logger', $message['ctxt_from']); - - // Test with extraPrefix - $formatter = new LogstashFormatter('test', null, null, 'CTX', LogstashFormatter::V1); - $message = json_decode($formatter->format($record), true); - - $this->assertArrayHasKey('CTXfrom', $message); - $this->assertEquals('logger', $message['CTXfrom']); - } - - /** - * @covers Monolog\Formatter\LogstashFormatter::format - */ - public function testFormatWithExtraV1() - { - $formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => 'pair'), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $this->assertArrayHasKey('key', $message); - $this->assertEquals('pair', $message['key']); - - // Test with extraPrefix - $formatter = new LogstashFormatter('test', null, 'EXT', 'ctxt_', LogstashFormatter::V1); - $message = json_decode($formatter->format($record), true); - - $this->assertArrayHasKey('EXTkey', $message); - $this->assertEquals('pair', $message['EXTkey']); - } - - public function testFormatWithApplicationNameV1() - { - $formatter = new LogstashFormatter('app', 'test', null, 'ctxt_', LogstashFormatter::V1); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => 'pair'), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $this->assertArrayHasKey('type', $message); - $this->assertEquals('app', $message['type']); - } - - public function testFormatWithLatin9Data() - { - if (version_compare(PHP_VERSION, '5.5.0', '<')) { - // Ignore the warning that will be emitted by PHP <5.5.0 - \PHPUnit_Framework_Error_Warning::$enabled = false; - } - $formatter = new LogstashFormatter('test', 'hostname'); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => '¯\_(ツ)_/¯', - 'context' => array(), - 'datetime' => new \DateTime("@0"), - 'extra' => array( - 'user_agent' => "\xD6WN; FBCR/OrangeEspa\xF1a; Vers\xE3o/4.0; F\xE4rist", - ), - 'message' => 'log', - ); - - $message = json_decode($formatter->format($record), true); - - $this->assertEquals("1970-01-01T00:00:00.000000+00:00", $message['@timestamp']); - $this->assertEquals('log', $message['@message']); - $this->assertEquals('¯\_(ツ)_/¯', $message['@fields']['channel']); - $this->assertContains('¯\_(ツ)_/¯', $message['@tags']); - $this->assertEquals(Logger::ERROR, $message['@fields']['level']); - $this->assertEquals('test', $message['@type']); - $this->assertEquals('hostname', $message['@source']); - if (version_compare(PHP_VERSION, '5.5.0', '>=')) { - $this->assertEquals('ÖWN; FBCR/OrangeEspaña; Versão/4.0; Färist', $message['@fields']['user_agent']); - } else { - // PHP <5.5 does not return false for an element encoding failure, - // instead it emits a warning (possibly) and nulls the value. - $this->assertEquals(null, $message['@fields']['user_agent']); - } - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/MongoDBFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/MongoDBFormatterTest.php deleted file mode 100644 index 52e699e0..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/MongoDBFormatterTest.php +++ /dev/null @@ -1,262 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -use Monolog\Logger; - -/** - * @author Florian Plattner - */ -class MongoDBFormatterTest extends \PHPUnit_Framework_TestCase -{ - public function setUp() - { - if (!class_exists('MongoDate')) { - $this->markTestSkipped('mongo extension not installed'); - } - } - - public function constructArgumentProvider() - { - return array( - array(1, true, 1, true), - array(0, false, 0, false), - ); - } - - /** - * @param $traceDepth - * @param $traceAsString - * @param $expectedTraceDepth - * @param $expectedTraceAsString - * - * @dataProvider constructArgumentProvider - */ - public function testConstruct($traceDepth, $traceAsString, $expectedTraceDepth, $expectedTraceAsString) - { - $formatter = new MongoDBFormatter($traceDepth, $traceAsString); - - $reflTrace = new \ReflectionProperty($formatter, 'exceptionTraceAsString'); - $reflTrace->setAccessible(true); - $this->assertEquals($expectedTraceAsString, $reflTrace->getValue($formatter)); - - $reflDepth = new\ReflectionProperty($formatter, 'maxNestingLevel'); - $reflDepth->setAccessible(true); - $this->assertEquals($expectedTraceDepth, $reflDepth->getValue($formatter)); - } - - public function testSimpleFormat() - { - $record = array( - 'message' => 'some log message', - 'context' => array(), - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTime('2014-02-01 00:00:00'), - 'extra' => array(), - ); - - $formatter = new MongoDBFormatter(); - $formattedRecord = $formatter->format($record); - - $this->assertCount(7, $formattedRecord); - $this->assertEquals('some log message', $formattedRecord['message']); - $this->assertEquals(array(), $formattedRecord['context']); - $this->assertEquals(Logger::WARNING, $formattedRecord['level']); - $this->assertEquals(Logger::getLevelName(Logger::WARNING), $formattedRecord['level_name']); - $this->assertEquals('test', $formattedRecord['channel']); - $this->assertInstanceOf('\MongoDate', $formattedRecord['datetime']); - $this->assertEquals('0.00000000 1391212800', $formattedRecord['datetime']->__toString()); - $this->assertEquals(array(), $formattedRecord['extra']); - } - - public function testRecursiveFormat() - { - $someObject = new \stdClass(); - $someObject->foo = 'something'; - $someObject->bar = 'stuff'; - - $record = array( - 'message' => 'some log message', - 'context' => array( - 'stuff' => new \DateTime('2014-02-01 02:31:33'), - 'some_object' => $someObject, - 'context_string' => 'some string', - 'context_int' => 123456, - 'except' => new \Exception('exception message', 987), - ), - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTime('2014-02-01 00:00:00'), - 'extra' => array(), - ); - - $formatter = new MongoDBFormatter(); - $formattedRecord = $formatter->format($record); - - $this->assertCount(5, $formattedRecord['context']); - $this->assertInstanceOf('\MongoDate', $formattedRecord['context']['stuff']); - $this->assertEquals('0.00000000 1391221893', $formattedRecord['context']['stuff']->__toString()); - $this->assertEquals( - array( - 'foo' => 'something', - 'bar' => 'stuff', - 'class' => 'stdClass', - ), - $formattedRecord['context']['some_object'] - ); - $this->assertEquals('some string', $formattedRecord['context']['context_string']); - $this->assertEquals(123456, $formattedRecord['context']['context_int']); - - $this->assertCount(5, $formattedRecord['context']['except']); - $this->assertEquals('exception message', $formattedRecord['context']['except']['message']); - $this->assertEquals(987, $formattedRecord['context']['except']['code']); - $this->assertInternalType('string', $formattedRecord['context']['except']['file']); - $this->assertInternalType('integer', $formattedRecord['context']['except']['code']); - $this->assertInternalType('string', $formattedRecord['context']['except']['trace']); - $this->assertEquals('Exception', $formattedRecord['context']['except']['class']); - } - - public function testFormatDepthArray() - { - $record = array( - 'message' => 'some log message', - 'context' => array( - 'nest2' => array( - 'property' => 'anything', - 'nest3' => array( - 'nest4' => 'value', - 'property' => 'nothing', - ), - ), - ), - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTime('2014-02-01 00:00:00'), - 'extra' => array(), - ); - - $formatter = new MongoDBFormatter(2); - $formattedResult = $formatter->format($record); - - $this->assertEquals( - array( - 'nest2' => array( - 'property' => 'anything', - 'nest3' => '[...]', - ), - ), - $formattedResult['context'] - ); - } - - public function testFormatDepthArrayInfiniteNesting() - { - $record = array( - 'message' => 'some log message', - 'context' => array( - 'nest2' => array( - 'property' => 'something', - 'nest3' => array( - 'property' => 'anything', - 'nest4' => array( - 'property' => 'nothing', - ), - ), - ), - ), - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTime('2014-02-01 00:00:00'), - 'extra' => array(), - ); - - $formatter = new MongoDBFormatter(0); - $formattedResult = $formatter->format($record); - - $this->assertEquals( - array( - 'nest2' => array( - 'property' => 'something', - 'nest3' => array( - 'property' => 'anything', - 'nest4' => array( - 'property' => 'nothing', - ), - ), - ), - ), - $formattedResult['context'] - ); - } - - public function testFormatDepthObjects() - { - $someObject = new \stdClass(); - $someObject->property = 'anything'; - $someObject->nest3 = new \stdClass(); - $someObject->nest3->property = 'nothing'; - $someObject->nest3->nest4 = 'invisible'; - - $record = array( - 'message' => 'some log message', - 'context' => array( - 'nest2' => $someObject, - ), - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTime('2014-02-01 00:00:00'), - 'extra' => array(), - ); - - $formatter = new MongoDBFormatter(2, true); - $formattedResult = $formatter->format($record); - - $this->assertEquals( - array( - 'nest2' => array( - 'property' => 'anything', - 'nest3' => '[...]', - 'class' => 'stdClass', - ), - ), - $formattedResult['context'] - ); - } - - public function testFormatDepthException() - { - $record = array( - 'message' => 'some log message', - 'context' => array( - 'nest2' => new \Exception('exception message', 987), - ), - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTime('2014-02-01 00:00:00'), - 'extra' => array(), - ); - - $formatter = new MongoDBFormatter(2, false); - $formattedRecord = $formatter->format($record); - - $this->assertEquals('exception message', $formattedRecord['context']['nest2']['message']); - $this->assertEquals(987, $formattedRecord['context']['nest2']['code']); - $this->assertEquals('[...]', $formattedRecord['context']['nest2']['trace']); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php deleted file mode 100644 index 57bcdf98..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ /dev/null @@ -1,423 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -/** - * @covers Monolog\Formatter\NormalizerFormatter - */ -class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase -{ - public function tearDown() - { - \PHPUnit_Framework_Error_Warning::$enabled = true; - - return parent::tearDown(); - } - - public function testFormat() - { - $formatter = new NormalizerFormatter('Y-m-d'); - $formatted = $formatter->format(array( - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'message' => 'foo', - 'datetime' => new \DateTime, - 'extra' => array('foo' => new TestFooNorm, 'bar' => new TestBarNorm, 'baz' => array(), 'res' => fopen('php://memory', 'rb')), - 'context' => array( - 'foo' => 'bar', - 'baz' => 'qux', - 'inf' => INF, - '-inf' => -INF, - 'nan' => acos(4), - ), - )); - - $this->assertEquals(array( - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'message' => 'foo', - 'datetime' => date('Y-m-d'), - 'extra' => array( - 'foo' => '[object] (Monolog\\Formatter\\TestFooNorm: {"foo":"foo"})', - 'bar' => '[object] (Monolog\\Formatter\\TestBarNorm: bar)', - 'baz' => array(), - 'res' => '[resource] (stream)', - ), - 'context' => array( - 'foo' => 'bar', - 'baz' => 'qux', - 'inf' => 'INF', - '-inf' => '-INF', - 'nan' => 'NaN', - ), - ), $formatted); - } - - public function testFormatExceptions() - { - $formatter = new NormalizerFormatter('Y-m-d'); - $e = new \LogicException('bar'); - $e2 = new \RuntimeException('foo', 0, $e); - $formatted = $formatter->format(array( - 'exception' => $e2, - )); - - $this->assertGreaterThan(5, count($formatted['exception']['trace'])); - $this->assertTrue(isset($formatted['exception']['previous'])); - unset($formatted['exception']['trace'], $formatted['exception']['previous']); - - $this->assertEquals(array( - 'exception' => array( - 'class' => get_class($e2), - 'message' => $e2->getMessage(), - 'code' => $e2->getCode(), - 'file' => $e2->getFile().':'.$e2->getLine(), - ), - ), $formatted); - } - - public function testFormatSoapFaultException() - { - if (!class_exists('SoapFault')) { - $this->markTestSkipped('Requires the soap extension'); - } - - $formatter = new NormalizerFormatter('Y-m-d'); - $e = new \SoapFault('foo', 'bar', 'hello', 'world'); - $formatted = $formatter->format(array( - 'exception' => $e, - )); - - unset($formatted['exception']['trace']); - - $this->assertEquals(array( - 'exception' => array( - 'class' => 'SoapFault', - 'message' => 'bar', - 'code' => 0, - 'file' => $e->getFile().':'.$e->getLine(), - 'faultcode' => 'foo', - 'faultactor' => 'hello', - 'detail' => 'world', - ), - ), $formatted); - } - - public function testFormatToStringExceptionHandle() - { - $formatter = new NormalizerFormatter('Y-m-d'); - $this->setExpectedException('RuntimeException', 'Could not convert to string'); - $formatter->format(array( - 'myObject' => new TestToStringError(), - )); - } - - public function testBatchFormat() - { - $formatter = new NormalizerFormatter('Y-m-d'); - $formatted = $formatter->formatBatch(array( - array( - 'level_name' => 'CRITICAL', - 'channel' => 'test', - 'message' => 'bar', - 'context' => array(), - 'datetime' => new \DateTime, - 'extra' => array(), - ), - array( - 'level_name' => 'WARNING', - 'channel' => 'log', - 'message' => 'foo', - 'context' => array(), - 'datetime' => new \DateTime, - 'extra' => array(), - ), - )); - $this->assertEquals(array( - array( - 'level_name' => 'CRITICAL', - 'channel' => 'test', - 'message' => 'bar', - 'context' => array(), - 'datetime' => date('Y-m-d'), - 'extra' => array(), - ), - array( - 'level_name' => 'WARNING', - 'channel' => 'log', - 'message' => 'foo', - 'context' => array(), - 'datetime' => date('Y-m-d'), - 'extra' => array(), - ), - ), $formatted); - } - - /** - * Test issue #137 - */ - public function testIgnoresRecursiveObjectReferences() - { - // set up the recursion - $foo = new \stdClass(); - $bar = new \stdClass(); - - $foo->bar = $bar; - $bar->foo = $foo; - - // set an error handler to assert that the error is not raised anymore - $that = $this; - set_error_handler(function ($level, $message, $file, $line, $context) use ($that) { - if (error_reporting() & $level) { - restore_error_handler(); - $that->fail("$message should not be raised"); - } - }); - - $formatter = new NormalizerFormatter(); - $reflMethod = new \ReflectionMethod($formatter, 'toJson'); - $reflMethod->setAccessible(true); - $res = $reflMethod->invoke($formatter, array($foo, $bar), true); - - restore_error_handler(); - - $this->assertEquals(@json_encode(array($foo, $bar)), $res); - } - - public function testIgnoresInvalidTypes() - { - // set up the recursion - $resource = fopen(__FILE__, 'r'); - - // set an error handler to assert that the error is not raised anymore - $that = $this; - set_error_handler(function ($level, $message, $file, $line, $context) use ($that) { - if (error_reporting() & $level) { - restore_error_handler(); - $that->fail("$message should not be raised"); - } - }); - - $formatter = new NormalizerFormatter(); - $reflMethod = new \ReflectionMethod($formatter, 'toJson'); - $reflMethod->setAccessible(true); - $res = $reflMethod->invoke($formatter, array($resource), true); - - restore_error_handler(); - - $this->assertEquals(@json_encode(array($resource)), $res); - } - - public function testNormalizeHandleLargeArrays() - { - $formatter = new NormalizerFormatter(); - $largeArray = range(1, 2000); - - $res = $formatter->format(array( - 'level_name' => 'CRITICAL', - 'channel' => 'test', - 'message' => 'bar', - 'context' => array($largeArray), - 'datetime' => new \DateTime, - 'extra' => array(), - )); - - $this->assertCount(1000, $res['context'][0]); - $this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']); - } - - /** - * @expectedException RuntimeException - */ - public function testThrowsOnInvalidEncoding() - { - if (version_compare(PHP_VERSION, '5.5.0', '<')) { - // Ignore the warning that will be emitted by PHP <5.5.0 - \PHPUnit_Framework_Error_Warning::$enabled = false; - } - $formatter = new NormalizerFormatter(); - $reflMethod = new \ReflectionMethod($formatter, 'toJson'); - $reflMethod->setAccessible(true); - - // send an invalid unicode sequence as a object that can't be cleaned - $record = new \stdClass; - $record->message = "\xB1\x31"; - $res = $reflMethod->invoke($formatter, $record); - if (PHP_VERSION_ID < 50500 && $res === '{"message":null}') { - throw new \RuntimeException('PHP 5.3/5.4 throw a warning and null the value instead of returning false entirely'); - } - } - - public function testConvertsInvalidEncodingAsLatin9() - { - if (version_compare(PHP_VERSION, '5.5.0', '<')) { - // Ignore the warning that will be emitted by PHP <5.5.0 - \PHPUnit_Framework_Error_Warning::$enabled = false; - } - $formatter = new NormalizerFormatter(); - $reflMethod = new \ReflectionMethod($formatter, 'toJson'); - $reflMethod->setAccessible(true); - - $res = $reflMethod->invoke($formatter, array('message' => "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE")); - - if (version_compare(PHP_VERSION, '5.5.0', '>=')) { - $this->assertSame('{"message":"€ŠšŽžŒœŸ"}', $res); - } else { - // PHP <5.5 does not return false for an element encoding failure, - // instead it emits a warning (possibly) and nulls the value. - $this->assertSame('{"message":null}', $res); - } - } - - /** - * @param mixed $in Input - * @param mixed $expect Expected output - * @covers Monolog\Formatter\NormalizerFormatter::detectAndCleanUtf8 - * @dataProvider providesDetectAndCleanUtf8 - */ - public function testDetectAndCleanUtf8($in, $expect) - { - $formatter = new NormalizerFormatter(); - $formatter->detectAndCleanUtf8($in); - $this->assertSame($expect, $in); - } - - public function providesDetectAndCleanUtf8() - { - $obj = new \stdClass; - - return array( - 'null' => array(null, null), - 'int' => array(123, 123), - 'float' => array(123.45, 123.45), - 'bool false' => array(false, false), - 'bool true' => array(true, true), - 'ascii string' => array('abcdef', 'abcdef'), - 'latin9 string' => array("\xB1\x31\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE\xFF", '±1€ŠšŽžŒœŸÿ'), - 'unicode string' => array('¤¦¨´¸¼½¾€ŠšŽžŒœŸ', '¤¦¨´¸¼½¾€ŠšŽžŒœŸ'), - 'empty array' => array(array(), array()), - 'array' => array(array('abcdef'), array('abcdef')), - 'object' => array($obj, $obj), - ); - } - - /** - * @param int $code - * @param string $msg - * @dataProvider providesHandleJsonErrorFailure - */ - public function testHandleJsonErrorFailure($code, $msg) - { - $formatter = new NormalizerFormatter(); - $reflMethod = new \ReflectionMethod($formatter, 'handleJsonError'); - $reflMethod->setAccessible(true); - - $this->setExpectedException('RuntimeException', $msg); - $reflMethod->invoke($formatter, $code, 'faked'); - } - - public function providesHandleJsonErrorFailure() - { - return array( - 'depth' => array(JSON_ERROR_DEPTH, 'Maximum stack depth exceeded'), - 'state' => array(JSON_ERROR_STATE_MISMATCH, 'Underflow or the modes mismatch'), - 'ctrl' => array(JSON_ERROR_CTRL_CHAR, 'Unexpected control character found'), - 'default' => array(-1, 'Unknown error'), - ); - } - - public function testExceptionTraceWithArgs() - { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported in HHVM since it detects errors differently'); - } - - // This happens i.e. in React promises or Guzzle streams where stream wrappers are registered - // and no file or line are included in the trace because it's treated as internal function - set_error_handler(function ($errno, $errstr, $errfile, $errline) { - throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); - }); - - try { - // This will contain $resource and $wrappedResource as arguments in the trace item - $resource = fopen('php://memory', 'rw+'); - fwrite($resource, 'test_resource'); - $wrappedResource = new TestFooNorm; - $wrappedResource->foo = $resource; - // Just do something stupid with a resource/wrapped resource as argument - array_keys($wrappedResource); - } catch (\Exception $e) { - restore_error_handler(); - } - - $formatter = new NormalizerFormatter(); - $record = array('context' => array('exception' => $e)); - $result = $formatter->format($record); - - $this->assertRegExp( - '%"resource":"\[resource\] \(stream\)"%', - $result['context']['exception']['trace'][0] - ); - - if (version_compare(PHP_VERSION, '5.5.0', '>=')) { - $pattern = '%"wrappedResource":"\[object\] \(Monolog\\\\\\\\Formatter\\\\\\\\TestFooNorm: \)"%'; - } else { - $pattern = '%\\\\"foo\\\\":null%'; - } - - // Tests that the wrapped resource is ignored while encoding, only works for PHP <= 5.4 - $this->assertRegExp( - $pattern, - $result['context']['exception']['trace'][0] - ); - } -} - -class TestFooNorm -{ - public $foo = 'foo'; -} - -class TestBarNorm -{ - public function __toString() - { - return 'bar'; - } -} - -class TestStreamFoo -{ - public $foo; - public $resource; - - public function __construct($resource) - { - $this->resource = $resource; - $this->foo = 'BAR'; - } - - public function __toString() - { - fseek($this->resource, 0); - - return $this->foo . ' - ' . (string) stream_get_contents($this->resource); - } -} - -class TestToStringError -{ - public function __toString() - { - throw new \RuntimeException('Could not convert to string'); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php deleted file mode 100644 index b1c8fd49..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/ScalarFormatterTest.php +++ /dev/null @@ -1,110 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -class ScalarFormatterTest extends \PHPUnit_Framework_TestCase -{ - private $formatter; - - public function setUp() - { - $this->formatter = new ScalarFormatter(); - } - - public function buildTrace(\Exception $e) - { - $data = array(); - $trace = $e->getTrace(); - foreach ($trace as $frame) { - if (isset($frame['file'])) { - $data[] = $frame['file'].':'.$frame['line']; - } else { - $data[] = json_encode($frame); - } - } - - return $data; - } - - public function encodeJson($data) - { - if (version_compare(PHP_VERSION, '5.4.0', '>=')) { - return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); - } - - return json_encode($data); - } - - public function testFormat() - { - $exception = new \Exception('foo'); - $formatted = $this->formatter->format(array( - 'foo' => 'string', - 'bar' => 1, - 'baz' => false, - 'bam' => array(1, 2, 3), - 'bat' => array('foo' => 'bar'), - 'bap' => \DateTime::createFromFormat(\DateTime::ISO8601, '1970-01-01T00:00:00+0000'), - 'ban' => $exception, - )); - - $this->assertSame(array( - 'foo' => 'string', - 'bar' => 1, - 'baz' => false, - 'bam' => $this->encodeJson(array(1, 2, 3)), - 'bat' => $this->encodeJson(array('foo' => 'bar')), - 'bap' => '1970-01-01 00:00:00', - 'ban' => $this->encodeJson(array( - 'class' => get_class($exception), - 'message' => $exception->getMessage(), - 'code' => $exception->getCode(), - 'file' => $exception->getFile() . ':' . $exception->getLine(), - 'trace' => $this->buildTrace($exception), - )), - ), $formatted); - } - - public function testFormatWithErrorContext() - { - $context = array('file' => 'foo', 'line' => 1); - $formatted = $this->formatter->format(array( - 'context' => $context, - )); - - $this->assertSame(array( - 'context' => $this->encodeJson($context), - ), $formatted); - } - - public function testFormatWithExceptionContext() - { - $exception = new \Exception('foo'); - $formatted = $this->formatter->format(array( - 'context' => array( - 'exception' => $exception, - ), - )); - - $this->assertSame(array( - 'context' => $this->encodeJson(array( - 'exception' => array( - 'class' => get_class($exception), - 'message' => $exception->getMessage(), - 'code' => $exception->getCode(), - 'file' => $exception->getFile() . ':' . $exception->getLine(), - 'trace' => $this->buildTrace($exception), - ), - )), - ), $formatted); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php deleted file mode 100644 index 52f15a36..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php +++ /dev/null @@ -1,142 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Formatter; - -use Monolog\Logger; - -class WildfireFormatterTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers Monolog\Formatter\WildfireFormatter::format - */ - public function testDefaultFormat() - { - $wildfire = new WildfireFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('ip' => '127.0.0.1'), - 'message' => 'log', - ); - - $message = $wildfire->format($record); - - $this->assertEquals( - '125|[{"Type":"ERROR","File":"","Line":"","Label":"meh"},' - .'{"message":"log","context":{"from":"logger"},"extra":{"ip":"127.0.0.1"}}]|', - $message - ); - } - - /** - * @covers Monolog\Formatter\WildfireFormatter::format - */ - public function testFormatWithFileAndLine() - { - $wildfire = new WildfireFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('from' => 'logger'), - 'datetime' => new \DateTime("@0"), - 'extra' => array('ip' => '127.0.0.1', 'file' => 'test', 'line' => 14), - 'message' => 'log', - ); - - $message = $wildfire->format($record); - - $this->assertEquals( - '129|[{"Type":"ERROR","File":"test","Line":14,"Label":"meh"},' - .'{"message":"log","context":{"from":"logger"},"extra":{"ip":"127.0.0.1"}}]|', - $message - ); - } - - /** - * @covers Monolog\Formatter\WildfireFormatter::format - */ - public function testFormatWithoutContext() - { - $wildfire = new WildfireFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ); - - $message = $wildfire->format($record); - - $this->assertEquals( - '58|[{"Type":"ERROR","File":"","Line":"","Label":"meh"},"log"]|', - $message - ); - } - - /** - * @covers Monolog\Formatter\WildfireFormatter::formatBatch - * @expectedException BadMethodCallException - */ - public function testBatchFormatThrowException() - { - $wildfire = new WildfireFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array(), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ); - - $wildfire->formatBatch(array($record)); - } - - /** - * @covers Monolog\Formatter\WildfireFormatter::format - */ - public function testTableFormat() - { - $wildfire = new WildfireFormatter(); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'table-channel', - 'context' => array( - WildfireFormatter::TABLE => array( - array('col1', 'col2', 'col3'), - array('val1', 'val2', 'val3'), - array('foo1', 'foo2', 'foo3'), - array('bar1', 'bar2', 'bar3'), - ), - ), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'table-message', - ); - - $message = $wildfire->format($record); - - $this->assertEquals( - '171|[{"Type":"TABLE","File":"","Line":"","Label":"table-channel: table-message"},[["col1","col2","col3"],["val1","val2","val3"],["foo1","foo2","foo3"],["bar1","bar2","bar3"]]]|', - $message - ); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php deleted file mode 100644 index 568eb9da..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php +++ /dev/null @@ -1,115 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; -use Monolog\Formatter\LineFormatter; -use Monolog\Processor\WebProcessor; - -class AbstractHandlerTest extends TestCase -{ - /** - * @covers Monolog\Handler\AbstractHandler::__construct - * @covers Monolog\Handler\AbstractHandler::getLevel - * @covers Monolog\Handler\AbstractHandler::setLevel - * @covers Monolog\Handler\AbstractHandler::getBubble - * @covers Monolog\Handler\AbstractHandler::setBubble - * @covers Monolog\Handler\AbstractHandler::getFormatter - * @covers Monolog\Handler\AbstractHandler::setFormatter - */ - public function testConstructAndGetSet() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array(Logger::WARNING, false)); - $this->assertEquals(Logger::WARNING, $handler->getLevel()); - $this->assertEquals(false, $handler->getBubble()); - - $handler->setLevel(Logger::ERROR); - $handler->setBubble(true); - $handler->setFormatter($formatter = new LineFormatter); - $this->assertEquals(Logger::ERROR, $handler->getLevel()); - $this->assertEquals(true, $handler->getBubble()); - $this->assertSame($formatter, $handler->getFormatter()); - } - - /** - * @covers Monolog\Handler\AbstractHandler::handleBatch - */ - public function testHandleBatch() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler'); - $handler->expects($this->exactly(2)) - ->method('handle'); - $handler->handleBatch(array($this->getRecord(), $this->getRecord())); - } - - /** - * @covers Monolog\Handler\AbstractHandler::isHandling - */ - public function testIsHandling() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array(Logger::WARNING, false)); - $this->assertTrue($handler->isHandling($this->getRecord())); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); - } - - /** - * @covers Monolog\Handler\AbstractHandler::__construct - */ - public function testHandlesPsrStyleLevels() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array('warning', false)); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); - $handler->setLevel('debug'); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::DEBUG))); - } - - /** - * @covers Monolog\Handler\AbstractHandler::getFormatter - * @covers Monolog\Handler\AbstractHandler::getDefaultFormatter - */ - public function testGetFormatterInitializesDefault() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler'); - $this->assertInstanceOf('Monolog\Formatter\LineFormatter', $handler->getFormatter()); - } - - /** - * @covers Monolog\Handler\AbstractHandler::pushProcessor - * @covers Monolog\Handler\AbstractHandler::popProcessor - * @expectedException LogicException - */ - public function testPushPopProcessor() - { - $logger = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler'); - $processor1 = new WebProcessor; - $processor2 = new WebProcessor; - - $logger->pushProcessor($processor1); - $logger->pushProcessor($processor2); - - $this->assertEquals($processor2, $logger->popProcessor()); - $this->assertEquals($processor1, $logger->popProcessor()); - $logger->popProcessor(); - } - - /** - * @covers Monolog\Handler\AbstractHandler::pushProcessor - * @expectedException InvalidArgumentException - */ - public function testPushProcessorWithNonCallable() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler'); - - $handler->pushProcessor(new \stdClass()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php deleted file mode 100644 index 24d4f63c..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php +++ /dev/null @@ -1,80 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; -use Monolog\Processor\WebProcessor; - -class AbstractProcessingHandlerTest extends TestCase -{ - /** - * @covers Monolog\Handler\AbstractProcessingHandler::handle - */ - public function testHandleLowerLevelMessage() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::WARNING, true)); - $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); - } - - /** - * @covers Monolog\Handler\AbstractProcessingHandler::handle - */ - public function testHandleBubbling() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::DEBUG, true)); - $this->assertFalse($handler->handle($this->getRecord())); - } - - /** - * @covers Monolog\Handler\AbstractProcessingHandler::handle - */ - public function testHandleNotBubbling() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::DEBUG, false)); - $this->assertTrue($handler->handle($this->getRecord())); - } - - /** - * @covers Monolog\Handler\AbstractProcessingHandler::handle - */ - public function testHandleIsFalseWhenNotHandled() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::WARNING, false)); - $this->assertTrue($handler->handle($this->getRecord())); - $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); - } - - /** - * @covers Monolog\Handler\AbstractProcessingHandler::processRecord - */ - public function testProcessRecord() - { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler'); - $handler->pushProcessor(new WebProcessor(array( - 'REQUEST_URI' => '', - 'REQUEST_METHOD' => '', - 'REMOTE_ADDR' => '', - 'SERVER_NAME' => '', - 'UNIQUE_ID' => '', - ))); - $handledRecord = null; - $handler->expects($this->once()) - ->method('write') - ->will($this->returnCallback(function ($record) use (&$handledRecord) { - $handledRecord = $record; - })) - ; - $handler->handle($this->getRecord()); - $this->assertEquals(6, count($handledRecord['extra'])); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php deleted file mode 100644 index 8e0e7237..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php +++ /dev/null @@ -1,136 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; -use PhpAmqpLib\Message\AMQPMessage; -use PhpAmqpLib\Connection\AMQPConnection; - -/** - * @covers Monolog\Handler\RotatingFileHandler - */ -class AmqpHandlerTest extends TestCase -{ - public function testHandleAmqpExt() - { - if (!class_exists('AMQPConnection') || !class_exists('AMQPExchange')) { - $this->markTestSkipped("amqp-php not installed"); - } - - if (!class_exists('AMQPChannel')) { - $this->markTestSkipped("Please update AMQP to version >= 1.0"); - } - - $messages = array(); - - $exchange = $this->getMock('AMQPExchange', array('publish', 'setName'), array(), '', false); - $exchange->expects($this->once()) - ->method('setName') - ->with('log') - ; - $exchange->expects($this->any()) - ->method('publish') - ->will($this->returnCallback(function ($message, $routing_key, $flags = 0, $attributes = array()) use (&$messages) { - $messages[] = array($message, $routing_key, $flags, $attributes); - })) - ; - - $handler = new AmqpHandler($exchange, 'log'); - - $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); - - $expected = array( - array( - 'message' => 'test', - 'context' => array( - 'data' => array(), - 'foo' => 34, - ), - 'level' => 300, - 'level_name' => 'WARNING', - 'channel' => 'test', - 'extra' => array(), - ), - 'warn.test', - 0, - array( - 'delivery_mode' => 2, - 'content_type' => 'application/json', - ), - ); - - $handler->handle($record); - - $this->assertCount(1, $messages); - $messages[0][0] = json_decode($messages[0][0], true); - unset($messages[0][0]['datetime']); - $this->assertEquals($expected, $messages[0]); - } - - public function testHandlePhpAmqpLib() - { - if (!class_exists('PhpAmqpLib\Connection\AMQPConnection')) { - $this->markTestSkipped("php-amqplib not installed"); - } - - $messages = array(); - - $exchange = $this->getMock('PhpAmqpLib\Channel\AMQPChannel', array('basic_publish', '__destruct'), array(), '', false); - - $exchange->expects($this->any()) - ->method('basic_publish') - ->will($this->returnCallback(function (AMQPMessage $msg, $exchange = "", $routing_key = "", $mandatory = false, $immediate = false, $ticket = null) use (&$messages) { - $messages[] = array($msg, $exchange, $routing_key, $mandatory, $immediate, $ticket); - })) - ; - - $handler = new AmqpHandler($exchange, 'log'); - - $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); - - $expected = array( - array( - 'message' => 'test', - 'context' => array( - 'data' => array(), - 'foo' => 34, - ), - 'level' => 300, - 'level_name' => 'WARNING', - 'channel' => 'test', - 'extra' => array(), - ), - 'log', - 'warn.test', - false, - false, - null, - array( - 'delivery_mode' => 2, - 'content_type' => 'application/json', - ), - ); - - $handler->handle($record); - - $this->assertCount(1, $messages); - - /* @var $msg AMQPMessage */ - $msg = $messages[0][0]; - $messages[0][0] = json_decode($msg->body, true); - $messages[0][] = $msg->get_properties(); - unset($messages[0][0]['datetime']); - - $this->assertEquals($expected, $messages[0]); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php deleted file mode 100644 index ffb1d746..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/BrowserConsoleHandlerTest.php +++ /dev/null @@ -1,130 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @covers Monolog\Handler\BrowserConsoleHandlerTest - */ -class BrowserConsoleHandlerTest extends TestCase -{ - protected function setUp() - { - BrowserConsoleHandler::reset(); - } - - protected function generateScript() - { - $reflMethod = new \ReflectionMethod('Monolog\Handler\BrowserConsoleHandler', 'generateScript'); - $reflMethod->setAccessible(true); - - return $reflMethod->invoke(null); - } - - public function testStyling() - { - $handler = new BrowserConsoleHandler(); - $handler->setFormatter($this->getIdentityFormatter()); - - $handler->handle($this->getRecord(Logger::DEBUG, 'foo[[bar]]{color: red}')); - - $expected = <<assertEquals($expected, $this->generateScript()); - } - - public function testEscaping() - { - $handler = new BrowserConsoleHandler(); - $handler->setFormatter($this->getIdentityFormatter()); - - $handler->handle($this->getRecord(Logger::DEBUG, "[foo] [[\"bar\n[baz]\"]]{color: red}")); - - $expected = <<assertEquals($expected, $this->generateScript()); - } - - public function testAutolabel() - { - $handler = new BrowserConsoleHandler(); - $handler->setFormatter($this->getIdentityFormatter()); - - $handler->handle($this->getRecord(Logger::DEBUG, '[[foo]]{macro: autolabel}')); - $handler->handle($this->getRecord(Logger::DEBUG, '[[bar]]{macro: autolabel}')); - $handler->handle($this->getRecord(Logger::DEBUG, '[[foo]]{macro: autolabel}')); - - $expected = <<assertEquals($expected, $this->generateScript()); - } - - public function testContext() - { - $handler = new BrowserConsoleHandler(); - $handler->setFormatter($this->getIdentityFormatter()); - - $handler->handle($this->getRecord(Logger::DEBUG, 'test', array('foo' => 'bar'))); - - $expected = <<assertEquals($expected, $this->generateScript()); - } - - public function testConcurrentHandlers() - { - $handler1 = new BrowserConsoleHandler(); - $handler1->setFormatter($this->getIdentityFormatter()); - - $handler2 = new BrowserConsoleHandler(); - $handler2->setFormatter($this->getIdentityFormatter()); - - $handler1->handle($this->getRecord(Logger::DEBUG, 'test1')); - $handler2->handle($this->getRecord(Logger::DEBUG, 'test2')); - $handler1->handle($this->getRecord(Logger::DEBUG, 'test3')); - $handler2->handle($this->getRecord(Logger::DEBUG, 'test4')); - - $expected = <<assertEquals($expected, $this->generateScript()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php deleted file mode 100644 index da8b3c39..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php +++ /dev/null @@ -1,158 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -class BufferHandlerTest extends TestCase -{ - private $shutdownCheckHandler; - - /** - * @covers Monolog\Handler\BufferHandler::__construct - * @covers Monolog\Handler\BufferHandler::handle - * @covers Monolog\Handler\BufferHandler::close - */ - public function testHandleBuffers() - { - $test = new TestHandler(); - $handler = new BufferHandler($test); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $this->assertFalse($test->hasDebugRecords()); - $this->assertFalse($test->hasInfoRecords()); - $handler->close(); - $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); - } - - /** - * @covers Monolog\Handler\BufferHandler::close - * @covers Monolog\Handler\BufferHandler::flush - */ - public function testPropagatesRecordsAtEndOfRequest() - { - $test = new TestHandler(); - $handler = new BufferHandler($test); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $this->shutdownCheckHandler = $test; - register_shutdown_function(array($this, 'checkPropagation')); - } - - public function checkPropagation() - { - if (!$this->shutdownCheckHandler->hasWarningRecords() || !$this->shutdownCheckHandler->hasDebugRecords()) { - echo '!!! BufferHandlerTest::testPropagatesRecordsAtEndOfRequest failed to verify that the messages have been propagated' . PHP_EOL; - exit(1); - } - } - - /** - * @covers Monolog\Handler\BufferHandler::handle - */ - public function testHandleBufferLimit() - { - $test = new TestHandler(); - $handler = new BufferHandler($test, 2); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->close(); - $this->assertTrue($test->hasWarningRecords()); - $this->assertTrue($test->hasInfoRecords()); - $this->assertFalse($test->hasDebugRecords()); - } - - /** - * @covers Monolog\Handler\BufferHandler::handle - */ - public function testHandleBufferLimitWithFlushOnOverflow() - { - $test = new TestHandler(); - $handler = new BufferHandler($test, 3, Logger::DEBUG, true, true); - - // send two records - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $this->assertFalse($test->hasDebugRecords()); - $this->assertCount(0, $test->getRecords()); - - // overflow - $handler->handle($this->getRecord(Logger::INFO)); - $this->assertTrue($test->hasDebugRecords()); - $this->assertCount(3, $test->getRecords()); - - // should buffer again - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertCount(3, $test->getRecords()); - - $handler->close(); - $this->assertCount(5, $test->getRecords()); - $this->assertTrue($test->hasWarningRecords()); - $this->assertTrue($test->hasInfoRecords()); - } - - /** - * @covers Monolog\Handler\BufferHandler::handle - */ - public function testHandleLevel() - { - $test = new TestHandler(); - $handler = new BufferHandler($test, 0, Logger::INFO); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->close(); - $this->assertTrue($test->hasWarningRecords()); - $this->assertTrue($test->hasInfoRecords()); - $this->assertFalse($test->hasDebugRecords()); - } - - /** - * @covers Monolog\Handler\BufferHandler::flush - */ - public function testFlush() - { - $test = new TestHandler(); - $handler = new BufferHandler($test, 0); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->flush(); - $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue($test->hasDebugRecords()); - $this->assertFalse($test->hasWarningRecords()); - } - - /** - * @covers Monolog\Handler\BufferHandler::handle - */ - public function testHandleUsesProcessors() - { - $test = new TestHandler(); - $handler = new BufferHandler($test); - $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; - - return $record; - }); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->flush(); - $this->assertTrue($test->hasWarningRecords()); - $records = $test->getRecords(); - $this->assertTrue($records[0]['extra']['foo']); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php deleted file mode 100644 index 0449f8b1..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ /dev/null @@ -1,156 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @covers Monolog\Handler\ChromePHPHandler - */ -class ChromePHPHandlerTest extends TestCase -{ - protected function setUp() - { - TestChromePHPHandler::reset(); - $_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; Chrome/1.0'; - } - - /** - * @dataProvider agentsProvider - */ - public function testHeaders($agent) - { - $_SERVER['HTTP_USER_AGENT'] = $agent; - - $handler = new TestChromePHPHandler(); - $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); - - $expected = array( - 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array( - 'version' => ChromePHPHandler::VERSION, - 'columns' => array('label', 'log', 'backtrace', 'type'), - 'rows' => array( - 'test', - 'test', - ), - 'request_uri' => '', - )))), - ); - - $this->assertEquals($expected, $handler->getHeaders()); - } - - public static function agentsProvider() - { - return array( - array('Monolog Test; Chrome/1.0'), - array('Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0'), - array('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/56.0.2924.76 Chrome/56.0.2924.76 Safari/537.36'), - array('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome Safari/537.36'), - ); - } - - public function testHeadersOverflow() - { - $handler = new TestChromePHPHandler(); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 150 * 1024))); - - // overflow chrome headers limit - $handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 100 * 1024))); - - $expected = array( - 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array( - 'version' => ChromePHPHandler::VERSION, - 'columns' => array('label', 'log', 'backtrace', 'type'), - 'rows' => array( - array( - 'test', - 'test', - 'unknown', - 'log', - ), - array( - 'test', - str_repeat('a', 150 * 1024), - 'unknown', - 'warn', - ), - array( - 'monolog', - 'Incomplete logs, chrome header size limit reached', - 'unknown', - 'warn', - ), - ), - 'request_uri' => '', - )))), - ); - - $this->assertEquals($expected, $handler->getHeaders()); - } - - public function testConcurrentHandlers() - { - $handler = new TestChromePHPHandler(); - $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); - - $handler2 = new TestChromePHPHandler(); - $handler2->setFormatter($this->getIdentityFormatter()); - $handler2->handle($this->getRecord(Logger::DEBUG)); - $handler2->handle($this->getRecord(Logger::WARNING)); - - $expected = array( - 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array( - 'version' => ChromePHPHandler::VERSION, - 'columns' => array('label', 'log', 'backtrace', 'type'), - 'rows' => array( - 'test', - 'test', - 'test', - 'test', - ), - 'request_uri' => '', - )))), - ); - - $this->assertEquals($expected, $handler2->getHeaders()); - } -} - -class TestChromePHPHandler extends ChromePHPHandler -{ - protected $headers = array(); - - public static function reset() - { - self::$initialized = false; - self::$overflowed = false; - self::$sendHeaders = true; - self::$json['rows'] = array(); - } - - protected function sendHeader($header, $content) - { - $this->headers[$header] = $content; - } - - public function getHeaders() - { - return $this->headers; - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php deleted file mode 100644 index 9fc4b388..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -class CouchDBHandlerTest extends TestCase -{ - public function testHandle() - { - $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); - - $handler = new CouchDBHandler(); - - try { - $handler->handle($record); - } catch (\RuntimeException $e) { - $this->markTestSkipped('Could not connect to couchdb server on http://localhost:5984'); - } - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/DeduplicationHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/DeduplicationHandlerTest.php deleted file mode 100644 index e2aff868..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/DeduplicationHandlerTest.php +++ /dev/null @@ -1,165 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -class DeduplicationHandlerTest extends TestCase -{ - /** - * @covers Monolog\Handler\DeduplicationHandler::flush - */ - public function testFlushPassthruIfAllRecordsUnderTrigger() - { - $test = new TestHandler(); - @unlink(sys_get_temp_dir().'/monolog_dedup.log'); - $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); - - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - - $handler->flush(); - - $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue($test->hasDebugRecords()); - $this->assertFalse($test->hasWarningRecords()); - } - - /** - * @covers Monolog\Handler\DeduplicationHandler::flush - * @covers Monolog\Handler\DeduplicationHandler::appendRecord - */ - public function testFlushPassthruIfEmptyLog() - { - $test = new TestHandler(); - @unlink(sys_get_temp_dir().'/monolog_dedup.log'); - $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); - - $handler->handle($this->getRecord(Logger::ERROR, 'Foo:bar')); - $handler->handle($this->getRecord(Logger::CRITICAL, "Foo\nbar")); - - $handler->flush(); - - $this->assertTrue($test->hasErrorRecords()); - $this->assertTrue($test->hasCriticalRecords()); - $this->assertFalse($test->hasWarningRecords()); - } - - /** - * @covers Monolog\Handler\DeduplicationHandler::flush - * @covers Monolog\Handler\DeduplicationHandler::appendRecord - * @covers Monolog\Handler\DeduplicationHandler::isDuplicate - * @depends testFlushPassthruIfEmptyLog - */ - public function testFlushSkipsIfLogExists() - { - $test = new TestHandler(); - $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); - - $handler->handle($this->getRecord(Logger::ERROR, 'Foo:bar')); - $handler->handle($this->getRecord(Logger::CRITICAL, "Foo\nbar")); - - $handler->flush(); - - $this->assertFalse($test->hasErrorRecords()); - $this->assertFalse($test->hasCriticalRecords()); - $this->assertFalse($test->hasWarningRecords()); - } - - /** - * @covers Monolog\Handler\DeduplicationHandler::flush - * @covers Monolog\Handler\DeduplicationHandler::appendRecord - * @covers Monolog\Handler\DeduplicationHandler::isDuplicate - * @depends testFlushPassthruIfEmptyLog - */ - public function testFlushPassthruIfLogTooOld() - { - $test = new TestHandler(); - $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); - - $record = $this->getRecord(Logger::ERROR); - $record['datetime']->modify('+62seconds'); - $handler->handle($record); - $record = $this->getRecord(Logger::CRITICAL); - $record['datetime']->modify('+62seconds'); - $handler->handle($record); - - $handler->flush(); - - $this->assertTrue($test->hasErrorRecords()); - $this->assertTrue($test->hasCriticalRecords()); - $this->assertFalse($test->hasWarningRecords()); - } - - /** - * @covers Monolog\Handler\DeduplicationHandler::flush - * @covers Monolog\Handler\DeduplicationHandler::appendRecord - * @covers Monolog\Handler\DeduplicationHandler::isDuplicate - * @covers Monolog\Handler\DeduplicationHandler::collectLogs - */ - public function testGcOldLogs() - { - $test = new TestHandler(); - @unlink(sys_get_temp_dir().'/monolog_dedup.log'); - $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); - - // handle two records from yesterday, and one recent - $record = $this->getRecord(Logger::ERROR); - $record['datetime']->modify('-1day -10seconds'); - $handler->handle($record); - $record2 = $this->getRecord(Logger::CRITICAL); - $record2['datetime']->modify('-1day -10seconds'); - $handler->handle($record2); - $record3 = $this->getRecord(Logger::CRITICAL); - $record3['datetime']->modify('-30seconds'); - $handler->handle($record3); - - // log is written as none of them are duplicate - $handler->flush(); - $this->assertSame( - $record['datetime']->getTimestamp() . ":ERROR:test\n" . - $record2['datetime']->getTimestamp() . ":CRITICAL:test\n" . - $record3['datetime']->getTimestamp() . ":CRITICAL:test\n", - file_get_contents(sys_get_temp_dir() . '/monolog_dedup.log') - ); - $this->assertTrue($test->hasErrorRecords()); - $this->assertTrue($test->hasCriticalRecords()); - $this->assertFalse($test->hasWarningRecords()); - - // clear test handler - $test->clear(); - $this->assertFalse($test->hasErrorRecords()); - $this->assertFalse($test->hasCriticalRecords()); - - // log new records, duplicate log gets GC'd at the end of this flush call - $handler->handle($record = $this->getRecord(Logger::ERROR)); - $handler->handle($record2 = $this->getRecord(Logger::CRITICAL)); - $handler->flush(); - - // log should now contain the new errors and the previous one that was recent enough - $this->assertSame( - $record3['datetime']->getTimestamp() . ":CRITICAL:test\n" . - $record['datetime']->getTimestamp() . ":ERROR:test\n" . - $record2['datetime']->getTimestamp() . ":CRITICAL:test\n", - file_get_contents(sys_get_temp_dir() . '/monolog_dedup.log') - ); - $this->assertTrue($test->hasErrorRecords()); - $this->assertTrue($test->hasCriticalRecords()); - $this->assertFalse($test->hasWarningRecords()); - } - - public static function tearDownAfterClass() - { - @unlink(sys_get_temp_dir().'/monolog_dedup.log'); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php deleted file mode 100644 index d67da90a..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php +++ /dev/null @@ -1,52 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -class DoctrineCouchDBHandlerTest extends TestCase -{ - protected function setup() - { - if (!class_exists('Doctrine\CouchDB\CouchDBClient')) { - $this->markTestSkipped('The "doctrine/couchdb" package is not installed'); - } - } - - public function testHandle() - { - $client = $this->getMockBuilder('Doctrine\\CouchDB\\CouchDBClient') - ->setMethods(array('postDocument')) - ->disableOriginalConstructor() - ->getMock(); - - $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); - - $expected = array( - 'message' => 'test', - 'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34), - 'level' => Logger::WARNING, - 'level_name' => 'WARNING', - 'channel' => 'test', - 'datetime' => $record['datetime']->format('Y-m-d H:i:s'), - 'extra' => array(), - ); - - $client->expects($this->once()) - ->method('postDocument') - ->with($expected); - - $handler = new DoctrineCouchDBHandler($client); - $handler->handle($record); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php deleted file mode 100644 index 2e6c348d..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ /dev/null @@ -1,82 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; - -class DynamoDbHandlerTest extends TestCase -{ - private $client; - - public function setUp() - { - if (!class_exists('Aws\DynamoDb\DynamoDbClient')) { - $this->markTestSkipped('aws/aws-sdk-php not installed'); - } - - $this->client = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient') - ->setMethods(array('formatAttributes', '__call')) - ->disableOriginalConstructor()->getMock(); - } - - public function testConstruct() - { - $this->assertInstanceOf('Monolog\Handler\DynamoDbHandler', new DynamoDbHandler($this->client, 'foo')); - } - - public function testInterface() - { - $this->assertInstanceOf('Monolog\Handler\HandlerInterface', new DynamoDbHandler($this->client, 'foo')); - } - - public function testGetFormatter() - { - $handler = new DynamoDbHandler($this->client, 'foo'); - $this->assertInstanceOf('Monolog\Formatter\ScalarFormatter', $handler->getFormatter()); - } - - public function testHandle() - { - $record = $this->getRecord(); - $formatter = $this->getMock('Monolog\Formatter\FormatterInterface'); - $formatted = array('foo' => 1, 'bar' => 2); - $handler = new DynamoDbHandler($this->client, 'foo'); - $handler->setFormatter($formatter); - - $isV3 = defined('Aws\Sdk::VERSION') && version_compare(\Aws\Sdk::VERSION, '3.0', '>='); - if ($isV3) { - $expFormatted = array('foo' => array('N' => 1), 'bar' => array('N' => 2)); - } else { - $expFormatted = $formatted; - } - - $formatter - ->expects($this->once()) - ->method('format') - ->with($record) - ->will($this->returnValue($formatted)); - $this->client - ->expects($isV3 ? $this->never() : $this->once()) - ->method('formatAttributes') - ->with($this->isType('array')) - ->will($this->returnValue($formatted)); - $this->client - ->expects($this->once()) - ->method('__call') - ->with('putItem', array(array( - 'TableName' => 'foo', - 'Item' => $expFormatted, - ))); - - $handler->handle($record); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php deleted file mode 100644 index 1687074b..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/ElasticSearchHandlerTest.php +++ /dev/null @@ -1,239 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Formatter\ElasticaFormatter; -use Monolog\Formatter\NormalizerFormatter; -use Monolog\TestCase; -use Monolog\Logger; -use Elastica\Client; -use Elastica\Request; -use Elastica\Response; - -class ElasticSearchHandlerTest extends TestCase -{ - /** - * @var Client mock - */ - protected $client; - - /** - * @var array Default handler options - */ - protected $options = array( - 'index' => 'my_index', - 'type' => 'doc_type', - ); - - public function setUp() - { - // Elastica lib required - if (!class_exists("Elastica\Client")) { - $this->markTestSkipped("ruflin/elastica not installed"); - } - - // base mock Elastica Client object - $this->client = $this->getMockBuilder('Elastica\Client') - ->setMethods(array('addDocuments')) - ->disableOriginalConstructor() - ->getMock(); - } - - /** - * @covers Monolog\Handler\ElasticSearchHandler::write - * @covers Monolog\Handler\ElasticSearchHandler::handleBatch - * @covers Monolog\Handler\ElasticSearchHandler::bulkSend - * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter - */ - public function testHandle() - { - // log message - $msg = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ); - - // format expected result - $formatter = new ElasticaFormatter($this->options['index'], $this->options['type']); - $expected = array($formatter->format($msg)); - - // setup ES client mock - $this->client->expects($this->any()) - ->method('addDocuments') - ->with($expected); - - // perform tests - $handler = new ElasticSearchHandler($this->client, $this->options); - $handler->handle($msg); - $handler->handleBatch(array($msg)); - } - - /** - * @covers Monolog\Handler\ElasticSearchHandler::setFormatter - */ - public function testSetFormatter() - { - $handler = new ElasticSearchHandler($this->client); - $formatter = new ElasticaFormatter('index_new', 'type_new'); - $handler->setFormatter($formatter); - $this->assertInstanceOf('Monolog\Formatter\ElasticaFormatter', $handler->getFormatter()); - $this->assertEquals('index_new', $handler->getFormatter()->getIndex()); - $this->assertEquals('type_new', $handler->getFormatter()->getType()); - } - - /** - * @covers Monolog\Handler\ElasticSearchHandler::setFormatter - * @expectedException InvalidArgumentException - * @expectedExceptionMessage ElasticSearchHandler is only compatible with ElasticaFormatter - */ - public function testSetFormatterInvalid() - { - $handler = new ElasticSearchHandler($this->client); - $formatter = new NormalizerFormatter(); - $handler->setFormatter($formatter); - } - - /** - * @covers Monolog\Handler\ElasticSearchHandler::__construct - * @covers Monolog\Handler\ElasticSearchHandler::getOptions - */ - public function testOptions() - { - $expected = array( - 'index' => $this->options['index'], - 'type' => $this->options['type'], - 'ignore_error' => false, - ); - $handler = new ElasticSearchHandler($this->client, $this->options); - $this->assertEquals($expected, $handler->getOptions()); - } - - /** - * @covers Monolog\Handler\ElasticSearchHandler::bulkSend - * @dataProvider providerTestConnectionErrors - */ - public function testConnectionErrors($ignore, $expectedError) - { - $clientOpts = array('host' => '127.0.0.1', 'port' => 1); - $client = new Client($clientOpts); - $handlerOpts = array('ignore_error' => $ignore); - $handler = new ElasticSearchHandler($client, $handlerOpts); - - if ($expectedError) { - $this->setExpectedException($expectedError[0], $expectedError[1]); - $handler->handle($this->getRecord()); - } else { - $this->assertFalse($handler->handle($this->getRecord())); - } - } - - /** - * @return array - */ - public function providerTestConnectionErrors() - { - return array( - array(false, array('RuntimeException', 'Error sending messages to Elasticsearch')), - array(true, false), - ); - } - - /** - * Integration test using localhost Elastic Search server - * - * @covers Monolog\Handler\ElasticSearchHandler::__construct - * @covers Monolog\Handler\ElasticSearchHandler::handleBatch - * @covers Monolog\Handler\ElasticSearchHandler::bulkSend - * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter - */ - public function testHandleIntegration() - { - $msg = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass), - 'datetime' => new \DateTime("@0"), - 'extra' => array(), - 'message' => 'log', - ); - - $expected = $msg; - $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); - $expected['context'] = array( - 'class' => '[object] (stdClass: {})', - 'foo' => 7, - 0 => 'bar', - ); - - $client = new Client(); - $handler = new ElasticSearchHandler($client, $this->options); - try { - $handler->handleBatch(array($msg)); - } catch (\RuntimeException $e) { - $this->markTestSkipped("Cannot connect to Elastic Search server on localhost"); - } - - // check document id from ES server response - $documentId = $this->getCreatedDocId($client->getLastResponse()); - $this->assertNotEmpty($documentId, 'No elastic document id received'); - - // retrieve document source from ES and validate - $document = $this->getDocSourceFromElastic( - $client, - $this->options['index'], - $this->options['type'], - $documentId - ); - $this->assertEquals($expected, $document); - - // remove test index from ES - $client->request("/{$this->options['index']}", Request::DELETE); - } - - /** - * Return last created document id from ES response - * @param Response $response Elastica Response object - * @return string|null - */ - protected function getCreatedDocId(Response $response) - { - $data = $response->getData(); - if (!empty($data['items'][0]['create']['_id'])) { - return $data['items'][0]['create']['_id']; - } - } - - /** - * Retrieve document by id from Elasticsearch - * @param Client $client Elastica client - * @param string $index - * @param string $type - * @param string $documentId - * @return array - */ - protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId) - { - $resp = $client->request("/{$index}/{$type}/{$documentId}", Request::GET); - $data = $resp->getData(); - if (!empty($data['_source'])) { - return $data['_source']; - } - - return array(); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php deleted file mode 100644 index 99785cbb..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/ErrorLogHandlerTest.php +++ /dev/null @@ -1,66 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; -use Monolog\Formatter\LineFormatter; - -function error_log() -{ - $GLOBALS['error_log'][] = func_get_args(); -} - -class ErrorLogHandlerTest extends TestCase -{ - protected function setUp() - { - $GLOBALS['error_log'] = array(); - } - - /** - * @covers Monolog\Handler\ErrorLogHandler::__construct - * @expectedException InvalidArgumentException - * @expectedExceptionMessage The given message type "42" is not supported - */ - public function testShouldNotAcceptAnInvalidTypeOnContructor() - { - new ErrorLogHandler(42); - } - - /** - * @covers Monolog\Handler\ErrorLogHandler::write - */ - public function testShouldLogMessagesUsingErrorLogFuncion() - { - $type = ErrorLogHandler::OPERATING_SYSTEM; - $handler = new ErrorLogHandler($type); - $handler->setFormatter(new LineFormatter('%channel%.%level_name%: %message% %context% %extra%', null, true)); - $handler->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); - - $this->assertSame("test.ERROR: Foo\nBar\r\n\r\nBaz [] []", $GLOBALS['error_log'][0][0]); - $this->assertSame($GLOBALS['error_log'][0][1], $type); - - $handler = new ErrorLogHandler($type, Logger::DEBUG, true, true); - $handler->setFormatter(new LineFormatter(null, null, true)); - $handler->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); - - $this->assertStringMatchesFormat('[%s] test.ERROR: Foo', $GLOBALS['error_log'][1][0]); - $this->assertSame($GLOBALS['error_log'][1][1], $type); - - $this->assertStringMatchesFormat('Bar', $GLOBALS['error_log'][2][0]); - $this->assertSame($GLOBALS['error_log'][2][1], $type); - - $this->assertStringMatchesFormat('Baz [] []', $GLOBALS['error_log'][3][0]); - $this->assertSame($GLOBALS['error_log'][3][1], $type); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php deleted file mode 100644 index 31b7686a..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/FilterHandlerTest.php +++ /dev/null @@ -1,170 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Logger; -use Monolog\TestCase; - -class FilterHandlerTest extends TestCase -{ - /** - * @covers Monolog\Handler\FilterHandler::isHandling - */ - public function testIsHandling() - { - $test = new TestHandler(); - $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::INFO))); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::NOTICE))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::WARNING))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::ERROR))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::CRITICAL))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::ALERT))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::EMERGENCY))); - } - - /** - * @covers Monolog\Handler\FilterHandler::handle - * @covers Monolog\Handler\FilterHandler::setAcceptedLevels - * @covers Monolog\Handler\FilterHandler::isHandling - */ - public function testHandleProcessOnlyNeededLevels() - { - $test = new TestHandler(); - $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE); - - $handler->handle($this->getRecord(Logger::DEBUG)); - $this->assertFalse($test->hasDebugRecords()); - - $handler->handle($this->getRecord(Logger::INFO)); - $this->assertTrue($test->hasInfoRecords()); - $handler->handle($this->getRecord(Logger::NOTICE)); - $this->assertTrue($test->hasNoticeRecords()); - - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertFalse($test->hasWarningRecords()); - $handler->handle($this->getRecord(Logger::ERROR)); - $this->assertFalse($test->hasErrorRecords()); - $handler->handle($this->getRecord(Logger::CRITICAL)); - $this->assertFalse($test->hasCriticalRecords()); - $handler->handle($this->getRecord(Logger::ALERT)); - $this->assertFalse($test->hasAlertRecords()); - $handler->handle($this->getRecord(Logger::EMERGENCY)); - $this->assertFalse($test->hasEmergencyRecords()); - - $test = new TestHandler(); - $handler = new FilterHandler($test, array(Logger::INFO, Logger::ERROR)); - - $handler->handle($this->getRecord(Logger::DEBUG)); - $this->assertFalse($test->hasDebugRecords()); - $handler->handle($this->getRecord(Logger::INFO)); - $this->assertTrue($test->hasInfoRecords()); - $handler->handle($this->getRecord(Logger::NOTICE)); - $this->assertFalse($test->hasNoticeRecords()); - $handler->handle($this->getRecord(Logger::ERROR)); - $this->assertTrue($test->hasErrorRecords()); - $handler->handle($this->getRecord(Logger::CRITICAL)); - $this->assertFalse($test->hasCriticalRecords()); - } - - /** - * @covers Monolog\Handler\FilterHandler::setAcceptedLevels - * @covers Monolog\Handler\FilterHandler::getAcceptedLevels - */ - public function testAcceptedLevelApi() - { - $test = new TestHandler(); - $handler = new FilterHandler($test); - - $levels = array(Logger::INFO, Logger::ERROR); - $handler->setAcceptedLevels($levels); - $this->assertSame($levels, $handler->getAcceptedLevels()); - - $handler->setAcceptedLevels(array('info', 'error')); - $this->assertSame($levels, $handler->getAcceptedLevels()); - - $levels = array(Logger::CRITICAL, Logger::ALERT, Logger::EMERGENCY); - $handler->setAcceptedLevels(Logger::CRITICAL, Logger::EMERGENCY); - $this->assertSame($levels, $handler->getAcceptedLevels()); - - $handler->setAcceptedLevels('critical', 'emergency'); - $this->assertSame($levels, $handler->getAcceptedLevels()); - } - - /** - * @covers Monolog\Handler\FilterHandler::handle - */ - public function testHandleUsesProcessors() - { - $test = new TestHandler(); - $handler = new FilterHandler($test, Logger::DEBUG, Logger::EMERGENCY); - $handler->pushProcessor( - function ($record) { - $record['extra']['foo'] = true; - - return $record; - } - ); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertTrue($test->hasWarningRecords()); - $records = $test->getRecords(); - $this->assertTrue($records[0]['extra']['foo']); - } - - /** - * @covers Monolog\Handler\FilterHandler::handle - */ - public function testHandleRespectsBubble() - { - $test = new TestHandler(); - - $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE, false); - $this->assertTrue($handler->handle($this->getRecord(Logger::INFO))); - $this->assertFalse($handler->handle($this->getRecord(Logger::WARNING))); - - $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE, true); - $this->assertFalse($handler->handle($this->getRecord(Logger::INFO))); - $this->assertFalse($handler->handle($this->getRecord(Logger::WARNING))); - } - - /** - * @covers Monolog\Handler\FilterHandler::handle - */ - public function testHandleWithCallback() - { - $test = new TestHandler(); - $handler = new FilterHandler( - function ($record, $handler) use ($test) { - return $test; - }, Logger::INFO, Logger::NOTICE, false - ); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $this->assertFalse($test->hasDebugRecords()); - $this->assertTrue($test->hasInfoRecords()); - } - - /** - * @covers Monolog\Handler\FilterHandler::handle - * @expectedException \RuntimeException - */ - public function testHandleWithBadCallbackThrowsException() - { - $handler = new FilterHandler( - function ($record, $handler) { - return 'foo'; - } - ); - $handler->handle($this->getRecord(Logger::WARNING)); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php deleted file mode 100644 index b92bf437..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php +++ /dev/null @@ -1,279 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; -use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; -use Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy; -use Psr\Log\LogLevel; - -class FingersCrossedHandlerTest extends TestCase -{ - /** - * @covers Monolog\Handler\FingersCrossedHandler::__construct - * @covers Monolog\Handler\FingersCrossedHandler::handle - * @covers Monolog\Handler\FingersCrossedHandler::activate - */ - public function testHandleBuffers() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $this->assertFalse($test->hasDebugRecords()); - $this->assertFalse($test->hasInfoRecords()); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->close(); - $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 3); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::handle - * @covers Monolog\Handler\FingersCrossedHandler::activate - */ - public function testHandleStopsBufferingAfterTrigger() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->close(); - $this->assertTrue($test->hasWarningRecords()); - $this->assertTrue($test->hasDebugRecords()); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::handle - * @covers Monolog\Handler\FingersCrossedHandler::activate - * @covers Monolog\Handler\FingersCrossedHandler::reset - */ - public function testHandleRestartBufferingAfterReset() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->reset(); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->close(); - $this->assertTrue($test->hasWarningRecords()); - $this->assertTrue($test->hasDebugRecords()); - $this->assertFalse($test->hasInfoRecords()); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::handle - * @covers Monolog\Handler\FingersCrossedHandler::activate - */ - public function testHandleRestartBufferingAfterBeingTriggeredWhenStopBufferingIsDisabled() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, Logger::WARNING, 0, false, false); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->close(); - $this->assertTrue($test->hasWarningRecords()); - $this->assertTrue($test->hasDebugRecords()); - $this->assertFalse($test->hasInfoRecords()); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::handle - * @covers Monolog\Handler\FingersCrossedHandler::activate - */ - public function testHandleBufferLimit() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, Logger::WARNING, 2); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertTrue($test->hasWarningRecords()); - $this->assertTrue($test->hasInfoRecords()); - $this->assertFalse($test->hasDebugRecords()); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::handle - * @covers Monolog\Handler\FingersCrossedHandler::activate - */ - public function testHandleWithCallback() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler(function ($record, $handler) use ($test) { - return $test; - }); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $this->assertFalse($test->hasDebugRecords()); - $this->assertFalse($test->hasInfoRecords()); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 3); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::handle - * @covers Monolog\Handler\FingersCrossedHandler::activate - * @expectedException RuntimeException - */ - public function testHandleWithBadCallbackThrowsException() - { - $handler = new FingersCrossedHandler(function ($record, $handler) { - return 'foo'; - }); - $handler->handle($this->getRecord(Logger::WARNING)); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::isHandling - */ - public function testIsHandlingAlways() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, Logger::ERROR); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::DEBUG))); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::__construct - * @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::__construct - * @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::isHandlerActivated - */ - public function testErrorLevelActivationStrategy() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $this->assertFalse($test->hasDebugRecords()); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertTrue($test->hasDebugRecords()); - $this->assertTrue($test->hasWarningRecords()); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::__construct - * @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::__construct - * @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::isHandlerActivated - */ - public function testErrorLevelActivationStrategyWithPsrLevel() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy('warning')); - $handler->handle($this->getRecord(Logger::DEBUG)); - $this->assertFalse($test->hasDebugRecords()); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertTrue($test->hasDebugRecords()); - $this->assertTrue($test->hasWarningRecords()); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::__construct - * @covers Monolog\Handler\FingersCrossedHandler::activate - */ - public function testOverrideActivationStrategy() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy('warning')); - $handler->handle($this->getRecord(Logger::DEBUG)); - $this->assertFalse($test->hasDebugRecords()); - $handler->activate(); - $this->assertTrue($test->hasDebugRecords()); - $handler->handle($this->getRecord(Logger::INFO)); - $this->assertTrue($test->hasInfoRecords()); - } - - /** - * @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::__construct - * @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::isHandlerActivated - */ - public function testChannelLevelActivationStrategy() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy(Logger::ERROR, array('othertest' => Logger::DEBUG))); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertFalse($test->hasWarningRecords()); - $record = $this->getRecord(Logger::DEBUG); - $record['channel'] = 'othertest'; - $handler->handle($record); - $this->assertTrue($test->hasDebugRecords()); - $this->assertTrue($test->hasWarningRecords()); - } - - /** - * @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::__construct - * @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::isHandlerActivated - */ - public function testChannelLevelActivationStrategyWithPsrLevels() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy('error', array('othertest' => 'debug'))); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertFalse($test->hasWarningRecords()); - $record = $this->getRecord(Logger::DEBUG); - $record['channel'] = 'othertest'; - $handler->handle($record); - $this->assertTrue($test->hasDebugRecords()); - $this->assertTrue($test->hasWarningRecords()); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::handle - * @covers Monolog\Handler\FingersCrossedHandler::activate - */ - public function testHandleUsesProcessors() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, Logger::INFO); - $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; - - return $record; - }); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertTrue($test->hasWarningRecords()); - $records = $test->getRecords(); - $this->assertTrue($records[0]['extra']['foo']); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::close - */ - public function testPassthruOnClose() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING), 0, true, true, Logger::INFO); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->close(); - $this->assertFalse($test->hasDebugRecords()); - $this->assertTrue($test->hasInfoRecords()); - } - - /** - * @covers Monolog\Handler\FingersCrossedHandler::close - */ - public function testPsrLevelPassthruOnClose() - { - $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING), 0, true, true, LogLevel::INFO); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->close(); - $this->assertFalse($test->hasDebugRecords()); - $this->assertTrue($test->hasInfoRecords()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php deleted file mode 100644 index 0eb10a63..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php +++ /dev/null @@ -1,96 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @covers Monolog\Handler\FirePHPHandler - */ -class FirePHPHandlerTest extends TestCase -{ - public function setUp() - { - TestFirePHPHandler::reset(); - $_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; FirePHP/1.0'; - } - - public function testHeaders() - { - $handler = new TestFirePHPHandler; - $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); - - $expected = array( - 'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2', - 'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1', - 'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3', - 'X-Wf-1-1-1-1' => 'test', - 'X-Wf-1-1-1-2' => 'test', - ); - - $this->assertEquals($expected, $handler->getHeaders()); - } - - public function testConcurrentHandlers() - { - $handler = new TestFirePHPHandler; - $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); - - $handler2 = new TestFirePHPHandler; - $handler2->setFormatter($this->getIdentityFormatter()); - $handler2->handle($this->getRecord(Logger::DEBUG)); - $handler2->handle($this->getRecord(Logger::WARNING)); - - $expected = array( - 'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2', - 'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1', - 'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3', - 'X-Wf-1-1-1-1' => 'test', - 'X-Wf-1-1-1-2' => 'test', - ); - - $expected2 = array( - 'X-Wf-1-1-1-3' => 'test', - 'X-Wf-1-1-1-4' => 'test', - ); - - $this->assertEquals($expected, $handler->getHeaders()); - $this->assertEquals($expected2, $handler2->getHeaders()); - } -} - -class TestFirePHPHandler extends FirePHPHandler -{ - protected $headers = array(); - - public static function reset() - { - self::$initialized = false; - self::$sendHeaders = true; - self::$messageIndex = 1; - } - - protected function sendHeader($header, $content) - { - $this->headers[$header] = $content; - } - - public function getHeaders() - { - return $this->headers; - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/Fixtures/.gitkeep b/vendor/monolog/monolog/tests/Monolog/Handler/Fixtures/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FleepHookHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FleepHookHandlerTest.php deleted file mode 100644 index 91cdd312..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/FleepHookHandlerTest.php +++ /dev/null @@ -1,85 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Formatter\LineFormatter; -use Monolog\Logger; -use Monolog\TestCase; - -/** - * @coversDefaultClass \Monolog\Handler\FleepHookHandler - */ -class FleepHookHandlerTest extends TestCase -{ - /** - * Default token to use in tests - */ - const TOKEN = '123abc'; - - /** - * @var FleepHookHandler - */ - private $handler; - - public function setUp() - { - parent::setUp(); - - if (!extension_loaded('openssl')) { - $this->markTestSkipped('This test requires openssl extension to run'); - } - - // Create instances of the handler and logger for convenience - $this->handler = new FleepHookHandler(self::TOKEN); - } - - /** - * @covers ::__construct - */ - public function testConstructorSetsExpectedDefaults() - { - $this->assertEquals(Logger::DEBUG, $this->handler->getLevel()); - $this->assertEquals(true, $this->handler->getBubble()); - } - - /** - * @covers ::getDefaultFormatter - */ - public function testHandlerUsesLineFormatterWhichIgnoresEmptyArrays() - { - $record = array( - 'message' => 'msg', - 'context' => array(), - 'level' => Logger::DEBUG, - 'level_name' => Logger::getLevelName(Logger::DEBUG), - 'channel' => 'channel', - 'datetime' => new \DateTime(), - 'extra' => array(), - ); - - $expectedFormatter = new LineFormatter(null, null, true, true); - $expected = $expectedFormatter->format($record); - - $handlerFormatter = $this->handler->getFormatter(); - $actual = $handlerFormatter->format($record); - - $this->assertEquals($expected, $actual, 'Empty context and extra arrays should not be rendered'); - } - - /** - * @covers ::__construct - */ - public function testConnectionStringisConstructedCorrectly() - { - $this->assertEquals('ssl://' . FleepHookHandler::FLEEP_HOST . ':443', $this->handler->getConnectionString()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php deleted file mode 100644 index 4b120d51..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/FlowdockHandlerTest.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Formatter\FlowdockFormatter; -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @author Dominik Liebler - * @see https://www.hipchat.com/docs/api - */ -class FlowdockHandlerTest extends TestCase -{ - /** - * @var resource - */ - private $res; - - /** - * @var FlowdockHandler - */ - private $handler; - - public function setUp() - { - if (!extension_loaded('openssl')) { - $this->markTestSkipped('This test requires openssl to run'); - } - } - - public function testWriteHeader() - { - $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/POST \/v1\/messages\/team_inbox\/.* HTTP\/1.1\\r\\nHost: api.flowdock.com\\r\\nContent-Type: application\/json\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); - - return $content; - } - - /** - * @depends testWriteHeader - */ - public function testWriteContent($content) - { - $this->assertRegexp('/"source":"test_source"/', $content); - $this->assertRegexp('/"from_address":"source@test\.com"/', $content); - } - - private function createHandler($token = 'myToken') - { - $constructorArgs = array($token, Logger::DEBUG); - $this->res = fopen('php://memory', 'a'); - $this->handler = $this->getMock( - '\Monolog\Handler\FlowdockHandler', - array('fsockopen', 'streamSetTimeout', 'closeSocket'), - $constructorArgs - ); - - $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, 'localhost:1234'); - - $this->handler->expects($this->any()) - ->method('fsockopen') - ->will($this->returnValue($this->res)); - $this->handler->expects($this->any()) - ->method('streamSetTimeout') - ->will($this->returnValue(true)); - $this->handler->expects($this->any()) - ->method('closeSocket') - ->will($this->returnValue(true)); - - $this->handler->setFormatter(new FlowdockFormatter('test_source', 'source@test.com')); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php deleted file mode 100644 index 9d007b13..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerLegacyTest.php +++ /dev/null @@ -1,95 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Gelf\Message; -use Monolog\TestCase; -use Monolog\Logger; -use Monolog\Formatter\GelfMessageFormatter; - -class GelfHandlerLegacyTest extends TestCase -{ - public function setUp() - { - if (!class_exists('Gelf\MessagePublisher') || !class_exists('Gelf\Message')) { - $this->markTestSkipped("mlehner/gelf-php not installed"); - } - - require_once __DIR__ . '/GelfMockMessagePublisher.php'; - } - - /** - * @covers Monolog\Handler\GelfHandler::__construct - */ - public function testConstruct() - { - $handler = new GelfHandler($this->getMessagePublisher()); - $this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler); - } - - protected function getHandler($messagePublisher) - { - $handler = new GelfHandler($messagePublisher); - - return $handler; - } - - protected function getMessagePublisher() - { - return new GelfMockMessagePublisher('localhost'); - } - - public function testDebug() - { - $messagePublisher = $this->getMessagePublisher(); - $handler = $this->getHandler($messagePublisher); - - $record = $this->getRecord(Logger::DEBUG, "A test debug message"); - $handler->handle($record); - - $this->assertEquals(7, $messagePublisher->lastMessage->getLevel()); - $this->assertEquals('test', $messagePublisher->lastMessage->getFacility()); - $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage()); - $this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage()); - } - - public function testWarning() - { - $messagePublisher = $this->getMessagePublisher(); - $handler = $this->getHandler($messagePublisher); - - $record = $this->getRecord(Logger::WARNING, "A test warning message"); - $handler->handle($record); - - $this->assertEquals(4, $messagePublisher->lastMessage->getLevel()); - $this->assertEquals('test', $messagePublisher->lastMessage->getFacility()); - $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage()); - $this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage()); - } - - public function testInjectedGelfMessageFormatter() - { - $messagePublisher = $this->getMessagePublisher(); - $handler = $this->getHandler($messagePublisher); - - $handler->setFormatter(new GelfMessageFormatter('mysystem', 'EXT', 'CTX')); - - $record = $this->getRecord(Logger::WARNING, "A test warning message"); - $record['extra']['blarg'] = 'yep'; - $record['context']['from'] = 'logger'; - $handler->handle($record); - - $this->assertEquals('mysystem', $messagePublisher->lastMessage->getHost()); - $this->assertArrayHasKey('_EXTblarg', $messagePublisher->lastMessage->toArray()); - $this->assertArrayHasKey('_CTXfrom', $messagePublisher->lastMessage->toArray()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php deleted file mode 100644 index 8cdd64f4..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php +++ /dev/null @@ -1,117 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Gelf\Message; -use Monolog\TestCase; -use Monolog\Logger; -use Monolog\Formatter\GelfMessageFormatter; - -class GelfHandlerTest extends TestCase -{ - public function setUp() - { - if (!class_exists('Gelf\Publisher') || !class_exists('Gelf\Message')) { - $this->markTestSkipped("graylog2/gelf-php not installed"); - } - } - - /** - * @covers Monolog\Handler\GelfHandler::__construct - */ - public function testConstruct() - { - $handler = new GelfHandler($this->getMessagePublisher()); - $this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler); - } - - protected function getHandler($messagePublisher) - { - $handler = new GelfHandler($messagePublisher); - - return $handler; - } - - protected function getMessagePublisher() - { - return $this->getMock('Gelf\Publisher', array('publish'), array(), '', false); - } - - public function testDebug() - { - $record = $this->getRecord(Logger::DEBUG, "A test debug message"); - $expectedMessage = new Message(); - $expectedMessage - ->setLevel(7) - ->setFacility("test") - ->setShortMessage($record['message']) - ->setTimestamp($record['datetime']) - ; - - $messagePublisher = $this->getMessagePublisher(); - $messagePublisher->expects($this->once()) - ->method('publish') - ->with($expectedMessage); - - $handler = $this->getHandler($messagePublisher); - - $handler->handle($record); - } - - public function testWarning() - { - $record = $this->getRecord(Logger::WARNING, "A test warning message"); - $expectedMessage = new Message(); - $expectedMessage - ->setLevel(4) - ->setFacility("test") - ->setShortMessage($record['message']) - ->setTimestamp($record['datetime']) - ; - - $messagePublisher = $this->getMessagePublisher(); - $messagePublisher->expects($this->once()) - ->method('publish') - ->with($expectedMessage); - - $handler = $this->getHandler($messagePublisher); - - $handler->handle($record); - } - - public function testInjectedGelfMessageFormatter() - { - $record = $this->getRecord(Logger::WARNING, "A test warning message"); - $record['extra']['blarg'] = 'yep'; - $record['context']['from'] = 'logger'; - - $expectedMessage = new Message(); - $expectedMessage - ->setLevel(4) - ->setFacility("test") - ->setHost("mysystem") - ->setShortMessage($record['message']) - ->setTimestamp($record['datetime']) - ->setAdditional("EXTblarg", 'yep') - ->setAdditional("CTXfrom", 'logger') - ; - - $messagePublisher = $this->getMessagePublisher(); - $messagePublisher->expects($this->once()) - ->method('publish') - ->with($expectedMessage); - - $handler = $this->getHandler($messagePublisher); - $handler->setFormatter(new GelfMessageFormatter('mysystem', 'EXT', 'CTX')); - $handler->handle($record); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/GelfMockMessagePublisher.php b/vendor/monolog/monolog/tests/Monolog/Handler/GelfMockMessagePublisher.php deleted file mode 100644 index 873d92fb..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/GelfMockMessagePublisher.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Gelf\MessagePublisher; -use Gelf\Message; - -class GelfMockMessagePublisher extends MessagePublisher -{ - public function publish(Message $message) - { - $this->lastMessage = $message; - } - - public $lastMessage = null; -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php deleted file mode 100644 index a1b86176..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php +++ /dev/null @@ -1,112 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -class GroupHandlerTest extends TestCase -{ - /** - * @covers Monolog\Handler\GroupHandler::__construct - * @expectedException InvalidArgumentException - */ - public function testConstructorOnlyTakesHandler() - { - new GroupHandler(array(new TestHandler(), "foo")); - } - - /** - * @covers Monolog\Handler\GroupHandler::__construct - * @covers Monolog\Handler\GroupHandler::handle - */ - public function testHandle() - { - $testHandlers = array(new TestHandler(), new TestHandler()); - $handler = new GroupHandler($testHandlers); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - foreach ($testHandlers as $test) { - $this->assertTrue($test->hasDebugRecords()); - $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); - } - } - - /** - * @covers Monolog\Handler\GroupHandler::handleBatch - */ - public function testHandleBatch() - { - $testHandlers = array(new TestHandler(), new TestHandler()); - $handler = new GroupHandler($testHandlers); - $handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO))); - foreach ($testHandlers as $test) { - $this->assertTrue($test->hasDebugRecords()); - $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); - } - } - - /** - * @covers Monolog\Handler\GroupHandler::isHandling - */ - public function testIsHandling() - { - $testHandlers = array(new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING)); - $handler = new GroupHandler($testHandlers); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR))); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); - } - - /** - * @covers Monolog\Handler\GroupHandler::handle - */ - public function testHandleUsesProcessors() - { - $test = new TestHandler(); - $handler = new GroupHandler(array($test)); - $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; - - return $record; - }); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertTrue($test->hasWarningRecords()); - $records = $test->getRecords(); - $this->assertTrue($records[0]['extra']['foo']); - } - - /** - * @covers Monolog\Handler\GroupHandler::handle - */ - public function testHandleBatchUsesProcessors() - { - $testHandlers = array(new TestHandler(), new TestHandler()); - $handler = new GroupHandler($testHandlers); - $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; - - return $record; - }); - $handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO))); - foreach ($testHandlers as $test) { - $this->assertTrue($test->hasDebugRecords()); - $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); - $records = $test->getRecords(); - $this->assertTrue($records[0]['extra']['foo']); - $this->assertTrue($records[1]['extra']['foo']); - } - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/HandlerWrapperTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/HandlerWrapperTest.php deleted file mode 100644 index d8d0452c..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/HandlerWrapperTest.php +++ /dev/null @@ -1,130 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; - -/** - * @author Alexey Karapetov - */ -class HandlerWrapperTest extends TestCase -{ - /** - * @var HandlerWrapper - */ - private $wrapper; - - private $handler; - - public function setUp() - { - parent::setUp(); - $this->handler = $this->getMock('Monolog\\Handler\\HandlerInterface'); - $this->wrapper = new HandlerWrapper($this->handler); - } - - /** - * @return array - */ - public function trueFalseDataProvider() - { - return array( - array(true), - array(false), - ); - } - - /** - * @param $result - * @dataProvider trueFalseDataProvider - */ - public function testIsHandling($result) - { - $record = $this->getRecord(); - $this->handler->expects($this->once()) - ->method('isHandling') - ->with($record) - ->willReturn($result); - - $this->assertEquals($result, $this->wrapper->isHandling($record)); - } - - /** - * @param $result - * @dataProvider trueFalseDataProvider - */ - public function testHandle($result) - { - $record = $this->getRecord(); - $this->handler->expects($this->once()) - ->method('handle') - ->with($record) - ->willReturn($result); - - $this->assertEquals($result, $this->wrapper->handle($record)); - } - - /** - * @param $result - * @dataProvider trueFalseDataProvider - */ - public function testHandleBatch($result) - { - $records = $this->getMultipleRecords(); - $this->handler->expects($this->once()) - ->method('handleBatch') - ->with($records) - ->willReturn($result); - - $this->assertEquals($result, $this->wrapper->handleBatch($records)); - } - - public function testPushProcessor() - { - $processor = function () {}; - $this->handler->expects($this->once()) - ->method('pushProcessor') - ->with($processor); - - $this->assertEquals($this->wrapper, $this->wrapper->pushProcessor($processor)); - } - - public function testPopProcessor() - { - $processor = function () {}; - $this->handler->expects($this->once()) - ->method('popProcessor') - ->willReturn($processor); - - $this->assertEquals($processor, $this->wrapper->popProcessor()); - } - - public function testSetFormatter() - { - $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); - $this->handler->expects($this->once()) - ->method('setFormatter') - ->with($formatter); - - $this->assertEquals($this->wrapper, $this->wrapper->setFormatter($formatter)); - } - - public function testGetFormatter() - { - $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); - $this->handler->expects($this->once()) - ->method('getFormatter') - ->willReturn($formatter); - - $this->assertEquals($formatter, $this->wrapper->getFormatter()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php deleted file mode 100644 index 52dc9dac..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php +++ /dev/null @@ -1,279 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @author Rafael Dohms - * @see https://www.hipchat.com/docs/api - */ -class HipChatHandlerTest extends TestCase -{ - private $res; - /** @var HipChatHandler */ - private $handler; - - public function testWriteHeader() - { - $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/POST \/v1\/rooms\/message\?format=json&auth_token=.* HTTP\/1.1\\r\\nHost: api.hipchat.com\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); - - return $content; - } - - public function testWriteCustomHostHeader() - { - $this->createHandler('myToken', 'room1', 'Monolog', true, 'hipchat.foo.bar'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/POST \/v1\/rooms\/message\?format=json&auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); - - return $content; - } - - public function testWriteV2() - { - $this->createHandler('myToken', 'room1', 'Monolog', false, 'hipchat.foo.bar', 'v2'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/POST \/v2\/room\/room1\/notification\?auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); - - return $content; - } - - public function testWriteV2Notify() - { - $this->createHandler('myToken', 'room1', 'Monolog', true, 'hipchat.foo.bar', 'v2'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/POST \/v2\/room\/room1\/notification\?auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); - - return $content; - } - - public function testRoomSpaces() - { - $this->createHandler('myToken', 'room name', 'Monolog', false, 'hipchat.foo.bar', 'v2'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/POST \/v2\/room\/room%20name\/notification\?auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); - - return $content; - } - - /** - * @depends testWriteHeader - */ - public function testWriteContent($content) - { - $this->assertRegexp('/notify=0&message=test1&message_format=text&color=red&room_id=room1&from=Monolog$/', $content); - } - - public function testWriteContentV1WithoutName() - { - $this->createHandler('myToken', 'room1', null, false, 'hipchat.foo.bar', 'v1'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/notify=0&message=test1&message_format=text&color=red&room_id=room1&from=$/', $content); - - return $content; - } - - /** - * @depends testWriteCustomHostHeader - */ - public function testWriteContentNotify($content) - { - $this->assertRegexp('/notify=1&message=test1&message_format=text&color=red&room_id=room1&from=Monolog$/', $content); - } - - /** - * @depends testWriteV2 - */ - public function testWriteContentV2($content) - { - $this->assertRegexp('/notify=false&message=test1&message_format=text&color=red&from=Monolog$/', $content); - } - - /** - * @depends testWriteV2Notify - */ - public function testWriteContentV2Notify($content) - { - $this->assertRegexp('/notify=true&message=test1&message_format=text&color=red&from=Monolog$/', $content); - } - - public function testWriteContentV2WithoutName() - { - $this->createHandler('myToken', 'room1', null, false, 'hipchat.foo.bar', 'v2'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/notify=false&message=test1&message_format=text&color=red$/', $content); - - return $content; - } - - public function testWriteWithComplexMessage() - { - $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content); - } - - public function testWriteTruncatesLongMessage() - { - $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, str_repeat('abcde', 2000))); - fseek($this->res, 0); - $content = fread($this->res, 12000); - - $this->assertRegexp('/message='.str_repeat('abcde', 1900).'\+%5Btruncated%5D/', $content); - } - - /** - * @dataProvider provideLevelColors - */ - public function testWriteWithErrorLevelsAndColors($level, $expectedColor) - { - $this->createHandler(); - $this->handler->handle($this->getRecord($level, 'Backup of database "example" finished in 16 minutes.')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/color='.$expectedColor.'/', $content); - } - - public function provideLevelColors() - { - return array( - array(Logger::DEBUG, 'gray'), - array(Logger::INFO, 'green'), - array(Logger::WARNING, 'yellow'), - array(Logger::ERROR, 'red'), - array(Logger::CRITICAL, 'red'), - array(Logger::ALERT, 'red'), - array(Logger::EMERGENCY,'red'), - array(Logger::NOTICE, 'green'), - ); - } - - /** - * @dataProvider provideBatchRecords - */ - public function testHandleBatch($records, $expectedColor) - { - $this->createHandler(); - - $this->handler->handleBatch($records); - - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/color='.$expectedColor.'/', $content); - } - - public function provideBatchRecords() - { - return array( - array( - array( - array('level' => Logger::WARNING, 'message' => 'Oh bugger!', 'level_name' => 'warning', 'datetime' => new \DateTime()), - array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()), - array('level' => Logger::CRITICAL, 'message' => 'Everything is broken!', 'level_name' => 'critical', 'datetime' => new \DateTime()), - ), - 'red', - ), - array( - array( - array('level' => Logger::WARNING, 'message' => 'Oh bugger!', 'level_name' => 'warning', 'datetime' => new \DateTime()), - array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()), - ), - 'yellow', - ), - array( - array( - array('level' => Logger::DEBUG, 'message' => 'Just debugging.', 'level_name' => 'debug', 'datetime' => new \DateTime()), - array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()), - ), - 'green', - ), - array( - array( - array('level' => Logger::DEBUG, 'message' => 'Just debugging.', 'level_name' => 'debug', 'datetime' => new \DateTime()), - ), - 'gray', - ), - ); - } - - private function createHandler($token = 'myToken', $room = 'room1', $name = 'Monolog', $notify = false, $host = 'api.hipchat.com', $version = 'v1') - { - $constructorArgs = array($token, $room, $name, $notify, Logger::DEBUG, true, true, 'text', $host, $version); - $this->res = fopen('php://memory', 'a'); - $this->handler = $this->getMock( - '\Monolog\Handler\HipChatHandler', - array('fsockopen', 'streamSetTimeout', 'closeSocket'), - $constructorArgs - ); - - $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, 'localhost:1234'); - - $this->handler->expects($this->any()) - ->method('fsockopen') - ->will($this->returnValue($this->res)); - $this->handler->expects($this->any()) - ->method('streamSetTimeout') - ->will($this->returnValue(true)); - $this->handler->expects($this->any()) - ->method('closeSocket') - ->will($this->returnValue(true)); - - $this->handler->setFormatter($this->getIdentityFormatter()); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testCreateWithTooLongName() - { - $hipChatHandler = new HipChatHandler('token', 'room', 'SixteenCharsHere'); - } - - public function testCreateWithTooLongNameV2() - { - // creating a handler with too long of a name but using the v2 api doesn't matter. - $hipChatHandler = new HipChatHandler('token', 'room', 'SixteenCharsHere', false, Logger::CRITICAL, true, true, 'test', 'api.hipchat.com', 'v2'); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php deleted file mode 100644 index b2deb40a..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/LogEntriesHandlerTest.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @author Robert Kaufmann III - */ -class LogEntriesHandlerTest extends TestCase -{ - /** - * @var resource - */ - private $res; - - /** - * @var LogEntriesHandler - */ - private $handler; - - public function testWriteContent() - { - $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test')); - - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] test.CRITICAL: Critical write test/', $content); - } - - public function testWriteBatchContent() - { - $records = array( - $this->getRecord(), - $this->getRecord(), - $this->getRecord(), - ); - $this->createHandler(); - $this->handler->handleBatch($records); - - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/(testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] .* \[\] \[\]\n){3}/', $content); - } - - private function createHandler() - { - $useSSL = extension_loaded('openssl'); - $args = array('testToken', $useSSL, Logger::DEBUG, true); - $this->res = fopen('php://memory', 'a'); - $this->handler = $this->getMock( - '\Monolog\Handler\LogEntriesHandler', - array('fsockopen', 'streamSetTimeout', 'closeSocket'), - $args - ); - - $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, 'localhost:1234'); - - $this->handler->expects($this->any()) - ->method('fsockopen') - ->will($this->returnValue($this->res)); - $this->handler->expects($this->any()) - ->method('streamSetTimeout') - ->will($this->returnValue(true)); - $this->handler->expects($this->any()) - ->method('closeSocket') - ->will($this->returnValue(true)); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php deleted file mode 100644 index 6754f3d6..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php +++ /dev/null @@ -1,75 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Logger; -use Monolog\TestCase; - -class MailHandlerTest extends TestCase -{ - /** - * @covers Monolog\Handler\MailHandler::handleBatch - */ - public function testHandleBatch() - { - $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); - $formatter->expects($this->once()) - ->method('formatBatch'); // Each record is formatted - - $handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler'); - $handler->expects($this->once()) - ->method('send'); - $handler->expects($this->never()) - ->method('write'); // write is for individual records - - $handler->setFormatter($formatter); - - $handler->handleBatch($this->getMultipleRecords()); - } - - /** - * @covers Monolog\Handler\MailHandler::handleBatch - */ - public function testHandleBatchNotSendsMailIfMessagesAreBelowLevel() - { - $records = array( - $this->getRecord(Logger::DEBUG, 'debug message 1'), - $this->getRecord(Logger::DEBUG, 'debug message 2'), - $this->getRecord(Logger::INFO, 'information'), - ); - - $handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler'); - $handler->expects($this->never()) - ->method('send'); - $handler->setLevel(Logger::ERROR); - - $handler->handleBatch($records); - } - - /** - * @covers Monolog\Handler\MailHandler::write - */ - public function testHandle() - { - $handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler'); - - $record = $this->getRecord(); - $records = array($record); - $records[0]['formatted'] = '['.$record['datetime']->format('Y-m-d H:i:s').'] test.WARNING: test [] []'."\n"; - - $handler->expects($this->once()) - ->method('send') - ->with($records[0]['formatted'], $records); - - $handler->handle($record); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php b/vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php deleted file mode 100644 index a0833225..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Raven_Client; - -class MockRavenClient extends Raven_Client -{ - public function capture($data, $stack, $vars = null) - { - $data = array_merge($this->get_user_data(), $data); - $this->lastData = $data; - $this->lastStack = $stack; - } - - public $lastData; - public $lastStack; -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php deleted file mode 100644 index 0fdef63a..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php +++ /dev/null @@ -1,65 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -class MongoDBHandlerTest extends TestCase -{ - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorShouldThrowExceptionForInvalidMongo() - { - new MongoDBHandler(new \stdClass(), 'DB', 'Collection'); - } - - public function testHandle() - { - $mongo = $this->getMock('Mongo', array('selectCollection'), array(), '', false); - $collection = $this->getMock('stdClass', array('save')); - - $mongo->expects($this->once()) - ->method('selectCollection') - ->with('DB', 'Collection') - ->will($this->returnValue($collection)); - - $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); - - $expected = array( - 'message' => 'test', - 'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34), - 'level' => Logger::WARNING, - 'level_name' => 'WARNING', - 'channel' => 'test', - 'datetime' => $record['datetime']->format('Y-m-d H:i:s'), - 'extra' => array(), - ); - - $collection->expects($this->once()) - ->method('save') - ->with($expected); - - $handler = new MongoDBHandler($mongo, 'DB', 'Collection'); - $handler->handle($record); - } -} - -if (!class_exists('Mongo')) { - class Mongo - { - public function selectCollection() - { - } - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php deleted file mode 100644 index ddf545db..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php +++ /dev/null @@ -1,111 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; -use InvalidArgumentException; - -function mail($to, $subject, $message, $additional_headers = null, $additional_parameters = null) -{ - $GLOBALS['mail'][] = func_get_args(); -} - -class NativeMailerHandlerTest extends TestCase -{ - protected function setUp() - { - $GLOBALS['mail'] = array(); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorHeaderInjection() - { - $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', "receiver@example.org\r\nFrom: faked@attacker.org"); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testSetterHeaderInjection() - { - $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org'); - $mailer->addHeader("Content-Type: text/html\r\nFrom: faked@attacker.org"); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testSetterArrayHeaderInjection() - { - $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org'); - $mailer->addHeader(array("Content-Type: text/html\r\nFrom: faked@attacker.org")); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testSetterContentTypeInjection() - { - $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org'); - $mailer->setContentType("text/html\r\nFrom: faked@attacker.org"); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testSetterEncodingInjection() - { - $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org'); - $mailer->setEncoding("utf-8\r\nFrom: faked@attacker.org"); - } - - public function testSend() - { - $to = 'spammer@example.org'; - $subject = 'dear victim'; - $from = 'receiver@example.org'; - - $mailer = new NativeMailerHandler($to, $subject, $from); - $mailer->handleBatch(array()); - - // batch is empty, nothing sent - $this->assertEmpty($GLOBALS['mail']); - - // non-empty batch - $mailer->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); - $this->assertNotEmpty($GLOBALS['mail']); - $this->assertInternalType('array', $GLOBALS['mail']); - $this->assertArrayHasKey('0', $GLOBALS['mail']); - $params = $GLOBALS['mail'][0]; - $this->assertCount(5, $params); - $this->assertSame($to, $params[0]); - $this->assertSame($subject, $params[1]); - $this->assertStringEndsWith(" test.ERROR: Foo Bar Baz [] []\n", $params[2]); - $this->assertSame("From: $from\r\nContent-type: text/plain; charset=utf-8\r\n", $params[3]); - $this->assertSame('', $params[4]); - } - - public function testMessageSubjectFormatting() - { - $mailer = new NativeMailerHandler('to@example.org', 'Alert: %level_name% %message%', 'from@example.org'); - $mailer->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); - $this->assertNotEmpty($GLOBALS['mail']); - $this->assertInternalType('array', $GLOBALS['mail']); - $this->assertArrayHasKey('0', $GLOBALS['mail']); - $params = $GLOBALS['mail'][0]; - $this->assertCount(5, $params); - $this->assertSame('Alert: ERROR Foo Bar Baz', $params[1]); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php deleted file mode 100644 index 4d3a615f..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php +++ /dev/null @@ -1,200 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Formatter\LineFormatter; -use Monolog\TestCase; -use Monolog\Logger; - -class NewRelicHandlerTest extends TestCase -{ - public static $appname; - public static $customParameters; - public static $transactionName; - - public function setUp() - { - self::$appname = null; - self::$customParameters = array(); - self::$transactionName = null; - } - - /** - * @expectedException Monolog\Handler\MissingExtensionException - */ - public function testThehandlerThrowsAnExceptionIfTheNRExtensionIsNotLoaded() - { - $handler = new StubNewRelicHandlerWithoutExtension(); - $handler->handle($this->getRecord(Logger::ERROR)); - } - - public function testThehandlerCanHandleTheRecord() - { - $handler = new StubNewRelicHandler(); - $handler->handle($this->getRecord(Logger::ERROR)); - } - - public function testThehandlerCanAddContextParamsToTheNewRelicTrace() - { - $handler = new StubNewRelicHandler(); - $handler->handle($this->getRecord(Logger::ERROR, 'log message', array('a' => 'b'))); - $this->assertEquals(array('context_a' => 'b'), self::$customParameters); - } - - public function testThehandlerCanAddExplodedContextParamsToTheNewRelicTrace() - { - $handler = new StubNewRelicHandler(Logger::ERROR, true, self::$appname, true); - $handler->handle($this->getRecord( - Logger::ERROR, - 'log message', - array('a' => array('key1' => 'value1', 'key2' => 'value2')) - )); - $this->assertEquals( - array('context_a_key1' => 'value1', 'context_a_key2' => 'value2'), - self::$customParameters - ); - } - - public function testThehandlerCanAddExtraParamsToTheNewRelicTrace() - { - $record = $this->getRecord(Logger::ERROR, 'log message'); - $record['extra'] = array('c' => 'd'); - - $handler = new StubNewRelicHandler(); - $handler->handle($record); - - $this->assertEquals(array('extra_c' => 'd'), self::$customParameters); - } - - public function testThehandlerCanAddExplodedExtraParamsToTheNewRelicTrace() - { - $record = $this->getRecord(Logger::ERROR, 'log message'); - $record['extra'] = array('c' => array('key1' => 'value1', 'key2' => 'value2')); - - $handler = new StubNewRelicHandler(Logger::ERROR, true, self::$appname, true); - $handler->handle($record); - - $this->assertEquals( - array('extra_c_key1' => 'value1', 'extra_c_key2' => 'value2'), - self::$customParameters - ); - } - - public function testThehandlerCanAddExtraContextAndParamsToTheNewRelicTrace() - { - $record = $this->getRecord(Logger::ERROR, 'log message', array('a' => 'b')); - $record['extra'] = array('c' => 'd'); - - $handler = new StubNewRelicHandler(); - $handler->handle($record); - - $expected = array( - 'context_a' => 'b', - 'extra_c' => 'd', - ); - - $this->assertEquals($expected, self::$customParameters); - } - - public function testThehandlerCanHandleTheRecordsFormattedUsingTheLineFormatter() - { - $handler = new StubNewRelicHandler(); - $handler->setFormatter(new LineFormatter()); - $handler->handle($this->getRecord(Logger::ERROR)); - } - - public function testTheAppNameIsNullByDefault() - { - $handler = new StubNewRelicHandler(); - $handler->handle($this->getRecord(Logger::ERROR, 'log message')); - - $this->assertEquals(null, self::$appname); - } - - public function testTheAppNameCanBeInjectedFromtheConstructor() - { - $handler = new StubNewRelicHandler(Logger::DEBUG, false, 'myAppName'); - $handler->handle($this->getRecord(Logger::ERROR, 'log message')); - - $this->assertEquals('myAppName', self::$appname); - } - - public function testTheAppNameCanBeOverriddenFromEachLog() - { - $handler = new StubNewRelicHandler(Logger::DEBUG, false, 'myAppName'); - $handler->handle($this->getRecord(Logger::ERROR, 'log message', array('appname' => 'logAppName'))); - - $this->assertEquals('logAppName', self::$appname); - } - - public function testTheTransactionNameIsNullByDefault() - { - $handler = new StubNewRelicHandler(); - $handler->handle($this->getRecord(Logger::ERROR, 'log message')); - - $this->assertEquals(null, self::$transactionName); - } - - public function testTheTransactionNameCanBeInjectedFromTheConstructor() - { - $handler = new StubNewRelicHandler(Logger::DEBUG, false, null, false, 'myTransaction'); - $handler->handle($this->getRecord(Logger::ERROR, 'log message')); - - $this->assertEquals('myTransaction', self::$transactionName); - } - - public function testTheTransactionNameCanBeOverriddenFromEachLog() - { - $handler = new StubNewRelicHandler(Logger::DEBUG, false, null, false, 'myTransaction'); - $handler->handle($this->getRecord(Logger::ERROR, 'log message', array('transaction_name' => 'logTransactName'))); - - $this->assertEquals('logTransactName', self::$transactionName); - } -} - -class StubNewRelicHandlerWithoutExtension extends NewRelicHandler -{ - protected function isNewRelicEnabled() - { - return false; - } -} - -class StubNewRelicHandler extends NewRelicHandler -{ - protected function isNewRelicEnabled() - { - return true; - } -} - -function newrelic_notice_error() -{ - return true; -} - -function newrelic_set_appname($appname) -{ - return NewRelicHandlerTest::$appname = $appname; -} - -function newrelic_name_transaction($transactionName) -{ - return NewRelicHandlerTest::$transactionName = $transactionName; -} - -function newrelic_add_custom_parameter($key, $value) -{ - NewRelicHandlerTest::$customParameters[$key] = $value; - - return true; -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php deleted file mode 100644 index 292df78c..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @covers Monolog\Handler\NullHandler::handle - */ -class NullHandlerTest extends TestCase -{ - public function testHandle() - { - $handler = new NullHandler(); - $this->assertTrue($handler->handle($this->getRecord())); - } - - public function testHandleLowerLevelRecord() - { - $handler = new NullHandler(Logger::WARNING); - $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/PHPConsoleHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/PHPConsoleHandlerTest.php deleted file mode 100644 index 152573ef..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/PHPConsoleHandlerTest.php +++ /dev/null @@ -1,273 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Exception; -use Monolog\ErrorHandler; -use Monolog\Logger; -use Monolog\TestCase; -use PhpConsole\Connector; -use PhpConsole\Dispatcher\Debug as DebugDispatcher; -use PhpConsole\Dispatcher\Errors as ErrorDispatcher; -use PhpConsole\Handler; -use PHPUnit_Framework_MockObject_MockObject; - -/** - * @covers Monolog\Handler\PHPConsoleHandler - * @author Sergey Barbushin https://www.linkedin.com/in/barbushin - */ -class PHPConsoleHandlerTest extends TestCase -{ - /** @var Connector|PHPUnit_Framework_MockObject_MockObject */ - protected $connector; - /** @var DebugDispatcher|PHPUnit_Framework_MockObject_MockObject */ - protected $debugDispatcher; - /** @var ErrorDispatcher|PHPUnit_Framework_MockObject_MockObject */ - protected $errorDispatcher; - - protected function setUp() - { - if (!class_exists('PhpConsole\Connector')) { - $this->markTestSkipped('PHP Console library not found. See https://github.com/barbushin/php-console#installation'); - } - $this->connector = $this->initConnectorMock(); - - $this->debugDispatcher = $this->initDebugDispatcherMock($this->connector); - $this->connector->setDebugDispatcher($this->debugDispatcher); - - $this->errorDispatcher = $this->initErrorDispatcherMock($this->connector); - $this->connector->setErrorsDispatcher($this->errorDispatcher); - } - - protected function initDebugDispatcherMock(Connector $connector) - { - return $this->getMockBuilder('PhpConsole\Dispatcher\Debug') - ->disableOriginalConstructor() - ->setMethods(array('dispatchDebug')) - ->setConstructorArgs(array($connector, $connector->getDumper())) - ->getMock(); - } - - protected function initErrorDispatcherMock(Connector $connector) - { - return $this->getMockBuilder('PhpConsole\Dispatcher\Errors') - ->disableOriginalConstructor() - ->setMethods(array('dispatchError', 'dispatchException')) - ->setConstructorArgs(array($connector, $connector->getDumper())) - ->getMock(); - } - - protected function initConnectorMock() - { - $connector = $this->getMockBuilder('PhpConsole\Connector') - ->disableOriginalConstructor() - ->setMethods(array( - 'sendMessage', - 'onShutDown', - 'isActiveClient', - 'setSourcesBasePath', - 'setServerEncoding', - 'setPassword', - 'enableSslOnlyMode', - 'setAllowedIpMasks', - 'setHeadersLimit', - 'startEvalRequestsListener', - )) - ->getMock(); - - $connector->expects($this->any()) - ->method('isActiveClient') - ->will($this->returnValue(true)); - - return $connector; - } - - protected function getHandlerDefaultOption($name) - { - $handler = new PHPConsoleHandler(array(), $this->connector); - $options = $handler->getOptions(); - - return $options[$name]; - } - - protected function initLogger($handlerOptions = array(), $level = Logger::DEBUG) - { - return new Logger('test', array( - new PHPConsoleHandler($handlerOptions, $this->connector, $level), - )); - } - - public function testInitWithDefaultConnector() - { - $handler = new PHPConsoleHandler(); - $this->assertEquals(spl_object_hash(Connector::getInstance()), spl_object_hash($handler->getConnector())); - } - - public function testInitWithCustomConnector() - { - $handler = new PHPConsoleHandler(array(), $this->connector); - $this->assertEquals(spl_object_hash($this->connector), spl_object_hash($handler->getConnector())); - } - - public function testDebug() - { - $this->debugDispatcher->expects($this->once())->method('dispatchDebug')->with($this->equalTo('test')); - $this->initLogger()->addDebug('test'); - } - - public function testDebugContextInMessage() - { - $message = 'test'; - $tag = 'tag'; - $context = array($tag, 'custom' => mt_rand()); - $expectedMessage = $message . ' ' . json_encode(array_slice($context, 1)); - $this->debugDispatcher->expects($this->once())->method('dispatchDebug')->with( - $this->equalTo($expectedMessage), - $this->equalTo($tag) - ); - $this->initLogger()->addDebug($message, $context); - } - - public function testDebugTags($tagsContextKeys = null) - { - $expectedTags = mt_rand(); - $logger = $this->initLogger($tagsContextKeys ? array('debugTagsKeysInContext' => $tagsContextKeys) : array()); - if (!$tagsContextKeys) { - $tagsContextKeys = $this->getHandlerDefaultOption('debugTagsKeysInContext'); - } - foreach ($tagsContextKeys as $key) { - $debugDispatcher = $this->initDebugDispatcherMock($this->connector); - $debugDispatcher->expects($this->once())->method('dispatchDebug')->with( - $this->anything(), - $this->equalTo($expectedTags) - ); - $this->connector->setDebugDispatcher($debugDispatcher); - $logger->addDebug('test', array($key => $expectedTags)); - } - } - - public function testError($classesPartialsTraceIgnore = null) - { - $code = E_USER_NOTICE; - $message = 'message'; - $file = __FILE__; - $line = __LINE__; - $this->errorDispatcher->expects($this->once())->method('dispatchError')->with( - $this->equalTo($code), - $this->equalTo($message), - $this->equalTo($file), - $this->equalTo($line), - $classesPartialsTraceIgnore ?: $this->equalTo($this->getHandlerDefaultOption('classesPartialsTraceIgnore')) - ); - $errorHandler = ErrorHandler::register($this->initLogger($classesPartialsTraceIgnore ? array('classesPartialsTraceIgnore' => $classesPartialsTraceIgnore) : array()), false); - $errorHandler->registerErrorHandler(array(), false, E_USER_WARNING); - $errorHandler->handleError($code, $message, $file, $line); - } - - public function testException() - { - $e = new Exception(); - $this->errorDispatcher->expects($this->once())->method('dispatchException')->with( - $this->equalTo($e) - ); - $handler = $this->initLogger(); - $handler->log( - \Psr\Log\LogLevel::ERROR, - sprintf('Uncaught Exception %s: "%s" at %s line %s', get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()), - array('exception' => $e) - ); - } - - /** - * @expectedException Exception - */ - public function testWrongOptionsThrowsException() - { - new PHPConsoleHandler(array('xxx' => 1)); - } - - public function testOptionEnabled() - { - $this->debugDispatcher->expects($this->never())->method('dispatchDebug'); - $this->initLogger(array('enabled' => false))->addDebug('test'); - } - - public function testOptionClassesPartialsTraceIgnore() - { - $this->testError(array('Class', 'Namespace\\')); - } - - public function testOptionDebugTagsKeysInContext() - { - $this->testDebugTags(array('key1', 'key2')); - } - - public function testOptionUseOwnErrorsAndExceptionsHandler() - { - $this->initLogger(array('useOwnErrorsHandler' => true, 'useOwnExceptionsHandler' => true)); - $this->assertEquals(array(Handler::getInstance(), 'handleError'), set_error_handler(function () { - })); - $this->assertEquals(array(Handler::getInstance(), 'handleException'), set_exception_handler(function () { - })); - } - - public static function provideConnectorMethodsOptionsSets() - { - return array( - array('sourcesBasePath', 'setSourcesBasePath', __DIR__), - array('serverEncoding', 'setServerEncoding', 'cp1251'), - array('password', 'setPassword', '******'), - array('enableSslOnlyMode', 'enableSslOnlyMode', true, false), - array('ipMasks', 'setAllowedIpMasks', array('127.0.0.*')), - array('headersLimit', 'setHeadersLimit', 2500), - array('enableEvalListener', 'startEvalRequestsListener', true, false), - ); - } - - /** - * @dataProvider provideConnectorMethodsOptionsSets - */ - public function testOptionCallsConnectorMethod($option, $method, $value, $isArgument = true) - { - $expectCall = $this->connector->expects($this->once())->method($method); - if ($isArgument) { - $expectCall->with($value); - } - new PHPConsoleHandler(array($option => $value), $this->connector); - } - - public function testOptionDetectDumpTraceAndSource() - { - new PHPConsoleHandler(array('detectDumpTraceAndSource' => true), $this->connector); - $this->assertTrue($this->connector->getDebugDispatcher()->detectTraceAndSource); - } - - public static function provideDumperOptionsValues() - { - return array( - array('dumperLevelLimit', 'levelLimit', 1001), - array('dumperItemsCountLimit', 'itemsCountLimit', 1002), - array('dumperItemSizeLimit', 'itemSizeLimit', 1003), - array('dumperDumpSizeLimit', 'dumpSizeLimit', 1004), - array('dumperDetectCallbacks', 'detectCallbacks', true), - ); - } - - /** - * @dataProvider provideDumperOptionsValues - */ - public function testDumperOptions($option, $dumperProperty, $value) - { - new PHPConsoleHandler(array($option => $value), $this->connector); - $this->assertEquals($value, $this->connector->getDumper()->$dumperProperty); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/PsrHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/PsrHandlerTest.php deleted file mode 100644 index 64eaab16..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/PsrHandlerTest.php +++ /dev/null @@ -1,50 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @covers Monolog\Handler\PsrHandler::handle - */ -class PsrHandlerTest extends TestCase -{ - public function logLevelProvider() - { - $levels = array(); - $monologLogger = new Logger(''); - - foreach ($monologLogger->getLevels() as $levelName => $level) { - $levels[] = array($levelName, $level); - } - - return $levels; - } - - /** - * @dataProvider logLevelProvider - */ - public function testHandlesAllLevels($levelName, $level) - { - $message = 'Hello, world! ' . $level; - $context = array('foo' => 'bar', 'level' => $level); - - $psrLogger = $this->getMock('Psr\Log\NullLogger'); - $psrLogger->expects($this->once()) - ->method('log') - ->with(strtolower($levelName), $message, $context); - - $handler = new PsrHandler($psrLogger); - $handler->handle(array('level' => $level, 'level_name' => $levelName, 'message' => $message, 'context' => $context)); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php deleted file mode 100644 index 56df474a..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php +++ /dev/null @@ -1,141 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * Almost all examples (expected header, titles, messages) taken from - * https://www.pushover.net/api - * @author Sebastian Göttschkes - * @see https://www.pushover.net/api - */ -class PushoverHandlerTest extends TestCase -{ - private $res; - private $handler; - - public function testWriteHeader() - { - $this->createHandler(); - $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/POST \/1\/messages.json HTTP\/1.1\\r\\nHost: api.pushover.net\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); - - return $content; - } - - /** - * @depends testWriteHeader - */ - public function testWriteContent($content) - { - $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}$/', $content); - } - - public function testWriteWithComplexTitle() - { - $this->createHandler('myToken', 'myUser', 'Backup finished - SQL1'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/title=Backup\+finished\+-\+SQL1/', $content); - } - - public function testWriteWithComplexMessage() - { - $this->createHandler(); - $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content); - } - - public function testWriteWithTooLongMessage() - { - $message = str_pad('test', 520, 'a'); - $this->createHandler(); - $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications - $this->handler->handle($this->getRecord(Logger::CRITICAL, $message)); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $expectedMessage = substr($message, 0, 505); - - $this->assertRegexp('/message=' . $expectedMessage . '&title/', $content); - } - - public function testWriteWithHighPriority() - { - $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}&priority=1$/', $content); - } - - public function testWriteWithEmergencyPriority() - { - $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200$/', $content); - } - - public function testWriteToMultipleUsers() - { - $this->createHandler('myToken', array('userA', 'userB')); - $this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/token=myToken&user=userA&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200POST/', $content); - $this->assertRegexp('/token=myToken&user=userB&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200$/', $content); - } - - private function createHandler($token = 'myToken', $user = 'myUser', $title = 'Monolog') - { - $constructorArgs = array($token, $user, $title); - $this->res = fopen('php://memory', 'a'); - $this->handler = $this->getMock( - '\Monolog\Handler\PushoverHandler', - array('fsockopen', 'streamSetTimeout', 'closeSocket'), - $constructorArgs - ); - - $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, 'localhost:1234'); - - $this->handler->expects($this->any()) - ->method('fsockopen') - ->will($this->returnValue($this->res)); - $this->handler->expects($this->any()) - ->method('streamSetTimeout') - ->will($this->returnValue(true)); - $this->handler->expects($this->any()) - ->method('closeSocket') - ->will($this->returnValue(true)); - - $this->handler->setFormatter($this->getIdentityFormatter()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php deleted file mode 100644 index 26d212b9..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php +++ /dev/null @@ -1,255 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; -use Monolog\Formatter\LineFormatter; - -class RavenHandlerTest extends TestCase -{ - public function setUp() - { - if (!class_exists('Raven_Client')) { - $this->markTestSkipped('raven/raven not installed'); - } - - require_once __DIR__ . '/MockRavenClient.php'; - } - - /** - * @covers Monolog\Handler\RavenHandler::__construct - */ - public function testConstruct() - { - $handler = new RavenHandler($this->getRavenClient()); - $this->assertInstanceOf('Monolog\Handler\RavenHandler', $handler); - } - - protected function getHandler($ravenClient) - { - $handler = new RavenHandler($ravenClient); - - return $handler; - } - - protected function getRavenClient() - { - $dsn = 'http://43f6017361224d098402974103bfc53d:a6a0538fc2934ba2bed32e08741b2cd3@marca.python.live.cheggnet.com:9000/1'; - - return new MockRavenClient($dsn); - } - - public function testDebug() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $record = $this->getRecord(Logger::DEBUG, 'A test debug message'); - $handler->handle($record); - - $this->assertEquals($ravenClient::DEBUG, $ravenClient->lastData['level']); - $this->assertContains($record['message'], $ravenClient->lastData['message']); - } - - public function testWarning() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $record = $this->getRecord(Logger::WARNING, 'A test warning message'); - $handler->handle($record); - - $this->assertEquals($ravenClient::WARNING, $ravenClient->lastData['level']); - $this->assertContains($record['message'], $ravenClient->lastData['message']); - } - - public function testTag() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $tags = array(1, 2, 'foo'); - $record = $this->getRecord(Logger::INFO, 'test', array('tags' => $tags)); - $handler->handle($record); - - $this->assertEquals($tags, $ravenClient->lastData['tags']); - } - - public function testExtraParameters() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $checksum = '098f6bcd4621d373cade4e832627b4f6'; - $release = '05a671c66aefea124cc08b76ea6d30bb'; - $eventId = '31423'; - $record = $this->getRecord(Logger::INFO, 'test', array('checksum' => $checksum, 'release' => $release, 'event_id' => $eventId)); - $handler->handle($record); - - $this->assertEquals($checksum, $ravenClient->lastData['checksum']); - $this->assertEquals($release, $ravenClient->lastData['release']); - $this->assertEquals($eventId, $ravenClient->lastData['event_id']); - } - - public function testFingerprint() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $fingerprint = array('{{ default }}', 'other value'); - $record = $this->getRecord(Logger::INFO, 'test', array('fingerprint' => $fingerprint)); - $handler->handle($record); - - $this->assertEquals($fingerprint, $ravenClient->lastData['fingerprint']); - } - - public function testUserContext() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $recordWithNoContext = $this->getRecord(Logger::INFO, 'test with default user context'); - // set user context 'externally' - - $user = array( - 'id' => '123', - 'email' => 'test@test.com', - ); - - $recordWithContext = $this->getRecord(Logger::INFO, 'test', array('user' => $user)); - - $ravenClient->user_context(array('id' => 'test_user_id')); - // handle context - $handler->handle($recordWithContext); - $this->assertEquals($user, $ravenClient->lastData['user']); - - // check to see if its reset - $handler->handle($recordWithNoContext); - $this->assertInternalType('array', $ravenClient->context->user); - $this->assertSame('test_user_id', $ravenClient->context->user['id']); - - // handle with null context - $ravenClient->user_context(null); - $handler->handle($recordWithContext); - $this->assertEquals($user, $ravenClient->lastData['user']); - - // check to see if its reset - $handler->handle($recordWithNoContext); - $this->assertNull($ravenClient->context->user); - } - - public function testException() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - try { - $this->methodThatThrowsAnException(); - } catch (\Exception $e) { - $record = $this->getRecord(Logger::ERROR, $e->getMessage(), array('exception' => $e)); - $handler->handle($record); - } - - $this->assertEquals($record['message'], $ravenClient->lastData['message']); - } - - public function testHandleBatch() - { - $records = $this->getMultipleRecords(); - $records[] = $this->getRecord(Logger::WARNING, 'warning'); - $records[] = $this->getRecord(Logger::WARNING, 'warning'); - - $logFormatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); - $logFormatter->expects($this->once())->method('formatBatch'); - - $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); - $formatter->expects($this->once())->method('format')->with($this->callback(function ($record) { - return $record['level'] == 400; - })); - - $handler = $this->getHandler($this->getRavenClient()); - $handler->setBatchFormatter($logFormatter); - $handler->setFormatter($formatter); - $handler->handleBatch($records); - } - - public function testHandleBatchDoNothingIfRecordsAreBelowLevel() - { - $records = array( - $this->getRecord(Logger::DEBUG, 'debug message 1'), - $this->getRecord(Logger::DEBUG, 'debug message 2'), - $this->getRecord(Logger::INFO, 'information'), - ); - - $handler = $this->getMock('Monolog\Handler\RavenHandler', null, array($this->getRavenClient())); - $handler->expects($this->never())->method('handle'); - $handler->setLevel(Logger::ERROR); - $handler->handleBatch($records); - } - - public function testHandleBatchPicksProperMessage() - { - $records = array( - $this->getRecord(Logger::DEBUG, 'debug message 1'), - $this->getRecord(Logger::DEBUG, 'debug message 2'), - $this->getRecord(Logger::INFO, 'information 1'), - $this->getRecord(Logger::ERROR, 'error 1'), - $this->getRecord(Logger::WARNING, 'warning'), - $this->getRecord(Logger::ERROR, 'error 2'), - $this->getRecord(Logger::INFO, 'information 2'), - ); - - $logFormatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); - $logFormatter->expects($this->once())->method('formatBatch'); - - $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); - $formatter->expects($this->once())->method('format')->with($this->callback(function ($record) use ($records) { - return $record['message'] == 'error 1'; - })); - - $handler = $this->getHandler($this->getRavenClient()); - $handler->setBatchFormatter($logFormatter); - $handler->setFormatter($formatter); - $handler->handleBatch($records); - } - - public function testGetSetBatchFormatter() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $handler->setBatchFormatter($formatter = new LineFormatter()); - $this->assertSame($formatter, $handler->getBatchFormatter()); - } - - public function testRelease() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - $release = 'v42.42.42'; - $handler->setRelease($release); - $record = $this->getRecord(Logger::INFO, 'test'); - $handler->handle($record); - $this->assertEquals($release, $ravenClient->lastData['release']); - - $localRelease = 'v41.41.41'; - $record = $this->getRecord(Logger::INFO, 'test', array('release' => $localRelease)); - $handler->handle($record); - $this->assertEquals($localRelease, $ravenClient->lastData['release']); - } - - private function methodThatThrowsAnException() - { - throw new \Exception('This is an exception'); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php deleted file mode 100644 index 689d5278..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php +++ /dev/null @@ -1,127 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; -use Monolog\Formatter\LineFormatter; - -class RedisHandlerTest extends TestCase -{ - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorShouldThrowExceptionForInvalidRedis() - { - new RedisHandler(new \stdClass(), 'key'); - } - - public function testConstructorShouldWorkWithPredis() - { - $redis = $this->getMock('Predis\Client'); - $this->assertInstanceof('Monolog\Handler\RedisHandler', new RedisHandler($redis, 'key')); - } - - public function testConstructorShouldWorkWithRedis() - { - $redis = $this->getMock('Redis'); - $this->assertInstanceof('Monolog\Handler\RedisHandler', new RedisHandler($redis, 'key')); - } - - public function testPredisHandle() - { - $redis = $this->getMock('Predis\Client', array('rpush')); - - // Predis\Client uses rpush - $redis->expects($this->once()) - ->method('rpush') - ->with('key', 'test'); - - $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); - - $handler = new RedisHandler($redis, 'key'); - $handler->setFormatter(new LineFormatter("%message%")); - $handler->handle($record); - } - - public function testRedisHandle() - { - $redis = $this->getMock('Redis', array('rpush')); - - // Redis uses rPush - $redis->expects($this->once()) - ->method('rPush') - ->with('key', 'test'); - - $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); - - $handler = new RedisHandler($redis, 'key'); - $handler->setFormatter(new LineFormatter("%message%")); - $handler->handle($record); - } - - public function testRedisHandleCapped() - { - $redis = $this->getMock('Redis', array('multi', 'rpush', 'ltrim', 'exec')); - - // Redis uses multi - $redis->expects($this->once()) - ->method('multi') - ->will($this->returnSelf()); - - $redis->expects($this->once()) - ->method('rpush') - ->will($this->returnSelf()); - - $redis->expects($this->once()) - ->method('ltrim') - ->will($this->returnSelf()); - - $redis->expects($this->once()) - ->method('exec') - ->will($this->returnSelf()); - - $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); - - $handler = new RedisHandler($redis, 'key', Logger::DEBUG, true, 10); - $handler->setFormatter(new LineFormatter("%message%")); - $handler->handle($record); - } - - public function testPredisHandleCapped() - { - $redis = $this->getMock('Predis\Client', array('transaction')); - - $redisTransaction = $this->getMock('Predis\Client', array('rpush', 'ltrim')); - - $redisTransaction->expects($this->once()) - ->method('rpush') - ->will($this->returnSelf()); - - $redisTransaction->expects($this->once()) - ->method('ltrim') - ->will($this->returnSelf()); - - // Redis uses multi - $redis->expects($this->once()) - ->method('transaction') - ->will($this->returnCallback(function ($cb) use ($redisTransaction) { - $cb($redisTransaction); - })); - - $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); - - $handler = new RedisHandler($redis, 'key', Logger::DEBUG, true, 10); - $handler->setFormatter(new LineFormatter("%message%")); - $handler->handle($record); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/RollbarHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/RollbarHandlerTest.php deleted file mode 100644 index f302e917..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/RollbarHandlerTest.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Exception; -use Monolog\TestCase; -use Monolog\Logger; -use PHPUnit_Framework_MockObject_MockObject as MockObject; - -/** - * @author Erik Johansson - * @see https://rollbar.com/docs/notifier/rollbar-php/ - * - * @coversDefaultClass Monolog\Handler\RollbarHandler - */ -class RollbarHandlerTest extends TestCase -{ - /** - * @var MockObject - */ - private $rollbarNotifier; - - /** - * @var array - */ - public $reportedExceptionArguments = null; - - protected function setUp() - { - parent::setUp(); - - $this->setupRollbarNotifierMock(); - } - - /** - * When reporting exceptions to Rollbar the - * level has to be set in the payload data - */ - public function testExceptionLogLevel() - { - $handler = $this->createHandler(); - - $handler->handle($this->createExceptionRecord(Logger::DEBUG)); - - $this->assertEquals('debug', $this->reportedExceptionArguments['payload']['level']); - } - - private function setupRollbarNotifierMock() - { - $this->rollbarNotifier = $this->getMockBuilder('RollbarNotifier') - ->setMethods(array('report_message', 'report_exception', 'flush')) - ->getMock(); - - $that = $this; - - $this->rollbarNotifier - ->expects($this->any()) - ->method('report_exception') - ->willReturnCallback(function ($exception, $context, $payload) use ($that) { - $that->reportedExceptionArguments = compact('exception', 'context', 'payload'); - }); - } - - private function createHandler() - { - return new RollbarHandler($this->rollbarNotifier, Logger::DEBUG); - } - - private function createExceptionRecord($level = Logger::DEBUG, $message = 'test', $exception = null) - { - return $this->getRecord($level, $message, array( - 'exception' => $exception ?: new Exception() - )); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php deleted file mode 100644 index f1feb228..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ /dev/null @@ -1,211 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use PHPUnit_Framework_Error_Deprecated; - -/** - * @covers Monolog\Handler\RotatingFileHandler - */ -class RotatingFileHandlerTest extends TestCase -{ - /** - * This var should be private but then the anonymous function - * in the `setUp` method won't be able to set it. `$this` cant't - * be used in the anonymous function in `setUp` because PHP 5.3 - * does not support it. - */ - public $lastError; - - public function setUp() - { - $dir = __DIR__.'/Fixtures'; - chmod($dir, 0777); - if (!is_writable($dir)) { - $this->markTestSkipped($dir.' must be writable to test the RotatingFileHandler.'); - } - $this->lastError = null; - $self = $this; - // workaround with &$self used for PHP 5.3 - set_error_handler(function($code, $message) use (&$self) { - $self->lastError = array( - 'code' => $code, - 'message' => $message, - ); - }); - } - - private function assertErrorWasTriggered($code, $message) - { - if (empty($this->lastError)) { - $this->fail( - sprintf( - 'Failed asserting that error with code `%d` and message `%s` was triggered', - $code, - $message - ) - ); - } - $this->assertEquals($code, $this->lastError['code'], sprintf('Expected an error with code %d to be triggered, got `%s` instead', $code, $this->lastError['code'])); - $this->assertEquals($message, $this->lastError['message'], sprintf('Expected an error with message `%d` to be triggered, got `%s` instead', $message, $this->lastError['message'])); - } - - public function testRotationCreatesNewFile() - { - touch(__DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400).'.rot'); - - $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot'); - $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord()); - - $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot'; - $this->assertTrue(file_exists($log)); - $this->assertEquals('test', file_get_contents($log)); - } - - /** - * @dataProvider rotationTests - */ - public function testRotation($createFile, $dateFormat, $timeCallback) - { - touch($old1 = __DIR__.'/Fixtures/foo-'.date($dateFormat, $timeCallback(-1)).'.rot'); - touch($old2 = __DIR__.'/Fixtures/foo-'.date($dateFormat, $timeCallback(-2)).'.rot'); - touch($old3 = __DIR__.'/Fixtures/foo-'.date($dateFormat, $timeCallback(-3)).'.rot'); - touch($old4 = __DIR__.'/Fixtures/foo-'.date($dateFormat, $timeCallback(-4)).'.rot'); - - $log = __DIR__.'/Fixtures/foo-'.date($dateFormat).'.rot'; - - if ($createFile) { - touch($log); - } - - $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2); - $handler->setFormatter($this->getIdentityFormatter()); - $handler->setFilenameFormat('{filename}-{date}', $dateFormat); - $handler->handle($this->getRecord()); - - $handler->close(); - - $this->assertTrue(file_exists($log)); - $this->assertTrue(file_exists($old1)); - $this->assertEquals($createFile, file_exists($old2)); - $this->assertEquals($createFile, file_exists($old3)); - $this->assertEquals($createFile, file_exists($old4)); - $this->assertEquals('test', file_get_contents($log)); - } - - public function rotationTests() - { - $now = time(); - $dayCallback = function($ago) use ($now) { - return $now + 86400 * $ago; - }; - $monthCallback = function($ago) { - return gmmktime(0, 0, 0, date('n') + $ago, 1, date('Y')); - }; - $yearCallback = function($ago) { - return gmmktime(0, 0, 0, 1, 1, date('Y') + $ago); - }; - - return array( - 'Rotation is triggered when the file of the current day is not present' - => array(true, RotatingFileHandler::FILE_PER_DAY, $dayCallback), - 'Rotation is not triggered when the file of the current day is already present' - => array(false, RotatingFileHandler::FILE_PER_DAY, $dayCallback), - - 'Rotation is triggered when the file of the current month is not present' - => array(true, RotatingFileHandler::FILE_PER_MONTH, $monthCallback), - 'Rotation is not triggered when the file of the current month is already present' - => array(false, RotatingFileHandler::FILE_PER_MONTH, $monthCallback), - - 'Rotation is triggered when the file of the current year is not present' - => array(true, RotatingFileHandler::FILE_PER_YEAR, $yearCallback), - 'Rotation is not triggered when the file of the current year is already present' - => array(false, RotatingFileHandler::FILE_PER_YEAR, $yearCallback), - ); - } - - /** - * @dataProvider dateFormatProvider - */ - public function testAllowOnlyFixedDefinedDateFormats($dateFormat, $valid) - { - $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2); - $handler->setFilenameFormat('{filename}-{date}', $dateFormat); - if (!$valid) { - $this->assertErrorWasTriggered( - E_USER_DEPRECATED, - 'Invalid date format - format must be one of RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), '. - 'RotatingFileHandler::FILE_PER_MONTH ("Y-m") or RotatingFileHandler::FILE_PER_YEAR ("Y"), '. - 'or you can set one of the date formats using slashes, underscores and/or dots instead of dashes.' - ); - } - } - - public function dateFormatProvider() - { - return array( - array(RotatingFileHandler::FILE_PER_DAY, true), - array(RotatingFileHandler::FILE_PER_MONTH, true), - array(RotatingFileHandler::FILE_PER_YEAR, true), - array('m-d-Y', false), - array('Y-m-d-h-i', false) - ); - } - - /** - * @dataProvider filenameFormatProvider - */ - public function testDisallowFilenameFormatsWithoutDate($filenameFormat, $valid) - { - $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2); - $handler->setFilenameFormat($filenameFormat, RotatingFileHandler::FILE_PER_DAY); - if (!$valid) { - $this->assertErrorWasTriggered( - E_USER_DEPRECATED, - 'Invalid filename format - format should contain at least `{date}`, because otherwise rotating is impossible.' - ); - } - } - - public function filenameFormatProvider() - { - return array( - array('{filename}', false), - array('{filename}-{date}', true), - array('{date}', true), - array('foobar-{date}', true), - array('foo-{date}-bar', true), - array('{date}-foobar', true), - array('foobar', false), - ); - } - - public function testReuseCurrentFile() - { - $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot'; - file_put_contents($log, "foo"); - $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot'); - $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord()); - $this->assertEquals('footest', file_get_contents($log)); - } - - public function tearDown() - { - foreach (glob(__DIR__.'/Fixtures/*.rot') as $file) { - unlink($file); - } - restore_error_handler(); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SamplingHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SamplingHandlerTest.php deleted file mode 100644 index b354cee1..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/SamplingHandlerTest.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; - -/** - * @covers Monolog\Handler\SamplingHandler::handle - */ -class SamplingHandlerTest extends TestCase -{ - public function testHandle() - { - $testHandler = new TestHandler(); - $handler = new SamplingHandler($testHandler, 2); - for ($i = 0; $i < 10000; $i++) { - $handler->handle($this->getRecord()); - } - $count = count($testHandler->getRecords()); - // $count should be half of 10k, so between 4k and 6k - $this->assertLessThan(6000, $count); - $this->assertGreaterThan(4000, $count); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/Slack/SlackRecordTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/Slack/SlackRecordTest.php deleted file mode 100644 index e1aa96d7..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/Slack/SlackRecordTest.php +++ /dev/null @@ -1,387 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler\Slack; - -use Monolog\Logger; -use Monolog\TestCase; - -/** - * @coversDefaultClass Monolog\Handler\Slack\SlackRecord - */ -class SlackRecordTest extends TestCase -{ - private $jsonPrettyPrintFlag; - - protected function setUp() - { - $this->jsonPrettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128; - } - - public function dataGetAttachmentColor() - { - return array( - array(Logger::DEBUG, SlackRecord::COLOR_DEFAULT), - array(Logger::INFO, SlackRecord::COLOR_GOOD), - array(Logger::NOTICE, SlackRecord::COLOR_GOOD), - array(Logger::WARNING, SlackRecord::COLOR_WARNING), - array(Logger::ERROR, SlackRecord::COLOR_DANGER), - array(Logger::CRITICAL, SlackRecord::COLOR_DANGER), - array(Logger::ALERT, SlackRecord::COLOR_DANGER), - array(Logger::EMERGENCY, SlackRecord::COLOR_DANGER), - ); - } - - /** - * @dataProvider dataGetAttachmentColor - * @param int $logLevel - * @param string $expectedColour RGB hex color or name of Slack color - * @covers ::getAttachmentColor - */ - public function testGetAttachmentColor($logLevel, $expectedColour) - { - $slackRecord = new SlackRecord(); - $this->assertSame( - $expectedColour, - $slackRecord->getAttachmentColor($logLevel) - ); - } - - public function testAddsChannel() - { - $channel = '#test'; - $record = new SlackRecord($channel); - $data = $record->getSlackData($this->getRecord()); - - $this->assertArrayHasKey('channel', $data); - $this->assertSame($channel, $data['channel']); - } - - public function testNoUsernameByDefault() - { - $record = new SlackRecord(); - $data = $record->getSlackData($this->getRecord()); - - $this->assertArrayNotHasKey('username', $data); - } - - /** - * @return array - */ - public function dataStringify() - { - $jsonPrettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128; - - $multipleDimensions = array(array(1, 2)); - $numericKeys = array('library' => 'monolog'); - $singleDimension = array(1, 'Hello', 'Jordi'); - - return array( - array(array(), '[]'), - array($multipleDimensions, json_encode($multipleDimensions, $jsonPrettyPrintFlag)), - array($numericKeys, json_encode($numericKeys, $jsonPrettyPrintFlag)), - array($singleDimension, json_encode($singleDimension)) - ); - } - - /** - * @dataProvider dataStringify - */ - public function testStringify($fields, $expectedResult) - { - $slackRecord = new SlackRecord( - '#test', - 'test', - true, - null, - true, - true - ); - - $this->assertSame($expectedResult, $slackRecord->stringify($fields)); - } - - public function testAddsCustomUsername() - { - $username = 'Monolog bot'; - $record = new SlackRecord(null, $username); - $data = $record->getSlackData($this->getRecord()); - - $this->assertArrayHasKey('username', $data); - $this->assertSame($username, $data['username']); - } - - public function testNoIcon() - { - $record = new SlackRecord(); - $data = $record->getSlackData($this->getRecord()); - - $this->assertArrayNotHasKey('icon_emoji', $data); - } - - public function testAddsIcon() - { - $record = $this->getRecord(); - $slackRecord = new SlackRecord(null, null, false, 'ghost'); - $data = $slackRecord->getSlackData($record); - - $slackRecord2 = new SlackRecord(null, null, false, 'http://github.com/Seldaek/monolog'); - $data2 = $slackRecord2->getSlackData($record); - - $this->assertArrayHasKey('icon_emoji', $data); - $this->assertSame(':ghost:', $data['icon_emoji']); - $this->assertArrayHasKey('icon_url', $data2); - $this->assertSame('http://github.com/Seldaek/monolog', $data2['icon_url']); - } - - public function testAttachmentsNotPresentIfNoAttachment() - { - $record = new SlackRecord(null, null, false); - $data = $record->getSlackData($this->getRecord()); - - $this->assertArrayNotHasKey('attachments', $data); - } - - public function testAddsOneAttachment() - { - $record = new SlackRecord(); - $data = $record->getSlackData($this->getRecord()); - - $this->assertArrayHasKey('attachments', $data); - $this->assertArrayHasKey(0, $data['attachments']); - $this->assertInternalType('array', $data['attachments'][0]); - } - - public function testTextEqualsMessageIfNoAttachment() - { - $message = 'Test message'; - $record = new SlackRecord(null, null, false); - $data = $record->getSlackData($this->getRecord(Logger::WARNING, $message)); - - $this->assertArrayHasKey('text', $data); - $this->assertSame($message, $data['text']); - } - - public function testTextEqualsFormatterOutput() - { - $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); - $formatter - ->expects($this->any()) - ->method('format') - ->will($this->returnCallback(function ($record) { return $record['message'] . 'test'; })); - - $formatter2 = $this->getMock('Monolog\\Formatter\\FormatterInterface'); - $formatter2 - ->expects($this->any()) - ->method('format') - ->will($this->returnCallback(function ($record) { return $record['message'] . 'test1'; })); - - $message = 'Test message'; - $record = new SlackRecord(null, null, false, null, false, false, array(), $formatter); - $data = $record->getSlackData($this->getRecord(Logger::WARNING, $message)); - - $this->assertArrayHasKey('text', $data); - $this->assertSame($message . 'test', $data['text']); - - $record->setFormatter($formatter2); - $data = $record->getSlackData($this->getRecord(Logger::WARNING, $message)); - - $this->assertArrayHasKey('text', $data); - $this->assertSame($message . 'test1', $data['text']); - } - - public function testAddsFallbackAndTextToAttachment() - { - $message = 'Test message'; - $record = new SlackRecord(null); - $data = $record->getSlackData($this->getRecord(Logger::WARNING, $message)); - - $this->assertSame($message, $data['attachments'][0]['text']); - $this->assertSame($message, $data['attachments'][0]['fallback']); - } - - public function testMapsLevelToColorAttachmentColor() - { - $record = new SlackRecord(null); - $errorLoggerRecord = $this->getRecord(Logger::ERROR); - $emergencyLoggerRecord = $this->getRecord(Logger::EMERGENCY); - $warningLoggerRecord = $this->getRecord(Logger::WARNING); - $infoLoggerRecord = $this->getRecord(Logger::INFO); - $debugLoggerRecord = $this->getRecord(Logger::DEBUG); - - $data = $record->getSlackData($errorLoggerRecord); - $this->assertSame(SlackRecord::COLOR_DANGER, $data['attachments'][0]['color']); - - $data = $record->getSlackData($emergencyLoggerRecord); - $this->assertSame(SlackRecord::COLOR_DANGER, $data['attachments'][0]['color']); - - $data = $record->getSlackData($warningLoggerRecord); - $this->assertSame(SlackRecord::COLOR_WARNING, $data['attachments'][0]['color']); - - $data = $record->getSlackData($infoLoggerRecord); - $this->assertSame(SlackRecord::COLOR_GOOD, $data['attachments'][0]['color']); - - $data = $record->getSlackData($debugLoggerRecord); - $this->assertSame(SlackRecord::COLOR_DEFAULT, $data['attachments'][0]['color']); - } - - public function testAddsShortAttachmentWithoutContextAndExtra() - { - $level = Logger::ERROR; - $levelName = Logger::getLevelName($level); - $record = new SlackRecord(null, null, true, null, true); - $data = $record->getSlackData($this->getRecord($level, 'test', array('test' => 1))); - - $attachment = $data['attachments'][0]; - $this->assertArrayHasKey('title', $attachment); - $this->assertArrayHasKey('fields', $attachment); - $this->assertSame($levelName, $attachment['title']); - $this->assertSame(array(), $attachment['fields']); - } - - public function testAddsShortAttachmentWithContextAndExtra() - { - $level = Logger::ERROR; - $levelName = Logger::getLevelName($level); - $context = array('test' => 1); - $extra = array('tags' => array('web')); - $record = new SlackRecord(null, null, true, null, true, true); - $loggerRecord = $this->getRecord($level, 'test', $context); - $loggerRecord['extra'] = $extra; - $data = $record->getSlackData($loggerRecord); - - $attachment = $data['attachments'][0]; - $this->assertArrayHasKey('title', $attachment); - $this->assertArrayHasKey('fields', $attachment); - $this->assertCount(2, $attachment['fields']); - $this->assertSame($levelName, $attachment['title']); - $this->assertSame( - array( - array( - 'title' => 'Extra', - 'value' => sprintf('```%s```', json_encode($extra, $this->jsonPrettyPrintFlag)), - 'short' => false - ), - array( - 'title' => 'Context', - 'value' => sprintf('```%s```', json_encode($context, $this->jsonPrettyPrintFlag)), - 'short' => false - ) - ), - $attachment['fields'] - ); - } - - public function testAddsLongAttachmentWithoutContextAndExtra() - { - $level = Logger::ERROR; - $levelName = Logger::getLevelName($level); - $record = new SlackRecord(null, null, true, null); - $data = $record->getSlackData($this->getRecord($level, 'test', array('test' => 1))); - - $attachment = $data['attachments'][0]; - $this->assertArrayHasKey('title', $attachment); - $this->assertArrayHasKey('fields', $attachment); - $this->assertCount(1, $attachment['fields']); - $this->assertSame('Message', $attachment['title']); - $this->assertSame( - array(array( - 'title' => 'Level', - 'value' => $levelName, - 'short' => false - )), - $attachment['fields'] - ); - } - - public function testAddsLongAttachmentWithContextAndExtra() - { - $level = Logger::ERROR; - $levelName = Logger::getLevelName($level); - $context = array('test' => 1); - $extra = array('tags' => array('web')); - $record = new SlackRecord(null, null, true, null, false, true); - $loggerRecord = $this->getRecord($level, 'test', $context); - $loggerRecord['extra'] = $extra; - $data = $record->getSlackData($loggerRecord); - - $expectedFields = array( - array( - 'title' => 'Level', - 'value' => $levelName, - 'short' => false, - ), - array( - 'title' => 'tags', - 'value' => sprintf('```%s```', json_encode($extra['tags'])), - 'short' => false - ), - array( - 'title' => 'test', - 'value' => $context['test'], - 'short' => false - ) - ); - - $attachment = $data['attachments'][0]; - $this->assertArrayHasKey('title', $attachment); - $this->assertArrayHasKey('fields', $attachment); - $this->assertCount(3, $attachment['fields']); - $this->assertSame('Message', $attachment['title']); - $this->assertSame( - $expectedFields, - $attachment['fields'] - ); - } - - public function testAddsTimestampToAttachment() - { - $record = $this->getRecord(); - $slackRecord = new SlackRecord(); - $data = $slackRecord->getSlackData($this->getRecord()); - - $attachment = $data['attachments'][0]; - $this->assertArrayHasKey('ts', $attachment); - $this->assertSame($record['datetime']->getTimestamp(), $attachment['ts']); - } - - public function testExcludeExtraAndContextFields() - { - $record = $this->getRecord( - Logger::WARNING, - 'test', - array('info' => array('library' => 'monolog', 'author' => 'Jordi')) - ); - $record['extra'] = array('tags' => array('web', 'cli')); - - $slackRecord = new SlackRecord(null, null, true, null, false, true, array('context.info.library', 'extra.tags.1')); - $data = $slackRecord->getSlackData($record); - $attachment = $data['attachments'][0]; - - $expected = array( - array( - 'title' => 'info', - 'value' => sprintf('```%s```', json_encode(array('author' => 'Jordi'), $this->jsonPrettyPrintFlag)), - 'short' => false - ), - array( - 'title' => 'tags', - 'value' => sprintf('```%s```', json_encode(array('web'))), - 'short' => false - ), - ); - - foreach ($expected as $field) { - $this->assertNotFalse(array_search($field, $attachment['fields'])); - break; - } - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SlackHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SlackHandlerTest.php deleted file mode 100644 index b12b01f4..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/SlackHandlerTest.php +++ /dev/null @@ -1,155 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; -use Monolog\Formatter\LineFormatter; -use Monolog\Handler\Slack\SlackRecord; - -/** - * @author Greg Kedzierski - * @see https://api.slack.com/ - */ -class SlackHandlerTest extends TestCase -{ - /** - * @var resource - */ - private $res; - - /** - * @var SlackHandler - */ - private $handler; - - public function setUp() - { - if (!extension_loaded('openssl')) { - $this->markTestSkipped('This test requires openssl to run'); - } - } - - public function testWriteHeader() - { - $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/POST \/api\/chat.postMessage HTTP\/1.1\\r\\nHost: slack.com\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); - } - - public function testWriteContent() - { - $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegExp('/username=Monolog/', $content); - $this->assertRegExp('/channel=channel1/', $content); - $this->assertRegExp('/token=myToken/', $content); - $this->assertRegExp('/attachments/', $content); - } - - public function testWriteContentUsesFormatterIfProvided() - { - $this->createHandler('myToken', 'channel1', 'Monolog', false); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->createHandler('myToken', 'channel1', 'Monolog', false); - $this->handler->setFormatter(new LineFormatter('foo--%message%')); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test2')); - fseek($this->res, 0); - $content2 = fread($this->res, 1024); - - $this->assertRegexp('/text=test1/', $content); - $this->assertRegexp('/text=foo--test2/', $content2); - } - - public function testWriteContentWithEmoji() - { - $this->createHandler('myToken', 'channel1', 'Monolog', true, 'alien'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/icon_emoji=%3Aalien%3A/', $content); - } - - /** - * @dataProvider provideLevelColors - */ - public function testWriteContentWithColors($level, $expectedColor) - { - $this->createHandler(); - $this->handler->handle($this->getRecord($level, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/%22color%22%3A%22'.$expectedColor.'/', $content); - } - - public function testWriteContentWithPlainTextMessage() - { - $this->createHandler('myToken', 'channel1', 'Monolog', false); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - fseek($this->res, 0); - $content = fread($this->res, 1024); - - $this->assertRegexp('/text=test1/', $content); - } - - public function provideLevelColors() - { - return array( - array(Logger::DEBUG, urlencode(SlackRecord::COLOR_DEFAULT)), - array(Logger::INFO, SlackRecord::COLOR_GOOD), - array(Logger::NOTICE, SlackRecord::COLOR_GOOD), - array(Logger::WARNING, SlackRecord::COLOR_WARNING), - array(Logger::ERROR, SlackRecord::COLOR_DANGER), - array(Logger::CRITICAL, SlackRecord::COLOR_DANGER), - array(Logger::ALERT, SlackRecord::COLOR_DANGER), - array(Logger::EMERGENCY,SlackRecord::COLOR_DANGER), - ); - } - - private function createHandler($token = 'myToken', $channel = 'channel1', $username = 'Monolog', $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeExtra = false) - { - $constructorArgs = array($token, $channel, $username, $useAttachment, $iconEmoji, Logger::DEBUG, true, $useShortAttachment, $includeExtra); - $this->res = fopen('php://memory', 'a'); - $this->handler = $this->getMock( - '\Monolog\Handler\SlackHandler', - array('fsockopen', 'streamSetTimeout', 'closeSocket'), - $constructorArgs - ); - - $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, 'localhost:1234'); - - $this->handler->expects($this->any()) - ->method('fsockopen') - ->will($this->returnValue($this->res)); - $this->handler->expects($this->any()) - ->method('streamSetTimeout') - ->will($this->returnValue(true)); - $this->handler->expects($this->any()) - ->method('closeSocket') - ->will($this->returnValue(true)); - - $this->handler->setFormatter($this->getIdentityFormatter()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SlackWebhookHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SlackWebhookHandlerTest.php deleted file mode 100644 index c9229e26..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/SlackWebhookHandlerTest.php +++ /dev/null @@ -1,107 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; -use Monolog\Formatter\LineFormatter; -use Monolog\Handler\Slack\SlackRecord; - -/** - * @author Haralan Dobrev - * @see https://api.slack.com/incoming-webhooks - * @coversDefaultClass Monolog\Handler\SlackWebhookHandler - */ -class SlackWebhookHandlerTest extends TestCase -{ - const WEBHOOK_URL = 'https://hooks.slack.com/services/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E'; - - /** - * @covers ::__construct - * @covers ::getSlackRecord - */ - public function testConstructorMinimal() - { - $handler = new SlackWebhookHandler(self::WEBHOOK_URL); - $record = $this->getRecord(); - $slackRecord = $handler->getSlackRecord(); - $this->assertInstanceOf('Monolog\Handler\Slack\SlackRecord', $slackRecord); - $this->assertEquals(array( - 'attachments' => array( - array( - 'fallback' => 'test', - 'text' => 'test', - 'color' => SlackRecord::COLOR_WARNING, - 'fields' => array( - array( - 'title' => 'Level', - 'value' => 'WARNING', - 'short' => false, - ), - ), - 'title' => 'Message', - 'mrkdwn_in' => array('fields'), - 'ts' => $record['datetime']->getTimestamp(), - ), - ), - ), $slackRecord->getSlackData($record)); - } - - /** - * @covers ::__construct - * @covers ::getSlackRecord - */ - public function testConstructorFull() - { - $handler = new SlackWebhookHandler( - self::WEBHOOK_URL, - 'test-channel', - 'test-username', - false, - ':ghost:', - false, - false, - Logger::DEBUG, - false - ); - - $slackRecord = $handler->getSlackRecord(); - $this->assertInstanceOf('Monolog\Handler\Slack\SlackRecord', $slackRecord); - $this->assertEquals(array( - 'username' => 'test-username', - 'text' => 'test', - 'channel' => 'test-channel', - 'icon_emoji' => ':ghost:', - ), $slackRecord->getSlackData($this->getRecord())); - } - - /** - * @covers ::getFormatter - */ - public function testGetFormatter() - { - $handler = new SlackWebhookHandler(self::WEBHOOK_URL); - $formatter = $handler->getFormatter(); - $this->assertInstanceOf('Monolog\Formatter\FormatterInterface', $formatter); - } - - /** - * @covers ::setFormatter - */ - public function testSetFormatter() - { - $handler = new SlackWebhookHandler(self::WEBHOOK_URL); - $formatter = new LineFormatter(); - $handler->setFormatter($formatter); - $this->assertSame($formatter, $handler->getFormatter()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SlackbotHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SlackbotHandlerTest.php deleted file mode 100644 index b1b02bde..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/SlackbotHandlerTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @author Haralan Dobrev - * @see https://slack.com/apps/A0F81R8ET-slackbot - * @coversDefaultClass Monolog\Handler\SlackbotHandler - */ -class SlackbotHandlerTest extends TestCase -{ - /** - * @covers ::__construct - */ - public function testConstructorMinimal() - { - $handler = new SlackbotHandler('test-team', 'test-token', 'test-channel'); - $this->assertInstanceOf('Monolog\Handler\AbstractProcessingHandler', $handler); - } - - /** - * @covers ::__construct - */ - public function testConstructorFull() - { - $handler = new SlackbotHandler( - 'test-team', - 'test-token', - 'test-channel', - Logger::DEBUG, - false - ); - $this->assertInstanceOf('Monolog\Handler\AbstractProcessingHandler', $handler); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php deleted file mode 100644 index 1f9c1f28..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php +++ /dev/null @@ -1,309 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @author Pablo de Leon Belloc - */ -class SocketHandlerTest extends TestCase -{ - /** - * @var Monolog\Handler\SocketHandler - */ - private $handler; - - /** - * @var resource - */ - private $res; - - /** - * @expectedException UnexpectedValueException - */ - public function testInvalidHostname() - { - $this->createHandler('garbage://here'); - $this->writeRecord('data'); - } - - /** - * @expectedException \InvalidArgumentException - */ - public function testBadConnectionTimeout() - { - $this->createHandler('localhost:1234'); - $this->handler->setConnectionTimeout(-1); - } - - public function testSetConnectionTimeout() - { - $this->createHandler('localhost:1234'); - $this->handler->setConnectionTimeout(10.1); - $this->assertEquals(10.1, $this->handler->getConnectionTimeout()); - } - - /** - * @expectedException \InvalidArgumentException - */ - public function testBadTimeout() - { - $this->createHandler('localhost:1234'); - $this->handler->setTimeout(-1); - } - - public function testSetTimeout() - { - $this->createHandler('localhost:1234'); - $this->handler->setTimeout(10.25); - $this->assertEquals(10.25, $this->handler->getTimeout()); - } - - public function testSetWritingTimeout() - { - $this->createHandler('localhost:1234'); - $this->handler->setWritingTimeout(10.25); - $this->assertEquals(10.25, $this->handler->getWritingTimeout()); - } - - public function testSetConnectionString() - { - $this->createHandler('tcp://localhost:9090'); - $this->assertEquals('tcp://localhost:9090', $this->handler->getConnectionString()); - } - - /** - * @expectedException UnexpectedValueException - */ - public function testExceptionIsThrownOnFsockopenError() - { - $this->setMockHandler(array('fsockopen')); - $this->handler->expects($this->once()) - ->method('fsockopen') - ->will($this->returnValue(false)); - $this->writeRecord('Hello world'); - } - - /** - * @expectedException UnexpectedValueException - */ - public function testExceptionIsThrownOnPfsockopenError() - { - $this->setMockHandler(array('pfsockopen')); - $this->handler->expects($this->once()) - ->method('pfsockopen') - ->will($this->returnValue(false)); - $this->handler->setPersistent(true); - $this->writeRecord('Hello world'); - } - - /** - * @expectedException UnexpectedValueException - */ - public function testExceptionIsThrownIfCannotSetTimeout() - { - $this->setMockHandler(array('streamSetTimeout')); - $this->handler->expects($this->once()) - ->method('streamSetTimeout') - ->will($this->returnValue(false)); - $this->writeRecord('Hello world'); - } - - /** - * @expectedException RuntimeException - */ - public function testWriteFailsOnIfFwriteReturnsFalse() - { - $this->setMockHandler(array('fwrite')); - - $callback = function ($arg) { - $map = array( - 'Hello world' => 6, - 'world' => false, - ); - - return $map[$arg]; - }; - - $this->handler->expects($this->exactly(2)) - ->method('fwrite') - ->will($this->returnCallback($callback)); - - $this->writeRecord('Hello world'); - } - - /** - * @expectedException RuntimeException - */ - public function testWriteFailsIfStreamTimesOut() - { - $this->setMockHandler(array('fwrite', 'streamGetMetadata')); - - $callback = function ($arg) { - $map = array( - 'Hello world' => 6, - 'world' => 5, - ); - - return $map[$arg]; - }; - - $this->handler->expects($this->exactly(1)) - ->method('fwrite') - ->will($this->returnCallback($callback)); - $this->handler->expects($this->exactly(1)) - ->method('streamGetMetadata') - ->will($this->returnValue(array('timed_out' => true))); - - $this->writeRecord('Hello world'); - } - - /** - * @expectedException RuntimeException - */ - public function testWriteFailsOnIncompleteWrite() - { - $this->setMockHandler(array('fwrite', 'streamGetMetadata')); - - $res = $this->res; - $callback = function ($string) use ($res) { - fclose($res); - - return strlen('Hello'); - }; - - $this->handler->expects($this->exactly(1)) - ->method('fwrite') - ->will($this->returnCallback($callback)); - $this->handler->expects($this->exactly(1)) - ->method('streamGetMetadata') - ->will($this->returnValue(array('timed_out' => false))); - - $this->writeRecord('Hello world'); - } - - public function testWriteWithMemoryFile() - { - $this->setMockHandler(); - $this->writeRecord('test1'); - $this->writeRecord('test2'); - $this->writeRecord('test3'); - fseek($this->res, 0); - $this->assertEquals('test1test2test3', fread($this->res, 1024)); - } - - public function testWriteWithMock() - { - $this->setMockHandler(array('fwrite')); - - $callback = function ($arg) { - $map = array( - 'Hello world' => 6, - 'world' => 5, - ); - - return $map[$arg]; - }; - - $this->handler->expects($this->exactly(2)) - ->method('fwrite') - ->will($this->returnCallback($callback)); - - $this->writeRecord('Hello world'); - } - - public function testClose() - { - $this->setMockHandler(); - $this->writeRecord('Hello world'); - $this->assertInternalType('resource', $this->res); - $this->handler->close(); - $this->assertFalse(is_resource($this->res), "Expected resource to be closed after closing handler"); - } - - public function testCloseDoesNotClosePersistentSocket() - { - $this->setMockHandler(); - $this->handler->setPersistent(true); - $this->writeRecord('Hello world'); - $this->assertTrue(is_resource($this->res)); - $this->handler->close(); - $this->assertTrue(is_resource($this->res)); - } - - /** - * @expectedException \RuntimeException - */ - public function testAvoidInfiniteLoopWhenNoDataIsWrittenForAWritingTimeoutSeconds() - { - $this->setMockHandler(array('fwrite', 'streamGetMetadata')); - - $this->handler->expects($this->any()) - ->method('fwrite') - ->will($this->returnValue(0)); - - $this->handler->expects($this->any()) - ->method('streamGetMetadata') - ->will($this->returnValue(array('timed_out' => false))); - - $this->handler->setWritingTimeout(1); - - $this->writeRecord('Hello world'); - } - - private function createHandler($connectionString) - { - $this->handler = new SocketHandler($connectionString); - $this->handler->setFormatter($this->getIdentityFormatter()); - } - - private function writeRecord($string) - { - $this->handler->handle($this->getRecord(Logger::WARNING, $string)); - } - - private function setMockHandler(array $methods = array()) - { - $this->res = fopen('php://memory', 'a'); - - $defaultMethods = array('fsockopen', 'pfsockopen', 'streamSetTimeout'); - $newMethods = array_diff($methods, $defaultMethods); - - $finalMethods = array_merge($defaultMethods, $newMethods); - - $this->handler = $this->getMock( - '\Monolog\Handler\SocketHandler', $finalMethods, array('localhost:1234') - ); - - if (!in_array('fsockopen', $methods)) { - $this->handler->expects($this->any()) - ->method('fsockopen') - ->will($this->returnValue($this->res)); - } - - if (!in_array('pfsockopen', $methods)) { - $this->handler->expects($this->any()) - ->method('pfsockopen') - ->will($this->returnValue($this->res)); - } - - if (!in_array('streamSetTimeout', $methods)) { - $this->handler->expects($this->any()) - ->method('streamSetTimeout') - ->will($this->returnValue(true)); - } - - $this->handler->setFormatter($this->getIdentityFormatter()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php deleted file mode 100644 index 487030fe..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php +++ /dev/null @@ -1,184 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -class StreamHandlerTest extends TestCase -{ - /** - * @covers Monolog\Handler\StreamHandler::__construct - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWrite() - { - $handle = fopen('php://memory', 'a+'); - $handler = new StreamHandler($handle); - $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::WARNING, 'test')); - $handler->handle($this->getRecord(Logger::WARNING, 'test2')); - $handler->handle($this->getRecord(Logger::WARNING, 'test3')); - fseek($handle, 0); - $this->assertEquals('testtest2test3', fread($handle, 100)); - } - - /** - * @covers Monolog\Handler\StreamHandler::close - */ - public function testCloseKeepsExternalHandlersOpen() - { - $handle = fopen('php://memory', 'a+'); - $handler = new StreamHandler($handle); - $this->assertTrue(is_resource($handle)); - $handler->close(); - $this->assertTrue(is_resource($handle)); - } - - /** - * @covers Monolog\Handler\StreamHandler::close - */ - public function testClose() - { - $handler = new StreamHandler('php://memory'); - $handler->handle($this->getRecord(Logger::WARNING, 'test')); - $streamProp = new \ReflectionProperty('Monolog\Handler\StreamHandler', 'stream'); - $streamProp->setAccessible(true); - $handle = $streamProp->getValue($handler); - - $this->assertTrue(is_resource($handle)); - $handler->close(); - $this->assertFalse(is_resource($handle)); - } - - /** - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWriteCreatesTheStreamResource() - { - $handler = new StreamHandler('php://memory'); - $handler->handle($this->getRecord()); - } - - /** - * @covers Monolog\Handler\StreamHandler::__construct - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWriteLocking() - { - $temp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'monolog_locked_log'; - $handler = new StreamHandler($temp, Logger::DEBUG, true, null, true); - $handler->handle($this->getRecord()); - } - - /** - * @expectedException LogicException - * @covers Monolog\Handler\StreamHandler::__construct - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWriteMissingResource() - { - $handler = new StreamHandler(null); - $handler->handle($this->getRecord()); - } - - public function invalidArgumentProvider() - { - return array( - array(1), - array(array()), - array(array('bogus://url')), - ); - } - - /** - * @dataProvider invalidArgumentProvider - * @expectedException InvalidArgumentException - * @covers Monolog\Handler\StreamHandler::__construct - */ - public function testWriteInvalidArgument($invalidArgument) - { - $handler = new StreamHandler($invalidArgument); - } - - /** - * @expectedException UnexpectedValueException - * @covers Monolog\Handler\StreamHandler::__construct - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWriteInvalidResource() - { - $handler = new StreamHandler('bogus://url'); - $handler->handle($this->getRecord()); - } - - /** - * @expectedException UnexpectedValueException - * @covers Monolog\Handler\StreamHandler::__construct - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWriteNonExistingResource() - { - $handler = new StreamHandler('ftp://foo/bar/baz/'.rand(0, 10000)); - $handler->handle($this->getRecord()); - } - - /** - * @covers Monolog\Handler\StreamHandler::__construct - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWriteNonExistingPath() - { - $handler = new StreamHandler(sys_get_temp_dir().'/bar/'.rand(0, 10000).DIRECTORY_SEPARATOR.rand(0, 10000)); - $handler->handle($this->getRecord()); - } - - /** - * @covers Monolog\Handler\StreamHandler::__construct - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWriteNonExistingFileResource() - { - $handler = new StreamHandler('file://'.sys_get_temp_dir().'/bar/'.rand(0, 10000).DIRECTORY_SEPARATOR.rand(0, 10000)); - $handler->handle($this->getRecord()); - } - - /** - * @expectedException Exception - * @expectedExceptionMessageRegExp /There is no existing directory at/ - * @covers Monolog\Handler\StreamHandler::__construct - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWriteNonExistingAndNotCreatablePath() - { - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - $this->markTestSkipped('Permissions checks can not run on windows'); - } - $handler = new StreamHandler('/foo/bar/'.rand(0, 10000).DIRECTORY_SEPARATOR.rand(0, 10000)); - $handler->handle($this->getRecord()); - } - - /** - * @expectedException Exception - * @expectedExceptionMessageRegExp /There is no existing directory at/ - * @covers Monolog\Handler\StreamHandler::__construct - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWriteNonExistingAndNotCreatableFileResource() - { - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - $this->markTestSkipped('Permissions checks can not run on windows'); - } - $handler = new StreamHandler('file:///foo/bar/'.rand(0, 10000).DIRECTORY_SEPARATOR.rand(0, 10000)); - $handler->handle($this->getRecord()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SwiftMailerHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SwiftMailerHandlerTest.php deleted file mode 100644 index 1d62940f..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/SwiftMailerHandlerTest.php +++ /dev/null @@ -1,113 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Logger; -use Monolog\TestCase; - -class SwiftMailerHandlerTest extends TestCase -{ - /** @var \Swift_Mailer|\PHPUnit_Framework_MockObject_MockObject */ - private $mailer; - - public function setUp() - { - $this->mailer = $this - ->getMockBuilder('Swift_Mailer') - ->disableOriginalConstructor() - ->getMock(); - } - - public function testMessageCreationIsLazyWhenUsingCallback() - { - $this->mailer->expects($this->never()) - ->method('send'); - - $callback = function () { - throw new \RuntimeException('Swift_Message creation callback should not have been called in this test'); - }; - $handler = new SwiftMailerHandler($this->mailer, $callback); - - $records = array( - $this->getRecord(Logger::DEBUG), - $this->getRecord(Logger::INFO), - ); - $handler->handleBatch($records); - } - - public function testMessageCanBeCustomizedGivenLoggedData() - { - // Wire Mailer to expect a specific Swift_Message with a customized Subject - $expectedMessage = new \Swift_Message(); - $this->mailer->expects($this->once()) - ->method('send') - ->with($this->callback(function ($value) use ($expectedMessage) { - return $value instanceof \Swift_Message - && $value->getSubject() === 'Emergency' - && $value === $expectedMessage; - })); - - // Callback dynamically changes subject based on number of logged records - $callback = function ($content, array $records) use ($expectedMessage) { - $subject = count($records) > 0 ? 'Emergency' : 'Normal'; - $expectedMessage->setSubject($subject); - - return $expectedMessage; - }; - $handler = new SwiftMailerHandler($this->mailer, $callback); - - // Logging 1 record makes this an Emergency - $records = array( - $this->getRecord(Logger::EMERGENCY), - ); - $handler->handleBatch($records); - } - - public function testMessageSubjectFormatting() - { - // Wire Mailer to expect a specific Swift_Message with a customized Subject - $messageTemplate = new \Swift_Message(); - $messageTemplate->setSubject('Alert: %level_name% %message%'); - $receivedMessage = null; - - $this->mailer->expects($this->once()) - ->method('send') - ->with($this->callback(function ($value) use (&$receivedMessage) { - $receivedMessage = $value; - return true; - })); - - $handler = new SwiftMailerHandler($this->mailer, $messageTemplate); - - $records = array( - $this->getRecord(Logger::EMERGENCY), - ); - $handler->handleBatch($records); - - $this->assertEquals('Alert: EMERGENCY test', $receivedMessage->getSubject()); - } - - public function testMessageHaveUniqueId() - { - $messageTemplate = new \Swift_Message(); - $handler = new SwiftMailerHandler($this->mailer, $messageTemplate); - - $method = new \ReflectionMethod('Monolog\Handler\SwiftMailerHandler', 'buildMessage'); - $method->setAccessible(true); - $method->invokeArgs($handler, array($messageTemplate, array())); - - $builtMessage1 = $method->invoke($handler, $messageTemplate, array()); - $builtMessage2 = $method->invoke($handler, $messageTemplate, array()); - - $this->assertFalse($builtMessage1->getId() === $builtMessage2->getId(), 'Two different messages have the same id'); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php deleted file mode 100644 index 8f9e46bf..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Logger; - -class SyslogHandlerTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers Monolog\Handler\SyslogHandler::__construct - */ - public function testConstruct() - { - $handler = new SyslogHandler('test'); - $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler); - - $handler = new SyslogHandler('test', LOG_USER); - $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler); - - $handler = new SyslogHandler('test', 'user'); - $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler); - - $handler = new SyslogHandler('test', LOG_USER, Logger::DEBUG, true, LOG_PERROR); - $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler); - } - - /** - * @covers Monolog\Handler\SyslogHandler::__construct - */ - public function testConstructInvalidFacility() - { - $this->setExpectedException('UnexpectedValueException'); - $handler = new SyslogHandler('test', 'unknown'); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php deleted file mode 100644 index 7ee8a985..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ /dev/null @@ -1,76 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; - -/** - * @requires extension sockets - */ -class SyslogUdpHandlerTest extends TestCase -{ - /** - * @expectedException UnexpectedValueException - */ - public function testWeValidateFacilities() - { - $handler = new SyslogUdpHandler("ip", null, "invalidFacility"); - } - - public function testWeSplitIntoLines() - { - $time = '2014-01-07T12:34'; - $pid = getmypid(); - $host = gethostname(); - - $handler = $this->getMockBuilder('\Monolog\Handler\SyslogUdpHandler') - ->setConstructorArgs(array("127.0.0.1", 514, "authpriv")) - ->setMethods(array('getDateTime')) - ->getMock(); - - $handler->method('getDateTime') - ->willReturn($time); - - $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); - - $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('write'), array('lol', 'lol')); - $socket->expects($this->at(0)) - ->method('write') - ->with("lol", "<".(LOG_AUTHPRIV + LOG_WARNING).">1 $time $host php $pid - - "); - $socket->expects($this->at(1)) - ->method('write') - ->with("hej", "<".(LOG_AUTHPRIV + LOG_WARNING).">1 $time $host php $pid - - "); - - $handler->setSocket($socket); - - $handler->handle($this->getRecordWithMessage("hej\nlol")); - } - - public function testSplitWorksOnEmptyMsg() - { - $handler = new SyslogUdpHandler("127.0.0.1", 514, "authpriv"); - $handler->setFormatter($this->getIdentityFormatter()); - - $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('write'), array('lol', 'lol')); - $socket->expects($this->never()) - ->method('write'); - - $handler->setSocket($socket); - - $handler->handle($this->getRecordWithMessage(null)); - } - - protected function getRecordWithMessage($msg) - { - return array('message' => $msg, 'level' => \Monolog\Logger::WARNING, 'context' => null, 'extra' => array(), 'channel' => 'lol'); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php deleted file mode 100644 index bfb8d3df..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php +++ /dev/null @@ -1,70 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -/** - * @covers Monolog\Handler\TestHandler - */ -class TestHandlerTest extends TestCase -{ - /** - * @dataProvider methodProvider - */ - public function testHandler($method, $level) - { - $handler = new TestHandler; - $record = $this->getRecord($level, 'test'.$method); - $this->assertFalse($handler->hasRecords($level)); - $this->assertFalse($handler->hasRecord($record, $level)); - $this->assertFalse($handler->{'has'.$method}($record), 'has'.$method); - $this->assertFalse($handler->{'has'.$method.'ThatContains'}('test'), 'has'.$method.'ThatContains'); - $this->assertFalse($handler->{'has'.$method.'ThatPasses'}(function ($rec) { - return true; - }), 'has'.$method.'ThatPasses'); - $this->assertFalse($handler->{'has'.$method.'ThatMatches'}('/test\w+/')); - $this->assertFalse($handler->{'has'.$method.'Records'}(), 'has'.$method.'Records'); - $handler->handle($record); - - $this->assertFalse($handler->{'has'.$method}('bar'), 'has'.$method); - $this->assertTrue($handler->hasRecords($level)); - $this->assertTrue($handler->hasRecord($record, $level)); - $this->assertTrue($handler->{'has'.$method}($record), 'has'.$method); - $this->assertTrue($handler->{'has'.$method}('test'.$method), 'has'.$method); - $this->assertTrue($handler->{'has'.$method.'ThatContains'}('test'), 'has'.$method.'ThatContains'); - $this->assertTrue($handler->{'has'.$method.'ThatPasses'}(function ($rec) { - return true; - }), 'has'.$method.'ThatPasses'); - $this->assertTrue($handler->{'has'.$method.'ThatMatches'}('/test\w+/')); - $this->assertTrue($handler->{'has'.$method.'Records'}(), 'has'.$method.'Records'); - - $records = $handler->getRecords(); - unset($records[0]['formatted']); - $this->assertEquals(array($record), $records); - } - - public function methodProvider() - { - return array( - array('Emergency', Logger::EMERGENCY), - array('Alert' , Logger::ALERT), - array('Critical' , Logger::CRITICAL), - array('Error' , Logger::ERROR), - array('Warning' , Logger::WARNING), - array('Info' , Logger::INFO), - array('Notice' , Logger::NOTICE), - array('Debug' , Logger::DEBUG), - ); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php deleted file mode 100644 index fa524d00..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/UdpSocketTest.php +++ /dev/null @@ -1,64 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Handler\SyslogUdp\UdpSocket; - -/** - * @requires extension sockets - */ -class UdpSocketTest extends TestCase -{ - public function testWeDoNotTruncateShortMessages() - { - $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('send'), array('lol', 'lol')); - - $socket->expects($this->at(0)) - ->method('send') - ->with("HEADER: The quick brown fox jumps over the lazy dog"); - - $socket->write("The quick brown fox jumps over the lazy dog", "HEADER: "); - } - - public function testLongMessagesAreTruncated() - { - $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('send'), array('lol', 'lol')); - - $truncatedString = str_repeat("derp", 16254).'d'; - - $socket->expects($this->exactly(1)) - ->method('send') - ->with("HEADER" . $truncatedString); - - $longString = str_repeat("derp", 20000); - - $socket->write($longString, "HEADER"); - } - - public function testDoubleCloseDoesNotError() - { - $socket = new UdpSocket('127.0.0.1', 514); - $socket->close(); - $socket->close(); - } - - /** - * @expectedException LogicException - */ - public function testWriteAfterCloseErrors() - { - $socket = new UdpSocket('127.0.0.1', 514); - $socket->close(); - $socket->write('foo', "HEADER"); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php deleted file mode 100644 index 8d37a1fc..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php +++ /dev/null @@ -1,121 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; -use Monolog\Logger; - -class WhatFailureGroupHandlerTest extends TestCase -{ - /** - * @covers Monolog\Handler\WhatFailureGroupHandler::__construct - * @expectedException InvalidArgumentException - */ - public function testConstructorOnlyTakesHandler() - { - new WhatFailureGroupHandler(array(new TestHandler(), "foo")); - } - - /** - * @covers Monolog\Handler\WhatFailureGroupHandler::__construct - * @covers Monolog\Handler\WhatFailureGroupHandler::handle - */ - public function testHandle() - { - $testHandlers = array(new TestHandler(), new TestHandler()); - $handler = new WhatFailureGroupHandler($testHandlers); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - foreach ($testHandlers as $test) { - $this->assertTrue($test->hasDebugRecords()); - $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); - } - } - - /** - * @covers Monolog\Handler\WhatFailureGroupHandler::handleBatch - */ - public function testHandleBatch() - { - $testHandlers = array(new TestHandler(), new TestHandler()); - $handler = new WhatFailureGroupHandler($testHandlers); - $handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO))); - foreach ($testHandlers as $test) { - $this->assertTrue($test->hasDebugRecords()); - $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); - } - } - - /** - * @covers Monolog\Handler\WhatFailureGroupHandler::isHandling - */ - public function testIsHandling() - { - $testHandlers = array(new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING)); - $handler = new WhatFailureGroupHandler($testHandlers); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR))); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); - } - - /** - * @covers Monolog\Handler\WhatFailureGroupHandler::handle - */ - public function testHandleUsesProcessors() - { - $test = new TestHandler(); - $handler = new WhatFailureGroupHandler(array($test)); - $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; - - return $record; - }); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertTrue($test->hasWarningRecords()); - $records = $test->getRecords(); - $this->assertTrue($records[0]['extra']['foo']); - } - - /** - * @covers Monolog\Handler\WhatFailureGroupHandler::handle - */ - public function testHandleException() - { - $test = new TestHandler(); - $exception = new ExceptionTestHandler(); - $handler = new WhatFailureGroupHandler(array($exception, $test, $exception)); - $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; - - return $record; - }); - $handler->handle($this->getRecord(Logger::WARNING)); - $this->assertTrue($test->hasWarningRecords()); - $records = $test->getRecords(); - $this->assertTrue($records[0]['extra']['foo']); - } -} - -class ExceptionTestHandler extends TestHandler -{ - /** - * {@inheritdoc} - */ - public function handle(array $record) - { - parent::handle($record); - - throw new \Exception("ExceptionTestHandler::handle"); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php deleted file mode 100644 index 69b001ea..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\TestCase; - -class ZendMonitorHandlerTest extends TestCase -{ - protected $zendMonitorHandler; - - public function setUp() - { - if (!function_exists('zend_monitor_custom_event')) { - $this->markTestSkipped('ZendServer is not installed'); - } - } - - /** - * @covers Monolog\Handler\ZendMonitorHandler::write - */ - public function testWrite() - { - $record = $this->getRecord(); - $formatterResult = array( - 'message' => $record['message'], - ); - - $zendMonitor = $this->getMockBuilder('Monolog\Handler\ZendMonitorHandler') - ->setMethods(array('writeZendMonitorCustomEvent', 'getDefaultFormatter')) - ->getMock(); - - $formatterMock = $this->getMockBuilder('Monolog\Formatter\NormalizerFormatter') - ->disableOriginalConstructor() - ->getMock(); - - $formatterMock->expects($this->once()) - ->method('format') - ->will($this->returnValue($formatterResult)); - - $zendMonitor->expects($this->once()) - ->method('getDefaultFormatter') - ->will($this->returnValue($formatterMock)); - - $levelMap = $zendMonitor->getLevelMap(); - - $zendMonitor->expects($this->once()) - ->method('writeZendMonitorCustomEvent') - ->with($levelMap[$record['level']], $record['message'], $formatterResult); - - $zendMonitor->handle($record); - } - - /** - * @covers Monolog\Handler\ZendMonitorHandler::getDefaultFormatter - */ - public function testGetDefaultFormatterReturnsNormalizerFormatter() - { - $zendMonitor = new ZendMonitorHandler(); - $this->assertInstanceOf('Monolog\Formatter\NormalizerFormatter', $zendMonitor->getDefaultFormatter()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/LoggerTest.php b/vendor/monolog/monolog/tests/Monolog/LoggerTest.php deleted file mode 100644 index 1ecc34a0..00000000 --- a/vendor/monolog/monolog/tests/Monolog/LoggerTest.php +++ /dev/null @@ -1,548 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog; - -use Monolog\Processor\WebProcessor; -use Monolog\Handler\TestHandler; - -class LoggerTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers Monolog\Logger::getName - */ - public function testGetName() - { - $logger = new Logger('foo'); - $this->assertEquals('foo', $logger->getName()); - } - - /** - * @covers Monolog\Logger::getLevelName - */ - public function testGetLevelName() - { - $this->assertEquals('ERROR', Logger::getLevelName(Logger::ERROR)); - } - - /** - * @covers Monolog\Logger::withName - */ - public function testWithName() - { - $first = new Logger('first', array($handler = new TestHandler())); - $second = $first->withName('second'); - - $this->assertSame('first', $first->getName()); - $this->assertSame('second', $second->getName()); - $this->assertSame($handler, $second->popHandler()); - } - - /** - * @covers Monolog\Logger::toMonologLevel - */ - public function testConvertPSR3ToMonologLevel() - { - $this->assertEquals(Logger::toMonologLevel('debug'), 100); - $this->assertEquals(Logger::toMonologLevel('info'), 200); - $this->assertEquals(Logger::toMonologLevel('notice'), 250); - $this->assertEquals(Logger::toMonologLevel('warning'), 300); - $this->assertEquals(Logger::toMonologLevel('error'), 400); - $this->assertEquals(Logger::toMonologLevel('critical'), 500); - $this->assertEquals(Logger::toMonologLevel('alert'), 550); - $this->assertEquals(Logger::toMonologLevel('emergency'), 600); - } - - /** - * @covers Monolog\Logger::getLevelName - * @expectedException InvalidArgumentException - */ - public function testGetLevelNameThrows() - { - Logger::getLevelName(5); - } - - /** - * @covers Monolog\Logger::__construct - */ - public function testChannel() - { - $logger = new Logger('foo'); - $handler = new TestHandler; - $logger->pushHandler($handler); - $logger->addWarning('test'); - list($record) = $handler->getRecords(); - $this->assertEquals('foo', $record['channel']); - } - - /** - * @covers Monolog\Logger::addRecord - */ - public function testLog() - { - $logger = new Logger(__METHOD__); - - $handler = $this->getMock('Monolog\Handler\NullHandler', array('handle')); - $handler->expects($this->once()) - ->method('handle'); - $logger->pushHandler($handler); - - $this->assertTrue($logger->addWarning('test')); - } - - /** - * @covers Monolog\Logger::addRecord - */ - public function testLogNotHandled() - { - $logger = new Logger(__METHOD__); - - $handler = $this->getMock('Monolog\Handler\NullHandler', array('handle'), array(Logger::ERROR)); - $handler->expects($this->never()) - ->method('handle'); - $logger->pushHandler($handler); - - $this->assertFalse($logger->addWarning('test')); - } - - public function testHandlersInCtor() - { - $handler1 = new TestHandler; - $handler2 = new TestHandler; - $logger = new Logger(__METHOD__, array($handler1, $handler2)); - - $this->assertEquals($handler1, $logger->popHandler()); - $this->assertEquals($handler2, $logger->popHandler()); - } - - public function testProcessorsInCtor() - { - $processor1 = new WebProcessor; - $processor2 = new WebProcessor; - $logger = new Logger(__METHOD__, array(), array($processor1, $processor2)); - - $this->assertEquals($processor1, $logger->popProcessor()); - $this->assertEquals($processor2, $logger->popProcessor()); - } - - /** - * @covers Monolog\Logger::pushHandler - * @covers Monolog\Logger::popHandler - * @expectedException LogicException - */ - public function testPushPopHandler() - { - $logger = new Logger(__METHOD__); - $handler1 = new TestHandler; - $handler2 = new TestHandler; - - $logger->pushHandler($handler1); - $logger->pushHandler($handler2); - - $this->assertEquals($handler2, $logger->popHandler()); - $this->assertEquals($handler1, $logger->popHandler()); - $logger->popHandler(); - } - - /** - * @covers Monolog\Logger::setHandlers - */ - public function testSetHandlers() - { - $logger = new Logger(__METHOD__); - $handler1 = new TestHandler; - $handler2 = new TestHandler; - - $logger->pushHandler($handler1); - $logger->setHandlers(array($handler2)); - - // handler1 has been removed - $this->assertEquals(array($handler2), $logger->getHandlers()); - - $logger->setHandlers(array( - "AMapKey" => $handler1, - "Woop" => $handler2, - )); - - // Keys have been scrubbed - $this->assertEquals(array($handler1, $handler2), $logger->getHandlers()); - } - - /** - * @covers Monolog\Logger::pushProcessor - * @covers Monolog\Logger::popProcessor - * @expectedException LogicException - */ - public function testPushPopProcessor() - { - $logger = new Logger(__METHOD__); - $processor1 = new WebProcessor; - $processor2 = new WebProcessor; - - $logger->pushProcessor($processor1); - $logger->pushProcessor($processor2); - - $this->assertEquals($processor2, $logger->popProcessor()); - $this->assertEquals($processor1, $logger->popProcessor()); - $logger->popProcessor(); - } - - /** - * @covers Monolog\Logger::pushProcessor - * @expectedException InvalidArgumentException - */ - public function testPushProcessorWithNonCallable() - { - $logger = new Logger(__METHOD__); - - $logger->pushProcessor(new \stdClass()); - } - - /** - * @covers Monolog\Logger::addRecord - */ - public function testProcessorsAreExecuted() - { - $logger = new Logger(__METHOD__); - $handler = new TestHandler; - $logger->pushHandler($handler); - $logger->pushProcessor(function ($record) { - $record['extra']['win'] = true; - - return $record; - }); - $logger->addError('test'); - list($record) = $handler->getRecords(); - $this->assertTrue($record['extra']['win']); - } - - /** - * @covers Monolog\Logger::addRecord - */ - public function testProcessorsAreCalledOnlyOnce() - { - $logger = new Logger(__METHOD__); - $handler = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler->expects($this->any()) - ->method('isHandling') - ->will($this->returnValue(true)) - ; - $handler->expects($this->any()) - ->method('handle') - ->will($this->returnValue(true)) - ; - $logger->pushHandler($handler); - - $processor = $this->getMockBuilder('Monolog\Processor\WebProcessor') - ->disableOriginalConstructor() - ->setMethods(array('__invoke')) - ->getMock() - ; - $processor->expects($this->once()) - ->method('__invoke') - ->will($this->returnArgument(0)) - ; - $logger->pushProcessor($processor); - - $logger->addError('test'); - } - - /** - * @covers Monolog\Logger::addRecord - */ - public function testProcessorsNotCalledWhenNotHandled() - { - $logger = new Logger(__METHOD__); - $handler = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler->expects($this->once()) - ->method('isHandling') - ->will($this->returnValue(false)) - ; - $logger->pushHandler($handler); - $that = $this; - $logger->pushProcessor(function ($record) use ($that) { - $that->fail('The processor should not be called'); - }); - $logger->addAlert('test'); - } - - /** - * @covers Monolog\Logger::addRecord - */ - public function testHandlersNotCalledBeforeFirstHandling() - { - $logger = new Logger(__METHOD__); - - $handler1 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler1->expects($this->never()) - ->method('isHandling') - ->will($this->returnValue(false)) - ; - $handler1->expects($this->once()) - ->method('handle') - ->will($this->returnValue(false)) - ; - $logger->pushHandler($handler1); - - $handler2 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler2->expects($this->once()) - ->method('isHandling') - ->will($this->returnValue(true)) - ; - $handler2->expects($this->once()) - ->method('handle') - ->will($this->returnValue(false)) - ; - $logger->pushHandler($handler2); - - $handler3 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler3->expects($this->once()) - ->method('isHandling') - ->will($this->returnValue(false)) - ; - $handler3->expects($this->never()) - ->method('handle') - ; - $logger->pushHandler($handler3); - - $logger->debug('test'); - } - - /** - * @covers Monolog\Logger::addRecord - */ - public function testHandlersNotCalledBeforeFirstHandlingWithAssocArray() - { - $handler1 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler1->expects($this->never()) - ->method('isHandling') - ->will($this->returnValue(false)) - ; - $handler1->expects($this->once()) - ->method('handle') - ->will($this->returnValue(false)) - ; - - $handler2 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler2->expects($this->once()) - ->method('isHandling') - ->will($this->returnValue(true)) - ; - $handler2->expects($this->once()) - ->method('handle') - ->will($this->returnValue(false)) - ; - - $handler3 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler3->expects($this->once()) - ->method('isHandling') - ->will($this->returnValue(false)) - ; - $handler3->expects($this->never()) - ->method('handle') - ; - - $logger = new Logger(__METHOD__, array('last' => $handler3, 'second' => $handler2, 'first' => $handler1)); - - $logger->debug('test'); - } - - /** - * @covers Monolog\Logger::addRecord - */ - public function testBubblingWhenTheHandlerReturnsFalse() - { - $logger = new Logger(__METHOD__); - - $handler1 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler1->expects($this->any()) - ->method('isHandling') - ->will($this->returnValue(true)) - ; - $handler1->expects($this->once()) - ->method('handle') - ->will($this->returnValue(false)) - ; - $logger->pushHandler($handler1); - - $handler2 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler2->expects($this->any()) - ->method('isHandling') - ->will($this->returnValue(true)) - ; - $handler2->expects($this->once()) - ->method('handle') - ->will($this->returnValue(false)) - ; - $logger->pushHandler($handler2); - - $logger->debug('test'); - } - - /** - * @covers Monolog\Logger::addRecord - */ - public function testNotBubblingWhenTheHandlerReturnsTrue() - { - $logger = new Logger(__METHOD__); - - $handler1 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler1->expects($this->any()) - ->method('isHandling') - ->will($this->returnValue(true)) - ; - $handler1->expects($this->never()) - ->method('handle') - ; - $logger->pushHandler($handler1); - - $handler2 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler2->expects($this->any()) - ->method('isHandling') - ->will($this->returnValue(true)) - ; - $handler2->expects($this->once()) - ->method('handle') - ->will($this->returnValue(true)) - ; - $logger->pushHandler($handler2); - - $logger->debug('test'); - } - - /** - * @covers Monolog\Logger::isHandling - */ - public function testIsHandling() - { - $logger = new Logger(__METHOD__); - - $handler1 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler1->expects($this->any()) - ->method('isHandling') - ->will($this->returnValue(false)) - ; - - $logger->pushHandler($handler1); - $this->assertFalse($logger->isHandling(Logger::DEBUG)); - - $handler2 = $this->getMock('Monolog\Handler\HandlerInterface'); - $handler2->expects($this->any()) - ->method('isHandling') - ->will($this->returnValue(true)) - ; - - $logger->pushHandler($handler2); - $this->assertTrue($logger->isHandling(Logger::DEBUG)); - } - - /** - * @dataProvider logMethodProvider - * @covers Monolog\Logger::addDebug - * @covers Monolog\Logger::addInfo - * @covers Monolog\Logger::addNotice - * @covers Monolog\Logger::addWarning - * @covers Monolog\Logger::addError - * @covers Monolog\Logger::addCritical - * @covers Monolog\Logger::addAlert - * @covers Monolog\Logger::addEmergency - * @covers Monolog\Logger::debug - * @covers Monolog\Logger::info - * @covers Monolog\Logger::notice - * @covers Monolog\Logger::warn - * @covers Monolog\Logger::err - * @covers Monolog\Logger::crit - * @covers Monolog\Logger::alert - * @covers Monolog\Logger::emerg - */ - public function testLogMethods($method, $expectedLevel) - { - $logger = new Logger('foo'); - $handler = new TestHandler; - $logger->pushHandler($handler); - $logger->{$method}('test'); - list($record) = $handler->getRecords(); - $this->assertEquals($expectedLevel, $record['level']); - } - - public function logMethodProvider() - { - return array( - // monolog methods - array('addDebug', Logger::DEBUG), - array('addInfo', Logger::INFO), - array('addNotice', Logger::NOTICE), - array('addWarning', Logger::WARNING), - array('addError', Logger::ERROR), - array('addCritical', Logger::CRITICAL), - array('addAlert', Logger::ALERT), - array('addEmergency', Logger::EMERGENCY), - - // ZF/Sf2 compat methods - array('debug', Logger::DEBUG), - array('info', Logger::INFO), - array('notice', Logger::NOTICE), - array('warn', Logger::WARNING), - array('err', Logger::ERROR), - array('crit', Logger::CRITICAL), - array('alert', Logger::ALERT), - array('emerg', Logger::EMERGENCY), - ); - } - - /** - * @dataProvider setTimezoneProvider - * @covers Monolog\Logger::setTimezone - */ - public function testSetTimezone($tz) - { - Logger::setTimezone($tz); - $logger = new Logger('foo'); - $handler = new TestHandler; - $logger->pushHandler($handler); - $logger->info('test'); - list($record) = $handler->getRecords(); - $this->assertEquals($tz, $record['datetime']->getTimezone()); - } - - public function setTimezoneProvider() - { - return array_map( - function ($tz) { return array(new \DateTimeZone($tz)); }, - \DateTimeZone::listIdentifiers() - ); - } - - /** - * @dataProvider useMicrosecondTimestampsProvider - * @covers Monolog\Logger::useMicrosecondTimestamps - * @covers Monolog\Logger::addRecord - */ - public function testUseMicrosecondTimestamps($micro, $assert) - { - $logger = new Logger('foo'); - $logger->useMicrosecondTimestamps($micro); - $handler = new TestHandler; - $logger->pushHandler($handler); - $logger->info('test'); - list($record) = $handler->getRecords(); - $this->{$assert}('000000', $record['datetime']->format('u')); - } - - public function useMicrosecondTimestampsProvider() - { - return array( - // this has a very small chance of a false negative (1/10^6) - 'with microseconds' => array(true, 'assertNotSame'), - 'without microseconds' => array(false, PHP_VERSION_ID >= 70100 ? 'assertNotSame' : 'assertSame'), - ); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php deleted file mode 100644 index 5adb505d..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Processor/GitProcessorTest.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Processor; - -use Monolog\TestCase; - -class GitProcessorTest extends TestCase -{ - /** - * @covers Monolog\Processor\GitProcessor::__invoke - */ - public function testProcessor() - { - $processor = new GitProcessor(); - $record = $processor($this->getRecord()); - - $this->assertArrayHasKey('git', $record['extra']); - $this->assertTrue(!is_array($record['extra']['git']['branch'])); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php deleted file mode 100644 index 0dd411d7..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php +++ /dev/null @@ -1,123 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Acme; - -class Tester -{ - public function test($handler, $record) - { - $handler->handle($record); - } -} - -function tester($handler, $record) -{ - $handler->handle($record); -} - -namespace Monolog\Processor; - -use Monolog\Logger; -use Monolog\TestCase; -use Monolog\Handler\TestHandler; - -class IntrospectionProcessorTest extends TestCase -{ - public function getHandler() - { - $processor = new IntrospectionProcessor(); - $handler = new TestHandler(); - $handler->pushProcessor($processor); - - return $handler; - } - - public function testProcessorFromClass() - { - $handler = $this->getHandler(); - $tester = new \Acme\Tester; - $tester->test($handler, $this->getRecord()); - list($record) = $handler->getRecords(); - $this->assertEquals(__FILE__, $record['extra']['file']); - $this->assertEquals(18, $record['extra']['line']); - $this->assertEquals('Acme\Tester', $record['extra']['class']); - $this->assertEquals('test', $record['extra']['function']); - } - - public function testProcessorFromFunc() - { - $handler = $this->getHandler(); - \Acme\tester($handler, $this->getRecord()); - list($record) = $handler->getRecords(); - $this->assertEquals(__FILE__, $record['extra']['file']); - $this->assertEquals(24, $record['extra']['line']); - $this->assertEquals(null, $record['extra']['class']); - $this->assertEquals('Acme\tester', $record['extra']['function']); - } - - public function testLevelTooLow() - { - $input = array( - 'level' => Logger::DEBUG, - 'extra' => array(), - ); - - $expected = $input; - - $processor = new IntrospectionProcessor(Logger::CRITICAL); - $actual = $processor($input); - - $this->assertEquals($expected, $actual); - } - - public function testLevelEqual() - { - $input = array( - 'level' => Logger::CRITICAL, - 'extra' => array(), - ); - - $expected = $input; - $expected['extra'] = array( - 'file' => null, - 'line' => null, - 'class' => 'ReflectionMethod', - 'function' => 'invokeArgs', - ); - - $processor = new IntrospectionProcessor(Logger::CRITICAL); - $actual = $processor($input); - - $this->assertEquals($expected, $actual); - } - - public function testLevelHigher() - { - $input = array( - 'level' => Logger::EMERGENCY, - 'extra' => array(), - ); - - $expected = $input; - $expected['extra'] = array( - 'file' => null, - 'line' => null, - 'class' => 'ReflectionMethod', - 'function' => 'invokeArgs', - ); - - $processor = new IntrospectionProcessor(Logger::CRITICAL); - $actual = $processor($input); - - $this->assertEquals($expected, $actual); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php deleted file mode 100644 index eb666144..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Processor; - -use Monolog\TestCase; - -class MemoryPeakUsageProcessorTest extends TestCase -{ - /** - * @covers Monolog\Processor\MemoryPeakUsageProcessor::__invoke - * @covers Monolog\Processor\MemoryProcessor::formatBytes - */ - public function testProcessor() - { - $processor = new MemoryPeakUsageProcessor(); - $record = $processor($this->getRecord()); - $this->assertArrayHasKey('memory_peak_usage', $record['extra']); - $this->assertRegExp('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_peak_usage']); - } - - /** - * @covers Monolog\Processor\MemoryPeakUsageProcessor::__invoke - * @covers Monolog\Processor\MemoryProcessor::formatBytes - */ - public function testProcessorWithoutFormatting() - { - $processor = new MemoryPeakUsageProcessor(true, false); - $record = $processor($this->getRecord()); - $this->assertArrayHasKey('memory_peak_usage', $record['extra']); - $this->assertInternalType('int', $record['extra']['memory_peak_usage']); - $this->assertGreaterThan(0, $record['extra']['memory_peak_usage']); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php deleted file mode 100644 index 4692dbfc..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Processor; - -use Monolog\TestCase; - -class MemoryUsageProcessorTest extends TestCase -{ - /** - * @covers Monolog\Processor\MemoryUsageProcessor::__invoke - * @covers Monolog\Processor\MemoryProcessor::formatBytes - */ - public function testProcessor() - { - $processor = new MemoryUsageProcessor(); - $record = $processor($this->getRecord()); - $this->assertArrayHasKey('memory_usage', $record['extra']); - $this->assertRegExp('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_usage']); - } - - /** - * @covers Monolog\Processor\MemoryUsageProcessor::__invoke - * @covers Monolog\Processor\MemoryProcessor::formatBytes - */ - public function testProcessorWithoutFormatting() - { - $processor = new MemoryUsageProcessor(true, false); - $record = $processor($this->getRecord()); - $this->assertArrayHasKey('memory_usage', $record['extra']); - $this->assertInternalType('int', $record['extra']['memory_usage']); - $this->assertGreaterThan(0, $record['extra']['memory_usage']); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/MercurialProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/MercurialProcessorTest.php deleted file mode 100644 index 11f2b35a..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Processor/MercurialProcessorTest.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Processor; - -use Monolog\TestCase; - -class MercurialProcessorTest extends TestCase -{ - /** - * @covers Monolog\Processor\MercurialProcessor::__invoke - */ - public function testProcessor() - { - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - exec("where hg 2>NUL", $output, $result); - } else { - exec("which hg 2>/dev/null >/dev/null", $output, $result); - } - if ($result != 0) { - $this->markTestSkipped('hg is missing'); - return; - } - - `hg init`; - $processor = new MercurialProcessor(); - $record = $processor($this->getRecord()); - - $this->assertArrayHasKey('hg', $record['extra']); - $this->assertTrue(!is_array($record['extra']['hg']['branch'])); - $this->assertTrue(!is_array($record['extra']['hg']['revision'])); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php deleted file mode 100644 index 458d2a33..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Processor; - -use Monolog\TestCase; - -class ProcessIdProcessorTest extends TestCase -{ - /** - * @covers Monolog\Processor\ProcessIdProcessor::__invoke - */ - public function testProcessor() - { - $processor = new ProcessIdProcessor(); - $record = $processor($this->getRecord()); - $this->assertArrayHasKey('process_id', $record['extra']); - $this->assertInternalType('int', $record['extra']['process_id']); - $this->assertGreaterThan(0, $record['extra']['process_id']); - $this->assertEquals(getmypid(), $record['extra']['process_id']); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/PsrLogMessageProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/PsrLogMessageProcessorTest.php deleted file mode 100644 index 029a0c02..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Processor/PsrLogMessageProcessorTest.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Processor; - -class PsrLogMessageProcessorTest extends \PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getPairs - */ - public function testReplacement($val, $expected) - { - $proc = new PsrLogMessageProcessor; - - $message = $proc(array( - 'message' => '{foo}', - 'context' => array('foo' => $val), - )); - $this->assertEquals($expected, $message['message']); - } - - public function getPairs() - { - return array( - array('foo', 'foo'), - array('3', '3'), - array(3, '3'), - array(null, ''), - array(true, '1'), - array(false, ''), - array(new \stdClass, '[object stdClass]'), - array(array(), '[array]'), - ); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php deleted file mode 100644 index 0d860c61..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Processor/TagProcessorTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Processor; - -use Monolog\TestCase; - -class TagProcessorTest extends TestCase -{ - /** - * @covers Monolog\Processor\TagProcessor::__invoke - */ - public function testProcessor() - { - $tags = array(1, 2, 3); - $processor = new TagProcessor($tags); - $record = $processor($this->getRecord()); - - $this->assertEquals($tags, $record['extra']['tags']); - } - - /** - * @covers Monolog\Processor\TagProcessor::__invoke - */ - public function testProcessorTagModification() - { - $tags = array(1, 2, 3); - $processor = new TagProcessor($tags); - - $record = $processor($this->getRecord()); - $this->assertEquals($tags, $record['extra']['tags']); - - $processor->setTags(array('a', 'b')); - $record = $processor($this->getRecord()); - $this->assertEquals(array('a', 'b'), $record['extra']['tags']); - - $processor->addTags(array('a', 'c', 'foo' => 'bar')); - $record = $processor($this->getRecord()); - $this->assertEquals(array('a', 'b', 'a', 'c', 'foo' => 'bar'), $record['extra']['tags']); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php deleted file mode 100644 index 5d13058f..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Processor; - -use Monolog\TestCase; - -class UidProcessorTest extends TestCase -{ - /** - * @covers Monolog\Processor\UidProcessor::__invoke - */ - public function testProcessor() - { - $processor = new UidProcessor(); - $record = $processor($this->getRecord()); - $this->assertArrayHasKey('uid', $record['extra']); - } - - public function testGetUid() - { - $processor = new UidProcessor(10); - $this->assertEquals(10, strlen($processor->getUid())); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php deleted file mode 100644 index 4105baf7..00000000 --- a/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php +++ /dev/null @@ -1,113 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Processor; - -use Monolog\TestCase; - -class WebProcessorTest extends TestCase -{ - public function testProcessor() - { - $server = array( - 'REQUEST_URI' => 'A', - 'REMOTE_ADDR' => 'B', - 'REQUEST_METHOD' => 'C', - 'HTTP_REFERER' => 'D', - 'SERVER_NAME' => 'F', - 'UNIQUE_ID' => 'G', - ); - - $processor = new WebProcessor($server); - $record = $processor($this->getRecord()); - $this->assertEquals($server['REQUEST_URI'], $record['extra']['url']); - $this->assertEquals($server['REMOTE_ADDR'], $record['extra']['ip']); - $this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']); - $this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']); - $this->assertEquals($server['SERVER_NAME'], $record['extra']['server']); - $this->assertEquals($server['UNIQUE_ID'], $record['extra']['unique_id']); - } - - public function testProcessorDoNothingIfNoRequestUri() - { - $server = array( - 'REMOTE_ADDR' => 'B', - 'REQUEST_METHOD' => 'C', - ); - $processor = new WebProcessor($server); - $record = $processor($this->getRecord()); - $this->assertEmpty($record['extra']); - } - - public function testProcessorReturnNullIfNoHttpReferer() - { - $server = array( - 'REQUEST_URI' => 'A', - 'REMOTE_ADDR' => 'B', - 'REQUEST_METHOD' => 'C', - 'SERVER_NAME' => 'F', - ); - $processor = new WebProcessor($server); - $record = $processor($this->getRecord()); - $this->assertNull($record['extra']['referrer']); - } - - public function testProcessorDoesNotAddUniqueIdIfNotPresent() - { - $server = array( - 'REQUEST_URI' => 'A', - 'REMOTE_ADDR' => 'B', - 'REQUEST_METHOD' => 'C', - 'SERVER_NAME' => 'F', - ); - $processor = new WebProcessor($server); - $record = $processor($this->getRecord()); - $this->assertFalse(isset($record['extra']['unique_id'])); - } - - public function testProcessorAddsOnlyRequestedExtraFields() - { - $server = array( - 'REQUEST_URI' => 'A', - 'REMOTE_ADDR' => 'B', - 'REQUEST_METHOD' => 'C', - 'SERVER_NAME' => 'F', - ); - - $processor = new WebProcessor($server, array('url', 'http_method')); - $record = $processor($this->getRecord()); - - $this->assertSame(array('url' => 'A', 'http_method' => 'C'), $record['extra']); - } - - public function testProcessorConfiguringOfExtraFields() - { - $server = array( - 'REQUEST_URI' => 'A', - 'REMOTE_ADDR' => 'B', - 'REQUEST_METHOD' => 'C', - 'SERVER_NAME' => 'F', - ); - - $processor = new WebProcessor($server, array('url' => 'REMOTE_ADDR')); - $record = $processor($this->getRecord()); - - $this->assertSame(array('url' => 'B'), $record['extra']); - } - - /** - * @expectedException UnexpectedValueException - */ - public function testInvalidData() - { - new WebProcessor(new \stdClass); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php b/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php deleted file mode 100644 index ab899449..00000000 --- a/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog; - -use Monolog\Handler\TestHandler; -use Monolog\Formatter\LineFormatter; -use Monolog\Processor\PsrLogMessageProcessor; -use Psr\Log\Test\LoggerInterfaceTest; - -class PsrLogCompatTest extends LoggerInterfaceTest -{ - private $handler; - - public function getLogger() - { - $logger = new Logger('foo'); - $logger->pushHandler($handler = new TestHandler); - $logger->pushProcessor(new PsrLogMessageProcessor); - $handler->setFormatter(new LineFormatter('%level_name% %message%')); - - $this->handler = $handler; - - return $logger; - } - - public function getLogs() - { - $convert = function ($record) { - $lower = function ($match) { - return strtolower($match[0]); - }; - - return preg_replace_callback('{^[A-Z]+}', $lower, $record['formatted']); - }; - - return array_map($convert, $this->handler->getRecords()); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/RegistryTest.php b/vendor/monolog/monolog/tests/Monolog/RegistryTest.php deleted file mode 100644 index 15fdfbd2..00000000 --- a/vendor/monolog/monolog/tests/Monolog/RegistryTest.php +++ /dev/null @@ -1,153 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog; - -class RegistryTest extends \PHPUnit_Framework_TestCase -{ - protected function setUp() - { - Registry::clear(); - } - - /** - * @dataProvider hasLoggerProvider - * @covers Monolog\Registry::hasLogger - */ - public function testHasLogger(array $loggersToAdd, array $loggersToCheck, array $expectedResult) - { - foreach ($loggersToAdd as $loggerToAdd) { - Registry::addLogger($loggerToAdd); - } - foreach ($loggersToCheck as $index => $loggerToCheck) { - $this->assertSame($expectedResult[$index], Registry::hasLogger($loggerToCheck)); - } - } - - public function hasLoggerProvider() - { - $logger1 = new Logger('test1'); - $logger2 = new Logger('test2'); - $logger3 = new Logger('test3'); - - return array( - // only instances - array( - array($logger1), - array($logger1, $logger2), - array(true, false), - ), - // only names - array( - array($logger1), - array('test1', 'test2'), - array(true, false), - ), - // mixed case - array( - array($logger1, $logger2), - array('test1', $logger2, 'test3', $logger3), - array(true, true, false, false), - ), - ); - } - - /** - * @covers Monolog\Registry::clear - */ - public function testClearClears() - { - Registry::addLogger(new Logger('test1'), 'log'); - Registry::clear(); - - $this->setExpectedException('\InvalidArgumentException'); - Registry::getInstance('log'); - } - - /** - * @dataProvider removedLoggerProvider - * @covers Monolog\Registry::addLogger - * @covers Monolog\Registry::removeLogger - */ - public function testRemovesLogger($loggerToAdd, $remove) - { - Registry::addLogger($loggerToAdd); - Registry::removeLogger($remove); - - $this->setExpectedException('\InvalidArgumentException'); - Registry::getInstance($loggerToAdd->getName()); - } - - public function removedLoggerProvider() - { - $logger1 = new Logger('test1'); - - return array( - array($logger1, $logger1), - array($logger1, 'test1'), - ); - } - - /** - * @covers Monolog\Registry::addLogger - * @covers Monolog\Registry::getInstance - * @covers Monolog\Registry::__callStatic - */ - public function testGetsSameLogger() - { - $logger1 = new Logger('test1'); - $logger2 = new Logger('test2'); - - Registry::addLogger($logger1, 'test1'); - Registry::addLogger($logger2); - - $this->assertSame($logger1, Registry::getInstance('test1')); - $this->assertSame($logger2, Registry::test2()); - } - - /** - * @expectedException \InvalidArgumentException - * @covers Monolog\Registry::getInstance - */ - public function testFailsOnNonExistantLogger() - { - Registry::getInstance('test1'); - } - - /** - * @covers Monolog\Registry::addLogger - */ - public function testReplacesLogger() - { - $log1 = new Logger('test1'); - $log2 = new Logger('test2'); - - Registry::addLogger($log1, 'log'); - - Registry::addLogger($log2, 'log', true); - - $this->assertSame($log2, Registry::getInstance('log')); - } - - /** - * @expectedException \InvalidArgumentException - * @covers Monolog\Registry::addLogger - */ - public function testFailsOnUnspecifiedReplacement() - { - $log1 = new Logger('test1'); - $log2 = new Logger('test2'); - - Registry::addLogger($log1, 'log'); - - Registry::addLogger($log2, 'log'); - } -} diff --git a/vendor/monolog/monolog/tests/Monolog/TestCase.php b/vendor/monolog/monolog/tests/Monolog/TestCase.php deleted file mode 100644 index 4eb7b4c9..00000000 --- a/vendor/monolog/monolog/tests/Monolog/TestCase.php +++ /dev/null @@ -1,58 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog; - -class TestCase extends \PHPUnit_Framework_TestCase -{ - /** - * @return array Record - */ - protected function getRecord($level = Logger::WARNING, $message = 'test', $context = array()) - { - return array( - 'message' => $message, - 'context' => $context, - 'level' => $level, - 'level_name' => Logger::getLevelName($level), - 'channel' => 'test', - 'datetime' => \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true))), - 'extra' => array(), - ); - } - - /** - * @return array - */ - protected function getMultipleRecords() - { - return array( - $this->getRecord(Logger::DEBUG, 'debug message 1'), - $this->getRecord(Logger::DEBUG, 'debug message 2'), - $this->getRecord(Logger::INFO, 'information'), - $this->getRecord(Logger::WARNING, 'warning'), - $this->getRecord(Logger::ERROR, 'error'), - ); - } - - /** - * @return Monolog\Formatter\FormatterInterface - */ - protected function getIdentityFormatter() - { - $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); - $formatter->expects($this->any()) - ->method('format') - ->will($this->returnCallback(function ($record) { return $record['message']; })); - - return $formatter; - } -} diff --git a/vendor/psr/log/Psr/Log/LoggerInterface.php b/vendor/psr/log/Psr/Log/LoggerInterface.php index 5ea72438..e695046e 100644 --- a/vendor/psr/log/Psr/Log/LoggerInterface.php +++ b/vendor/psr/log/Psr/Log/LoggerInterface.php @@ -118,6 +118,8 @@ interface LoggerInterface * @param array $context * * @return void + * + * @throws \Psr\Log\InvalidArgumentException */ public function log($level, $message, array $context = array()); } diff --git a/vendor/psr/log/Psr/Log/LoggerTrait.php b/vendor/psr/log/Psr/Log/LoggerTrait.php index 867225df..e392fef0 100644 --- a/vendor/psr/log/Psr/Log/LoggerTrait.php +++ b/vendor/psr/log/Psr/Log/LoggerTrait.php @@ -135,6 +135,8 @@ trait LoggerTrait * @param array $context * * @return void + * + * @throws \Psr\Log\InvalidArgumentException */ abstract public function log($level, $message, array $context = array()); } diff --git a/vendor/psr/log/Psr/Log/NullLogger.php b/vendor/psr/log/Psr/Log/NullLogger.php index d8cd682c..c8f7293b 100644 --- a/vendor/psr/log/Psr/Log/NullLogger.php +++ b/vendor/psr/log/Psr/Log/NullLogger.php @@ -20,6 +20,8 @@ class NullLogger extends AbstractLogger * @param array $context * * @return void + * + * @throws \Psr\Log\InvalidArgumentException */ public function log($level, $message, array $context = array()) { diff --git a/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php b/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php index a0391a52..9ecb6c4b 100644 --- a/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php +++ b/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php @@ -4,6 +4,7 @@ namespace Psr\Log\Test; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; +use PHPUnit\Framework\TestCase; /** * Provides a base test class for ensuring compliance with the LoggerInterface. @@ -11,7 +12,7 @@ use Psr\Log\LogLevel; * Implementors can extend the class and implement abstract methods to run this * as part of their test suite. */ -abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase +abstract class LoggerInterfaceTest extends TestCase { /** * @return LoggerInterface @@ -101,6 +102,9 @@ abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase public function testContextCanContainAnything() { + $closed = fopen('php://memory', 'r'); + fclose($closed); + $context = array( 'bool' => true, 'null' => null, @@ -110,6 +114,7 @@ abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase 'nested' => array('with object' => new DummyTest), 'object' => new \DateTime, 'resource' => fopen('php://memory', 'r'), + 'closed' => $closed, ); $this->getLogger()->warning('Crazy context data', $context); @@ -136,5 +141,6 @@ class DummyTest { public function __toString() { + return 'DummyTest'; } } diff --git a/vendor/psr/log/Psr/Log/Test/TestLogger.php b/vendor/psr/log/Psr/Log/Test/TestLogger.php new file mode 100644 index 00000000..1be32304 --- /dev/null +++ b/vendor/psr/log/Psr/Log/Test/TestLogger.php @@ -0,0 +1,147 @@ + $level, + 'message' => $message, + 'context' => $context, + ]; + + $this->recordsByLevel[$record['level']][] = $record; + $this->records[] = $record; + } + + public function hasRecords($level) + { + return isset($this->recordsByLevel[$level]); + } + + public function hasRecord($record, $level) + { + if (is_string($record)) { + $record = ['message' => $record]; + } + return $this->hasRecordThatPasses(function ($rec) use ($record) { + if ($rec['message'] !== $record['message']) { + return false; + } + if (isset($record['context']) && $rec['context'] !== $record['context']) { + return false; + } + return true; + }, $level); + } + + public function hasRecordThatContains($message, $level) + { + return $this->hasRecordThatPasses(function ($rec) use ($message) { + return strpos($rec['message'], $message) !== false; + }, $level); + } + + public function hasRecordThatMatches($regex, $level) + { + return $this->hasRecordThatPasses(function ($rec) use ($regex) { + return preg_match($regex, $rec['message']) > 0; + }, $level); + } + + public function hasRecordThatPasses(callable $predicate, $level) + { + if (!isset($this->recordsByLevel[$level])) { + return false; + } + foreach ($this->recordsByLevel[$level] as $i => $rec) { + if (call_user_func($predicate, $rec, $i)) { + return true; + } + } + return false; + } + + public function __call($method, $args) + { + if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { + $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; + $level = strtolower($matches[2]); + if (method_exists($this, $genericMethod)) { + $args[] = $level; + return call_user_func_array([$this, $genericMethod], $args); + } + } + throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()'); + } + + public function reset() + { + $this->records = []; + $this->recordsByLevel = []; + } +} diff --git a/vendor/psr/log/README.md b/vendor/psr/log/README.md index 574bc1cb..a9f20c43 100644 --- a/vendor/psr/log/README.md +++ b/vendor/psr/log/README.md @@ -7,6 +7,13 @@ This repository holds all interfaces/classes/traits related to Note that this is not a logger of its own. It is merely an interface that describes a logger. See the specification for more details. +Installation +------------ + +```bash +composer require psr/log +``` + Usage ----- @@ -31,6 +38,12 @@ class Foo if ($this->logger) { $this->logger->info('Doing work'); } + + try { + $this->doSomethingElse(); + } catch (Exception $exception) { + $this->logger->error('Oh no!', array('exception' => $exception)); + } // do something useful } diff --git a/vendor/psr/log/composer.json b/vendor/psr/log/composer.json index 87934d70..3f6d4eea 100644 --- a/vendor/psr/log/composer.json +++ b/vendor/psr/log/composer.json @@ -20,7 +20,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } } } diff --git a/vendor/ralouphie/getallheaders/LICENSE b/vendor/ralouphie/getallheaders/LICENSE new file mode 100644 index 00000000..be5540c2 --- /dev/null +++ b/vendor/ralouphie/getallheaders/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Ralph Khattar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/ralouphie/getallheaders/README.md b/vendor/ralouphie/getallheaders/README.md new file mode 100644 index 00000000..9430d76b --- /dev/null +++ b/vendor/ralouphie/getallheaders/README.md @@ -0,0 +1,27 @@ +getallheaders +============= + +PHP `getallheaders()` polyfill. Compatible with PHP >= 5.3. + +[![Build Status](https://travis-ci.org/ralouphie/getallheaders.svg?branch=master)](https://travis-ci.org/ralouphie/getallheaders) +[![Coverage Status](https://coveralls.io/repos/ralouphie/getallheaders/badge.png?branch=master)](https://coveralls.io/r/ralouphie/getallheaders?branch=master) +[![Latest Stable Version](https://poser.pugx.org/ralouphie/getallheaders/v/stable.png)](https://packagist.org/packages/ralouphie/getallheaders) +[![Latest Unstable Version](https://poser.pugx.org/ralouphie/getallheaders/v/unstable.png)](https://packagist.org/packages/ralouphie/getallheaders) +[![License](https://poser.pugx.org/ralouphie/getallheaders/license.png)](https://packagist.org/packages/ralouphie/getallheaders) + + +This is a simple polyfill for [`getallheaders()`](http://www.php.net/manual/en/function.getallheaders.php). + +## Install + +For PHP version **`>= 5.6`**: + +``` +composer require ralouphie/getallheaders +``` + +For PHP version **`< 5.6`**: + +``` +composer require ralouphie/getallheaders "^2" +``` diff --git a/vendor/ralouphie/getallheaders/composer.json b/vendor/ralouphie/getallheaders/composer.json new file mode 100644 index 00000000..de8ce62e --- /dev/null +++ b/vendor/ralouphie/getallheaders/composer.json @@ -0,0 +1,26 @@ +{ + "name": "ralouphie/getallheaders", + "description": "A polyfill for getallheaders.", + "license": "MIT", + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^5 || ^6.5", + "php-coveralls/php-coveralls": "^2.1" + }, + "autoload": { + "files": ["src/getallheaders.php"] + }, + "autoload-dev": { + "psr-4": { + "getallheaders\\Tests\\": "tests/" + } + } +} diff --git a/vendor/ralouphie/getallheaders/src/getallheaders.php b/vendor/ralouphie/getallheaders/src/getallheaders.php new file mode 100644 index 00000000..c7285a5b --- /dev/null +++ b/vendor/ralouphie/getallheaders/src/getallheaders.php @@ -0,0 +1,46 @@ + 'Content-Type', + 'CONTENT_LENGTH' => 'Content-Length', + 'CONTENT_MD5' => 'Content-Md5', + ); + + foreach ($_SERVER as $key => $value) { + if (substr($key, 0, 5) === 'HTTP_') { + $key = substr($key, 5); + if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) { + $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key)))); + $headers[$key] = $value; + } + } elseif (isset($copy_server[$key])) { + $headers[$copy_server[$key]] = $value; + } + } + + if (!isset($headers['Authorization'])) { + if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { + $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + } elseif (isset($_SERVER['PHP_AUTH_USER'])) { + $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; + $headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass); + } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) { + $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST']; + } + } + + return $headers; + } + +} diff --git a/vendor/leafo/scssphp/LICENSE.md b/vendor/scssphp/scssphp/LICENSE.md similarity index 93% rename from vendor/leafo/scssphp/LICENSE.md rename to vendor/scssphp/scssphp/LICENSE.md index 2f5412f9..afcfdfb2 100644 --- a/vendor/leafo/scssphp/LICENSE.md +++ b/vendor/scssphp/scssphp/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2015 Leaf Corcoran, http://leafo.github.io/scssphp +Copyright (c) 2015 Leaf Corcoran, http://scssphp.github.io/scssphp Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/vendor/leafo/scssphp/README.md b/vendor/scssphp/scssphp/README.md similarity index 81% rename from vendor/leafo/scssphp/README.md rename to vendor/scssphp/scssphp/README.md index 53a4c7a4..f541e488 100644 --- a/vendor/leafo/scssphp/README.md +++ b/vendor/scssphp/scssphp/README.md @@ -1,12 +1,12 @@ # scssphp -### +### -[![Build](https://travis-ci.org/leafo/scssphp.svg?branch=master)](http://travis-ci.org/leafo/scssphp) -[![License](https://poser.pugx.org/leafo/scssphp/license.svg)](https://packagist.org/packages/leafo/scssphp) +[![Build](https://travis-ci.org/scssphp/scssphp.svg?branch=master)](http://travis-ci.org/scssphp/scssphp) +[![License](https://poser.pugx.org/scssphp/scssphp/license)](https://packagist.org/packages/scssphp/scssphp) `scssphp` is a compiler for SCSS written in PHP. -Checkout the homepage, , for directions on how to use. +Checkout the homepage, , for directions on how to use. ## Running Tests diff --git a/vendor/leafo/scssphp/bin/pscss b/vendor/scssphp/scssphp/bin/pscss similarity index 73% rename from vendor/leafo/scssphp/bin/pscss rename to vendor/scssphp/scssphp/bin/pscss index be1cb51c..f944b632 100644 --- a/vendor/leafo/scssphp/bin/pscss +++ b/vendor/scssphp/scssphp/bin/pscss @@ -3,24 +3,24 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ error_reporting(E_ALL); -if (version_compare(PHP_VERSION, '5.4') < 0) { - die('Requires PHP 5.4 or above'); +if (version_compare(PHP_VERSION, '5.6') < 0) { + die('Requires PHP 5.6 or above'); } include __DIR__ . '/../scss.inc.php'; -use Leafo\ScssPhp\Compiler; -use Leafo\ScssPhp\Parser; -use Leafo\ScssPhp\Version; +use ScssPhp\ScssPhp\Compiler; +use ScssPhp\ScssPhp\Parser; +use ScssPhp\ScssPhp\Version; $style = null; $loadPaths = null; @@ -62,7 +62,7 @@ function parseArgument(&$i, $options) { } for ($i = 1; $i < $argc; $i++) { - if ($argv[$i] === '-h' || $argv[$i] === '--help') { + if ($argv[$i] === '-?' || $argv[$i] === '-h' || $argv[$i] === '--help') { $exe = $argv[0]; $HELP = <<setFormatter('Leafo\\ScssPhp\\Formatter\\' . ucfirst($style)); + $scss->setFormatter('ScssPhp\\ScssPhp\\Formatter\\' . ucfirst($style)); } if ($sourceMap) { - $scss->setSourceMap(Compiler::SOURCE_MAP_FILE); + $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); } if ($encoding) { diff --git a/vendor/scssphp/scssphp/composer.json b/vendor/scssphp/scssphp/composer.json new file mode 100644 index 00000000..ff0590fb --- /dev/null +++ b/vendor/scssphp/scssphp/composer.json @@ -0,0 +1,51 @@ +{ + "name": "scssphp/scssphp", + "type": "library", + "description": "scssphp is a compiler for SCSS written in PHP.", + "keywords": ["css", "stylesheet", "scss", "sass", "less"], + "homepage": "http://scssphp.github.io/scssphp/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthon Pang", + "email": "apang@softwaredevelopment.ca", + "homepage": "https://github.com/robocoder" + }, + { + "name": "Cédric Morin", + "email": "cedric@yterium.com", + "homepage": "https://github.com/Cerdic" + } + ], + "autoload": { + "psr-4": { "ScssPhp\\ScssPhp\\": "src/" } + }, + "autoload-dev": { + "psr-4": { "ScssPhp\\ScssPhp\\Tests\\": "tests/" } + }, + "require": { + "php": ">=5.6.0", + "ext-json": "*", + "ext-ctype": "*" + }, + "require-dev": { + "squizlabs/php_codesniffer": "~2.5", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3", + "twbs/bootstrap": "~4.3", + "zurb/foundation": "~6.5" + }, + "minimum-stability": "dev", + "bin": ["bin/pscss"], + "archive": { + "exclude": [ + "/Makefile", + "/.gitattributes", + "/.gitignore", + "/.travis.yml", + "/phpunit.xml.dist", + "/tests" + ] + } +} diff --git a/vendor/leafo/scssphp/example/Server.php b/vendor/scssphp/scssphp/example/Server.php similarity index 90% rename from vendor/leafo/scssphp/example/Server.php rename to vendor/scssphp/scssphp/example/Server.php index 6ea97018..6fa11e3a 100644 --- a/vendor/leafo/scssphp/example/Server.php +++ b/vendor/scssphp/scssphp/example/Server.php @@ -2,18 +2,18 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp; +namespace ScssPhp\ScssPhp; -use Leafo\ScssPhp\Compiler; -use Leafo\ScssPhp\Exception\ServerException; -use Leafo\ScssPhp\Version; +use ScssPhp\ScssPhp\Compiler; +use ScssPhp\ScssPhp\Exception\ServerException; +use ScssPhp\ScssPhp\Version; /** * Server @@ -38,7 +38,7 @@ class Server private $cacheDir; /** - * @var \Leafo\ScssPhp\Compiler + * @var \ScssPhp\ScssPhp\Compiler */ private $scss; @@ -62,13 +62,16 @@ class Server */ protected function inputName() { - switch (true) { - case isset($_GET['p']): - return $_GET['p']; - case isset($_SERVER['PATH_INFO']): - return $_SERVER['PATH_INFO']; - case isset($_SERVER['DOCUMENT_URI']): - return substr($_SERVER['DOCUMENT_URI'], strlen($_SERVER['SCRIPT_NAME'])); + if (isset($_GET['p'])) { + return $_GET['p']; + } + + if (isset($_SERVER['PATH_INFO'])) { + return $_SERVER['PATH_INFO']; + } + + if (isset($_SERVER['DOCUMENT_URI'])) { + return substr($_SERVER['DOCUMENT_URI'], strlen($_SERVER['SCRIPT_NAME'])); } } @@ -96,6 +99,8 @@ class Server /** * Get path to cached .css file * + * @param string $fname + * * @return string */ protected function cacheName($fname) @@ -106,6 +111,8 @@ class Server /** * Get path to meta data * + * @param string $out + * * @return string */ protected function metadataName($out) @@ -270,7 +277,7 @@ class Server * * @return string|bool * - * @throws \Leafo\ScssPhp\Exception\ServerException + * @throws \ScssPhp\ScssPhp\Exception\ServerException */ public function compileFile($in, $out = null) { @@ -284,11 +291,11 @@ class Server $compiled = $this->scss->compile(file_get_contents($in), $in); - if ($out !== null) { - return file_put_contents($out, $compiled); + if (is_null($out)) { + return $compiled; } - return $compiled; + return file_put_contents($out, $compiled); } /** @@ -395,7 +402,7 @@ class Server * * @return string Compiled CSS results * - * @throws \Leafo\ScssPhp\Exception\ServerException + * @throws \ScssPhp\ScssPhp\Exception\ServerException */ public function checkedCachedCompile($in, $out, $force = false) { @@ -466,27 +473,28 @@ class Server return null; } - if ($root !== null) { - // If we have a root value which means we should rebuild. - $out = array(); - $out['root'] = $root; - $out['compiled'] = $this->compileFile($root); - $out['files'] = $this->scss->getParsedFiles(); - $out['updated'] = time(); - return $out; - } else { + if (is_null($root)) { // No changes, pass back the structure // we were given initially. return $in; } + + // If we have a root value which means we should rebuild. + $out = []; + $out['root'] = $root; + $out['compiled'] = $this->compileFile($root); + $out['files'] = $this->scss->getParsedFiles(); + $out['updated'] = time(); + + return $out; } /** * Constructor * - * @param string $dir Root directory to .scss files - * @param string $cacheDir Cache directory - * @param \Leafo\ScssPhp\Compiler|null $scss SCSS compiler instance + * @param string $dir Root directory to .scss files + * @param string $cacheDir Cache directory + * @param \ScssPhp\ScssPhp\Compiler|null $scss SCSS compiler instance */ public function __construct($dir, $cacheDir = null, $scss = null) { diff --git a/vendor/leafo/scssphp/scss.inc.php b/vendor/scssphp/scssphp/scss.inc.php similarity index 80% rename from vendor/leafo/scssphp/scss.inc.php rename to vendor/scssphp/scssphp/scss.inc.php index 13c84bf5..e4ec7f18 100644 --- a/vendor/leafo/scssphp/scss.inc.php +++ b/vendor/scssphp/scssphp/scss.inc.php @@ -1,11 +1,12 @@ $lastModified) && + $cacheTime + self::$gcLifetime > time() + ) { + $c = file_get_contents($fileCache); + $c = unserialize($c); + + if (is_array($c) && isset($c['value'])) { + return $c['value']; + } + } + } + + return null; + } + + /** + * Put in cache the result of $operation on $what, + * which is known as dependant from the content of $options + * + * @param string $operation + * @param mixed $what + * @param mixed $value + * @param array $options + */ + public function setCache($operation, $what, $value, $options = []) + { + $fileCache = self::$cacheDir . self::cacheName($operation, $what, $options); + + $c = ['value' => $value]; + $c = serialize($c); + file_put_contents($fileCache, $c); + + if (self::$forceRefresh === 'once') { + self::$refreshed[$fileCache] = true; + } + } + + /** + * Get the cache name for the caching of $operation on $what, + * which is known as dependant from the content of $options + * + * @param string $operation + * @param mixed $what + * @param array $options + * + * @return string + */ + private static function cacheName($operation, $what, $options = []) + { + $t = [ + 'version' => self::CACHE_VERSION, + 'operation' => $operation, + 'what' => $what, + 'options' => $options + ]; + + $t = self::$prefix + . sha1(json_encode($t)) + . ".$operation" + . ".scsscache"; + + return $t; + } + + /** + * Check that the cache dir exists and is writeable + * + * @throws \Exception + */ + public static function checkCacheDir() + { + self::$cacheDir = str_replace('\\', '/', self::$cacheDir); + self::$cacheDir = rtrim(self::$cacheDir, '/') . '/'; + + if (! is_dir(self::$cacheDir)) { + if (! mkdir(self::$cacheDir)) { + throw new Exception('Cache directory couldn\'t be created: ' . self::$cacheDir); + } + } + + if (! is_writable(self::$cacheDir)) { + throw new Exception('Cache directory isn\'t writable: ' . self::$cacheDir); + } + } + + /** + * Delete unused cached files + */ + public static function cleanCache() + { + static $clean = false; + + if ($clean || empty(self::$cacheDir)) { + return; + } + + $clean = true; + + // only remove files with extensions created by SCSSPHP Cache + // css files removed based on the list files + $removeTypes = ['scsscache' => 1]; + + $files = scandir(self::$cacheDir); + + if (! $files) { + return; + } + + $checkTime = time() - self::$gcLifetime; + + foreach ($files as $file) { + // don't delete if the file wasn't created with SCSSPHP Cache + if (strpos($file, self::$prefix) !== 0) { + continue; + } + + $parts = explode('.', $file); + $type = array_pop($parts); + + if (! isset($removeTypes[$type])) { + continue; + } + + $fullPath = self::$cacheDir . $file; + $mtime = filemtime($fullPath); + + // don't delete if it's a relatively new file + if ($mtime > $checkTime) { + continue; + } + + unlink($fullPath); + } + } +} diff --git a/vendor/leafo/scssphp/src/Colors.php b/vendor/scssphp/scssphp/src/Colors.php similarity index 74% rename from vendor/leafo/scssphp/src/Colors.php rename to vendor/scssphp/scssphp/src/Colors.php index 2314ea58..ef6409ac 100644 --- a/vendor/leafo/scssphp/src/Colors.php +++ b/vendor/scssphp/scssphp/src/Colors.php @@ -2,14 +2,14 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp; +namespace ScssPhp\ScssPhp; /** * CSS Colors @@ -25,7 +25,7 @@ class Colors * * @var array */ - public static $cssColors = [ + protected static $cssColors = [ 'aliceblue' => '240,248,255', 'antiquewhite' => '250,235,215', 'aqua' => '0,255,255', @@ -176,4 +176,71 @@ class Colors 'yellow' => '255,255,0', 'yellowgreen' => '154,205,50', ]; + + /** + * Convert named color in a [r,g,b[,a]] array + * + * @param string $colorName + * + * @return array|null + */ + public static function colorNameToRGBa($colorName) + { + if (is_string($colorName) && isset(static::$cssColors[$colorName])) { + $rgba = explode(',', static::$cssColors[$colorName]); + + // only case with opacity is transparent, with opacity=0, so we can intval on opacity also + $rgba = array_map('intval', $rgba); + + return $rgba; + } + + return null; + } + + /** + * Reverse conversion : from RGBA to a color name if possible + * + * @param integer $r + * @param integer $g + * @param integer $b + * @param integer $a + * + * @return string|null + */ + public static function RGBaToColorName($r, $g, $b, $a = 1) + { + static $reverseColorTable = null; + + if (! is_numeric($r) || ! is_numeric($g) || ! is_numeric($b) || ! is_numeric($a)) { + return null; + } + + if ($a < 1) { + # specific case we dont' revert according to spec + #if (! $a && ! $r && ! $g && ! $b) { + # return 'transparent'; + #} + + return null; + } + + if (is_null($reverseColorTable)) { + $reverseColorTable = []; + + foreach (static::$cssColors as $name => $rgb_str) { + $rgb_str = explode(',', $rgb_str); + + if (count($rgb_str) == 3) { + $reverseColorTable[intval($rgb_str[0])][intval($rgb_str[1])][intval($rgb_str[2])] = $name; + } + } + } + + if (isset($reverseColorTable[intval($r)][intval($g)][intval($b)])) { + return $reverseColorTable[intval($r)][intval($g)][intval($b)]; + } + + return null; + } } diff --git a/vendor/leafo/scssphp/src/Compiler.php b/vendor/scssphp/scssphp/src/Compiler.php similarity index 52% rename from vendor/leafo/scssphp/src/Compiler.php rename to vendor/scssphp/scssphp/src/Compiler.php index 637f1c1c..711d3382 100644 --- a/vendor/leafo/scssphp/src/Compiler.php +++ b/vendor/scssphp/scssphp/src/Compiler.php @@ -2,26 +2,27 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp; +namespace ScssPhp\ScssPhp; -use Leafo\ScssPhp\Base\Range; -use Leafo\ScssPhp\Block; -use Leafo\ScssPhp\Colors; -use Leafo\ScssPhp\Compiler\Environment; -use Leafo\ScssPhp\Exception\CompilerException; -use Leafo\ScssPhp\Formatter\OutputBlock; -use Leafo\ScssPhp\Node; -use Leafo\ScssPhp\SourceMap\SourceMapGenerator; -use Leafo\ScssPhp\Type; -use Leafo\ScssPhp\Parser; -use Leafo\ScssPhp\Util; +use ScssPhp\ScssPhp\Base\Range; +use ScssPhp\ScssPhp\Block; +use ScssPhp\ScssPhp\Cache; +use ScssPhp\ScssPhp\Colors; +use ScssPhp\ScssPhp\Compiler\Environment; +use ScssPhp\ScssPhp\Exception\CompilerException; +use ScssPhp\ScssPhp\Formatter\OutputBlock; +use ScssPhp\ScssPhp\Node; +use ScssPhp\ScssPhp\SourceMap\SourceMapGenerator; +use ScssPhp\ScssPhp\Type; +use ScssPhp\ScssPhp\Parser; +use ScssPhp\ScssPhp\Util; /** * The scss compiler and parser. @@ -98,17 +99,17 @@ class Compiler 'function' => '^', ]; - static public $true = [Type::T_KEYWORD, 'true']; - static public $false = [Type::T_KEYWORD, 'false']; - static public $null = [Type::T_NULL]; - static public $nullString = [Type::T_STRING, '', []]; + static public $true = [Type::T_KEYWORD, 'true']; + static public $false = [Type::T_KEYWORD, 'false']; + static public $null = [Type::T_NULL]; + static public $nullString = [Type::T_STRING, '', []]; static public $defaultValue = [Type::T_KEYWORD, '']; static public $selfSelector = [Type::T_SELF]; - static public $emptyList = [Type::T_LIST, '', []]; - static public $emptyMap = [Type::T_MAP, [], []]; - static public $emptyString = [Type::T_STRING, '"', []]; - static public $with = [Type::T_KEYWORD, 'with']; - static public $without = [Type::T_KEYWORD, 'without']; + static public $emptyList = [Type::T_LIST, '', []]; + static public $emptyMap = [Type::T_MAP, [], []]; + static public $emptyString = [Type::T_STRING, '"', []]; + static public $with = [Type::T_KEYWORD, 'with']; + static public $without = [Type::T_KEYWORD, 'without']; protected $importPaths = ['']; protected $importCache = []; @@ -129,15 +130,15 @@ class Compiler protected $sourceMapOptions = []; /** - * @var string|\Leafo\ScssPhp\Formatter + * @var string|\ScssPhp\ScssPhp\Formatter */ - protected $formatter = 'Leafo\ScssPhp\Formatter\Nested'; + protected $formatter = 'ScssPhp\ScssPhp\Formatter\Nested'; protected $rootEnv; protected $rootBlock; /** - * @var \Leafo\ScssPhp\Compiler\Environment + * @var \ScssPhp\ScssPhp\Compiler\Environment */ protected $env; protected $scope; @@ -145,26 +146,67 @@ class Compiler protected $charsetSeen; protected $sourceNames; - private $indentLevel; - private $commentsSeen; - private $extends; - private $extendsMap; - private $parsedFiles; - private $parser; - private $sourceIndex; - private $sourceLine; - private $sourceColumn; - private $stderr; - private $shouldEvaluate; - private $ignoreErrors; + protected $cache; + + protected $indentLevel; + protected $extends; + protected $extendsMap; + protected $parsedFiles; + protected $parser; + protected $sourceIndex; + protected $sourceLine; + protected $sourceColumn; + protected $stderr; + protected $shouldEvaluate; + protected $ignoreErrors; + + protected $callStack = []; /** * Constructor + * + * @param array|null $cacheOptions */ - public function __construct() + public function __construct($cacheOptions = null) { $this->parsedFiles = []; $this->sourceNames = []; + + if ($cacheOptions) { + $this->cache = new Cache($cacheOptions); + } + + $this->stderr = fopen('php://stderr', 'w'); + } + + /** + * Get compiler options + * + * @return array + */ + public function getCompileOptions() + { + $options = [ + 'importPaths' => $this->importPaths, + 'registeredVars' => $this->registeredVars, + 'registeredFeatures' => $this->registeredFeatures, + 'encoding' => $this->encoding, + 'sourceMap' => serialize($this->sourceMap), + 'sourceMapOptions' => $this->sourceMapOptions, + 'formatter' => $this->formatter, + ]; + + return $options; + } + + /** + * Set an alternative error output stream, for testing purpose only + * + * @param resource $handle + */ + public function setErrorOuput($handle) + { + $this->stderr = $handle; } /** @@ -179,8 +221,28 @@ class Compiler */ public function compile($code, $path = null) { + if ($this->cache) { + $cacheKey = ($path ? $path : "(stdin)") . ":" . md5($code); + $compileOptions = $this->getCompileOptions(); + $cache = $this->cache->getCache("compile", $cacheKey, $compileOptions); + + if (is_array($cache) && isset($cache['dependencies']) && isset($cache['out'])) { + // check if any dependency file changed before accepting the cache + foreach ($cache['dependencies'] as $file => $mtime) { + if (! is_file($file) || filemtime($file) !== $mtime) { + unset($cache); + break; + } + } + + if (isset($cache)) { + return $cache['out']; + } + } + } + + $this->indentLevel = -1; - $this->commentsSeen = []; $this->extends = []; $this->extendsMap = []; $this->sourceIndex = null; @@ -191,10 +253,9 @@ class Compiler $this->storeEnv = null; $this->charsetSeen = null; $this->shouldEvaluate = null; - $this->stderr = fopen('php://stderr', 'w'); $this->parser = $this->parserFactory($path); - $tree = $this->parser->parse($code); + $tree = $this->parser->parse($code); $this->parser = null; $this->formatter = new $this->formatter(); @@ -235,6 +296,15 @@ class Compiler $out .= sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl); } + if ($this->cache && isset($cacheKey) && isset($compileOptions)) { + $v = [ + 'dependencies' => $this->getParsedFiles(), + 'out' => &$out, + ]; + + $this->cache->setCache("compile", $cacheKey, $v, $compileOptions); + } + return $out; } @@ -243,11 +313,11 @@ class Compiler * * @param string $path * - * @return \Leafo\ScssPhp\Parser + * @return \ScssPhp\ScssPhp\Parser */ protected function parserFactory($path) { - $parser = new Parser($path, count($this->sourceNames), $this->encoding); + $parser = new Parser($path, count($this->sourceNames), $this->encoding, $this->cache); $this->sourceNames[] = $path; $this->addParsedFile($path); @@ -277,9 +347,9 @@ class Compiler /** * Push extends * - * @param array $target - * @param array $origin - * @param \stdClass $block + * @param array $target + * @param array $origin + * @param array|null $block */ protected function pushExtends($target, $origin, $block) { @@ -305,17 +375,17 @@ class Compiler * @param string $type * @param array $selectors * - * @return \Leafo\ScssPhp\Formatter\OutputBlock + * @return \ScssPhp\ScssPhp\Formatter\OutputBlock */ protected function makeOutputBlock($type, $selectors = null) { $out = new OutputBlock; - $out->type = $type; - $out->lines = []; - $out->children = []; - $out->parent = $this->scope; - $out->selectors = $selectors; - $out->depth = $this->env->depth; + $out->type = $type; + $out->lines = []; + $out->children = []; + $out->parent = $this->scope; + $out->selectors = $selectors; + $out->depth = $this->env->depth; if ($this->env->block instanceof Block) { $out->sourceName = $this->env->block->sourceName; @@ -333,7 +403,7 @@ class Compiler /** * Compile root * - * @param \Leafo\ScssPhp\Block $rootBlock + * @param \ScssPhp\ScssPhp\Block $rootBlock */ protected function compileRoot(Block $rootBlock) { @@ -372,8 +442,8 @@ class Compiler /** * Flatten selectors * - * @param \Leafo\ScssPhp\Formatter\OutputBlock $block - * @param string $parentKey + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * @param string $parentKey */ protected function flattenSelectors(OutputBlock $block, $parentKey = null) { @@ -428,6 +498,40 @@ class Compiler } } + /** + * Glue parts of :not( or :nth-child( ... that are in general splitted in selectors parts + * + * @param array $parts + * + * @return array + */ + protected function glueFunctionSelectors($parts) + { + $new = []; + + foreach ($parts as $part) { + if (is_array($part)) { + $part = $this->glueFunctionSelectors($part); + $new[] = $part; + } else { + // a selector part finishing with a ) is the last part of a :not( or :nth-child( + // and need to be joined to this + if (count($new) && is_string($new[count($new) - 1]) && + strlen($part) && substr($part, -1) === ')' && strpos($part, '(') === false + ) { + while (count($new)>1 && substr($new[count($new) - 1], -1) !== '(') { + $part = array_pop($new) . $part; + } + $new[count($new) - 1] .= $part; + } else { + $new[] = $part; + } + } + } + + return $new; + } + /** * Match extends * @@ -438,32 +542,60 @@ class Compiler */ protected function matchExtends($selector, &$out, $from = 0, $initial = true) { + static $partsPile = []; + $selector = $this->glueFunctionSelectors($selector); + + if (count($selector) == 1 && in_array(reset($selector), $partsPile)) { + return; + } + + $outRecurs = []; foreach ($selector as $i => $part) { if ($i < $from) { continue; } - if ($this->matchExtendsSingle($part, $origin)) { - $after = array_slice($selector, $i + 1); - $before = array_slice($selector, 0, $i); + // check that we are not building an infinite loop of extensions + // if the new part is just including a previous part don't try to extend anymore + if (count($part) > 1) { + foreach ($partsPile as $previousPart) { + if (! count(array_diff($previousPart, $part))) { + continue 2; + } + } + } + $partsPile[] = $part; + if ($this->matchExtendsSingle($part, $origin, $initial)) { + $after = array_slice($selector, $i + 1); + $before = array_slice($selector, 0, $i); list($before, $nonBreakableBefore) = $this->extractRelationshipFromFragment($before); foreach ($origin as $new) { $k = 0; // remove shared parts - if ($initial) { + if (count($new) > 1) { while ($k < $i && isset($new[$k]) && $selector[$k] === $new[$k]) { $k++; } } + if (count($nonBreakableBefore) and $k == count($new)) { + $k--; + } $replacement = []; $tempReplacement = $k > 0 ? array_slice($new, $k) : $new; for ($l = count($tempReplacement) - 1; $l >= 0; $l--) { - $slice = $tempReplacement[$l]; + $slice = []; + + foreach ($tempReplacement[$l] as $chunk) { + if (! in_array($chunk, $slice)) { + $slice[] = $chunk; + } + } + array_unshift($replacement, $slice); if (! $this->isImmediateRelationshipCombinator(end($slice))) { @@ -487,33 +619,93 @@ class Compiler continue; } - $out[] = $result; + $this->pushOrMergeExtentedSelector($out, $result); // recursively check for more matches - $this->matchExtends($result, $out, count($before) + count($mergedBefore), false); + $startRecurseFrom = count($before) + min(count($nonBreakableBefore), count($mergedBefore)); + if (count($origin) > 1) { + $this->matchExtends($result, $out, $startRecurseFrom, false); + } else { + $this->matchExtends($result, $outRecurs, $startRecurseFrom, false); + } // selector sequence merging if (! empty($before) && count($new) > 1) { - $sharedParts = $k > 0 ? array_slice($before, 0, $k) : []; + $preSharedParts = $k > 0 ? array_slice($before, 0, $k) : []; $postSharedParts = $k > 0 ? array_slice($before, $k) : $before; - list($injectBetweenSharedParts, $nonBreakable2) = $this->extractRelationshipFromFragment($afterBefore); + list($betweenSharedParts, $nonBreakabl2) = $this->extractRelationshipFromFragment($afterBefore); $result2 = array_merge( - $sharedParts, - $injectBetweenSharedParts, + $preSharedParts, + $betweenSharedParts, $postSharedParts, - $nonBreakable2, + $nonBreakabl2, $nonBreakableBefore, $replacement, $after ); - $out[] = $result2; + $this->pushOrMergeExtentedSelector($out, $result2); + } + } + } + array_pop($partsPile); + } + while (count($outRecurs)) { + $result = array_shift($outRecurs); + $this->pushOrMergeExtentedSelector($out, $result); + } + } + + /** + * Test a part for being a pseudo selector + * @param string $part + * @param array $matches + * @return bool + */ + protected function isPseudoSelector($part, &$matches) + { + if (strpos($part, ":") === 0 + && preg_match(",^::?([\w-]+)\((.+)\)$,", $part, $matches)) { + return true; + } + return false; + } + + /** + * Push extended selector except if + * - this is a pseudo selector + * - same as previous + * - in a white list + * in this case we merge the pseudo selector content + * @param array $out + * @param array $extended + */ + protected function pushOrMergeExtentedSelector(&$out, $extended) + { + if (count($out) && count($extended) === 1 && count(reset($extended)) === 1) { + $single = reset($extended); + $part = reset($single); + if ($this->isPseudoSelector($part, $matchesExtended) + && in_array($matchesExtended[1], [ 'slotted' ])) { + $prev = end($out); + $prev = $this->glueFunctionSelectors($prev); + if (count($prev) === 1 && count(reset($prev)) === 1) { + $single = reset($prev); + $part = reset($single); + if ($this->isPseudoSelector($part, $matchesPrev) + && $matchesPrev[1] === $matchesExtended[1]) { + $extended = explode($matchesExtended[1] . '(', $matchesExtended[0], 2); + $extended[1] = $matchesPrev[2] . ", " . $extended[1]; + $extended = implode($matchesExtended[1] . '(', $extended); + $extended = [ [ $extended ]]; + array_pop($out); } } } } + $out[] = $extended; } /** @@ -521,14 +713,20 @@ class Compiler * * @param array $rawSingle * @param array $outOrigin + * @param bool $initial * * @return boolean */ - protected function matchExtendsSingle($rawSingle, &$outOrigin) + protected function matchExtendsSingle($rawSingle, &$outOrigin, $initial = true) { $counts = []; $single = []; + // simple usual cases, no need to do the whole trick + if (in_array($rawSingle, [['>'],['+'],['~']])) { + return false; + } + foreach ($rawSingle as $part) { // matches Number if (! is_string($part)) { @@ -549,20 +747,46 @@ class Compiler $extendingDecoratedTag = preg_match('/^[a-z0-9]+$/i', $single[0], $matches) ? $matches[0] : false; } - foreach ($single as $part) { + $outOrigin = []; + $found = false; + + foreach ($single as $k => $part) { if (isset($this->extendsMap[$part])) { foreach ($this->extendsMap[$part] as $idx) { $counts[$idx] = isset($counts[$idx]) ? $counts[$idx] + 1 : 1; } } + if ($initial + && $this->isPseudoSelector($part, $matches) + && ! in_array($matches[1], [ 'not' ])) { + $buffer = $matches[2]; + $parser = $this->parserFactory(__METHOD__); + if ($parser->parseSelector($buffer, $subSelectors)) { + foreach ($subSelectors as $ksub => $subSelector) { + $subExtended = []; + $this->matchExtends($subSelector, $subExtended, 0, false); + if ($subExtended) { + $subSelectorsExtended = $subSelectors; + $subSelectorsExtended[$ksub] = $subExtended; + foreach ($subSelectorsExtended as $ksse => $sse) { + $subSelectorsExtended[$ksse] = $this->collapseSelectors($sse); + } + $subSelectorsExtended = implode(', ', $subSelectorsExtended); + $singleExtended = $single; + $singleExtended[$k] = str_replace("(".$buffer.")", "($subSelectorsExtended)", $part); + $outOrigin[] = [ $singleExtended ]; + $found = true; + } + } + } + } } - $outOrigin = []; - $found = false; - foreach ($counts as $idx => $count) { list($target, $origin, /* $block */) = $this->extends[$idx]; + $origin = $this->glueFunctionSelectors($origin); + // check count if ($count !== count($target)) { continue; @@ -603,7 +827,6 @@ class Compiler return $found; } - /** * Extract a relationship from the fragment. * @@ -613,18 +836,20 @@ class Compiler * the rest. * * @param array $fragment The selector fragment maybe ending with a direction relationship combinator. + * * @return array The selector without the relationship fragment if any, the relationship fragment. */ protected function extractRelationshipFromFragment(array $fragment) { $parents = []; $children = []; + $j = $i = count($fragment); for (;;) { $children = $j != $i ? array_slice($fragment, $j, $i - $j) : []; - $parents = array_slice($fragment, 0, $j); - $slice = end($parents); + $parents = array_slice($fragment, 0, $j); + $slice = end($parents); if (empty($slice) || ! $this->isImmediateRelationshipCombinator($slice[0])) { break; @@ -646,22 +871,25 @@ class Compiler */ protected function combineSelectorSingle($base, $other) { - $tag = []; - $out = []; - $wasTag = true; + $tag = []; + $out = []; + $wasTag = false; - foreach ([$base, $other] as $single) { + foreach ([array_reverse($base), array_reverse($other)] as $single) { foreach ($single as $part) { - if (preg_match('/^[\[.:#]/', $part)) { + if (preg_match('/^[\[:]/', $part)) { $out[] = $part; $wasTag = false; + } elseif (preg_match('/^[\.#]/', $part)) { + array_unshift($out, $part); + $wasTag = false; } elseif (preg_match('/^[^_-]/', $part)) { $tag[] = $part; $wasTag = true; } elseif ($wasTag) { $tag[count($tag) - 1] .= $part; } else { - $out[count($out) - 1] .= $part; + $out[] = $part; } } } @@ -676,19 +904,24 @@ class Compiler /** * Compile media * - * @param \Leafo\ScssPhp\Block $media + * @param \ScssPhp\ScssPhp\Block $media */ protected function compileMedia(Block $media) { $this->pushEnv($media); - $mediaQuery = $this->compileMediaQuery($this->multiplyMedia($this->env)); - - if (! empty($mediaQuery)) { - $this->scope = $this->makeOutputBlock(Type::T_MEDIA, [$mediaQuery]); + $mediaQueries = $this->compileMediaQuery($this->multiplyMedia($this->env)); + if (! empty($mediaQueries) && $mediaQueries) { + $previousScope = $this->scope; $parentScope = $this->mediaParent($this->scope); - $parentScope->children[] = $this->scope; + + foreach ($mediaQueries as $mediaQuery) { + $this->scope = $this->makeOutputBlock(Type::T_MEDIA, [$mediaQuery]); + + $parentScope->children[] = $this->scope; + $parentScope = $this->scope; + } // top level properties in a media cause it to be wrapped $needsWrap = false; @@ -718,11 +951,35 @@ class Compiler $wrapped->children = $media->children; $media->children = [[Type::T_BLOCK, $wrapped]]; + + if (isset($this->lineNumberStyle)) { + $annotation = $this->makeOutputBlock(Type::T_COMMENT); + $annotation->depth = 0; + + $file = $this->sourceNames[$media->sourceIndex]; + $line = $media->sourceLine; + + switch ($this->lineNumberStyle) { + case static::LINE_COMMENTS: + $annotation->lines[] = '/* line ' . $line + . ($file ? ', ' . $file : '') + . ' */'; + break; + + case static::DEBUG_INFO: + $annotation->lines[] = '@media -sass-debug-info{' + . ($file ? 'filename{font-family:"' . $file . '"}' : '') + . 'line{font-family:' . $line . '}}'; + break; + } + + $this->scope->children[] = $annotation; + } } $this->compileChildrenNoReturn($media->children, $this->scope); - $this->scope = $this->scope->parent; + $this->scope = $previousScope; } $this->popEnv(); @@ -731,9 +988,9 @@ class Compiler /** * Media parent * - * @param \Leafo\ScssPhp\Formatter\OutputBlock $scope + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope * - * @return \Leafo\ScssPhp\Formatter\OutputBlock + * @return \ScssPhp\ScssPhp\Formatter\OutputBlock */ protected function mediaParent(OutputBlock $scope) { @@ -751,33 +1008,42 @@ class Compiler /** * Compile directive * - * @param \Leafo\ScssPhp\Block $block + * @param \ScssPhp\ScssPhp\Block|array $block + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out */ - protected function compileDirective(Block $block) + protected function compileDirective($directive, OutputBlock $out) { - $s = '@' . $block->name; - - if (! empty($block->value)) { - $s .= ' ' . $this->compileValue($block->value); - } - - if ($block->name === 'keyframes' || substr($block->name, -10) === '-keyframes') { - $this->compileKeyframeBlock($block, [$s]); + if (is_array($directive)) { + $s = '@' . $directive[0]; + if (! empty($directive[1])) { + $s .= ' ' . $this->compileValue($directive[1]); + } + $this->appendRootDirective($s . ';', $out); } else { - $this->compileNestedBlock($block, [$s]); + $s = '@' . $directive->name; + + if (! empty($directive->value)) { + $s .= ' ' . $this->compileValue($directive->value); + } + + if ($directive->name === 'keyframes' || substr($directive->name, -10) === '-keyframes') { + $this->compileKeyframeBlock($directive, [$s]); + } else { + $this->compileNestedBlock($directive, [$s]); + } } } /** * Compile at-root * - * @param \Leafo\ScssPhp\Block $block + * @param \ScssPhp\ScssPhp\Block $block */ protected function compileAtRoot(Block $block) { $env = $this->pushEnv($block); $envs = $this->compactEnv($env); - $without = isset($block->with) ? $this->compileWith($block->with) : static::WITH_RULE; + list($with, $without) = $this->compileWith(isset($block->with) ? $block->with : null); // wrap inline selector if ($block->selector) { @@ -790,18 +1056,29 @@ class Compiler $wrapped->comments = []; $wrapped->parent = $block; $wrapped->children = $block->children; + $wrapped->selfParent = $block->selfParent; $block->children = [[Type::T_BLOCK, $wrapped]]; + $block->selector = null; } - $this->env = $this->filterWithout($envs, $without); - $newBlock = $this->spliceTree($envs, $block, $without); + $selfParent = $block->selfParent; + + if (! $block->selfParent->selectors && isset($block->parent) && $block->parent && + isset($block->parent->selectors) && $block->parent->selectors + ) { + $selfParent = $block->parent; + } + + $this->env = $this->filterWithWithout($envs, $with, $without); $saveScope = $this->scope; - $this->scope = $this->rootBlock; + $this->scope = $this->filterScopeWithWithout($saveScope, $with, $without); - $this->compileChild($newBlock, $this->scope); + // propagate selfParent to the children where they still can be useful + $this->compileChildrenNoReturn($block->children, $this->scope, $selfParent); + $this->scope = $this->completeScope($this->scope, $saveScope); $this->scope = $saveScope; $this->env = $this->extractEnv($envs); @@ -809,152 +1086,190 @@ class Compiler } /** - * Splice parse tree + * Filter at-root scope depending of with/without option * - * @param array $envs - * @param \Leafo\ScssPhp\Block $block - * @param integer $without + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * @param array $with + * @param array $without * - * @return array + * @return mixed */ - private function spliceTree($envs, Block $block, $without) + protected function filterScopeWithWithout($scope, $with, $without) { - $newBlock = null; + $filteredScopes = []; + $childStash = []; - foreach ($envs as $e) { - if (! isset($e->block)) { - continue; - } - - if ($e->block === $block) { - continue; - } - - if (isset($e->block->type) && $e->block->type === Type::T_AT_ROOT) { - continue; - } - - if ($e->block && $this->isWithout($without, $e->block)) { - continue; - } - - $b = new Block; - $b->sourceName = $e->block->sourceName; - $b->sourceIndex = $e->block->sourceIndex; - $b->sourceLine = $e->block->sourceLine; - $b->sourceColumn = $e->block->sourceColumn; - $b->selectors = []; - $b->comments = $e->block->comments; - $b->parent = null; - - if ($newBlock) { - $type = isset($newBlock->type) ? $newBlock->type : Type::T_BLOCK; - - $b->children = [[$type, $newBlock]]; - - $newBlock->parent = $b; - } elseif (count($block->children)) { - foreach ($block->children as $child) { - if ($child[0] === Type::T_BLOCK) { - $child[1]->parent = $b; - } - } - - $b->children = $block->children; - } - - if (isset($e->block->type)) { - $b->type = $e->block->type; - } - - if (isset($e->block->name)) { - $b->name = $e->block->name; - } - - if (isset($e->block->queryList)) { - $b->queryList = $e->block->queryList; - } - - if (isset($e->block->value)) { - $b->value = $e->block->value; - } - - $newBlock = $b; + if ($scope->type === TYPE::T_ROOT) { + return $scope; } - $type = isset($newBlock->type) ? $newBlock->type : Type::T_BLOCK; + // start from the root + while ($scope->parent && $scope->parent->type !== TYPE::T_ROOT) { + array_unshift($childStash, $scope); + $scope = $scope->parent; + } - return [$type, $newBlock]; + for (;;) { + if (! $scope) { + break; + } + + if ($this->isWith($scope, $with, $without)) { + $s = clone $scope; + $s->children = []; + $s->lines = []; + $s->parent = null; + + if ($s->type !== Type::T_MEDIA && $s->type !== Type::T_DIRECTIVE) { + $s->selectors = []; + } + + $filteredScopes[] = $s; + } + + if (count($childStash)) { + $scope = array_shift($childStash); + } elseif ($scope->children) { + $scope = end($scope->children); + } else { + $scope = null; + } + } + + if (! count($filteredScopes)) { + return $this->rootBlock; + } + + $newScope = array_shift($filteredScopes); + $newScope->parent = $this->rootBlock; + + $this->rootBlock->children[] = $newScope; + + $p = &$newScope; + + while (count($filteredScopes)) { + $s = array_shift($filteredScopes); + $s->parent = $p; + $p->children[] = $s; + $newScope = &$p->children[0]; + $p = &$p->children[0]; + } + + return $newScope; } /** - * Compile @at-root's with: inclusion / without: exclusion into filter flags + * found missing selector from a at-root compilation in the previous scope + * (if at-root is just enclosing a property, the selector is in the parent tree) * - * @param array $with + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $previousScope * - * @return integer + * @return mixed */ - private function compileWith($with) + protected function completeScope($scope, $previousScope) { - static $mapping = [ - 'rule' => self::WITH_RULE, - 'media' => self::WITH_MEDIA, - 'supports' => self::WITH_SUPPORTS, - 'all' => self::WITH_ALL, - ]; + if (! $scope->type && (! $scope->selectors || ! count($scope->selectors)) && count($scope->lines)) { + $scope->selectors = $this->findScopeSelectors($previousScope, $scope->depth); + } - // exclude selectors by default - $without = static::WITH_RULE; + if ($scope->children) { + foreach ($scope->children as $k => $c) { + $scope->children[$k] = $this->completeScope($c, $previousScope); + } + } - if ($this->libMapHasKey([$with, static::$with])) { - $without = static::WITH_ALL; + return $scope; + } - $list = $this->coerceList($this->libMapGet([$with, static::$with])); + /** + * Find a selector by the depth node in the scope + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * @param integer $depth + * + * @return array + */ + protected function findScopeSelectors($scope, $depth) + { + if ($scope->depth === $depth && $scope->selectors) { + return $scope->selectors; + } - foreach ($list[2] as $item) { - $keyword = $this->compileStringContent($this->coerceString($item)); - - if (array_key_exists($keyword, $mapping)) { - $without &= ~($mapping[$keyword]); + if ($scope->children) { + foreach (array_reverse($scope->children) as $c) { + if ($s = $this->findScopeSelectors($c, $depth)) { + return $s; } } } - if ($this->libMapHasKey([$with, static::$without])) { - $without = 0; + return []; + } - $list = $this->coerceList($this->libMapGet([$with, static::$without])); + /** + * Compile @at-root's with: inclusion / without: exclusion into 2 lists uses to filter scope/env later + * + * @param array $withCondition + * + * @return array + */ + protected function compileWith($withCondition) + { + // just compile what we have in 2 lists + $with = []; + $without = ['rule' => true]; - foreach ($list[2] as $item) { - $keyword = $this->compileStringContent($this->coerceString($item)); + if ($withCondition) { + if ($this->libMapHasKey([$withCondition, static::$with])) { + $without = []; // cancel the default + $list = $this->coerceList($this->libMapGet([$withCondition, static::$with])); - if (array_key_exists($keyword, $mapping)) { - $without |= $mapping[$keyword]; + foreach ($list[2] as $item) { + $keyword = $this->compileStringContent($this->coerceString($item)); + + $with[$keyword] = true; + } + } + + if ($this->libMapHasKey([$withCondition, static::$without])) { + $without = []; // cancel the default + $list = $this->coerceList($this->libMapGet([$withCondition, static::$without])); + + foreach ($list[2] as $item) { + $keyword = $this->compileStringContent($this->coerceString($item)); + + $without[$keyword] = true; } } } - return $without; + return [$with, $without]; } /** * Filter env stack * * @param array $envs - * @param integer $without + * @param array $with + * @param array $without * - * @return \Leafo\ScssPhp\Compiler\Environment + * @return \ScssPhp\ScssPhp\Compiler\Environment */ - private function filterWithout($envs, $without) + protected function filterWithWithout($envs, $with, $without) { $filtered = []; foreach ($envs as $e) { - if ($e->block && $this->isWithout($without, $e->block)) { - continue; - } + if ($e->block && ! $this->isWith($e->block, $with, $without)) { + $ec = clone $e; + $ec->block = null; + $ec->selectors = []; - $filtered[] = $e; + $filtered[] = $ec; + } else { + $filtered[] = $e; + } } return $this->extractEnv($filtered); @@ -963,31 +1278,76 @@ class Compiler /** * Filter WITH rules * - * @param integer $without - * @param \Leafo\ScssPhp\Block $block + * @param \ScssPhp\ScssPhp\Block|\ScssPhp\ScssPhp\Formatter\OutputBlock $block + * @param array $with + * @param array $without * * @return boolean */ - private function isWithout($without, Block $block) + protected function isWith($block, $with, $without) { - if ((($without & static::WITH_RULE) && isset($block->selectors)) || - (($without & static::WITH_MEDIA) && - isset($block->type) && $block->type === Type::T_MEDIA) || - (($without & static::WITH_SUPPORTS) && - isset($block->type) && $block->type === Type::T_DIRECTIVE && - isset($block->name) && $block->name === 'supports') - ) { - return true; + if (isset($block->type)) { + if ($block->type === Type::T_MEDIA) { + return $this->testWithWithout('media', $with, $without); + } + + if ($block->type === Type::T_DIRECTIVE) { + if (isset($block->name)) { + return $this->testWithWithout($block->name, $with, $without); + } elseif (isset($block->selectors) && preg_match(',@(\w+),ims', json_encode($block->selectors), $m)) { + return $this->testWithWithout($m[1], $with, $without); + } else { + return $this->testWithWithout('???', $with, $without); + } + } + } elseif (isset($block->selectors)) { + // a selector starting with number is a keyframe rule + if (count($block->selectors)) { + $s = reset($block->selectors); + + while (is_array($s)) { + $s = reset($s); + } + + if (is_object($s) && $s instanceof Node\Number) { + return $this->testWithWithout('keyframes', $with, $without); + } + } + + return $this->testWithWithout('rule', $with, $without); } - return false; + return true; } + /** + * Test a single type of block against with/without lists + * + * @param string $what + * @param array $with + * @param array $without + * + * @return boolean + * true if the block should be kept, false to reject + */ + protected function testWithWithout($what, $with, $without) + { + + // if without, reject only if in the list (or 'all' is in the list) + if (count($without)) { + return (isset($without[$what]) || isset($without['all'])) ? false : true; + } + + // otherwise reject all what is not in the with list + return (isset($with[$what]) || isset($with['all'])) ? true : false; + } + + /** * Compile keyframe block * - * @param \Leafo\ScssPhp\Block $block - * @param array $selectors + * @param \ScssPhp\ScssPhp\Block $block + * @param array $selectors */ protected function compileKeyframeBlock(Block $block, $selectors) { @@ -1011,11 +1371,45 @@ class Compiler $this->popEnv(); } + /** + * Compile nested properties lines + * + * @param \ScssPhp\ScssPhp\Block $block + * @param OutputBlock $out + */ + protected function compileNestedPropertiesBlock(Block $block, OutputBlock $out) + { + $prefix = $this->compileValue($block->prefix) . '-'; + + $nested = $this->makeOutputBlock($block->type); + $nested->parent = $out; + + if ($block->hasValue) { + $nested->depth = $out->depth + 1; + } + + $out->children[] = $nested; + + foreach ($block->children as $child) { + switch ($child[0]) { + case Type::T_ASSIGN: + array_unshift($child[1][2], $prefix); + break; + + case Type::T_NESTED_PROPERTY: + array_unshift($child[1]->prefix[2], $prefix); + break; + } + + $this->compileChild($child, $nested); + } + } + /** * Compile nested block * - * @param \Leafo\ScssPhp\Block $block - * @param array $selectors + * @param \ScssPhp\ScssPhp\Block $block + * @param array $selectors */ protected function compileNestedBlock(Block $block, $selectors) { @@ -1024,6 +1418,35 @@ class Compiler $this->scope = $this->makeOutputBlock($block->type, $selectors); $this->scope->parent->children[] = $this->scope; + // wrap assign children in a block + // except for @font-face + if ($block->type !== Type::T_DIRECTIVE || $block->name !== "font-face") { + // need wrapping? + $needWrapping = false; + + foreach ($block->children as $child) { + if ($child[0] === Type::T_ASSIGN) { + $needWrapping = true; + break; + } + } + + if ($needWrapping) { + $wrapped = new Block; + $wrapped->sourceName = $block->sourceName; + $wrapped->sourceIndex = $block->sourceIndex; + $wrapped->sourceLine = $block->sourceLine; + $wrapped->sourceColumn = $block->sourceColumn; + $wrapped->selectors = []; + $wrapped->comments = []; + $wrapped->parent = $block; + $wrapped->children = $block->children; + $wrapped->selfParent = $block->selfParent; + + $block->children = [[Type::T_BLOCK, $wrapped]]; + } + } + $this->compileChildrenNoReturn($block->children, $this->scope); $this->scope = $this->scope->parent; @@ -1047,7 +1470,7 @@ class Compiler * * @see Compiler::compileChild() * - * @param \Leafo\ScssPhp\Block $block + * @param \ScssPhp\ScssPhp\Block $block */ protected function compileBlock(Block $block) { @@ -1083,16 +1506,62 @@ class Compiler $this->scope->children[] = $out; if (count($block->children)) { - $out->selectors = $this->multiplySelectors($env); + $out->selectors = $this->multiplySelectors($env, $block->selfParent); - $this->compileChildrenNoReturn($block->children, $out); + // propagate selfParent to the children where they still can be useful + $selfParentSelectors = null; + + if (isset($block->selfParent->selectors)) { + $selfParentSelectors = $block->selfParent->selectors; + $block->selfParent->selectors = $out->selectors; + } + + $this->compileChildrenNoReturn($block->children, $out, $block->selfParent); + + // and revert for the following children of the same block + if ($selfParentSelectors) { + $block->selfParent->selectors = $selfParentSelectors; + } } - $this->formatter->stripSemicolon($out->lines); - $this->popEnv(); } + + /** + * Compile the value of a comment that can have interpolation + * + * @param array $value + * @param boolean $pushEnv + * + * @return array|mixed|string + */ + protected function compileCommentValue($value, $pushEnv = false) + { + $c = $value[1]; + + if (isset($value[2])) { + if ($pushEnv) { + $this->pushEnv(); + $storeEnv = $this->storeEnv; + $this->storeEnv = $this->env; + } + + try { + $c = $this->compileValue($value[2]); + } catch (\Exception $e) { + // ignore error in comment compilation which are only interpolation + } + + if ($pushEnv) { + $this->storeEnv = $storeEnv; + $this->popEnv(); + } + } + + return $c; + } + /** * Compile root level comment * @@ -1101,7 +1570,8 @@ class Compiler protected function compileComment($block) { $out = $this->makeOutputBlock(Type::T_COMMENT); - $out->lines[] = $block[1]; + $out->lines[] = $this->compileCommentValue($block, true); + $this->scope->children[] = $out; } @@ -1120,8 +1590,9 @@ class Compiler // after evaluating interpolates, we might need a second pass if ($this->shouldEvaluate) { - $buffer = $this->collapseSelectors($selectors); - $parser = $this->parserFactory(__METHOD__); + $selectors = $this->revertSelfSelector($selectors); + $buffer = $this->collapseSelectors($selectors); + $parser = $this->parserFactory(__METHOD__); if ($parser->parseSelector($buffer, $newSelectors)) { $selectors = array_map([$this, 'evalSelector'], $newSelectors); @@ -1174,28 +1645,89 @@ class Compiler /** * Collapse selectors * - * @param array $selectors + * @param array $selectors + * @param boolean $selectorFormat + * if false return a collapsed string + * if true return an array description of a structured selector * * @return string */ - protected function collapseSelectors($selectors) + protected function collapseSelectors($selectors, $selectorFormat = false) { $parts = []; foreach ($selectors as $selector) { - $output = ''; + $output = []; + $glueNext = false; - array_walk_recursive( - $selector, - function ($value, $key) use (&$output) { - $output .= $value; + foreach ($selector as $node) { + $compound = ''; + + array_walk_recursive( + $node, + function ($value, $key) use (&$compound) { + $compound .= $value; + } + ); + + if ($selectorFormat && $this->isImmediateRelationshipCombinator($compound)) { + if (count($output)) { + $output[count($output) - 1] .= ' ' . $compound; + } else { + $output[] = $compound; + } + + $glueNext = true; + } elseif ($glueNext) { + $output[count($output) - 1] .= ' ' . $compound; + $glueNext = false; + } else { + $output[] = $compound; } - ); + } + + if ($selectorFormat) { + foreach ($output as &$o) { + $o = [Type::T_STRING, '', [$o]]; + } + + $output = [Type::T_LIST, ' ', $output]; + } else { + $output = implode(' ', $output); + } $parts[] = $output; } - return implode(', ', $parts); + if ($selectorFormat) { + $parts = [Type::T_LIST, ',', $parts]; + } else { + $parts = implode(', ', $parts); + } + + return $parts; + } + + /** + * Parse down the selector and revert [self] to "&" before a reparsing + * + * @param array $selectors + * + * @return array + */ + protected function revertSelfSelector($selectors) + { + foreach ($selectors as &$part) { + if (is_array($part)) { + if ($part === [Type::T_SELF]) { + $part = '&'; + } else { + $part = $this->revertSelfSelector($part); + } + } + } + + return $selectors; } /** @@ -1302,16 +1834,43 @@ class Compiler return false; } + protected function pushCallStack($name = '') + { + $this->callStack[] = [ + 'n' => $name, + Parser::SOURCE_INDEX => $this->sourceIndex, + Parser::SOURCE_LINE => $this->sourceLine, + Parser::SOURCE_COLUMN => $this->sourceColumn + ]; + + // infinite calling loop + if (count($this->callStack) > 25000) { + // not displayed but you can var_dump it to deep debug + $msg = $this->callStackMessage(true, 100); + $msg = "Infinite calling loop"; + + $this->throwError($msg); + } + } + + protected function popCallStack() + { + array_pop($this->callStack); + } + /** * Compile children and return result * - * @param array $stms - * @param \Leafo\ScssPhp\Formatter\OutputBlock $out + * @param array $stms + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param string $traceName * - * @return array + * @return array|null */ - protected function compileChildren($stms, OutputBlock $out) + protected function compileChildren($stms, OutputBlock $out, $traceName = '') { + $this->pushCallStack($traceName); + foreach ($stms as $stm) { $ret = $this->compileChild($stm, $out); @@ -1319,20 +1878,38 @@ class Compiler return $ret; } } + + $this->popCallStack(); + + return null; } /** * Compile children and throw exception if unexpected @return * - * @param array $stms - * @param \Leafo\ScssPhp\Formatter\OutputBlock $out + * @param array $stms + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param \ScssPhp\ScssPhp\Block $selfParent + * @param string $traceName * * @throws \Exception */ - protected function compileChildrenNoReturn($stms, OutputBlock $out) + protected function compileChildrenNoReturn($stms, OutputBlock $out, $selfParent = null, $traceName = '') { + $this->pushCallStack($traceName); + foreach ($stms as $stm) { - $ret = $this->compileChild($stm, $out); + if ($selfParent && isset($stm[1]) && is_object($stm[1]) && $stm[1] instanceof Block) { + $stm[1]->selfParent = $selfParent; + $ret = $this->compileChild($stm, $out); + $stm[1]->selfParent = null; + } elseif ($selfParent && in_array($stm[0], [TYPE::T_INCLUDE, TYPE::T_EXTEND])) { + $stm['selfParent'] = $selfParent; + $ret = $this->compileChild($stm, $out); + unset($stm['selfParent']); + } else { + $ret = $this->compileChild($stm, $out); + } if (isset($ret)) { $this->throwError('@return may only be used within a function'); @@ -1340,6 +1917,74 @@ class Compiler return; } } + + $this->popCallStack(); + } + + + /** + * evaluate media query : compile internal value keeping the structure inchanged + * + * @param array $queryList + * + * @return array + */ + protected function evaluateMediaQuery($queryList) + { + static $parser = null; + + $outQueryList = []; + + foreach ($queryList as $kql => $query) { + $shouldReparse = false; + + foreach ($query as $kq => $q) { + for ($i = 1; $i < count($q); $i++) { + $value = $this->compileValue($q[$i]); + + // the parser had no mean to know if media type or expression if it was an interpolation + // so you need to reparse if the T_MEDIA_TYPE looks like anything else a media type + if ($q[0] == Type::T_MEDIA_TYPE && + (strpos($value, '(') !== false || + strpos($value, ')') !== false || + strpos($value, ':') !== false || + strpos($value, ',') !== false) + ) { + $shouldReparse = true; + } + + $queryList[$kql][$kq][$i] = [Type::T_KEYWORD, $value]; + } + } + + if ($shouldReparse) { + if (is_null($parser)) { + $parser = $this->parserFactory(__METHOD__); + } + + $queryString = $this->compileMediaQuery([$queryList[$kql]]); + $queryString = reset($queryString); + + if (strpos($queryString, '@media ') === 0) { + $queryString = substr($queryString, 7); + $queries = []; + + if ($parser->parseMediaQueryList($queryString, $queries)) { + $queries = $this->evaluateMediaQuery($queries[2]); + + while (count($queries)) { + $outQueryList[] = array_shift($queries); + } + + continue; + } + } + } + + $outQueryList[] = $queryList[$kql]; + } + + return $outQueryList; } /** @@ -1347,31 +1992,76 @@ class Compiler * * @param array $queryList * - * @return string + * @return array */ protected function compileMediaQuery($queryList) { - $out = '@media'; - $first = true; + $start = '@media '; + $default = trim($start); + $out = []; + $current = ""; foreach ($queryList as $query) { $type = null; $parts = []; + $mediaTypeOnly = true; + + foreach ($query as $q) { + if ($q[0] !== Type::T_MEDIA_TYPE) { + $mediaTypeOnly = false; + break; + } + } + foreach ($query as $q) { switch ($q[0]) { case Type::T_MEDIA_TYPE: - if ($type) { - $type = $this->mergeMediaTypes( - $type, - array_map([$this, 'compileValue'], array_slice($q, 1)) - ); + $newType = array_map([$this, 'compileValue'], array_slice($q, 1)); - if (empty($type)) { // merge failed - return null; + // combining not and anything else than media type is too risky and should be avoided + if (! $mediaTypeOnly) { + if (in_array(Type::T_NOT, $newType) || ($type && in_array(Type::T_NOT, $type) )) { + if ($type) { + array_unshift($parts, implode(' ', array_filter($type))); + } + + if (! empty($parts)) { + if (strlen($current)) { + $current .= $this->formatter->tagSeparator; + } + + $current .= implode(' and ', $parts); + } + + if ($current) { + $out[] = $start . $current; + } + + $current = ""; + $type = null; + $parts = []; + } + } + + if ($newType === ['all'] && $default) { + $default = $start . 'all'; + } + + // all can be safely ignored and mixed with whatever else + if ($newType !== ['all']) { + if ($type) { + $type = $this->mergeMediaTypes($type, $newType); + + if (empty($type)) { + // merge failed : ignore this query that is not valid, skip to the next one + $parts = []; + $default = ''; // if everything fail, no @media at all + continue 3; + } + } else { + $type = $newType; } - } else { - $type = array_map([$this, 'compileValue'], array_slice($q, 1)); } break; @@ -1400,20 +2090,34 @@ class Compiler } if (! empty($parts)) { - if ($first) { - $first = false; - $out .= ' '; - } else { - $out .= $this->formatter->tagSeparator; + if (strlen($current)) { + $current .= $this->formatter->tagSeparator; } - $out .= implode(' and ', $parts); + $current .= implode(' and ', $parts); } } + if ($current) { + $out[] = $start . $current; + } + + // no @media type except all, and no conflict? + if (! $out && $default) { + $out[] = $default; + } + return $out; } + /** + * Merge direct relationships between selectors + * + * @param array $selectors1 + * @param array $selectors2 + * + * @return array + */ protected function mergeDirectRelationships($selectors1, $selectors2) { if (empty($selectors1) || empty($selectors2)) { @@ -1423,7 +2127,7 @@ class Compiler $part1 = end($selectors1); $part2 = end($selectors2); - if (! $this->isImmediateRelationshipCombinator($part1[0]) || $part1 !== $part2) { + if (! $this->isImmediateRelationshipCombinator($part1[0]) && $part1 !== $part2) { return array_merge($selectors1, $selectors2); } @@ -1433,13 +2137,18 @@ class Compiler $part1 = array_pop($selectors1); $part2 = array_pop($selectors2); - if ($this->isImmediateRelationshipCombinator($part1[0]) && $part1 !== $part2) { - $merged = array_merge($selectors1, [$part1], $selectors2, [$part2], $merged); + if (! $this->isImmediateRelationshipCombinator($part1[0]) && $part1 !== $part2) { + if ($this->isImmediateRelationshipCombinator(reset($merged)[0])) { + array_unshift($merged, [$part1[0] . $part2[0]]); + $merged = array_merge($selectors1, $selectors2, $merged); + } else { + $merged = array_merge($selectors1, [$part1], $selectors2, [$part2], $merged); + } + break; } array_unshift($merged, $part1); - array_unshift($merged, [array_pop($selectors1)[0] . array_pop($selectors2)[0]]); } while (! empty($selectors1) && ! empty($selectors2)); return $merged; @@ -1463,23 +2172,19 @@ class Compiler return $type1; } - $m1 = ''; - $t1 = ''; - if (count($type1) > 1) { - $m1= strtolower($type1[0]); - $t1= strtolower($type1[1]); + $m1 = strtolower($type1[0]); + $t1 = strtolower($type1[1]); } else { + $m1 = ''; $t1 = strtolower($type1[0]); } - $m2 = ''; - $t2 = ''; - if (count($type2) > 1) { $m2 = strtolower($type2[0]); $t2 = strtolower($type2[1]); } else { + $m2 = ''; $t2 = strtolower($type2[0]); } @@ -1514,13 +2219,13 @@ class Compiler /** * Compile import; returns true if the value was something that could be imported * - * @param array $rawPath - * @param array $out - * @param boolean $once + * @param array $rawPath + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param boolean $once * * @return boolean */ - protected function compileImport($rawPath, $out, $once = false) + protected function compileImport($rawPath, OutputBlock $out, $once = false) { if ($rawPath[0] === Type::T_STRING) { $path = $this->compileStringContent($rawPath); @@ -1534,6 +2239,8 @@ class Compiler return true; } + $this->appendRootDirective('@import ' . $this->compileValue($rawPath). ';', $out); + return false; } @@ -1545,57 +2252,155 @@ class Compiler foreach ($rawPath[2] as $path) { if ($path[0] !== Type::T_STRING) { + $this->appendRootDirective('@import ' . $this->compileValue($rawPath) . ';', $out); + return false; } } foreach ($rawPath[2] as $path) { - $this->compileImport($path, $out); + $this->compileImport($path, $out, $once); } return true; } + $this->appendRootDirective('@import ' . $this->compileValue($rawPath) . ';', $out); + return false; } + + /** + * Append a root directive like @import or @charset as near as the possible from the source code + * (keeping before comments, @import and @charset coming before in the source code) + * + * @param string $line + * @param @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param array $allowed + */ + protected function appendRootDirective($line, $out, $allowed = [Type::T_COMMENT]) + { + $root = $out; + + while ($root->parent) { + $root = $root->parent; + } + + $i = 0; + + while ($i < count($root->children)) { + if (! isset($root->children[$i]->type) || ! in_array($root->children[$i]->type, $allowed)) { + break; + } + + $i++; + } + + // remove incompatible children from the bottom of the list + $saveChildren = []; + + while ($i < count($root->children)) { + $saveChildren[] = array_pop($root->children); + } + + // insert the directive as a comment + $child = $this->makeOutputBlock(Type::T_COMMENT); + $child->lines[] = $line; + $child->sourceName = $this->sourceNames[$this->sourceIndex]; + $child->sourceLine = $this->sourceLine; + $child->sourceColumn = $this->sourceColumn; + + $root->children[] = $child; + + // repush children + while (count($saveChildren)) { + $root->children[] = array_pop($saveChildren); + } + } + + /** + * Append lines to the current output block: + * directly to the block or through a child if necessary + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param string $type + * @param string|mixed $line + */ + protected function appendOutputLine(OutputBlock $out, $type, $line) + { + $outWrite = &$out; + + if ($type === Type::T_COMMENT) { + $parent = $out->parent; + + if (end($parent->children) !== $out) { + $outWrite = &$parent->children[count($parent->children) - 1]; + } + } + + // check if it's a flat output or not + if (count($out->children)) { + $lastChild = &$out->children[count($out->children) - 1]; + + if ($lastChild->depth === $out->depth && is_null($lastChild->selectors) && ! count($lastChild->children)) { + $outWrite = $lastChild; + } else { + $nextLines = $this->makeOutputBlock($type); + $nextLines->parent = $out; + $nextLines->depth = $out->depth; + + $out->children[] = $nextLines; + $outWrite = &$nextLines; + } + } + + $outWrite->lines[] = $line; + } + /** * Compile child; returns a value to halt execution * - * @param array $child - * @param \Leafo\ScssPhp\Formatter\OutputBlock $out + * @param array $child + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out * * @return array */ protected function compileChild($child, OutputBlock $out) { - $this->sourceIndex = isset($child[Parser::SOURCE_INDEX]) ? $child[Parser::SOURCE_INDEX] : null; - $this->sourceLine = isset($child[Parser::SOURCE_LINE]) ? $child[Parser::SOURCE_LINE] : -1; - $this->sourceColumn = isset($child[Parser::SOURCE_COLUMN]) ? $child[Parser::SOURCE_COLUMN] : -1; + if (isset($child[Parser::SOURCE_LINE])) { + $this->sourceIndex = isset($child[Parser::SOURCE_INDEX]) ? $child[Parser::SOURCE_INDEX] : null; + $this->sourceLine = isset($child[Parser::SOURCE_LINE]) ? $child[Parser::SOURCE_LINE] : -1; + $this->sourceColumn = isset($child[Parser::SOURCE_COLUMN]) ? $child[Parser::SOURCE_COLUMN] : -1; + } elseif (is_array($child) && isset($child[1]->sourceLine)) { + $this->sourceIndex = $child[1]->sourceIndex; + $this->sourceLine = $child[1]->sourceLine; + $this->sourceColumn = $child[1]->sourceColumn; + } elseif (! empty($out->sourceLine) && ! empty($out->sourceName)) { + $this->sourceLine = $out->sourceLine; + $this->sourceIndex = array_search($out->sourceName, $this->sourceNames); + $this->sourceColumn = $out->sourceColumn; + + if ($this->sourceIndex === false) { + $this->sourceIndex = null; + } + } switch ($child[0]) { case Type::T_SCSSPHP_IMPORT_ONCE: - list(, $rawPath) = $child; + $rawPath = $this->reduce($child[1]); - $rawPath = $this->reduce($rawPath); - - if (! $this->compileImport($rawPath, $out, true)) { - $out->lines[] = '@import ' . $this->compileValue($rawPath) . ';'; - } + $this->compileImport($rawPath, $out, true); break; case Type::T_IMPORT: - list(, $rawPath) = $child; + $rawPath = $this->reduce($child[1]); - $rawPath = $this->reduce($rawPath); - - if (! $this->compileImport($rawPath, $out)) { - $out->lines[] = '@import ' . $this->compileValue($rawPath) . ';'; - } + $this->compileImport($rawPath, $out); break; case Type::T_DIRECTIVE: - $this->compileDirective($child[1]); + $this->compileDirective($child[1], $out); break; case Type::T_AT_ROOT: @@ -1613,8 +2418,7 @@ class Compiler case Type::T_CHARSET: if (! $this->charsetSeen) { $this->charsetSeen = true; - - $out->lines[] = '@charset ' . $this->compileValue($child[1]) . ';'; + $this->appendRootDirective('@charset ' . $this->compileValue($child[1]) . ';', $out); } break; @@ -1622,35 +2426,98 @@ class Compiler list(, $name, $value) = $child; if ($name[0] === Type::T_VARIABLE) { - $flags = isset($child[3]) ? $child[3] : []; + $flags = isset($child[3]) ? $child[3] : []; $isDefault = in_array('!default', $flags); - $isGlobal = in_array('!global', $flags); + $isGlobal = in_array('!global', $flags); if ($isGlobal) { - $this->set($name[1], $this->reduce($value), false, $this->rootEnv); + $this->set($name[1], $this->reduce($value), false, $this->rootEnv, $value); break; } $shouldSet = $isDefault && - (($result = $this->get($name[1], false)) === null - || $result === static::$null); + (is_null($result = $this->get($name[1], false)) || + $result === static::$null); if (! $isDefault || $shouldSet) { - $this->set($name[1], $this->reduce($value)); + $this->set($name[1], $this->reduce($value), true, null, $value); } break; } $compiledName = $this->compileValue($name); - // handle shorthand syntax: size / line-height - if ($compiledName === 'font') { - if ($value[0] === Type::T_EXPRESSION && $value[1] === '/') { - $value = $this->expToString($value); - } elseif ($value[0] === Type::T_LIST) { - foreach ($value[2] as &$item) { + // handle shorthand syntaxes : size / line-height... + if (in_array($compiledName, ['font', 'grid-row', 'grid-column', 'border-radius'])) { + if ($value[0] === Type::T_VARIABLE) { + // if the font value comes from variable, the content is already reduced + // (i.e., formulas were already calculated), so we need the original unreduced value + $value = $this->get($value[1], true, null, true); + } + + $shorthandValue=&$value; + + $shorthandDividerNeedsUnit = false; + $maxListElements = null; + $maxShorthandDividers = 1; + + switch ($compiledName) { + case 'border-radius': + $maxListElements = 4; + $shorthandDividerNeedsUnit = true; + break; + } + + if ($compiledName === 'font' and $value[0] === Type::T_LIST && $value[1]==',') { + // this is the case if more than one font is given: example: "font: 400 1em/1.3 arial,helvetica" + // we need to handle the first list element + $shorthandValue=&$value[2][0]; + } + + if ($shorthandValue[0] === Type::T_EXPRESSION && $shorthandValue[1] === '/') { + $revert = true; + + if ($shorthandDividerNeedsUnit) { + $divider = $shorthandValue[3]; + + if (is_array($divider)) { + $divider = $this->reduce($divider, true); + } + + if (intval($divider->dimension) and !count($divider->units)) { + $revert = false; + } + } + + if ($revert) { + $shorthandValue = $this->expToString($shorthandValue); + } + } elseif ($shorthandValue[0] === Type::T_LIST) { + foreach ($shorthandValue[2] as &$item) { if ($item[0] === Type::T_EXPRESSION && $item[1] === '/') { - $item = $this->expToString($item); + if ($maxShorthandDividers > 0) { + $revert = true; + // if the list of values is too long, this has to be a shorthand, + // otherwise it could be a real division + if (is_null($maxListElements) or count($shorthandValue[2]) <= $maxListElements) { + if ($shorthandDividerNeedsUnit) { + $divider = $item[3]; + + if (is_array($divider)) { + $divider = $this->reduce($divider, true); + } + + if (intval($divider->dimension) and !count($divider->units)) { + $revert = false; + } + } + } + + if ($revert) { + $item = $this->expToString($item); + $maxShorthandDividers--; + } + } } } } @@ -1668,10 +2535,11 @@ class Compiler $compiledValue = $this->compileValue($value); - $out->lines[] = $this->formatter->property( + $line = $this->formatter->property( $compiledName, $compiledValue ); + $this->appendOutputLine($out, Type::T_ASSIGN, $line); break; case Type::T_COMMENT: @@ -1680,27 +2548,32 @@ class Compiler break; } - $out->lines[] = $child[1]; + $line = $this->compileCommentValue($child, true); + $this->appendOutputLine($out, Type::T_COMMENT, $line); break; case Type::T_MIXIN: case Type::T_FUNCTION: list(, $block) = $child; - - $this->set(static::$namespaces[$block->type] . $block->name, $block); + // the block need to be able to go up to it's parent env to resolve vars + $block->parentEnv = $this->getStoreEnv(); + $this->set(static::$namespaces[$block->type] . $block->name, $block, true); break; case Type::T_EXTEND: - list(, $selectors) = $child; - - foreach ($selectors as $sel) { + foreach ($child[1] as $sel) { $results = $this->evalSelectors([$sel]); foreach ($results as $result) { // only use the first one $result = current($result); + $selectors = $out->selectors; - $this->pushExtends($result, $out->selectors, $child); + if (! $selectors && isset($child['selfParent'])) { + $selectors = $this->multiplySelectors($this->env, $child['selfParent']); + } + + $this->pushExtends($result, $selectors, $child); } } break; @@ -1827,31 +2700,12 @@ class Compiler return $this->reduce($child[1], true); case Type::T_NESTED_PROPERTY: - list(, $prop) = $child; - - $prefixed = []; - $prefix = $this->compileValue($prop->prefix) . '-'; - - foreach ($prop->children as $child) { - switch ($child[0]) { - case Type::T_ASSIGN: - array_unshift($child[1][2], $prefix); - break; - - case Type::T_NESTED_PROPERTY: - array_unshift($child[1]->prefix[2], $prefix); - break; - } - - $prefixed[] = $child; - } - - $this->compileChildrenNoReturn($prefixed, $out); + $this->compileNestedPropertiesBlock($child[1], $out); break; case Type::T_INCLUDE: // including a mixin - list(, $name, $argValues, $content) = $child; + list(, $name, $argValues, $content, $argUsing) = $child; $mixin = $this->get(static::$namespaces['mixin'] . $name, false); @@ -1869,10 +2723,43 @@ class Compiler $storeEnv = $this->storeEnv; $this->storeEnv = $this->env; - if (isset($content)) { - $content->scope = $callingScope; + // Find the parent selectors in the env to be able to know what '&' refers to in the mixin + // and assign this fake parent to childs + $selfParent = null; - $this->setRaw(static::$namespaces['special'] . 'content', $content, $this->env); + if (isset($child['selfParent']) && isset($child['selfParent']->selectors)) { + $selfParent = $child['selfParent']; + } else { + $parentSelectors = $this->multiplySelectors($this->env); + + if ($parentSelectors) { + $parent = new Block(); + $parent->selectors = $parentSelectors; + + foreach ($mixin->children as $k => $child) { + if (isset($child[1]) && is_object($child[1]) && $child[1] instanceof Block) { + $mixin->children[$k][1]->parent = $parent; + } + } + } + } + + // clone the stored content to not have its scope spoiled by a further call to the same mixin + // i.e., recursive @include of the same mixin + if (isset($content)) { + $copyContent = clone $content; + $copyContent->scope = clone $callingScope; + + $this->setRaw(static::$namespaces['special'] . 'content', $copyContent, $this->env); + } else { + $this->setRaw(static::$namespaces['special'] . 'content', null, $this->env); + } + + // save the "using" argument list for applying it to when "@content" is invoked + if (isset($argUsing)) { + $this->setRaw(static::$namespaces['special'] . 'using', $argUsing, $this->env); + } else { + $this->setRaw(static::$namespaces['special'] . 'using', null, $this->env); } if (isset($mixin->args)) { @@ -1881,7 +2768,13 @@ class Compiler $this->env->marker = 'mixin'; - $this->compileChildrenNoReturn($mixin->children, $out); + if (! empty($mixin->parentEnv)) { + $this->env->declarationScopeParent = $mixin->parentEnv; + } else { + $this->throwError("@mixin $name() without parentEnv"); + } + + $this->compileChildrenNoReturn($mixin->children, $out, $selfParent, $this->env->marker . " " . $name); $this->storeEnv = $storeEnv; @@ -1889,19 +2782,35 @@ class Compiler break; case Type::T_MIXIN_CONTENT: - $content = $this->get(static::$namespaces['special'] . 'content', false, $this->getStoreEnv()) - ?: $this->get(static::$namespaces['special'] . 'content', false, $this->env); + $env = isset($this->storeEnv) ? $this->storeEnv : $this->env; + $content = $this->get(static::$namespaces['special'] . 'content', false, $env); + $argUsing = $this->get(static::$namespaces['special'] . 'using', false, $env); + $argContent = $child[1]; if (! $content) { $content = new \stdClass(); - $content->scope = new \stdClass(); - $content->children = $this->storeEnv->parent->block->children; + $content->scope = new \stdClass(); + $content->children = $env->parent->block->children; break; } $storeEnv = $this->storeEnv; + $varsUsing = []; + + if (isset($argUsing) && isset($argContent)) { + // Get the arguments provided for the content with the names provided in the "using" argument list + $this->storeEnv = $this->env; + $varsUsing = $this->applyArguments($argUsing, $argContent, false); + } + + // restore the scope from the @content $this->storeEnv = $content->scope; + // append the vars from using if any + foreach ($varsUsing as $name => $val) { + $this->set($name, $val, true, $this->storeEnv); + } + $this->compileChildrenNoReturn($content->children, $out); $this->storeEnv = $storeEnv; @@ -1910,25 +2819,31 @@ class Compiler case Type::T_DEBUG: list(, $value) = $child; - $line = $this->sourceLine; + $fname = $this->sourceNames[$this->sourceIndex]; + $line = $this->sourceLine; $value = $this->compileValue($this->reduce($value, true)); - fwrite($this->stderr, "Line $line DEBUG: $value\n"); + + fwrite($this->stderr, "File $fname on line $line DEBUG: $value\n"); break; case Type::T_WARN: list(, $value) = $child; - $line = $this->sourceLine; + $fname = $this->sourceNames[$this->sourceIndex]; + $line = $this->sourceLine; $value = $this->compileValue($this->reduce($value, true)); - fwrite($this->stderr, "Line $line WARN: $value\n"); + + fwrite($this->stderr, "File $fname on line $line WARN: $value\n"); break; case Type::T_ERROR: list(, $value) = $child; - $line = $this->sourceLine; + $fname = $this->sourceNames[$this->sourceIndex]; + $line = $this->sourceLine; $value = $this->compileValue($this->reduce($value, true)); - $this->throwError("Line $line ERROR: $value\n"); + + $this->throwError("File $fname on line $line ERROR: $value\n"); break; case Type::T_CONTROL: @@ -1973,7 +2888,7 @@ class Compiler * * @param array $value * - * @return array + * @return boolean */ protected function isTruthy($value) { @@ -2004,7 +2919,7 @@ class Compiler switch ($value[0]) { case Type::T_EXPRESSION: if ($value[1] === '/') { - return $this->shouldEval($value[2], $value[3]); + return $this->shouldEval($value[2]) || $this->shouldEval($value[3]); } // fall-thru @@ -2022,13 +2937,15 @@ class Compiler * @param array $value * @param boolean $inExp * - * @return array|\Leafo\ScssPhp\Node\Number + * @return null|string|array|\ScssPhp\ScssPhp\Node\Number */ protected function reduce($value, $inExp = false) { - list($type) = $value; + if (is_null($value)) { + return null; + } - switch ($type) { + switch ($value[0]) { case Type::T_EXPRESSION: list(, $op, $left, $right, $inParens) = $value; @@ -2042,16 +2959,15 @@ class Compiler } // special case: looks like css shorthand - if ($opName == 'div' && ! $inParens && ! $inExp && isset($right[2]) - && (($right[0] !== Type::T_NUMBER && $right[2] != '') - || ($right[0] === Type::T_NUMBER && ! $right->unitless())) + if ($opName == 'div' && ! $inParens && ! $inExp && isset($right[2]) && + (($right[0] !== Type::T_NUMBER && $right[2] != '') || + ($right[0] === Type::T_NUMBER && ! $right->unitless())) ) { return $this->expToString($value); } - $left = $this->coerceForExpression($left); + $left = $this->coerceForExpression($left); $right = $this->coerceForExpression($right); - $ltype = $left[0]; $rtype = $right[0]; @@ -2161,9 +3077,7 @@ class Compiler return [Type::T_STRING, '', [$op, $exp]]; case Type::T_VARIABLE: - list(, $name) = $value; - - return $this->reduce($this->get($name)); + return $this->reduce($this->get($value[1])); case Type::T_LIST: foreach ($value[2] as &$item) { @@ -2195,12 +3109,20 @@ class Compiler case Type::T_INTERPOLATE: $value[1] = $this->reduce($value[1]); + if ($inExp) { + return $value[1]; + } + return $value; case Type::T_FUNCTION_CALL: - list(, $name, $argValues) = $value; + return $this->fncall($value[1], $value[2]); - return $this->fncall($name, $argValues); + case Type::T_SELF: + $selfSelector = $this->multiplySelectors($this->env); + $selfSelector = $this->collapseSelectors($selfSelector, true); + + return $selfSelector; default: return $value; @@ -2215,7 +3137,7 @@ class Compiler * * @return array|null */ - private function fncall($name, $argValues) + protected function fncall($name, $argValues) { // SCSS @function if ($this->callScssFunction($name, $argValues, $returnValue)) { @@ -2261,9 +3183,8 @@ class Compiler public function normalizeValue($value) { $value = $this->coerceForExpression($this->reduce($value)); - list($type) = $value; - switch ($type) { + switch ($value[0]) { case Type::T_LIST: $value = $this->extractInterpolation($value); @@ -2275,10 +3196,14 @@ class Compiler $value[2][$key] = $this->normalizeValue($item); } + if (! empty($value['enclosing'])) { + unset($value['enclosing']); + } + return $value; case Type::T_STRING: - return [$type, '"', [$this->compileStringContent($value)]]; + return [$value[0], '"', [$this->compileStringContent($value)]]; case Type::T_NUMBER: return $value->normalize(); @@ -2297,7 +3222,7 @@ class Compiler * @param array $left * @param array $right * - * @return \Leafo\ScssPhp\Node\Number + * @return \ScssPhp\ScssPhp\Node\Number */ protected function opAddNumberNumber($left, $right) { @@ -2310,7 +3235,7 @@ class Compiler * @param array $left * @param array $right * - * @return \Leafo\ScssPhp\Node\Number + * @return \ScssPhp\ScssPhp\Node\Number */ protected function opMulNumberNumber($left, $right) { @@ -2323,7 +3248,7 @@ class Compiler * @param array $left * @param array $right * - * @return \Leafo\ScssPhp\Node\Number + * @return \ScssPhp\ScssPhp\Node\Number */ protected function opSubNumberNumber($left, $right) { @@ -2336,7 +3261,7 @@ class Compiler * @param array $left * @param array $right * - * @return array|\Leafo\ScssPhp\Node\Number + * @return array|\ScssPhp\ScssPhp\Node\Number */ protected function opDivNumberNumber($left, $right) { @@ -2353,7 +3278,7 @@ class Compiler * @param array $left * @param array $right * - * @return \Leafo\ScssPhp\Node\Number + * @return \ScssPhp\ScssPhp\Node\Number */ protected function opModNumberNumber($left, $right) { @@ -2366,7 +3291,7 @@ class Compiler * @param array $left * @param array $right * - * @return array + * @return array|null */ protected function opAdd($left, $right) { @@ -2389,6 +3314,8 @@ class Compiler return $strRight; } + + return null; } /** @@ -2398,15 +3325,21 @@ class Compiler * @param array $right * @param boolean $shouldEval * - * @return array + * @return array|null */ protected function opAnd($left, $right, $shouldEval) { + $truthy = ($left === static::$null || $right === static::$null) || + ($left === static::$false || $left === static::$true) && + ($right === static::$false || $right === static::$true); + if (! $shouldEval) { - return; + if (! $truthy) { + return null; + } } - if ($left !== static::$false and $left !== static::$null) { + if ($left !== static::$false && $left !== static::$null) { return $this->reduce($right, true); } @@ -2420,15 +3353,21 @@ class Compiler * @param array $right * @param boolean $shouldEval * - * @return array + * @return array|null */ protected function opOr($left, $right, $shouldEval) { + $truthy = ($left === static::$null || $right === static::$null) || + ($left === static::$false || $left === static::$true) && + ($right === static::$false || $right === static::$true); + if (! $shouldEval) { - return; + if (! $truthy) { + return null; + } } - if ($left !== static::$false and $left !== static::$null) { + if ($left !== static::$false && $left !== static::$null) { return $left; } @@ -2639,7 +3578,7 @@ class Compiler * @param array $left * @param array $right * - * @return \Leafo\ScssPhp\Node\Number + * @return \ScssPhp\ScssPhp\Node\Number */ protected function opCmpNumberNumber($left, $right) { @@ -2677,15 +3616,13 @@ class Compiler * * @param array $value * - * @return string + * @return string|array */ public function compileValue($value) { $value = $this->reduce($value); - list($type) = $value; - - switch ($type) { + switch ($value[0]) { case Type::T_KEYWORD: return $value[1]; @@ -2696,14 +3633,38 @@ class Compiler // [4] - optional alpha component list(, $r, $g, $b) = $value; - $r = round($r); - $g = round($g); - $b = round($b); + $r = $this->compileRGBAValue($r); + $g = $this->compileRGBAValue($g); + $b = $this->compileRGBAValue($b); - if (count($value) === 5 && $value[4] !== 1) { // rgba - $a = new Node\Number($value[4], ''); + if (count($value) === 5) { + $alpha = $this->compileRGBAValue($value[4], true); - return 'rgba(' . $r . ', ' . $g . ', ' . $b . ', ' . $a . ')'; + if (! is_numeric($alpha) || $alpha < 1) { + $colorName = Colors::RGBaToColorName($r, $g, $b, $alpha); + + if (! is_null($colorName)) { + return $colorName; + } + + if (is_numeric($alpha)) { + $a = new Node\Number($alpha, ''); + } else { + $a = $alpha; + } + + return 'rgba(' . $r . ', ' . $g . ', ' . $b . ', ' . $a . ')'; + } + } + + if (! is_numeric($r) || ! is_numeric($g) || ! is_numeric($b)) { + return 'rgb(' . $r . ', ' . $g . ', ' . $b . ')'; + } + + $colorName = Colors::RGBaToColorName($r, $g, $b); + + if (! is_null($colorName)) { + return $colorName; } $h = sprintf('#%02x%02x%02x', $r, $g, $b); @@ -2734,9 +3695,28 @@ class Compiler } list(, $delim, $items) = $value; + $pre = $post = ""; + if (! empty($value['enclosing'])) { + switch ($value['enclosing']) { + case 'parent': + //$pre = "("; + //$post = ")"; + break; + case 'forced_parent': + $pre = "("; + $post = ")"; + break; + case 'bracket': + case 'forced_bracket': + $pre = "["; + $post = "]"; + break; + } + } + $prefix_value = ''; if ($delim !== ' ') { - $delim .= ' '; + $prefix_value = ' '; } $filtered = []; @@ -2746,14 +3726,18 @@ class Compiler continue; } - $filtered[] = $this->compileValue($item); + $compiled = $this->compileValue($item); + if ($prefix_value && strlen($compiled)) { + $compiled = $prefix_value . $compiled; + } + $filtered[] = $compiled; } - return implode("$delim", $filtered); + return $pre . substr(implode("$delim", $filtered), strlen($prefix_value)) . $post; case Type::T_MAP: - $keys = $value[1]; - $values = $value[2]; + $keys = $value[1]; + $values = $value[2]; $filtered = []; for ($i = 0, $s = count($keys); $i < $s; $i++) { @@ -2771,20 +3755,29 @@ class Compiler list(, $interpolate, $left, $right) = $value; list(,, $whiteLeft, $whiteRight) = $interpolate; + $delim = $left[1]; + + if ($delim && $delim !== ' ' && ! $whiteLeft) { + $delim .= ' '; + } + $left = count($left[2]) > 0 ? - $this->compileValue($left) . $whiteLeft : ''; + $this->compileValue($left) . $delim . $whiteLeft: ''; + + $delim = $right[1]; + + if ($delim && $delim !== ' ') { + $delim .= ' '; + } $right = count($right[2]) > 0 ? - $whiteRight . $this->compileValue($right) : ''; + $whiteRight . $delim . $this->compileValue($right) : ''; return $left . $this->compileValue($interpolate) . $right; case Type::T_INTERPOLATE: - // raw parse node - list(, $exp) = $value; - // strip quotes if it's a string - $reduced = $this->reduce($exp); + $reduced = $this->reduce($value[1]); switch ($reduced[0]) { case Type::T_LIST: @@ -2808,6 +3801,7 @@ class Compiler } $temp = $this->compileValue([Type::T_KEYWORD, $item]); + if ($temp[0] === Type::T_STRING) { $filtered[] = $this->compileStringContent($temp); } elseif ($temp[0] === Type::T_KEYWORD) { @@ -2833,8 +3827,11 @@ class Compiler case Type::T_NULL: return 'null'; + case Type::T_COMMENT: + return $this->compileCommentValue($value); + default: - $this->throwError("unknown value type: $type"); + $this->throwError("unknown value type: ".json_encode($value)); } } @@ -2898,44 +3895,70 @@ class Compiler /** * Find the final set of selectors * - * @param \Leafo\ScssPhp\Compiler\Environment $env + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param \ScssPhp\ScssPhp\Block $selfParent * * @return array */ - protected function multiplySelectors(Environment $env) + protected function multiplySelectors(Environment $env, $selfParent = null) { $envs = $this->compactEnv($env); $selectors = []; $parentSelectors = [[]]; + $selfParentSelectors = null; + + if (! is_null($selfParent) && $selfParent->selectors) { + $selfParentSelectors = $this->evalSelectors($selfParent->selectors); + } + while ($env = array_pop($envs)) { if (empty($env->selectors)) { continue; } - $selectors = []; + $selectors = $env->selectors; - foreach ($env->selectors as $selector) { - foreach ($parentSelectors as $parent) { - $selectors[] = $this->joinSelectors($parent, $selector); + do { + $stillHasSelf = false; + $prevSelectors = $selectors; + $selectors = []; + + foreach ($prevSelectors as $selector) { + foreach ($parentSelectors as $parent) { + if ($selfParentSelectors) { + foreach ($selfParentSelectors as $selfParent) { + // if no '&' in the selector, each call will give same result, only add once + $s = $this->joinSelectors($parent, $selector, $stillHasSelf, $selfParent); + $selectors[serialize($s)] = $s; + } + } else { + $s = $this->joinSelectors($parent, $selector, $stillHasSelf); + $selectors[serialize($s)] = $s; + } + } } - } + } while ($stillHasSelf); $parentSelectors = $selectors; } + $selectors = array_values($selectors); + return $selectors; } /** * Join selectors; looks for & to replace, or append parent before child * - * @param array $parent - * @param array $child - * + * @param array $parent + * @param array $child + * @param boolean &$stillHasSelf + * @param array $selfParentSelectors + * @return array */ - protected function joinSelectors($parent, $child) + protected function joinSelectors($parent, $child, &$stillHasSelf, $selfParentSelectors = null) { $setSelf = false; $out = []; @@ -2944,16 +3967,35 @@ class Compiler $newPart = []; foreach ($part as $p) { - if ($p === static::$selfSelector) { + // only replace & once and should be recalled to be able to make combinations + if ($p === static::$selfSelector && $setSelf) { + $stillHasSelf = true; + } + + if ($p === static::$selfSelector && ! $setSelf) { $setSelf = true; - foreach ($parent as $i => $parentPart) { + if (is_null($selfParentSelectors)) { + $selfParentSelectors = $parent; + } + + foreach ($selfParentSelectors as $i => $parentPart) { if ($i > 0) { $out[] = $newPart; $newPart = []; } foreach ($parentPart as $pp) { + if (is_array($pp)) { + $flatten = []; + + array_walk_recursive($pp, function ($a) use (&$flatten) { + $flatten[] = $a; + }); + + $pp = implode($flatten); + } + $newPart[] = $pp; } } @@ -2971,8 +4013,8 @@ class Compiler /** * Multiply media * - * @param \Leafo\ScssPhp\Compiler\Environment $env - * @param array $childQueries + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param array $childQueries * * @return array */ @@ -2993,7 +4035,15 @@ class Compiler ? $env->block->queryList : [[[Type::T_MEDIA_VALUE, $env->block->value]]]; - if ($childQueries === null) { + $store = [$this->env, $this->storeEnv]; + + $this->env = $env; + $this->storeEnv = null; + $parentQueries = $this->evaluateMediaQuery($parentQueries); + + list($this->env, $this->storeEnv) = $store; + + if (is_null($childQueries)) { $childQueries = $parentQueries; } else { $originalQueries = $childQueries; @@ -3001,7 +4051,11 @@ class Compiler foreach ($parentQueries as $parentQuery) { foreach ($originalQueries as $childQuery) { - $childQueries []= array_merge($parentQuery, $childQuery); + $childQueries[] = array_merge( + $parentQuery, + [[Type::T_MEDIA_TYPE, [Type::T_KEYWORD, 'all']]], + $childQuery + ); } } } @@ -3012,11 +4066,11 @@ class Compiler /** * Convert env linked list to stack * - * @param \Leafo\ScssPhp\Compiler\Environment $env + * @param \ScssPhp\ScssPhp\Compiler\Environment $env * * @return array */ - private function compactEnv(Environment $env) + protected function compactEnv(Environment $env) { for ($envs = []; $env; $env = $env->parent) { $envs[] = $env; @@ -3030,9 +4084,9 @@ class Compiler * * @param array $envs * - * @return \Leafo\ScssPhp\Compiler\Environment + * @return \ScssPhp\ScssPhp\Compiler\Environment */ - private function extractEnv($envs) + protected function extractEnv($envs) { for ($env = null; $e = array_pop($envs);) { $e->parent = $env; @@ -3045,9 +4099,9 @@ class Compiler /** * Push environment * - * @param \Leafo\ScssPhp\Block $block + * @param \ScssPhp\ScssPhp\Block $block * - * @return \Leafo\ScssPhp\Compiler\Environment + * @return \ScssPhp\ScssPhp\Compiler\Environment */ protected function pushEnv(Block $block = null) { @@ -3073,7 +4127,7 @@ class Compiler /** * Get store environment * - * @return \Leafo\ScssPhp\Compiler\Environment + * @return \ScssPhp\ScssPhp\Compiler\Environment */ protected function getStoreEnv() { @@ -3083,12 +4137,13 @@ class Compiler /** * Set variable * - * @param string $name - * @param mixed $value - * @param boolean $shadow - * @param \Leafo\ScssPhp\Compiler\Environment $env + * @param string $name + * @param mixed $value + * @param boolean $shadow + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param mixed $valueUnreduced */ - protected function set($name, $value, $shadow = false, Environment $env = null) + protected function set($name, $value, $shadow = false, Environment $env = null, $valueUnreduced = null) { $name = $this->normalizeName($name); @@ -3097,20 +4152,21 @@ class Compiler } if ($shadow) { - $this->setRaw($name, $value, $env); + $this->setRaw($name, $value, $env, $valueUnreduced); } else { - $this->setExisting($name, $value, $env); + $this->setExisting($name, $value, $env, $valueUnreduced); } } /** * Set existing variable * - * @param string $name - * @param mixed $value - * @param \Leafo\ScssPhp\Compiler\Environment $env + * @param string $name + * @param mixed $value + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param mixed $valueUnreduced */ - protected function setExisting($name, $value, Environment $env) + protected function setExisting($name, $value, Environment $env, $valueUnreduced = null) { $storeEnv = $env; @@ -3135,18 +4191,27 @@ class Compiler } $env->store[$name] = $value; + + if ($valueUnreduced) { + $env->storeUnreduced[$name] = $valueUnreduced; + } } /** * Set raw variable * - * @param string $name - * @param mixed $value - * @param \Leafo\ScssPhp\Compiler\Environment $env + * @param string $name + * @param mixed $value + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param mixed $valueUnreduced */ - protected function setRaw($name, $value, Environment $env) + protected function setRaw($name, $value, Environment $env, $valueUnreduced = null) { $env->store[$name] = $value; + + if ($valueUnreduced) { + $env->storeUnreduced[$name] = $valueUnreduced; + } } /** @@ -3154,13 +4219,14 @@ class Compiler * * @api * - * @param string $name - * @param boolean $shouldThrow - * @param \Leafo\ScssPhp\Compiler\Environment $env + * @param string $name + * @param boolean $shouldThrow + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param boolean $unreduced * - * @return mixed + * @return mixed|null */ - public function get($name, $shouldThrow = true, Environment $env = null) + public function get($name, $shouldThrow = true, Environment $env = null, $unreduced = false) { $normalizedName = $this->normalizeName($name); $specialContentKey = static::$namespaces['special'] . 'content'; @@ -3169,22 +4235,34 @@ class Compiler $env = $this->getStoreEnv(); } - $nextIsRoot = false; $hasNamespace = $normalizedName[0] === '^' || $normalizedName[0] === '@' || $normalizedName[0] === '%'; + $maxDepth = 10000; + for (;;) { + if ($maxDepth-- <= 0) { + break; + } + if (array_key_exists($normalizedName, $env->store)) { + if ($unreduced && isset($env->storeUnreduced[$normalizedName])) { + return $env->storeUnreduced[$normalizedName]; + } + return $env->store[$normalizedName]; } if (! $hasNamespace && isset($env->marker)) { - if (! $nextIsRoot && ! empty($env->store[$specialContentKey])) { + if (! empty($env->store[$specialContentKey])) { $env = $env->store[$specialContentKey]->scope; - $nextIsRoot = true; continue; } - $env = $this->rootEnv; + if (! empty($env->declarationScopeParent)) { + $env = $env->declarationScopeParent; + } else { + $env = $this->rootEnv; + } continue; } @@ -3196,23 +4274,24 @@ class Compiler } if ($shouldThrow) { - $this->throwError("Undefined variable \$$name"); + $this->throwError("Undefined variable \$$name" . ($maxDepth <= 0 ? " (infinite recursion)" : "")); } // found nothing + return null; } /** * Has variable? * - * @param string $name - * @param \Leafo\ScssPhp\Compiler\Environment $env + * @param string $name + * @param \ScssPhp\ScssPhp\Compiler\Environment $env * * @return boolean */ protected function has($name, Environment $env = null) { - return $this->get($name, false, $env) !== null; + return ! is_null($this->get($name, false, $env)); } /** @@ -3286,7 +4365,7 @@ class Compiler */ public function addParsedFile($path) { - if (isset($path) && file_exists($path)) { + if (isset($path) && is_file($path)) { $this->parsedFiles[realpath($path)] = filemtime($path); } } @@ -3308,7 +4387,7 @@ class Compiler * * @api * - * @param string $path + * @param string|callable $path */ public function addImportPath($path) { @@ -3430,10 +4509,10 @@ class Compiler /** * Import file * - * @param string $path - * @param array $out + * @param string $path + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out */ - protected function importFile($path, $out) + protected function importFile($path, OutputBlock $out) { // see if tree is cached $realPath = realpath($path); @@ -3451,6 +4530,7 @@ class Compiler } $pi = pathinfo($path); + array_unshift($this->importPaths, $pi['dirname']); $this->compileChildrenNoReturn($tree->children, $out); array_shift($this->importPaths); @@ -3470,9 +4550,9 @@ class Compiler $urls = []; // for "normal" scss imports (ignore vanilla css and external requests) - if (! preg_match('/\.css$|^https?:\/\//', $url)) { + if (! preg_match('~\.css$|^https?://~', $url)) { // try both normal and the _partial filename - $urls = [$url, preg_replace('/[^\/]+$/', '_\0', $url)]; + $urls = [$url, preg_replace('~[^/]+$~', '_\0', $url)]; } $hasExtension = preg_match('/[.]s?css$/', $url); @@ -3481,12 +4561,15 @@ class Compiler if (is_string($dir)) { // check urls for normal import paths foreach ($urls as $full) { - $full = $dir - . (! empty($dir) && substr($dir, -1) !== '/' ? '/' : '') - . $full; + $separator = ( + ! empty($dir) && + substr($dir, -1) !== '/' && + substr($full, 0, 1) !== '/' + ) ? '/' : ''; + $full = $dir . $separator . $full; - if ($this->fileExists($file = $full . '.scss') || - ($hasExtension && $this->fileExists($file = $full)) + if (is_file($file = $full . '.scss') || + ($hasExtension && is_file($file = $full)) ) { return $file; } @@ -3495,7 +4578,7 @@ class Compiler // check custom callback for import path $file = call_user_func($dir, $url); - if ($file !== null) { + if (! is_null($file)) { return $file; } } @@ -3523,11 +4606,13 @@ class Compiler * * @param boolean $ignoreErrors * - * @return \Leafo\ScssPhp\Compiler + * @return \ScssPhp\ScssPhp\Compiler */ public function setIgnoreErrors($ignoreErrors) { $this->ignoreErrors = $ignoreErrors; + + return $this; } /** @@ -3537,7 +4622,7 @@ class Compiler * * @param string $msg Message with optional sprintf()-style vararg parameters * - * @throws \Leafo\ScssPhp\Exception\CompilerException + * @throws \ScssPhp\ScssPhp\Exception\CompilerException */ public function throwError($msg) { @@ -3545,16 +4630,62 @@ class Compiler return; } + $line = $this->sourceLine; + $column = $this->sourceColumn; + + $loc = isset($this->sourceNames[$this->sourceIndex]) + ? $this->sourceNames[$this->sourceIndex] . " on line $line, at column $column" + : "line: $line, column: $column"; + if (func_num_args() > 1) { $msg = call_user_func_array('sprintf', func_get_args()); } - $line = $this->sourceLine; - $msg = "$msg: line: $line"; + $msg = "$msg: $loc"; + + $callStackMsg = $this->callStackMessage(); + + if ($callStackMsg) { + $msg .= "\nCall Stack:\n" . $callStackMsg; + } throw new CompilerException($msg); } + /** + * Beautify call stack for output + * + * @param boolean $all + * @param null $limit + * + * @return string + */ + protected function callStackMessage($all = false, $limit = null) + { + $callStackMsg = []; + $ncall = 0; + + if ($this->callStack) { + foreach (array_reverse($this->callStack) as $call) { + if ($all || (isset($call['n']) && $call['n'])) { + $msg = "#" . $ncall++ . " " . $call['n'] . " "; + $msg .= (isset($this->sourceNames[$call[Parser::SOURCE_INDEX]]) + ? $this->sourceNames[$call[Parser::SOURCE_INDEX]] + : '(unknown file)'); + $msg .= " on line " . $call[Parser::SOURCE_LINE]; + + $callStackMsg[] = $msg; + + if (! is_null($limit) && $ncall > $limit) { + break; + } + } + } + } + + return implode("\n", $callStackMsg); + } + /** * Handle import loop * @@ -3565,6 +4696,10 @@ class Compiler protected function handleImportLoop($name) { for ($env = $this->env; $env; $env = $env->parent) { + if (! $env->block) { + continue; + } + $file = $this->sourceNames[$env->block->sourceIndex]; if (realpath($file) === $name) { @@ -3574,18 +4709,6 @@ class Compiler } } - /** - * Does file exist? - * - * @param string $name - * - * @return boolean - */ - protected function fileExists($name) - { - return file_exists($name) && is_file($name); - } - /** * Call SCSS @function * @@ -3619,8 +4742,13 @@ class Compiler $tmp->children = []; $this->env->marker = 'function'; + if (! empty($func->parentEnv)) { + $this->env->declarationScopeParent = $func->parentEnv; + } else { + $this->throwError("@function $name() without parentEnv"); + } - $ret = $this->compileChildren($func->children, $tmp); + $ret = $this->compileChildren($func->children, $tmp, $this->env->marker . " " . $name); $this->storeEnv = $storeEnv; @@ -3655,11 +4783,17 @@ class Compiler return false; } - @list($sorted, $kwargs) = $this->sortArgs($prototype, $args); + @list($sorted, $kwargs) = $this->sortNativeFunctionArgs($libName, $prototype, $args); if ($name !== 'if' && $name !== 'call') { + $inExp = true; + + if ($name === 'join') { + $inExp = false; + } + foreach ($sorted as &$val) { - $val = $this->reduce($val, true); + $val = $this->reduce($val, $inExp); } } @@ -3697,62 +4831,170 @@ class Compiler /** * Sorts keyword arguments * - * @param array $prototype - * @param array $args + * @param string $functionName + * @param array $prototypes + * @param array $args * * @return array */ - protected function sortArgs($prototype, $args) + protected function sortNativeFunctionArgs($functionName, $prototypes, $args) { - $keyArgs = []; - $posArgs = []; + static $parser = null; - // separate positional and keyword arguments - foreach ($args as $arg) { - list($key, $value) = $arg; + if (! isset($prototypes)) { + $keyArgs = []; + $posArgs = []; - $key = $key[1]; + // separate positional and keyword arguments + foreach ($args as $arg) { + list($key, $value) = $arg; - if (empty($key)) { - $posArgs[] = empty($arg[2]) ? $value : $arg; - } else { - $keyArgs[$key] = $value; + $key = $key[1]; + + if (empty($key)) { + $posArgs[] = empty($arg[2]) ? $value : $arg; + } else { + $keyArgs[$key] = $value; + } } - } - if (! isset($prototype)) { return [$posArgs, $keyArgs]; } - // copy positional args - $finalArgs = array_pad($posArgs, count($prototype), null); + // specific cases ? + if (in_array($functionName, ['libRgb', 'libRgba', 'libHsl', 'libHsla'])) { + // notation 100 127 255 / 0 is in fact a simple list of 4 values + foreach ($args as $k => $arg) { + if ($arg[1][0] === Type::T_LIST && count($arg[1][2]) === 3) { + $last = end($arg[1][2]); - // overwrite positional args with keyword args - foreach ($prototype as $i => $names) { - foreach ((array) $names as $name) { - if (isset($keyArgs[$name])) { - $finalArgs[$i] = $keyArgs[$name]; + if ($last[0] === Type::T_EXPRESSION && $last[1] === '/') { + array_pop($arg[1][2]); + $arg[1][2][] = $last[2]; + $arg[1][2][] = $last[3]; + $args[$k] = $arg; + } } } } + $finalArgs = []; + + if (! is_array(reset($prototypes))) { + $prototypes = [$prototypes]; + } + + $keyArgs = []; + + // trying each prototypes + $prototypeHasMatch = false; + $exceptionMessage = ''; + + foreach ($prototypes as $prototype) { + $argDef = []; + + foreach ($prototype as $i => $p) { + $default = null; + $p = explode(':', $p, 2); + $name = array_shift($p); + + if (count($p)) { + $p = trim(reset($p)); + + if ($p === 'null') { + // differentiate this null from the static::$null + $default = [Type::T_KEYWORD, 'null']; + } else { + if (is_null($parser)) { + $parser = $this->parserFactory(__METHOD__); + } + + $parser->parseValue($p, $default); + } + } + + $isVariable = false; + + if (substr($name, -3) === '...') { + $isVariable = true; + $name = substr($name, 0, -3); + } + + $argDef[] = [$name, $default, $isVariable]; + } + + try { + $vars = $this->applyArguments($argDef, $args, false, false); + + // ensure all args are populated + foreach ($prototype as $i => $p) { + $name = explode(':', $p)[0]; + + if (! isset($finalArgs[$i])) { + $finalArgs[$i] = null; + } + } + + // apply positional args + foreach (array_values($vars) as $i => $val) { + $finalArgs[$i] = $val; + } + + $keyArgs = array_merge($keyArgs, $vars); + $prototypeHasMatch = true; + + // overwrite positional args with keyword args + foreach ($prototype as $i => $p) { + $name = explode(':', $p)[0]; + + if (isset($keyArgs[$name])) { + $finalArgs[$i] = $keyArgs[$name]; + } + + // special null value as default: translate to real null here + if ($finalArgs[$i] === [Type::T_KEYWORD, 'null']) { + $finalArgs[$i] = null; + } + } + // should we break if this prototype seems fulfilled? + } catch (CompilerException $e) { + $exceptionMessage = $e->getMessage(); + } + } + + if ($exceptionMessage && ! $prototypeHasMatch) { + $this->throwError($exceptionMessage); + } + return [$finalArgs, $keyArgs]; } /** * Apply argument values per definition * - * @param array $argDef - * @param array $argValues + * @param array $argDef + * @param array $argValues + * @param boolean $storeInEnv + * @param boolean $reduce + * only used if $storeInEnv = false + * + * @return array * * @throws \Exception */ - protected function applyArguments($argDef, $argValues) + protected function applyArguments($argDef, $argValues, $storeInEnv = true, $reduce = true) { - $storeEnv = $this->getStoreEnv(); + $output = []; + if (is_array($argValues) && count($argValues) && end($argValues) === static::$null) { + array_pop($argValues); + } - $env = new Environment; - $env->store = $storeEnv->store; + if ($storeInEnv) { + $storeEnv = $this->getStoreEnv(); + + $env = new Environment; + $env->store = $storeEnv->store; + } $hasVariable = false; $args = []; @@ -3764,37 +5006,64 @@ class Compiler $hasVariable |= $isVariable; } - $keywordArgs = []; + $splatSeparator = null; + $keywordArgs = []; $deferredKeywordArgs = []; - $remaining = []; + $remaining = []; + $hasKeywordArgument = false; // assign the keyword args foreach ((array) $argValues as $arg) { if (! empty($arg[0])) { - if (! isset($args[$arg[0][1]])) { + $hasKeywordArgument = true; + + $name = $arg[0][1]; + if (! isset($args[$name])) { + foreach (array_keys($args) as $an) { + if (str_replace("_", "-", $an) === str_replace("_", "-", $name)) { + $name = $an; + break; + } + } + } + if (! isset($args[$name]) || $args[$name][3]) { if ($hasVariable) { - $deferredKeywordArgs[$arg[0][1]] = $arg[1]; + $deferredKeywordArgs[$name] = $arg[1]; } else { $this->throwError("Mixin or function doesn't have an argument named $%s.", $arg[0][1]); break; } - } elseif ($args[$arg[0][1]][0] < count($remaining)) { + } elseif ($args[$name][0] < count($remaining)) { $this->throwError("The argument $%s was passed both by position and by name.", $arg[0][1]); break; } else { - $keywordArgs[$arg[0][1]] = $arg[1]; + $keywordArgs[$name] = $arg[1]; } - } elseif (count($keywordArgs)) { - $this->throwError('Positional arguments must come before keyword arguments.'); - break; } elseif ($arg[2] === true) { $val = $this->reduce($arg[1], true); if ($val[0] === Type::T_LIST) { foreach ($val[2] as $name => $item) { if (! is_numeric($name)) { - $keywordArgs[$name] = $item; + if (! isset($args[$name])) { + foreach (array_keys($args) as $an) { + if (str_replace("_", "-", $an) === str_replace("_", "-", $name)) { + $name = $an; + break; + } + } + } + + if ($hasVariable) { + $deferredKeywordArgs[$name] = $item; + } else { + $keywordArgs[$name] = $item; + } } else { + if (is_null($splatSeparator)) { + $splatSeparator = $val[1]; + } + $remaining[] = $item; } } @@ -3804,14 +5073,34 @@ class Compiler $item = $val[2][$i]; if (! is_numeric($name)) { - $keywordArgs[$name] = $item; + if (! isset($args[$name])) { + foreach (array_keys($args) as $an) { + if (str_replace("_", "-", $an) === str_replace("_", "-", $name)) { + $name = $an; + break; + } + } + } + + if ($hasVariable) { + $deferredKeywordArgs[$name] = $item; + } else { + $keywordArgs[$name] = $item; + } } else { + if (is_null($splatSeparator)) { + $splatSeparator = $val[1]; + } + $remaining[] = $item; } } } else { $remaining[] = $val; } + } elseif ($hasKeywordArgument) { + $this->throwError('Positional arguments must come before keyword arguments.'); + break; } else { $remaining[] = $arg[1]; } @@ -3821,7 +5110,7 @@ class Compiler list($i, $name, $default, $isVariable) = $arg; if ($isVariable) { - $val = [Type::T_LIST, ',', [], $isVariable]; + $val = [Type::T_LIST, is_null($splatSeparator) ? ',' : $splatSeparator , [], $isVariable]; for ($count = count($remaining); $i < $count; $i++) { $val[2][] = $remaining[$i]; @@ -3841,10 +5130,16 @@ class Compiler break; } - $this->set($name, $this->reduce($val, true), true, $env); + if ($storeInEnv) { + $this->set($name, $this->reduce($val, true), true, $env); + } else { + $output[$name] = ($reduce ? $this->reduce($val, true) : $val); + } } - $storeEnv->store = $env->store; + if ($storeInEnv) { + $storeEnv->store = $env->store; + } foreach ($args as $arg) { list($i, $name, $default, $isVariable) = $arg; @@ -3853,8 +5148,14 @@ class Compiler continue; } - $this->set($name, $this->reduce($default, true), true); + if ($storeInEnv) { + $this->set($name, $this->reduce($default, true), true); + } else { + $output[$name] = ($reduce ? $this->reduce($default, true) : $default); + } } + + return $output; } /** @@ -3862,9 +5163,9 @@ class Compiler * * @param mixed $value * - * @return array|\Leafo\ScssPhp\Node\Number + * @return array|\ScssPhp\ScssPhp\Node\Number */ - private function coerceValue($value) + protected function coerceValue($value) { if (is_array($value) || $value instanceof \ArrayAccess) { return $value; @@ -3874,7 +5175,7 @@ class Compiler return $this->toBool($value); } - if ($value === null) { + if (is_null($value)) { return static::$null; } @@ -3886,30 +5187,14 @@ class Compiler return static::$emptyString; } - if (preg_match('/^(#([0-9a-f]{6})|#([0-9a-f]{3}))$/i', $value, $m)) { - $color = [Type::T_COLOR]; - - if (isset($m[3])) { - $num = hexdec($m[3]); - - foreach ([3, 2, 1] as $i) { - $t = $num & 0xf; - $color[$i] = $t << 4 | $t; - $num >>= 4; - } - } else { - $num = hexdec($m[2]); - - foreach ([3, 2, 1] as $i) { - $color[$i] = $num & 0xff; - $num >>= 8; - } - } + $value = [Type::T_KEYWORD, $value]; + $color = $this->coerceColor($value); + if ($color) { return $color; } - return [Type::T_KEYWORD, $value]; + return $value; } /** @@ -3925,7 +5210,9 @@ class Compiler return $item; } - if ($item === static::$emptyList) { + if ($item[0] === static::$emptyList[0] + && $item[1] === static::$emptyList[1] + && $item[2] === static::$emptyList[2]) { return static::$emptyMap; } @@ -3955,10 +5242,21 @@ class Compiler $key = $keys[$i]; $value = $values[$i]; + switch ($key[0]) { + case Type::T_LIST: + case Type::T_MAP: + case Type::T_STRING: + break; + + default: + $key = [Type::T_KEYWORD, $this->compileStringContent($this->coerceString($key))]; + break; + } + $list[] = [ Type::T_LIST, '', - [[Type::T_KEYWORD, $this->compileStringContent($this->coerceString($key))], $value] + [$key, $value] ]; } @@ -3991,21 +5289,106 @@ class Compiler * * @return array|null */ - protected function coerceColor($value) + protected function coerceColor($value, $inRGBFunction = false) { switch ($value[0]) { case Type::T_COLOR: + for ($i = 1; $i <= 3; $i++) { + if (! is_numeric($value[$i])) { + $cv = $this->compileRGBAValue($value[$i]); + + if (! is_numeric($cv)) { + return null; + } + + $value[$i] = $cv; + } + + if (isset($value[4])) { + if (! is_numeric($value[4])) { + $cv = $this->compileRGBAValue($value[4], true); + + if (! is_numeric($cv)) { + return null; + } + + $value[4] = $cv; + } + } + } + return $value; + case Type::T_LIST: + if ($inRGBFunction) { + if (count($value[2]) == 3 || count($value[2]) == 4) { + $color = $value[2]; + array_unshift($color, Type::T_COLOR); + + return $this->coerceColor($color); + } + } + + return null; + case Type::T_KEYWORD: + if (! is_string($value[1])) { + return null; + } + $name = strtolower($value[1]); + // hexa color? + if (preg_match('/^#([0-9a-f]+)$/i', $name, $m)) { + $nofValues = strlen($m[1]); - if (isset(Colors::$cssColors[$name])) { - $rgba = explode(',', Colors::$cssColors[$name]); + if (in_array($nofValues, [3, 4, 6, 8])) { + $nbChannels = 3; + $color = []; + $num = hexdec($m[1]); + switch ($nofValues) { + case 4: + $nbChannels = 4; + // then continuing with the case 3: + case 3: + for ($i = 0; $i < $nbChannels; $i++) { + $t = $num & 0xf; + array_unshift($color, $t << 4 | $t); + $num >>= 4; + } + + break; + + case 8: + $nbChannels = 4; + // then continuing with the case 6: + case 6: + for ($i = 0; $i < $nbChannels; $i++) { + array_unshift($color, $num & 0xff); + $num >>= 8; + } + + break; + } + + if ($nbChannels === 4) { + if ($color[3] === 255) { + $color[3] = 1; // fully opaque + } else { + $color[3] = round($color[3] / 255, 3); + } + } + + array_unshift($color, Type::T_COLOR); + + return $color; + } + } + + if ($rgba = Colors::colorNameToRGBa($name)) { return isset($rgba[3]) - ? [Type::T_COLOR, (int) $rgba[0], (int) $rgba[1], (int) $rgba[2], (int) $rgba[3]] - : [Type::T_COLOR, (int) $rgba[0], (int) $rgba[1], (int) $rgba[2]]; + ? [Type::T_COLOR, $rgba[0], $rgba[1], $rgba[2], $rgba[3]] + : [Type::T_COLOR, $rgba[0], $rgba[1], $rgba[2]]; } return null; @@ -4014,6 +5397,88 @@ class Compiler return null; } + /** + * @param integer|\ScssPhp\ScssPhp\Node\Number $value + * @param boolean $isAlpha + * + * @return integer|mixed + */ + protected function compileRGBAValue($value, $isAlpha = false) + { + if ($isAlpha) { + return $this->compileColorPartValue($value, 0, 1, false); + } + + return $this->compileColorPartValue($value, 0, 255, true); + } + + /** + * @param mixed $value + * @param integer|float $min + * @param integer|float $max + * @param boolean $isInt + * @param boolean $clamp + * @param boolean $modulo + * + * @return integer|mixed + */ + protected function compileColorPartValue($value, $min, $max, $isInt = true, $clamp = true, $modulo = false) + { + if (! is_numeric($value)) { + if (is_array($value)) { + $reduced = $this->reduce($value); + + if (is_object($reduced) && $value->type === Type::T_NUMBER) { + $value = $reduced; + } + } + + if (is_object($value) && $value->type === Type::T_NUMBER) { + $num = $value->dimension; + + if (count($value->units)) { + $unit = array_keys($value->units); + $unit = reset($unit); + + switch ($unit) { + case '%': + $num *= $max / 100; + break; + default: + break; + } + } + + $value = $num; + } elseif (is_array($value)) { + $value = $this->compileValue($value); + } + } + + if (is_numeric($value)) { + if ($isInt) { + $value = round($value); + } + + if ($clamp) { + $value = min($max, max($min, $value)); + } + + if ($modulo) { + $value = $value % $max; + + // still negative? + while ($value < $min) { + $value += $max; + } + } + + return $value; + } + + return $value; + } + /** * Coerce value to string * @@ -4066,7 +5531,7 @@ class Compiler $value = $this->coerceMap($value); if ($value[0] !== Type::T_MAP) { - $this->throwError('expecting map'); + $this->throwError('expecting map, %s received', $value[0]); } return $value; @@ -4086,7 +5551,7 @@ class Compiler public function assertList($value) { if ($value[0] !== Type::T_LIST) { - $this->throwError('expecting list'); + $this->throwError('expecting list, %s received', $value[0]); } return $value; @@ -4109,7 +5574,7 @@ class Compiler return $color; } - $this->throwError('expecting color'); + $this->throwError('expecting color, %s received', $value[0]); } /** @@ -4126,7 +5591,7 @@ class Compiler public function assertNumber($value) { if ($value[0] !== Type::T_NUMBER) { - $this->throwError('expecting number'); + $this->throwError('expecting number, %s received', $value[0]); } return $value[1]; @@ -4203,7 +5668,7 @@ class Compiler * * @return float */ - private function hueToRGB($m1, $m2, $h) + protected function hueToRGB($m1, $m2, $h) { if ($h < 0) { $h += 1; @@ -4261,46 +5726,27 @@ class Compiler // Built in functions - //protected static $libCall = ['name', 'args...']; + protected static $libCall = ['name', 'args...']; protected function libCall($args, $kwargs) { $name = $this->compileStringContent($this->coerceString($this->reduce(array_shift($args), true))); + $callArgs = []; - $posArgs = []; - - foreach ($args as $arg) { - if (empty($arg[0])) { - if ($arg[2] === true) { - $tmp = $this->reduce($arg[1]); - - if ($tmp[0] === Type::T_LIST) { - foreach ($tmp[2] as $item) { - $posArgs[] = [null, $item, false]; - } - } else { - $posArgs[] = [null, $tmp, true]; - } - - continue; - } - - $posArgs[] = [null, $this->reduce($arg), false]; - continue; + // $kwargs['args'] is [Type::T_LIST, ',', [..]] + foreach ($kwargs['args'][2] as $varname => $arg) { + if (is_numeric($varname)) { + $varname = null; + } else { + $varname = [ 'var', $varname]; } - $posArgs[] = [null, $arg, false]; + $callArgs[] = [$varname, $arg, false]; } - if (count($kwargs)) { - foreach ($kwargs as $key => $value) { - $posArgs[] = [[Type::T_VARIABLE, $key], $value, false]; - } - } - - return $this->reduce([Type::T_FUNCTION_CALL, $name, $posArgs]); + return $this->reduce([Type::T_FUNCTION_CALL, $name, $callArgs]); } - protected static $libIf = ['condition', 'if-true', 'if-false']; + protected static $libIf = ['condition', 'if-true', 'if-false:']; protected function libIf($args) { list($cond, $t, $f) = $args; @@ -4344,30 +5790,68 @@ class Compiler return false === $key ? static::$null : $key + 1; } - protected static $libRgb = ['red', 'green', 'blue']; - protected function libRgb($args) + protected static $libRgb = [ + ['color'], + ['color', 'alpha'], + ['channels'], + ['red', 'green', 'blue'], + ['red', 'green', 'blue', 'alpha'] ]; + protected function libRgb($args, $kwargs, $funcName = 'rgb') { - list($r, $g, $b) = $args; + switch (count($args)) { + case 1: + if (! $color = $this->coerceColor($args[0], true)) { + $color = [Type::T_STRING, '', [$funcName . '(', $args[0], ')']]; + } + break; - return [Type::T_COLOR, $r[1], $g[1], $b[1]]; + case 3: + $color = [Type::T_COLOR, $args[0], $args[1], $args[2]]; + + if (! $color = $this->coerceColor($color)) { + $color = [Type::T_STRING, '', [$funcName .'(', $args[0], ', ', $args[1], ', ', $args[2], ')']]; + } + + return $color; + + case 2: + if ($color = $this->coerceColor($args[0], true)) { + $alpha = $this->compileRGBAValue($args[1], true); + + if (is_numeric($alpha)) { + $color[4] = $alpha; + } else { + $color = [Type::T_STRING, '', + [$funcName . '(', $color[1], ', ', $color[2], ', ', $color[3], ', ', $alpha, ')']]; + } + } else { + $color = [Type::T_STRING, '', [$funcName . '(', $args[0], ')']]; + } + break; + + case 4: + default: + $color = [Type::T_COLOR, $args[0], $args[1], $args[2], $args[3]]; + + if (! $color = $this->coerceColor($color)) { + $color = [Type::T_STRING, '', + [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ', ', $args[3], ')']]; + } + break; + } + + return $color; } protected static $libRgba = [ - ['red', 'color'], - 'green', 'blue', 'alpha']; - protected function libRgba($args) + ['color'], + ['color', 'alpha'], + ['channels'], + ['red', 'green', 'blue'], + ['red', 'green', 'blue', 'alpha'] ]; + protected function libRgba($args, $kwargs) { - if ($color = $this->coerceColor($args[0])) { - $num = isset($args[3]) ? $args[3] : $args[1]; - $alpha = $this->assertNumber($num); - $color[4] = $alpha; - - return $color; - } - - list($r, $g, $b, $a) = $args; - - return [Type::T_COLOR, $r[1], $g[1], $b[1], $a[1]]; + return $this->libRgb($args, $kwargs, 'rgba'); } // helper function for adjust_color, change_color, and scale_color @@ -4375,21 +5859,25 @@ class Compiler { $color = $this->assertColor($args[0]); - foreach ([1, 2, 3, 7] as $i) { - if (isset($args[$i])) { - $val = $this->assertNumber($args[$i]); - $ii = $i === 7 ? 4 : $i; // alpha - $color[$ii] = call_user_func($fn, isset($color[$ii]) ? $color[$ii] : 0, $val, $i); + foreach ([1 => 1, 2 => 2, 3 => 3, 7 => 4] as $iarg => $irgba) { + if (isset($args[$iarg])) { + $val = $this->assertNumber($args[$iarg]); + + if (! isset($color[$irgba])) { + $color[$irgba] = (($irgba < 4) ? 0 : 1); + } + + $color[$irgba] = call_user_func($fn, $color[$irgba], $val, $iarg); } } - if (isset($args[4]) || isset($args[5]) || isset($args[6])) { + if (! empty($args[4]) || ! empty($args[5]) || ! empty($args[6])) { $hsl = $this->toHSL($color[1], $color[2], $color[3]); - foreach ([4, 5, 6] as $i) { - if (isset($args[$i])) { - $val = $this->assertNumber($args[$i]); - $hsl[$i - 3] = call_user_func($fn, $hsl[$i - 3], $val, $i); + foreach ([4 => 1, 5 => 2, 6 => 3] as $iarg => $ihsl) { + if (! empty($args[$iarg])) { + $val = $this->assertNumber($args[$iarg]); + $hsl[$ihsl] = call_user_func($fn, $hsl[$ihsl], $val, $iarg); } } @@ -4406,8 +5894,8 @@ class Compiler } protected static $libAdjustColor = [ - 'color', 'red', 'green', 'blue', - 'hue', 'saturation', 'lightness', 'alpha' + 'color', 'red:null', 'green:null', 'blue:null', + 'hue:null', 'saturation:null', 'lightness:null', 'alpha:null' ]; protected function libAdjustColor($args) { @@ -4417,8 +5905,8 @@ class Compiler } protected static $libChangeColor = [ - 'color', 'red', 'green', 'blue', - 'hue', 'saturation', 'lightness', 'alpha' + 'color', 'red:null', 'green:null', 'blue:null', + 'hue:null', 'saturation:null', 'lightness:null', 'alpha:null' ]; protected function libChangeColor($args) { @@ -4428,8 +5916,8 @@ class Compiler } protected static $libScaleColor = [ - 'color', 'red', 'green', 'blue', - 'hue', 'saturation', 'lightness', 'alpha' + 'color', 'red:null', 'green:null', 'blue:null', + 'hue:null', 'saturation:null', 'lightness:null', 'alpha:null' ]; protected function libScaleColor($args) { @@ -4472,7 +5960,7 @@ class Compiler $color = $this->coerceColor($args[0]); $color[4] = isset($color[4]) ? round(255 * $color[4]) : 255; - return sprintf('#%02X%02X%02X%02X', $color[4], $color[1], $color[2], $color[3]); + return [Type::T_STRING, '', [sprintf('#%02X%02X%02X%02X', $color[4], $color[1], $color[2], $color[3])]]; } protected static $libRed = ['color']; @@ -4523,7 +6011,7 @@ class Compiler } // mix two colors - protected static $libMix = ['color-1', 'color-2', 'weight']; + protected static $libMix = ['color-1', 'color-2', 'weight:0.5']; protected function libMix($args) { list($first, $second, $weight) = $args; @@ -4559,25 +6047,56 @@ class Compiler return $this->fixColor($new); } - protected static $libHsl = ['hue', 'saturation', 'lightness']; - protected function libHsl($args) + protected static $libHsl =[ + ['channels'], + ['hue', 'saturation', 'lightness'], + ['hue', 'saturation', 'lightness', 'alpha'] ]; + protected function libHsl($args, $kwargs, $funcName = 'hsl') { - list($h, $s, $l) = $args; + if (count($args) == 1) { + if ($args[0][0] !== Type::T_LIST || count($args[0][2]) < 3 || count($args[0][2]) > 4) { + return [Type::T_STRING, '', [$funcName . '(', $args[0], ')']]; + } - return $this->toRGB($h[1], $s[1], $l[1]); - } + $args = $args[0][2]; + } - protected static $libHsla = ['hue', 'saturation', 'lightness', 'alpha']; - protected function libHsla($args) - { - list($h, $s, $l, $a) = $args; + $hue = $this->compileColorPartValue($args[0], 0, 360, false, false, true); + $saturation = $this->compileColorPartValue($args[1], 0, 100, false); + $lightness = $this->compileColorPartValue($args[2], 0, 100, false); - $color = $this->toRGB($h[1], $s[1], $l[1]); - $color[4] = $a[1]; + $alpha = null; + + if (count($args) === 4) { + $alpha = $this->compileColorPartValue($args[3], 0, 100, false); + + if (! is_numeric($hue) || ! is_numeric($saturation) || ! is_numeric($lightness) || ! is_numeric($alpha)) { + return [Type::T_STRING, '', + [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ', ', $args[3], ')']]; + } + } else { + if (! is_numeric($hue) || ! is_numeric($saturation) || ! is_numeric($lightness)) { + return [Type::T_STRING, '', [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ')']]; + } + } + + $color = $this->toRGB($hue, $saturation, $lightness); + + if (! is_null($alpha)) { + $color[4] = $alpha; + } return $color; } + protected static $libHsla = [ + ['channels'], + ['hue', 'saturation', 'lightness', 'alpha:1'] ]; + protected function libHsla($args, $kwargs) + { + return $this->libHsl($args, $kwargs, 'hsla'); + } + protected static $libHue = ['color']; protected function libHue($args) { @@ -4645,7 +6164,7 @@ class Compiler return $this->adjustHsl($color, 3, -$amount); } - protected static $libSaturate = ['color', 'amount']; + protected static $libSaturate = [['color', 'amount'], ['number']]; protected function libSaturate($args) { $value = $args[0]; @@ -4687,21 +6206,32 @@ class Compiler return $this->adjustHsl($this->assertColor($args[0]), 1, 180); } - protected static $libInvert = ['color']; + protected static $libInvert = ['color', 'weight:1']; protected function libInvert($args) { - $value = $args[0]; + list($value, $weight) = $args; + + if (! isset($weight)) { + $weight = 1; + } else { + $weight = $this->coercePercent($weight); + } if ($value[0] === Type::T_NUMBER) { return null; } $color = $this->assertColor($value); - $color[1] = 255 - $color[1]; - $color[2] = 255 - $color[2]; - $color[3] = 255 - $color[3]; + $inverted = $color; + $inverted[1] = 255 - $inverted[1]; + $inverted[2] = 255 - $inverted[2]; + $inverted[3] = 255 - $inverted[3]; - return $color; + if ($weight < 1) { + return $this->libMix([$inverted, $color, [Type::T_NUMBER, $weight]]); + } + + return $inverted; } // increases opacity by amount @@ -4810,7 +6340,7 @@ class Compiler $min = null; foreach ($numbers as $key => $number) { - if (null === $min || $number[1] <= $min[1]) { + if (is_null($min) || $number[1] <= $min[1]) { $min = [$key, $number[1]]; } } @@ -4824,7 +6354,7 @@ class Compiler $max = null; foreach ($numbers as $key => $number) { - if (null === $max || $number[1] >= $max[1]) { + if (is_null($max) || $number[1] >= $max[1]) { $max = [$key, $number[1]]; } } @@ -4841,9 +6371,9 @@ class Compiler */ protected function getNormalizedNumbers($args) { - $unit = null; + $unit = null; $originalUnit = null; - $numbers = []; + $numbers = []; foreach ($args as $key => $item) { if ($item[0] !== Type::T_NUMBER) { @@ -4853,7 +6383,7 @@ class Compiler $number = $item->normalize(); - if (null === $unit) { + if (is_null($unit)) { $unit = $number[2]; $originalUnit = $item->unitStr(); } elseif ($number[1] && $unit !== $number[2]) { @@ -4925,7 +6455,7 @@ class Compiler if (! isset($list[2][$n])) { $this->throwError('Invalid argument for "n"'); - return; + return null; } $list[2][$n] = $args[2]; @@ -4937,11 +6467,15 @@ class Compiler protected function libMapGet($args) { $map = $this->assertMap($args[0]); - $key = $this->compileStringContent($this->coerceString($args[1])); + $key = $args[1]; - for ($i = count($map[1]) - 1; $i >= 0; $i--) { - if ($key === $this->compileStringContent($this->coerceString($map[1][$i]))) { - return $map[2][$i]; + if (! is_null($key)) { + $key = $this->compileStringContent($this->coerceString($key)); + + for ($i = count($map[1]) - 1; $i >= 0; $i--) { + if ($key === $this->compileStringContent($this->coerceString($map[1][$i]))) { + return $map[2][$i]; + } } } @@ -5036,6 +6570,18 @@ class Compiler return [Type::T_MAP, $keys, $values]; } + protected static $libIsBracketed = ['list']; + protected function libIsBracketed($args) + { + $list = $args[0]; + $this->coerceList($list, ' '); + if (! empty($list['enclosing']) && $list['enclosing'] === 'bracket') { + return true; + } + return false; + } + + protected function listSeparatorForJoin($list1, $sep) { if (! isset($sep)) { @@ -5047,26 +6593,56 @@ class Compiler return ','; case 'space': - return ''; + return ' '; default: return $list1[1]; } } - protected static $libJoin = ['list1', 'list2', 'separator']; + protected static $libJoin = ['list1', 'list2', 'separator:null', 'bracketed:auto']; protected function libJoin($args) { - list($list1, $list2, $sep) = $args; + list($list1, $list2, $sep, $bracketed) = $args; $list1 = $this->coerceList($list1, ' '); $list2 = $this->coerceList($list2, ' '); - $sep = $this->listSeparatorForJoin($list1, $sep); + $sep = $this->listSeparatorForJoin($list1, $sep); - return [Type::T_LIST, $sep, array_merge($list1[2], $list2[2])]; + if ($bracketed === static::$true) { + $bracketed = true; + } elseif ($bracketed === static::$false) { + $bracketed = false; + } elseif ($bracketed === [Type::T_KEYWORD, 'auto']) { + $bracketed = 'auto'; + } elseif ($bracketed === static::$null) { + $bracketed = false; + } else { + $bracketed = $this->compileValue($bracketed); + $bracketed = ! ! $bracketed; + if ($bracketed === true) { + $bracketed = true; + } + } + + if ($bracketed === 'auto') { + $bracketed = false; + if (! empty($list1['enclosing']) && $list1['enclosing'] === 'bracket') { + $bracketed = true; + } + } + + $res = [Type::T_LIST, $sep, array_merge($list1[2], $list2[2])]; + if (isset($list1['enclosing'])) { + $res['enlcosing'] = $list1['enclosing']; + } + if ($bracketed) { + $res['enclosing'] = 'bracket'; + } + return $res; } - protected static $libAppend = ['list', 'val', 'separator']; + protected static $libAppend = ['list', 'val', 'separator:null']; protected function libAppend($args) { list($list1, $value, $sep) = $args; @@ -5074,13 +6650,17 @@ class Compiler $list1 = $this->coerceList($list1, ' '); $sep = $this->listSeparatorForJoin($list1, $sep); - return [Type::T_LIST, $sep, array_merge($list1[2], [$value])]; + $res = [Type::T_LIST, $sep, array_merge($list1[2], [$value])]; + if (isset($list1['enclosing'])) { + $res['enclosing'] = $list1['enclosing']; + } + return $res; } protected function libZip($args) { - foreach ($args as $arg) { - $this->assertList($arg); + foreach ($args as $key => $arg) { + $args[$key] = $this->coerceList($arg); } $lists = []; @@ -5163,7 +6743,7 @@ class Compiler ) { $this->throwError('Invalid argument(s) for "comparable"'); - return; + return null; } $number1 = $number1->normalize(); @@ -5211,10 +6791,10 @@ class Compiler return new Node\Number(strlen($stringContent), ''); } - protected static $libStrSlice = ['string', 'start-at', 'end-at']; + protected static $libStrSlice = ['string', 'start-at', 'end-at:-1']; protected function libStrSlice($args) { - if (isset($args[2]) && $args[2][1] == 0) { + if (isset($args[2]) && ! $args[2][1]) { return static::$nullString; } @@ -5227,7 +6807,7 @@ class Compiler $start--; } - $end = (int) $args[2][1]; + $end = isset($args[2]) ? (int) $args[2][1] : -1; $length = $end < 0 ? $end + 1 : ($end > 0 ? $end - $start : $end); $string[2] = $length @@ -5343,7 +6923,7 @@ class Compiler if ($n < 1) { $this->throwError("limit must be greater than or equal to 1"); - return; + return null; } return new Node\Number(mt_rand(1, $n), ''); @@ -5365,13 +6945,670 @@ class Compiler return [Type::T_STRING, '', ['u' . str_pad(base_convert($id, 10, 36), 8, '0', STR_PAD_LEFT)]]; } + protected function inspectFormatValue($value, $force_enclosing_display = false) + { + if ($value === static::$null) { + $value = [Type::T_KEYWORD, 'null']; + } + $stringValue = [$value]; + if ($value[0] === Type::T_LIST) { + if (end($value[2]) === static::$null) { + array_pop($value[2]); + $value[2][] = [Type::T_STRING, '', ['']]; + $force_enclosing_display = true; + } + if (! empty($value['enclosing'])) { + if ($force_enclosing_display + || ($value['enclosing'] === 'bracket' ) + || !count($value[2])) { + $value['enclosing'] = 'forced_'.$value['enclosing']; + $force_enclosing_display = true; + } + } + foreach ($value[2] as $k => $listelement) { + $value[2][$k] = $this->inspectFormatValue($listelement, $force_enclosing_display); + } + $stringValue = [$value]; + } + + return [Type::T_STRING, '', $stringValue]; + } + protected static $libInspect = ['value']; protected function libInspect($args) { - if ($args[0] === static::$null) { - return [Type::T_KEYWORD, 'null']; + $value = $args[0]; + return $this->inspectFormatValue($value); + } + + /** + * Preprocess selector args + * + * @param array $arg + * + * @return array|boolean + */ + protected function getSelectorArg($arg) + { + static $parser = null; + + if (is_null($parser)) { + $parser = $this->parserFactory(__METHOD__); } - return $args[0]; + $arg = $this->libUnquote([$arg]); + $arg = $this->compileValue($arg); + + $parsedSelector = []; + + if ($parser->parseSelector($arg, $parsedSelector)) { + $selector = $this->evalSelectors($parsedSelector); + $gluedSelector = $this->glueFunctionSelectors($selector); + + return $gluedSelector; + } + + return false; + } + + /** + * Postprocess selector to output in right format + * + * @param array $selectors + * + * @return string + */ + protected function formatOutputSelector($selectors) + { + $selectors = $this->collapseSelectors($selectors, true); + + return $selectors; + } + + protected static $libIsSuperselector = ['super', 'sub']; + protected function libIsSuperselector($args) + { + list($super, $sub) = $args; + + $super = $this->getSelectorArg($super); + $sub = $this->getSelectorArg($sub); + + return $this->isSuperSelector($super, $sub); + } + + /** + * Test a $super selector again $sub + * + * @param array $super + * @param array $sub + * + * @return boolean + */ + protected function isSuperSelector($super, $sub) + { + // one and only one selector for each arg + if (! $super || count($super) !== 1) { + $this->throwError("Invalid super selector for isSuperSelector()"); + } + + if (! $sub || count($sub) !== 1) { + $this->throwError("Invalid sub selector for isSuperSelector()"); + } + + $super = reset($super); + $sub = reset($sub); + + $i = 0; + $nextMustMatch = false; + + foreach ($super as $node) { + $compound = ''; + + array_walk_recursive( + $node, + function ($value, $key) use (&$compound) { + $compound .= $value; + } + ); + + if ($this->isImmediateRelationshipCombinator($compound)) { + if ($node !== $sub[$i]) { + return false; + } + + $nextMustMatch = true; + $i++; + } else { + while ($i < count($sub) && ! $this->isSuperPart($node, $sub[$i])) { + if ($nextMustMatch) { + return false; + } + + $i++; + } + + if ($i >= count($sub)) { + return false; + } + + $nextMustMatch = false; + $i++; + } + } + + return true; + } + + /** + * Test a part of super selector again a part of sub selector + * + * @param array $superParts + * @param array $subParts + * + * @return boolean + */ + protected function isSuperPart($superParts, $subParts) + { + $i = 0; + + foreach ($superParts as $superPart) { + while ($i < count($subParts) && $subParts[$i] !== $superPart) { + $i++; + } + + if ($i >= count($subParts)) { + return false; + } + + $i++; + } + + return true; + } + + protected static $libSelectorAppend = ['selector...']; + protected function libSelectorAppend($args) + { + // get the selector... list + $args = reset($args); + $args = $args[2]; + + if (count($args) < 1) { + $this->throwError("selector-append() needs at least 1 argument"); + } + + $selectors = array_map([$this, 'getSelectorArg'], $args); + + return $this->formatOutputSelector($this->selectorAppend($selectors)); + } + + /** + * Append parts of the last selector in the list to the previous, recursively + * + * @param array $selectors + * + * @return array + * + * @throws \ScssPhp\ScssPhp\Exception\CompilerException + */ + protected function selectorAppend($selectors) + { + $lastSelectors = array_pop($selectors); + + if (! $lastSelectors) { + $this->throwError("Invalid selector list in selector-append()"); + } + + while (count($selectors)) { + $previousSelectors = array_pop($selectors); + + if (! $previousSelectors) { + $this->throwError("Invalid selector list in selector-append()"); + } + + // do the trick, happening $lastSelector to $previousSelector + $appended = []; + + foreach ($lastSelectors as $lastSelector) { + $previous = $previousSelectors; + + foreach ($lastSelector as $lastSelectorParts) { + foreach ($lastSelectorParts as $lastSelectorPart) { + foreach ($previous as $i => $previousSelector) { + foreach ($previousSelector as $j => $previousSelectorParts) { + $previous[$i][$j][] = $lastSelectorPart; + } + } + } + } + + foreach ($previous as $ps) { + $appended[] = $ps; + } + } + + $lastSelectors = $appended; + } + + return $lastSelectors; + } + + protected static $libSelectorExtend = ['selectors', 'extendee', 'extender']; + protected function libSelectorExtend($args) + { + list($selectors, $extendee, $extender) = $args; + + $selectors = $this->getSelectorArg($selectors); + $extendee = $this->getSelectorArg($extendee); + $extender = $this->getSelectorArg($extender); + + if (! $selectors || ! $extendee || ! $extender) { + $this->throwError("selector-extend() invalid arguments"); + } + + $extended = $this->extendOrReplaceSelectors($selectors, $extendee, $extender); + + return $this->formatOutputSelector($extended); + } + + protected static $libSelectorReplace = ['selectors', 'original', 'replacement']; + protected function libSelectorReplace($args) + { + list($selectors, $original, $replacement) = $args; + + $selectors = $this->getSelectorArg($selectors); + $original = $this->getSelectorArg($original); + $replacement = $this->getSelectorArg($replacement); + + if (! $selectors || ! $original || ! $replacement) { + $this->throwError("selector-replace() invalid arguments"); + } + + $replaced = $this->extendOrReplaceSelectors($selectors, $original, $replacement, true); + + return $this->formatOutputSelector($replaced); + } + + /** + * Extend/replace in selectors + * used by selector-extend and selector-replace that use the same logic + * + * @param array $selectors + * @param array $extendee + * @param array $extender + * @param boolean $replace + * + * @return array + */ + protected function extendOrReplaceSelectors($selectors, $extendee, $extender, $replace = false) + { + $saveExtends = $this->extends; + $saveExtendsMap = $this->extendsMap; + + $this->extends = []; + $this->extendsMap = []; + + foreach ($extendee as $es) { + // only use the first one + $this->pushExtends(reset($es), $extender, null); + } + + $extended = []; + + foreach ($selectors as $selector) { + if (! $replace) { + $extended[] = $selector; + } + + $n = count($extended); + + $this->matchExtends($selector, $extended); + + // if didnt match, keep the original selector if we are in a replace operation + if ($replace and count($extended) === $n) { + $extended[] = $selector; + } + } + + $this->extends = $saveExtends; + $this->extendsMap = $saveExtendsMap; + + return $extended; + } + + protected static $libSelectorNest = ['selector...']; + protected function libSelectorNest($args) + { + // get the selector... list + $args = reset($args); + $args = $args[2]; + + if (count($args) < 1) { + $this->throwError("selector-nest() needs at least 1 argument"); + } + + $selectorsMap = array_map([$this, 'getSelectorArg'], $args); + $envs = []; + + foreach ($selectorsMap as $selectors) { + $env = new Environment(); + $env->selectors = $selectors; + + $envs[] = $env; + } + + $envs = array_reverse($envs); + $env = $this->extractEnv($envs); + $outputSelectors = $this->multiplySelectors($env); + + return $this->formatOutputSelector($outputSelectors); + } + + protected static $libSelectorParse = ['selectors']; + protected function libSelectorParse($args) + { + $selectors = reset($args); + $selectors = $this->getSelectorArg($selectors); + + return $this->formatOutputSelector($selectors); + } + + protected static $libSelectorUnify = ['selectors1', 'selectors2']; + protected function libSelectorUnify($args) + { + list($selectors1, $selectors2) = $args; + + $selectors1 = $this->getSelectorArg($selectors1); + $selectors2 = $this->getSelectorArg($selectors2); + + if (! $selectors1 || ! $selectors2) { + $this->throwError("selector-unify() invalid arguments"); + } + + // only consider the first compound of each + $compound1 = reset($selectors1); + $compound2 = reset($selectors2); + + // unify them and that's it + $unified = $this->unifyCompoundSelectors($compound1, $compound2); + + return $this->formatOutputSelector($unified); + } + + /** + * The selector-unify magic as its best + * (at least works as expected on test cases) + * + * @param array $compound1 + * @param array $compound2 + * + * @return array|mixed + */ + protected function unifyCompoundSelectors($compound1, $compound2) + { + if (! count($compound1)) { + return $compound2; + } + + if (! count($compound2)) { + return $compound1; + } + + // check that last part are compatible + $lastPart1 = array_pop($compound1); + $lastPart2 = array_pop($compound2); + $last = $this->mergeParts($lastPart1, $lastPart2); + + if (! $last) { + return [[]]; + } + + $unifiedCompound = [$last]; + $unifiedSelectors = [$unifiedCompound]; + + // do the rest + while (count($compound1) || count($compound2)) { + $part1 = end($compound1); + $part2 = end($compound2); + + if ($part1 && ($match2 = $this->matchPartInCompound($part1, $compound2))) { + list($compound2, $part2, $after2) = $match2; + + if ($after2) { + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, $after2); + } + + $c = $this->mergeParts($part1, $part2); + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, [$c]); + + $part1 = $part2 = null; + + array_pop($compound1); + } + + if ($part2 && ($match1 = $this->matchPartInCompound($part2, $compound1))) { + list($compound1, $part1, $after1) = $match1; + + if ($after1) { + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, $after1); + } + + $c = $this->mergeParts($part2, $part1); + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, [$c]); + + $part1 = $part2 = null; + + array_pop($compound2); + } + + $new = []; + + if ($part1 && $part2) { + array_pop($compound1); + array_pop($compound2); + + $s = $this->prependSelectors($unifiedSelectors, [$part2]); + $new = array_merge($new, $this->prependSelectors($s, [$part1])); + $s = $this->prependSelectors($unifiedSelectors, [$part1]); + $new = array_merge($new, $this->prependSelectors($s, [$part2])); + } elseif ($part1) { + array_pop($compound1); + + $new = array_merge($new, $this->prependSelectors($unifiedSelectors, [$part1])); + } elseif ($part2) { + array_pop($compound2); + + $new = array_merge($new, $this->prependSelectors($unifiedSelectors, [$part2])); + } + + if ($new) { + $unifiedSelectors = $new; + } + } + + return $unifiedSelectors; + } + + /** + * Prepend each selector from $selectors with $parts + * + * @param array $selectors + * @param array $parts + * + * @return array + */ + protected function prependSelectors($selectors, $parts) + { + $new = []; + + foreach ($selectors as $compoundSelector) { + array_unshift($compoundSelector, $parts); + + $new[] = $compoundSelector; + } + + return $new; + } + + /** + * Try to find a matching part in a compound: + * - with same html tag name + * - with some class or id or something in common + * + * @param array $part + * @param array $compound + * + * @return array|boolean + */ + protected function matchPartInCompound($part, $compound) + { + $partTag = $this->findTagName($part); + $before = $compound; + $after = []; + + // try to find a match by tag name first + while (count($before)) { + $p = array_pop($before); + + if ($partTag && $partTag !== '*' && $partTag == $this->findTagName($p)) { + return [$before, $p, $after]; + } + + $after[] = $p; + } + + // try again matching a non empty intersection and a compatible tagname + $before = $compound; + $after = []; + + while (count($before)) { + $p = array_pop($before); + + if ($this->checkCompatibleTags($partTag, $this->findTagName($p))) { + if (count(array_intersect($part, $p))) { + return [$before, $p, $after]; + } + } + + $after[] = $p; + } + + return false; + } + + /** + * Merge two part list taking care that + * - the html tag is coming first - if any + * - the :something are coming last + * + * @param array $parts1 + * @param array $parts2 + * + * @return array + */ + protected function mergeParts($parts1, $parts2) + { + $tag1 = $this->findTagName($parts1); + $tag2 = $this->findTagName($parts2); + $tag = $this->checkCompatibleTags($tag1, $tag2); + + // not compatible tags + if ($tag === false) { + return []; + } + + if ($tag) { + if ($tag1) { + $parts1 = array_diff($parts1, [$tag1]); + } + + if ($tag2) { + $parts2 = array_diff($parts2, [$tag2]); + } + } + + $mergedParts = array_merge($parts1, $parts2); + $mergedOrderedParts = []; + + foreach ($mergedParts as $part) { + if (strpos($part, ':') === 0) { + $mergedOrderedParts[] = $part; + } + } + + $mergedParts = array_diff($mergedParts, $mergedOrderedParts); + $mergedParts = array_merge($mergedParts, $mergedOrderedParts); + + if ($tag) { + array_unshift($mergedParts, $tag); + } + + return $mergedParts; + } + + /** + * Check the compatibility between two tag names: + * if both are defined they should be identical or one has to be '*' + * + * @param string $tag1 + * @param string $tag2 + * + * @return array|boolean + */ + protected function checkCompatibleTags($tag1, $tag2) + { + $tags = [$tag1, $tag2]; + $tags = array_unique($tags); + $tags = array_filter($tags); + + if (count($tags) > 1) { + $tags = array_diff($tags, ['*']); + } + + // not compatible nodes + if (count($tags) > 1) { + return false; + } + + return $tags; + } + + /** + * Find the html tag name in a selector parts list + * + * @param array $parts + * + * @return mixed|string + */ + protected function findTagName($parts) + { + foreach ($parts as $part) { + if (! preg_match('/^[\[.:#%_-]/', $part)) { + return $part; + } + } + + return ''; + } + + protected static $libSimpleSelectors = ['selector']; + protected function libSimpleSelectors($args) + { + $selector = reset($args); + $selector = $this->getSelectorArg($selector); + + // remove selectors list layer, keeping the first one + $selector = reset($selector); + + // remove parts list layer, keeping the first part + $part = reset($selector); + + $listParts = []; + + foreach ($part as $p) { + $listParts[] = [Type::T_STRING, '', [$p]]; + } + + return [Type::T_LIST, ',', $listParts]; } } diff --git a/vendor/leafo/scssphp/src/Compiler/Environment.php b/vendor/scssphp/scssphp/src/Compiler/Environment.php similarity index 58% rename from vendor/leafo/scssphp/src/Compiler/Environment.php rename to vendor/scssphp/scssphp/src/Compiler/Environment.php index fe309dd3..03eb86a5 100644 --- a/vendor/leafo/scssphp/src/Compiler/Environment.php +++ b/vendor/scssphp/scssphp/src/Compiler/Environment.php @@ -2,14 +2,14 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Compiler; +namespace ScssPhp\ScssPhp\Compiler; /** * Compiler environment @@ -19,12 +19,12 @@ namespace Leafo\ScssPhp\Compiler; class Environment { /** - * @var \Leafo\ScssPhp\Block + * @var \ScssPhp\ScssPhp\Block */ public $block; /** - * @var \Leafo\ScssPhp\Compiler\Environment + * @var \ScssPhp\ScssPhp\Compiler\Environment */ public $parent; @@ -33,6 +33,11 @@ class Environment */ public $store; + /** + * @var array + */ + public $storeUnreduced; + /** * @var integer */ diff --git a/vendor/leafo/scssphp/src/Exception/CompilerException.php b/vendor/scssphp/scssphp/src/Exception/CompilerException.php similarity index 65% rename from vendor/leafo/scssphp/src/Exception/CompilerException.php rename to vendor/scssphp/scssphp/src/Exception/CompilerException.php index 7ca2e2b3..a9d134fc 100644 --- a/vendor/leafo/scssphp/src/Exception/CompilerException.php +++ b/vendor/scssphp/scssphp/src/Exception/CompilerException.php @@ -2,14 +2,14 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Exception; +namespace ScssPhp\ScssPhp\Exception; /** * Compiler exception diff --git a/vendor/leafo/scssphp/src/Exception/ParserException.php b/vendor/scssphp/scssphp/src/Exception/ParserException.php similarity index 64% rename from vendor/leafo/scssphp/src/Exception/ParserException.php rename to vendor/scssphp/scssphp/src/Exception/ParserException.php index 6d64335f..2fa12dd7 100644 --- a/vendor/leafo/scssphp/src/Exception/ParserException.php +++ b/vendor/scssphp/scssphp/src/Exception/ParserException.php @@ -2,14 +2,14 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Exception; +namespace ScssPhp\ScssPhp\Exception; /** * Parser Exception diff --git a/vendor/leafo/scssphp/src/Exception/RangeException.php b/vendor/scssphp/scssphp/src/Exception/RangeException.php similarity index 64% rename from vendor/leafo/scssphp/src/Exception/RangeException.php rename to vendor/scssphp/scssphp/src/Exception/RangeException.php index 3ba6bf14..ee36c97e 100644 --- a/vendor/leafo/scssphp/src/Exception/RangeException.php +++ b/vendor/scssphp/scssphp/src/Exception/RangeException.php @@ -2,14 +2,14 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Exception; +namespace ScssPhp\ScssPhp\Exception; /** * Range exception diff --git a/vendor/leafo/scssphp/src/Exception/ServerException.php b/vendor/scssphp/scssphp/src/Exception/ServerException.php similarity index 64% rename from vendor/leafo/scssphp/src/Exception/ServerException.php rename to vendor/scssphp/scssphp/src/Exception/ServerException.php index d0ed0842..d4a207af 100644 --- a/vendor/leafo/scssphp/src/Exception/ServerException.php +++ b/vendor/scssphp/scssphp/src/Exception/ServerException.php @@ -2,14 +2,14 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Exception; +namespace ScssPhp\ScssPhp\Exception; /** * Server Exception diff --git a/vendor/leafo/scssphp/src/Formatter.php b/vendor/scssphp/scssphp/src/Formatter.php similarity index 63% rename from vendor/leafo/scssphp/src/Formatter.php rename to vendor/scssphp/scssphp/src/Formatter.php index b4f90aa9..e1777045 100644 --- a/vendor/leafo/scssphp/src/Formatter.php +++ b/vendor/scssphp/scssphp/src/Formatter.php @@ -2,17 +2,17 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp; +namespace ScssPhp\ScssPhp; -use Leafo\ScssPhp\Formatter\OutputBlock; -use Leafo\ScssPhp\SourceMap\SourceMapGenerator; +use ScssPhp\ScssPhp\Formatter\OutputBlock; +use ScssPhp\ScssPhp\SourceMap\SourceMapGenerator; /** * Base formatter @@ -62,7 +62,7 @@ abstract class Formatter public $keepSemicolons; /** - * @var \Leafo\ScssPhp\Formatter\OutputBlock + * @var \ScssPhp\ScssPhp\Formatter\OutputBlock */ protected $currentBlock; @@ -77,10 +77,15 @@ abstract class Formatter protected $currentColumn; /** - * @var \Leafo\ScssPhp\SourceMap\SourceMapGenerator + * @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator */ protected $sourceMapGenerator; + /** + * @var string + */ + protected $strippedSemicolon; + /** * Initialize formatter * @@ -113,30 +118,10 @@ abstract class Formatter return rtrim($name) . $this->assignSeparator . $value . ';'; } - /** - * Strip semi-colon appended by property(); it's a separator, not a terminator - * - * @api - * - * @param array $lines - */ - public function stripSemicolon(&$lines) - { - if ($this->keepSemicolons) { - return; - } - - if (($count = count($lines)) - && substr($lines[$count - 1], -1) === ';' - ) { - $lines[$count - 1] = substr($lines[$count - 1], 0, -1); - } - } - /** * Output lines inside a block * - * @param \Leafo\ScssPhp\Formatter\OutputBlock $block + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block */ protected function blockLines(OutputBlock $block) { @@ -154,7 +139,7 @@ abstract class Formatter /** * Output block selectors * - * @param \Leafo\ScssPhp\Formatter\OutputBlock $block + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block */ protected function blockSelectors(OutputBlock $block) { @@ -168,7 +153,7 @@ abstract class Formatter /** * Output block children * - * @param \Leafo\ScssPhp\Formatter\OutputBlock $block + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block */ protected function blockChildren(OutputBlock $block) { @@ -180,7 +165,7 @@ abstract class Formatter /** * Output non-empty block * - * @param \Leafo\ScssPhp\Formatter\OutputBlock $block + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block */ protected function block(OutputBlock $block) { @@ -209,6 +194,10 @@ abstract class Formatter if (! empty($block->selectors)) { $this->indentLevel--; + if (! $this->keepSemicolons) { + $this->strippedSemicolon = ''; + } + if (empty($block->children)) { $this->write($this->break); } @@ -217,13 +206,41 @@ abstract class Formatter } } + /** + * Test and clean safely empty children + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return boolean + */ + protected function testEmptyChildren($block) + { + $isEmpty = empty($block->lines); + + if ($block->children) { + foreach ($block->children as $k => &$child) { + if (! $this->testEmptyChildren($child)) { + $isEmpty = false; + continue; + } + + if ($child->type === Type::T_MEDIA || $child->type === Type::T_DIRECTIVE) { + $child->children = []; + $child->selectors = null; + } + } + } + + return $isEmpty; + } + /** * Entry point to formatting a block * * @api * - * @param \Leafo\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree - * @param \Leafo\ScssPhp\SourceMap\SourceMapGenerator|null $sourceMapGenerator Optional source map generator + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree + * @param \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator|null $sourceMapGenerator Optional source map generator * * @return string */ @@ -232,11 +249,13 @@ abstract class Formatter $this->sourceMapGenerator = null; if ($sourceMapGenerator) { - $this->currentLine = 1; - $this->currentColumn = 0; + $this->currentLine = 1; + $this->currentColumn = 0; $this->sourceMapGenerator = $sourceMapGenerator; } + $this->testEmptyChildren($block); + ob_start(); $this->block($block); @@ -247,16 +266,39 @@ abstract class Formatter } /** + * Output content + * * @param string $str */ protected function write($str) { + if (! empty($this->strippedSemicolon)) { + echo $this->strippedSemicolon; + + $this->strippedSemicolon = ''; + } + + /* + * Maybe Strip semi-colon appended by property(); it's a separator, not a terminator + * will be striped for real before a closing, otherwise displayed unchanged starting the next write + */ + if (! $this->keepSemicolons && + $str && + (strpos($str, ';') !== false) && + (substr($str, -1) === ';') + ) { + $str = substr($str, 0, -1); + + $this->strippedSemicolon = ';'; + } + if ($this->sourceMapGenerator) { $this->sourceMapGenerator->addMapping( $this->currentLine, $this->currentColumn, $this->currentBlock->sourceLine, - $this->currentBlock->sourceColumn - 1, //columns from parser are off by one + //columns from parser are off by one + $this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0, $this->currentBlock->sourceName ); diff --git a/vendor/leafo/scssphp/src/Formatter/Compact.php b/vendor/scssphp/scssphp/src/Formatter/Compact.php similarity index 81% rename from vendor/leafo/scssphp/src/Formatter/Compact.php rename to vendor/scssphp/scssphp/src/Formatter/Compact.php index 4efa1a08..591f0c92 100644 --- a/vendor/leafo/scssphp/src/Formatter/Compact.php +++ b/vendor/scssphp/scssphp/src/Formatter/Compact.php @@ -2,16 +2,16 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Formatter; +namespace ScssPhp\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter; +use ScssPhp\ScssPhp\Formatter; /** * Compact formatter diff --git a/vendor/leafo/scssphp/src/Formatter/Compressed.php b/vendor/scssphp/scssphp/src/Formatter/Compressed.php similarity index 64% rename from vendor/leafo/scssphp/src/Formatter/Compressed.php rename to vendor/scssphp/scssphp/src/Formatter/Compressed.php index 1faa7e11..ec4722ea 100644 --- a/vendor/leafo/scssphp/src/Formatter/Compressed.php +++ b/vendor/scssphp/scssphp/src/Formatter/Compressed.php @@ -2,17 +2,17 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Formatter; +namespace ScssPhp\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter\OutputBlock; +use ScssPhp\ScssPhp\Formatter; +use ScssPhp\ScssPhp\Formatter\OutputBlock; /** * Compressed formatter @@ -59,4 +59,23 @@ class Compressed extends Formatter $this->write($this->break); } } + + /** + * Output block selectors + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + */ + protected function blockSelectors(OutputBlock $block) + { + $inner = $this->indentStr(); + + $this->write( + $inner + . implode( + $this->tagSeparator, + str_replace([' > ', ' + ', ' ~ '], ['>', '+', '~'], $block->selectors) + ) + . $this->open . $this->break + ); + } } diff --git a/vendor/leafo/scssphp/src/Formatter/Crunched.php b/vendor/scssphp/scssphp/src/Formatter/Crunched.php similarity index 61% rename from vendor/leafo/scssphp/src/Formatter/Crunched.php rename to vendor/scssphp/scssphp/src/Formatter/Crunched.php index 42d77b5f..51ccb516 100644 --- a/vendor/leafo/scssphp/src/Formatter/Crunched.php +++ b/vendor/scssphp/scssphp/src/Formatter/Crunched.php @@ -2,17 +2,17 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Formatter; +namespace ScssPhp\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter\OutputBlock; +use ScssPhp\ScssPhp\Formatter; +use ScssPhp\ScssPhp\Formatter\OutputBlock; /** * Crunched formatter @@ -57,4 +57,23 @@ class Crunched extends Formatter $this->write($this->break); } } + + /** + * Output block selectors + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + */ + protected function blockSelectors(OutputBlock $block) + { + $inner = $this->indentStr(); + + $this->write( + $inner + . implode( + $this->tagSeparator, + str_replace([' > ', ' + ', ' ~ '], ['>', '+', '~'], $block->selectors) + ) + . $this->open . $this->break + ); + } } diff --git a/vendor/leafo/scssphp/src/Formatter/Debug.php b/vendor/scssphp/scssphp/src/Formatter/Debug.php similarity index 92% rename from vendor/leafo/scssphp/src/Formatter/Debug.php rename to vendor/scssphp/scssphp/src/Formatter/Debug.php index bfcbf41a..94e70c81 100644 --- a/vendor/leafo/scssphp/src/Formatter/Debug.php +++ b/vendor/scssphp/scssphp/src/Formatter/Debug.php @@ -2,17 +2,17 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Formatter; +namespace ScssPhp\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter\OutputBlock; +use ScssPhp\ScssPhp\Formatter; +use ScssPhp\ScssPhp\Formatter\OutputBlock; /** * Debug formatter diff --git a/vendor/leafo/scssphp/src/Formatter/Expanded.php b/vendor/scssphp/scssphp/src/Formatter/Expanded.php similarity index 81% rename from vendor/leafo/scssphp/src/Formatter/Expanded.php rename to vendor/scssphp/scssphp/src/Formatter/Expanded.php index d8c1e887..9549c6cf 100644 --- a/vendor/leafo/scssphp/src/Formatter/Expanded.php +++ b/vendor/scssphp/scssphp/src/Formatter/Expanded.php @@ -2,17 +2,17 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Formatter; +namespace ScssPhp\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter\OutputBlock; +use ScssPhp\ScssPhp\Formatter; +use ScssPhp\ScssPhp\Formatter\OutputBlock; /** * Expanded formatter @@ -55,7 +55,7 @@ class Expanded extends Formatter foreach ($block->lines as $index => $line) { if (substr($line, 0, 2) === '/*') { - $block->lines[$index] = preg_replace('/(\r|\n)+/', $glue, $line); + $block->lines[$index] = preg_replace('/[\r\n]+/', $glue, $line); } } diff --git a/vendor/scssphp/scssphp/src/Formatter/Nested.php b/vendor/scssphp/scssphp/src/Formatter/Nested.php new file mode 100644 index 00000000..f9e7f037 --- /dev/null +++ b/vendor/scssphp/scssphp/src/Formatter/Nested.php @@ -0,0 +1,228 @@ + + */ +class Nested extends Formatter +{ + /** + * @var integer + */ + private $depth; + + /** + * {@inheritdoc} + */ + public function __construct() + { + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = "\n"; + $this->open = ' {'; + $this->close = ' }'; + $this->tagSeparator = ', '; + $this->assignSeparator = ': '; + $this->keepSemicolons = true; + } + + /** + * {@inheritdoc} + */ + protected function indentStr() + { + $n = $this->depth - 1; + + return str_repeat($this->indentChar, max($this->indentLevel + $n, 0)); + } + + /** + * {@inheritdoc} + */ + protected function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + + $glue = $this->break . $inner; + + foreach ($block->lines as $index => $line) { + if (substr($line, 0, 2) === '/*') { + $block->lines[$index] = preg_replace('/[\r\n]+/', $glue, $line); + } + } + + $this->write($inner . implode($glue, $block->lines)); + } + + /** + * {@inheritdoc} + */ + protected function block(OutputBlock $block) + { + static $depths; + static $downLevel; + static $closeBlock; + static $previousEmpty; + static $previousHasSelector; + + if ($block->type === 'root') { + $depths = [ 0 ]; + $downLevel = ''; + $closeBlock = ''; + $this->depth = 0; + $previousEmpty = false; + $previousHasSelector = false; + } + + $isMediaOrDirective = in_array($block->type, [Type::T_DIRECTIVE, Type::T_MEDIA]); + $isSupport = ($block->type === Type::T_DIRECTIVE + && $block->selectors && strpos(implode('', $block->selectors), '@supports') !== false); + + while ($block->depth < end($depths) || ($block->depth == 1 && end($depths) == 1)) { + array_pop($depths); + $this->depth--; + + if (! $this->depth && ($block->depth <= 1 || (! $this->indentLevel && $block->type === Type::T_COMMENT)) && + (($block->selectors && ! $isMediaOrDirective) || $previousHasSelector) + ) { + $downLevel = $this->break; + } + + if (empty($block->lines) && empty($block->children)) { + $previousEmpty = true; + } + } + + if (empty($block->lines) && empty($block->children)) { + return; + } + + $this->currentBlock = $block; + + if (! empty($block->lines) || (! empty($block->children) && ($this->depth < 1 || $isSupport))) { + if ($block->depth > end($depths)) { + if (! $previousEmpty || $this->depth < 1) { + $this->depth++; + $depths[] = $block->depth; + } else { + // keep the current depth unchanged but take the block depth as a new reference for following blocks + array_pop($depths); + $depths[] = $block->depth; + } + } + } + + $previousEmpty = ($block->type === Type::T_COMMENT); + $previousHasSelector = false; + + if (! empty($block->selectors)) { + if ($closeBlock) { + $this->write($closeBlock); + $closeBlock = ''; + } + + if ($downLevel) { + $this->write($downLevel); + $downLevel = ''; + } + + $this->blockSelectors($block); + + $this->indentLevel++; + } + + if (! empty($block->lines)) { + if ($closeBlock) { + $this->write($closeBlock); + $closeBlock = ''; + } + + if ($downLevel) { + $this->write($downLevel); + $downLevel = ''; + } + + $this->blockLines($block); + + $closeBlock = $this->break; + } + + if (! empty($block->children)) { + if ($this->depth > 0 && ($isMediaOrDirective || ! $this->hasFlatChild($block))) { + array_pop($depths); + + $this->depth--; + $this->blockChildren($block); + $this->depth++; + + $depths[] = $block->depth; + } else { + $this->blockChildren($block); + } + } + + // reclear to not be spoiled by children if T_DIRECTIVE + if ($block->type === Type::T_DIRECTIVE) { + $previousHasSelector = false; + } + + if (! empty($block->selectors)) { + $this->indentLevel--; + + if (! $this->keepSemicolons) { + $this->strippedSemicolon = ''; + } + + $this->write($this->close); + + $closeBlock = $this->break; + + if ($this->depth > 1 && ! empty($block->children)) { + array_pop($depths); + $this->depth--; + } + + if (! $isMediaOrDirective) { + $previousHasSelector = true; + } + } + + if ($block->type === 'root') { + $this->write($this->break); + } + } + + /** + * Block has flat child + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return boolean + */ + private function hasFlatChild($block) + { + foreach ($block->children as $child) { + if (empty($child->selectors)) { + return true; + } + } + + return false; + } +} diff --git a/vendor/leafo/scssphp/src/Formatter/OutputBlock.php b/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php similarity index 80% rename from vendor/leafo/scssphp/src/Formatter/OutputBlock.php rename to vendor/scssphp/scssphp/src/Formatter/OutputBlock.php index 5eb589c9..3e6fd928 100644 --- a/vendor/leafo/scssphp/src/Formatter/OutputBlock.php +++ b/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php @@ -2,14 +2,14 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Formatter; +namespace ScssPhp\ScssPhp\Formatter; /** * Output block @@ -44,7 +44,7 @@ class OutputBlock public $children; /** - * @var \Leafo\ScssPhp\Formatter\OutputBlock + * @var \ScssPhp\ScssPhp\Formatter\OutputBlock */ public $parent; diff --git a/vendor/leafo/scssphp/src/Node.php b/vendor/scssphp/scssphp/src/Node.php similarity index 79% rename from vendor/leafo/scssphp/src/Node.php rename to vendor/scssphp/scssphp/src/Node.php index b9f7945a..dab565a6 100644 --- a/vendor/leafo/scssphp/src/Node.php +++ b/vendor/scssphp/scssphp/src/Node.php @@ -2,14 +2,14 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp; +namespace ScssPhp\ScssPhp; /** * Base node diff --git a/vendor/leafo/scssphp/src/Node/Number.php b/vendor/scssphp/scssphp/src/Node/Number.php similarity index 93% rename from vendor/leafo/scssphp/src/Node/Number.php rename to vendor/scssphp/scssphp/src/Node/Number.php index 42c16803..acbabff7 100644 --- a/vendor/leafo/scssphp/src/Node/Number.php +++ b/vendor/scssphp/scssphp/src/Node/Number.php @@ -2,18 +2,18 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp\Node; +namespace ScssPhp\ScssPhp\Node; -use Leafo\ScssPhp\Compiler; -use Leafo\ScssPhp\Node; -use Leafo\ScssPhp\Type; +use ScssPhp\ScssPhp\Compiler; +use ScssPhp\ScssPhp\Node; +use ScssPhp\ScssPhp\Type; /** * Dimension + optional units @@ -100,7 +100,7 @@ class Number extends Node implements \ArrayAccess * * @param array $units * - * @return \Leafo\ScssPhp\Node\Number + * @return \ScssPhp\ScssPhp\Node\Number */ public function coerce($units) { @@ -123,7 +123,7 @@ class Number extends Node implements \ArrayAccess /** * Normalize number * - * @return \Leafo\ScssPhp\Node\Number + * @return \ScssPhp\ScssPhp\Node\Number */ public function normalize() { @@ -141,17 +141,17 @@ class Number extends Node implements \ArrayAccess public function offsetExists($offset) { if ($offset === -3) { - return $this->sourceColumn !== null; + return ! is_null($this->sourceColumn); } if ($offset === -2) { - return $this->sourceLine !== null; + return ! is_null($this->sourceLine); } - if ($offset === -1 - || $offset === 0 - || $offset === 1 - || $offset === 2 + if ($offset === -1 || + $offset === 0 || + $offset === 1 || + $offset === 2 ) { return true; } @@ -259,7 +259,7 @@ class Number extends Node implements \ArrayAccess /** * Output number * - * @param \Leafo\ScssPhp\Compiler $compiler + * @param \ScssPhp\ScssPhp\Compiler $compiler * * @return string */ diff --git a/vendor/leafo/scssphp/src/Parser.php b/vendor/scssphp/scssphp/src/Parser.php similarity index 57% rename from vendor/leafo/scssphp/src/Parser.php rename to vendor/scssphp/scssphp/src/Parser.php index de86f094..6a30af12 100644 --- a/vendor/leafo/scssphp/src/Parser.php +++ b/vendor/scssphp/scssphp/src/Parser.php @@ -2,20 +2,21 @@ /** * SCSSPHP * - * @copyright 2012-2018 Leaf Corcoran + * @copyright 2012-2019 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * - * @link http://leafo.github.io/scssphp + * @link http://scssphp.github.io/scssphp */ -namespace Leafo\ScssPhp; +namespace ScssPhp\ScssPhp; -use Leafo\ScssPhp\Block; -use Leafo\ScssPhp\Compiler; -use Leafo\ScssPhp\Exception\ParserException; -use Leafo\ScssPhp\Node; -use Leafo\ScssPhp\Type; +use ScssPhp\ScssPhp\Block; +use ScssPhp\ScssPhp\Cache; +use ScssPhp\ScssPhp\Compiler; +use ScssPhp\ScssPhp\Exception\ParserException; +use ScssPhp\ScssPhp\Node; +use ScssPhp\ScssPhp\Type; /** * Parser @@ -53,6 +54,8 @@ class Parser protected static $operatorPattern; protected static $whitePattern; + protected $cache; + private $sourceName; private $sourceIndex; private $sourcePositions; @@ -61,27 +64,32 @@ class Parser private $env; private $inParens; private $eatWhiteDefault; + private $discardComments; private $buffer; private $utf8; private $encoding; private $patternModifiers; + private $commentsSeen; /** * Constructor * * @api * - * @param string $sourceName - * @param integer $sourceIndex - * @param string $encoding + * @param string $sourceName + * @param integer $sourceIndex + * @param string $encoding + * @param \ScssPhp\ScssPhp\Cache $cache */ - public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8') + public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8', $cache = null) { $this->sourceName = $sourceName ?: '(stdin)'; $this->sourceIndex = $sourceIndex; $this->charset = null; $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8'; $this->patternModifiers = $this->utf8 ? 'Aisu' : 'Ais'; + $this->commentsSeen = []; + $this->discardComments = false; if (empty(static::$operatorPattern)) { static::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=\>|\<\=?|and|or)'; @@ -95,6 +103,10 @@ class Parser ? '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisuS' : '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisS'; } + + if ($cache) { + $this->cache = $cache; + } } /** @@ -116,13 +128,15 @@ class Parser * * @param string $msg * - * @throws \Leafo\ScssPhp\Exception\ParserException + * @throws \ScssPhp\ScssPhp\Exception\ParserException */ public function throwParseError($msg = 'parse error') { - list($line, /* $column */) = $this->getSourcePosition($this->count); + list($line, $column) = $this->getSourcePosition($this->count); - $loc = empty($this->sourceName) ? "line: $line" : "$this->sourceName on line $line"; + $loc = empty($this->sourceName) + ? "line: $line, column: $column" + : "$this->sourceName on line $line, at column $column"; if ($this->peek("(.*?)(\n|$)", $m, $this->count)) { throw new ParserException("$msg: failed at `$m[1]` $loc"); @@ -138,10 +152,23 @@ class Parser * * @param string $buffer * - * @return \Leafo\ScssPhp\Block + * @return \ScssPhp\ScssPhp\Block */ public function parse($buffer) { + if ($this->cache) { + $cacheKey = $this->sourceName . ":" . md5($buffer); + $parseOptions = [ + 'charset' => $this->charset, + 'utf8' => $this->utf8, + ]; + $v = $this->cache->getCache("parse", $cacheKey, $parseOptions); + + if (! is_null($v)) { + return $v; + } + } + // strip BOM (byte order marker) if (substr($buffer, 0, 3) === "\xef\xbb\xbf") { $buffer = substr($buffer, 3); @@ -177,10 +204,12 @@ class Parser array_unshift($this->env->children, $this->charset); } - $this->env->isRoot = true; - $this->restoreEncoding(); + if ($this->cache) { + $this->cache->setCache("parse", $cacheKey, $this->env, $parseOptions); + } + return $this->env; } @@ -189,8 +218,8 @@ class Parser * * @api * - * @param string $buffer - * @param string $out + * @param string $buffer + * @param string|array $out * * @return boolean */ @@ -216,8 +245,8 @@ class Parser * * @api * - * @param string $buffer - * @param string $out + * @param string $buffer + * @param string|array $out * * @return boolean */ @@ -238,6 +267,33 @@ class Parser return $selector; } + /** + * Parse a media Query + * + * @api + * + * @param string $buffer + * @param string|array $out + * + * @return boolean + */ + public function parseMediaQueryList($buffer, &$out) + { + $this->count = 0; + $this->env = null; + $this->inParens = false; + $this->eatWhiteDefault = true; + $this->buffer = (string) $buffer; + + $this->saveEncoding(); + + $isMediaQuery = $this->mediaQueryList($out); + + $this->restoreEncoding(); + + return $isMediaQuery; + } + /** * Parse a single chunk off the head of the buffer and append it to the * current parse environment. @@ -271,7 +327,7 @@ class Parser * the buffer position will be left at an invalid state. In order to * avoid this, Compiler::seek() is used to remember and set buffer positions. * - * Before parsing a chain, use $s = $this->seek() to remember the current + * Before parsing a chain, use $s = $this->count to remember the current * position into $s. Then if a chain fails, use $this->seek($s) to * go back where we started. * @@ -279,25 +335,28 @@ class Parser */ protected function parseChunk() { - $s = $this->seek(); + $s = $this->count; // the directives if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] === '@') { - if ($this->literal('@at-root') && + if ($this->literal('@at-root', 8) && ($this->selectors($selector) || true) && ($this->map($with) || true) && - $this->literal('{') + (($this->matchChar('(') + && $this->interpolation($with) + && $this->matchChar(')')) || true) && + $this->matchChar('{', false) ) { $atRoot = $this->pushSpecialBlock(Type::T_AT_ROOT, $s); $atRoot->selector = $selector; - $atRoot->with = $with; + $atRoot->with = $with; return true; } $this->seek($s); - if ($this->literal('@media') && $this->mediaQueryList($mediaQueryList) && $this->literal('{')) { + if ($this->literal('@media', 6) && $this->mediaQueryList($mediaQueryList) && $this->matchChar('{', false)) { $media = $this->pushSpecialBlock(Type::T_MEDIA, $s); $media->queryList = $mediaQueryList[2]; @@ -306,10 +365,10 @@ class Parser $this->seek($s); - if ($this->literal('@mixin') && + if ($this->literal('@mixin', 6) && $this->keyword($mixinName) && ($this->argumentDef($args) || true) && - $this->literal('{') + $this->matchChar('{', false) ) { $mixin = $this->pushSpecialBlock(Type::T_MIXIN, $s); $mixin->name = $mixinName; @@ -320,15 +379,24 @@ class Parser $this->seek($s); - if ($this->literal('@include') && + if ($this->literal('@include', 8) && $this->keyword($mixinName) && - ($this->literal('(') && + ($this->matchChar('(') && ($this->argValues($argValues) || true) && - $this->literal(')') || true) && + $this->matchChar(')') || true) && ($this->end() || - $this->literal('{') && $hasBlock = true) + ($this->literal('using', 5) && + $this->argumentDef($argUsing) && + ($this->end() || $this->matchChar('{') && $hasBlock = true)) || + $this->matchChar('{') && $hasBlock = true) ) { - $child = [Type::T_INCLUDE, $mixinName, isset($argValues) ? $argValues : null, null]; + $child = [ + Type::T_INCLUDE, + $mixinName, + isset($argValues) ? $argValues : null, + null, + isset($argUsing) ? $argUsing : null + ]; if (! empty($hasBlock)) { $include = $this->pushSpecialBlock(Type::T_INCLUDE, $s); @@ -342,7 +410,7 @@ class Parser $this->seek($s); - if ($this->literal('@scssphp-import-once') && + if ($this->literal('@scssphp-import-once', 20) && $this->valueList($importPath) && $this->end() ) { @@ -353,7 +421,7 @@ class Parser $this->seek($s); - if ($this->literal('@import') && + if ($this->literal('@import', 7) && $this->valueList($importPath) && $this->end() ) { @@ -364,7 +432,7 @@ class Parser $this->seek($s); - if ($this->literal('@import') && + if ($this->literal('@import', 7) && $this->url($importPath) && $this->end() ) { @@ -375,7 +443,7 @@ class Parser $this->seek($s); - if ($this->literal('@extend') && + if ($this->literal('@extend', 7) && $this->selectors($selectors) && $this->end() ) { @@ -388,10 +456,10 @@ class Parser $this->seek($s); - if ($this->literal('@function') && + if ($this->literal('@function', 9) && $this->keyword($fnName) && $this->argumentDef($args) && - $this->literal('{') + $this->matchChar('{', false) ) { $func = $this->pushSpecialBlock(Type::T_FUNCTION, $s); $func->name = $fnName; @@ -402,7 +470,7 @@ class Parser $this->seek($s); - if ($this->literal('@break') && $this->end()) { + if ($this->literal('@break', 6) && $this->end()) { $this->append([Type::T_BREAK], $s); return true; @@ -410,7 +478,7 @@ class Parser $this->seek($s); - if ($this->literal('@continue') && $this->end()) { + if ($this->literal('@continue', 9) && $this->end()) { $this->append([Type::T_CONTINUE], $s); return true; @@ -418,8 +486,7 @@ class Parser $this->seek($s); - - if ($this->literal('@return') && ($this->valueList($retVal) || true) && $this->end()) { + if ($this->literal('@return', 7) && ($this->valueList($retVal) || true) && $this->end()) { $this->append([Type::T_RETURN, isset($retVal) ? $retVal : [Type::T_NULL]], $s); return true; @@ -427,11 +494,11 @@ class Parser $this->seek($s); - if ($this->literal('@each') && + if ($this->literal('@each', 5) && $this->genericList($varNames, 'variable', ',', false) && - $this->literal('in') && + $this->literal('in', 2) && $this->valueList($list) && - $this->literal('{') + $this->matchChar('{', false) ) { $each = $this->pushSpecialBlock(Type::T_EACH, $s); @@ -446,9 +513,9 @@ class Parser $this->seek($s); - if ($this->literal('@while') && + if ($this->literal('@while', 6) && $this->expression($cond) && - $this->literal('{') + $this->matchChar('{', false) ) { $while = $this->pushSpecialBlock(Type::T_WHILE, $s); $while->cond = $cond; @@ -458,19 +525,19 @@ class Parser $this->seek($s); - if ($this->literal('@for') && + if ($this->literal('@for', 4) && $this->variable($varName) && - $this->literal('from') && + $this->literal('from', 4) && $this->expression($start) && - ($this->literal('through') || - ($forUntil = true && $this->literal('to'))) && + ($this->literal('through', 7) || + ($forUntil = true && $this->literal('to', 2))) && $this->expression($end) && - $this->literal('{') + $this->matchChar('{', false) ) { $for = $this->pushSpecialBlock(Type::T_FOR, $s); - $for->var = $varName[1]; + $for->var = $varName[1]; $for->start = $start; - $for->end = $end; + $for->end = $end; $for->until = isset($forUntil); return true; @@ -478,9 +545,15 @@ class Parser $this->seek($s); - if ($this->literal('@if') && $this->valueList($cond) && $this->literal('{')) { + if ($this->literal('@if', 3) && $this->valueList($cond) && $this->matchChar('{', false)) { $if = $this->pushSpecialBlock(Type::T_IF, $s); - $if->cond = $cond; + while ($cond[0] === Type::T_LIST + && !empty($cond['enclosing']) + && $cond['enclosing'] === 'parent' + && count($cond[2]) == 1) { + $cond = reset($cond[2]); + } + $if->cond = $cond; $if->cases = []; return true; @@ -488,7 +561,7 @@ class Parser $this->seek($s); - if ($this->literal('@debug') && + if ($this->literal('@debug', 6) && $this->valueList($value) && $this->end() ) { @@ -499,7 +572,7 @@ class Parser $this->seek($s); - if ($this->literal('@warn') && + if ($this->literal('@warn', 5) && $this->valueList($value) && $this->end() ) { @@ -510,7 +583,7 @@ class Parser $this->seek($s); - if ($this->literal('@error') && + if ($this->literal('@error', 6) && $this->valueList($value) && $this->end() ) { @@ -521,8 +594,15 @@ class Parser $this->seek($s); - if ($this->literal('@content') && $this->end()) { - $this->append([Type::T_MIXIN_CONTENT], $s); + #if ($this->literal('@content', 8)) + + if ($this->literal('@content', 8) && + ($this->end() || + $this->matchChar('(') && + $this->argValues($argContent) && + $this->matchChar(')') && + $this->end())) { + $this->append([Type::T_MIXIN_CONTENT, isset($argContent) ? $argContent : null], $s); return true; } @@ -534,10 +614,10 @@ class Parser if (isset($last) && $last[0] === Type::T_IF) { list(, $if) = $last; - if ($this->literal('@else')) { - if ($this->literal('{')) { + if ($this->literal('@else', 5)) { + if ($this->matchChar('{', false)) { $else = $this->pushSpecialBlock(Type::T_ELSE, $s); - } elseif ($this->literal('if') && $this->valueList($cond) && $this->literal('{')) { + } elseif ($this->literal('if', 2) && $this->valueList($cond) && $this->matchChar('{', false)) { $else = $this->pushSpecialBlock(Type::T_ELSEIF, $s); $else->cond = $cond; } @@ -554,7 +634,7 @@ class Parser } // only retain the first @charset directive encountered - if ($this->literal('@charset') && + if ($this->literal('@charset', 8) && $this->valueList($charset) && $this->end() ) { @@ -575,11 +655,24 @@ class Parser $this->seek($s); + if ($this->literal('@supports', 9) && + ($t1=$this->supportsQuery($supportQuery)) && + ($t2=$this->matchChar('{', false)) + ) { + $directive = $this->pushSpecialBlock(Type::T_DIRECTIVE, $s); + $directive->name = 'supports'; + $directive->value = $supportQuery; + + return true; + } + + $this->seek($s); + // doesn't match built in directive, do generic one - if ($this->literal('@', false) && + if ($this->matchChar('@', false) && $this->keyword($dirName) && ($this->variable($dirValue) || $this->openString('{', $dirValue) || true) && - $this->literal('{') + $this->matchChar('{', false) ) { if ($dirName === 'media') { $directive = $this->pushSpecialBlock(Type::T_MEDIA, $s); @@ -597,13 +690,26 @@ class Parser $this->seek($s); + // maybe it's a generic blockless directive + if ($this->matchChar('@', false) && + $this->keyword($dirName) && + $this->valueList($dirValue) && + $this->end() + ) { + $this->append([Type::T_DIRECTIVE, [$dirName, $dirValue]], $s); + + return true; + } + + $this->seek($s); + return false; } // property shortcut // captures most properties before having to parse a selector if ($this->keyword($name, false) && - $this->literal(': ') && + $this->literal(': ', 2) && $this->valueList($value) && $this->end() ) { @@ -617,7 +723,7 @@ class Parser // variable assigns if ($this->variable($name) && - $this->literal(':') && + $this->matchChar(':') && $this->valueList($value) && $this->end() ) { @@ -631,31 +737,42 @@ class Parser $this->seek($s); // misc - if ($this->literal('-->')) { + if ($this->literal('-->', 3)) { return true; } // opening css block - if ($this->selectors($selectors) && $this->literal('{')) { + if ($this->selectors($selectors) && $this->matchChar('{', false)) { $this->pushBlock($selectors, $s); + if ($this->eatWhiteDefault) { + $this->whitespace(); + $this->append(null); // collect comments at the beginning if needed + } + return true; } $this->seek($s); // property assign, or nested assign - if ($this->propertyName($name) && $this->literal(':')) { + if ($this->propertyName($name) && $this->matchChar(':')) { $foundSomething = false; if ($this->valueList($value)) { + if (empty($this->env->parent)) { + $this->throwParseError('expected "{"'); + } + $this->append([Type::T_ASSIGN, $name, $value], $s); $foundSomething = true; } - if ($this->literal('{')) { + if ($this->matchChar('{', false)) { $propBlock = $this->pushSpecialBlock(Type::T_NESTED_PROPERTY, $s); $propBlock->prefix = $name; + $propBlock->hasValue = $foundSomething; + $foundSomething = true; } elseif ($foundSomething) { $foundSomething = $this->end(); @@ -669,9 +786,15 @@ class Parser $this->seek($s); // closing a block - if ($this->literal('}')) { + if ($this->matchChar('}', false)) { $block = $this->popBlock(); + if (! isset($block->type) || $block->type !== Type::T_IF) { + if ($this->env->parent) { + $this->append(null); // collect comments before next statement if needed + } + } + if (isset($block->type) && $block->type === Type::T_INCLUDE) { $include = $block->child; unset($block->child); @@ -682,12 +805,21 @@ class Parser $this->append([$type, $block], $s); } + // collect comments just after the block closing if needed + if ($this->eatWhiteDefault) { + $this->whitespace(); + + if ($this->env->comments) { + $this->append(null); + } + } + return true; } // extra stuff - if ($this->literal(';') || - $this->literal('