From 08130773c4feeeff876cd4065d7dbd085e6b7dc5 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Fri, 30 Aug 2013 15:38:40 +0200 Subject: [PATCH] adding vendors see BT#6613 --- composer.json | 5 + vendor/alchemy/binary-driver/.travis.yml | 11 + vendor/alchemy/binary-driver/CHANGELOG.md | 61 + vendor/alchemy/binary-driver/LICENSE | 21 + vendor/alchemy/binary-driver/README.md | 190 +++ vendor/alchemy/binary-driver/composer.json | 38 + vendor/alchemy/binary-driver/phpunit.xml.dist | 31 + .../Alchemy/BinaryDriver/AbstractBinary.php | 220 +++ .../BinaryDriver/BinaryDriverTestCase.php | 76 + .../Alchemy/BinaryDriver/BinaryInterface.php | 66 + .../Alchemy/BinaryDriver/Configuration.php | 107 ++ .../ConfigurationAwareInterface.php | 29 + .../BinaryDriver/ConfigurationInterface.php | 58 + .../Exception/ExceptionInterface.php | 16 + .../Exception/ExecutableNotFoundException.php | 16 + .../Exception/ExecutionFailureException.php | 16 + .../Exception/InvalidArgumentException.php | 16 + .../BinaryDriver/Listeners/DebugListener.php | 58 + .../Listeners/ListenerInterface.php | 32 + .../BinaryDriver/Listeners/Listeners.php | 88 ++ .../BinaryDriver/ProcessBuilderFactory.php | 177 +++ .../ProcessBuilderFactoryAwareInterface.php | 29 + .../ProcessBuilderFactoryInterface.php | 65 + .../Alchemy/BinaryDriver/ProcessRunner.php | 104 ++ .../ProcessRunnerAwareInterface.php | 29 + .../BinaryDriver/ProcessRunnerInterface.php | 33 + .../Tests/BinaryDriver/AbstractBinaryTest.php | 297 ++++ .../AbstractProcessBuilderFactoryTest.php | 97 ++ .../Tests/BinaryDriver/ConfigurationTest.php | 78 + .../LTSProcessBuilderFactoryTest.php | 66 + .../Listeners/DebugListenerTest.php | 33 + .../BinaryDriver/Listeners/ListenersTest.php | 92 ++ .../NONLTSProcessBuilderFactoryTest.php | 15 + .../Tests/BinaryDriver/ProcessRunnerTest.php | 208 +++ .../alchemy/binary-driver/tests/bootstrap.php | 4 + vendor/autoload.php | 7 + vendor/composer/ClassLoader.php | 246 ++++ vendor/composer/autoload_classmap.php | 9 + vendor/composer/autoload_namespaces.php | 16 + vendor/composer/autoload_real.php | 43 + vendor/composer/installed.json | 397 +++++ vendor/doctrine/cache/.travis.yml | 9 + vendor/doctrine/cache/LICENSE | 19 + vendor/doctrine/cache/README.md | 9 + vendor/doctrine/cache/composer.json | 29 + .../lib/Doctrine/Common/Cache/ApcCache.php | 91 ++ .../lib/Doctrine/Common/Cache/ArrayCache.php | 93 ++ .../cache/lib/Doctrine/Common/Cache/Cache.php | 111 ++ .../Doctrine/Common/Cache/CacheProvider.php | 240 +++ .../Doctrine/Common/Cache/CouchbaseCache.php | 121 ++ .../lib/Doctrine/Common/Cache/FileCache.php | 158 ++ .../Doctrine/Common/Cache/FilesystemCache.php | 113 ++ .../Doctrine/Common/Cache/MemcacheCache.php | 121 ++ .../Doctrine/Common/Cache/MemcachedCache.php | 124 ++ .../Doctrine/Common/Cache/PhpFileCache.php | 107 ++ .../lib/Doctrine/Common/Cache/RedisCache.php | 130 ++ .../lib/Doctrine/Common/Cache/RiakCache.php | 250 ++++ .../Doctrine/Common/Cache/WinCacheCache.php | 91 ++ .../lib/Doctrine/Common/Cache/XcacheCache.php | 109 ++ .../Doctrine/Common/Cache/ZendDataCache.php | 83 ++ vendor/doctrine/cache/phpunit.xml.dist | 31 + .../Tests/Common/Cache/ApcCacheTest.php | 20 + .../Tests/Common/Cache/ArrayCacheTest.php | 21 + .../Doctrine/Tests/Common/Cache/CacheTest.php | 103 ++ .../Tests/Common/Cache/CouchbaseCacheTest.php | 47 + .../Tests/Common/Cache/FileCacheTest.php | 107 ++ .../Common/Cache/FilesystemCacheTest.php | 102 ++ .../Tests/Common/Cache/MemcacheCacheTest.php | 45 + .../Tests/Common/Cache/MemcachedCacheTest.php | 48 + .../Tests/Common/Cache/PhpFileCacheTest.php | 154 ++ .../Tests/Common/Cache/RedisCacheTest.php | 30 + .../Tests/Common/Cache/RiakCacheTest.php | 64 + .../Tests/Common/Cache/WinCacheCacheTest.php | 20 + .../Tests/Common/Cache/XcacheCacheTest.php | 20 + .../Tests/Common/Cache/ZendDataCacheTest.php | 28 + .../tests/Doctrine/Tests/DoctrineTestCase.php | 10 + .../cache/tests/Doctrine/Tests/TestInit.php | 23 + vendor/evenement/evenement/.travis.yml | 11 + vendor/evenement/evenement/LICENSE | 19 + vendor/evenement/evenement/README.md | 74 + vendor/evenement/evenement/composer.json | 20 + vendor/evenement/evenement/phpunit.xml.dist | 25 + .../evenement/src/Evenement/EventEmitter.php | 73 + .../evenement/src/Evenement/EventEmitter2.php | 114 ++ .../src/Evenement/EventEmitterInterface.php | 22 + .../Evenement/Tests/EventEmitter2Test.php | 160 ++ .../Evenement/Tests/EventEmitterTest.php | 236 +++ .../tests/Evenement/Tests/Listener.php | 38 + .../evenement/evenement/tests/bootstrap.php | 28 + vendor/monolog/monolog/CHANGELOG.mdown | 110 ++ vendor/monolog/monolog/LICENSE | 19 + vendor/monolog/monolog/README.mdown | 248 ++++ vendor/monolog/monolog/composer.json | 39 + vendor/monolog/monolog/doc/extending.md | 76 + vendor/monolog/monolog/doc/sockets.md | 37 + vendor/monolog/monolog/doc/usage.md | 158 ++ vendor/monolog/monolog/phpunit.xml.dist | 15 + .../monolog/src/Monolog/ErrorHandler.php | 209 +++ .../Monolog/Formatter/ChromePHPFormatter.php | 79 + .../Monolog/Formatter/FormatterInterface.php | 36 + .../Formatter/GelfMessageFormatter.php | 94 ++ .../src/Monolog/Formatter/JsonFormatter.php | 38 + .../src/Monolog/Formatter/LineFormatter.php | 102 ++ .../Monolog/Formatter/LogstashFormatter.php | 98 ++ .../Monolog/Formatter/NormalizerFormatter.php | 137 ++ .../Monolog/Formatter/WildfireFormatter.php | 102 ++ .../src/Monolog/Handler/AbstractHandler.php | 174 +++ .../Handler/AbstractProcessingHandler.php | 66 + .../src/Monolog/Handler/AmqpHandler.php | 69 + .../src/Monolog/Handler/BufferHandler.php | 98 ++ .../src/Monolog/Handler/ChromePHPHandler.php | 183 +++ .../src/Monolog/Handler/CouchDBHandler.php | 72 + .../src/Monolog/Handler/CubeHandler.php | 145 ++ .../Handler/DoctrineCouchDBHandler.php | 45 + .../src/Monolog/Handler/ErrorLogHandler.php | 46 + .../ActivationStrategyInterface.php | 28 + .../ChannelLevelActivationStrategy.php | 57 + .../ErrorLevelActivationStrategy.php | 32 + .../Monolog/Handler/FingersCrossedHandler.php | 118 ++ .../src/Monolog/Handler/FirePHPHandler.php | 184 +++ .../src/Monolog/Handler/GelfHandler.php | 66 + .../src/Monolog/Handler/GroupHandler.php | 80 + .../src/Monolog/Handler/HandlerInterface.php | 88 ++ .../src/Monolog/Handler/HipChatHandler.php | 153 ++ .../src/Monolog/Handler/MailHandler.php | 55 + .../Handler/MissingExtensionException.php | 22 + .../src/Monolog/Handler/MongoDBHandler.php | 55 + .../Monolog/Handler/NativeMailerHandler.php | 68 + .../src/Monolog/Handler/NewRelicHandler.php | 61 + .../src/Monolog/Handler/NullHandler.php | 45 + .../src/Monolog/Handler/PushoverHandler.php | 120 ++ .../src/Monolog/Handler/RavenHandler.php | 167 +++ .../src/Monolog/Handler/RedisHandler.php | 58 + .../Monolog/Handler/RotatingFileHandler.php | 124 ++ .../src/Monolog/Handler/SocketHandler.php | 285 ++++ .../src/Monolog/Handler/StreamHandler.php | 76 + .../Monolog/Handler/SwiftMailerHandler.php | 55 + .../src/Monolog/Handler/SyslogHandler.php | 127 ++ .../src/Monolog/Handler/TestHandler.php | 140 ++ .../Monolog/Handler/ZendMonitorHandler.php | 95 ++ vendor/monolog/monolog/src/Monolog/Logger.php | 574 ++++++++ .../Processor/IntrospectionProcessor.php | 58 + .../Processor/MemoryPeakUsageProcessor.php | 40 + .../src/Monolog/Processor/MemoryProcessor.php | 50 + .../Processor/MemoryUsageProcessor.php | 40 + .../Monolog/Processor/ProcessIdProcessor.php | 40 + .../Processor/PsrLogMessageProcessor.php | 42 + .../src/Monolog/Processor/UidProcessor.php | 38 + .../src/Monolog/Processor/WebProcessor.php | 62 + .../tests/Monolog/ErrorHandlerTest.php | 31 + .../Formatter/ChromePHPFormatterTest.php | 158 ++ .../Formatter/GelfMessageFormatterTest.php | 158 ++ .../Monolog/Formatter/JsonFormatterTest.php | 41 + .../Monolog/Formatter/LineFormatterTest.php | 164 +++ .../Formatter/LogstashFormatterTest.php | 160 ++ .../Formatter/NormalizerFormatterTest.php | 182 +++ .../Formatter/WildfireFormatterTest.php | 111 ++ .../Functional/Handler/FirePHPHandlerTest.php | 32 + .../Monolog/Handler/AbstractHandlerTest.php | 104 ++ .../Handler/AbstractProcessingHandlerTest.php | 79 + .../Monolog/Handler/AmqpExchangeMock.php | 38 + .../tests/Monolog/Handler/AmqpHandlerTest.php | 74 + .../Monolog/Handler/BufferHandlerTest.php | 149 ++ .../Monolog/Handler/ChromePHPHandlerTest.php | 139 ++ .../Monolog/Handler/CouchDBHandlerTest.php | 41 + .../Handler/DoctrineCouchDBHandlerTest.php | 52 + .../Handler/FingersCrossedHandlerTest.php | 189 +++ .../Monolog/Handler/FirePHPHandlerTest.php | 94 ++ .../tests/Monolog/Handler/Fixtures/.gitkeep | 0 .../tests/Monolog/Handler/GelfHandlerTest.php | 94 ++ .../tests/Monolog/Handler/GelfMocks.php | 25 + .../Monolog/Handler/GroupHandlerTest.php | 89 ++ .../Monolog/Handler/HipChatHandlerTest.php | 110 ++ .../tests/Monolog/Handler/MailHandlerTest.php | 75 + .../tests/Monolog/Handler/MockRavenClient.php | 26 + .../Monolog/Handler/MongoDBHandlerTest.php | 63 + .../Handler/NativeMailerHandlerTest.php | 43 + .../Monolog/Handler/NewRelicHandlerTest.php | 65 + .../tests/Monolog/Handler/NullHandlerTest.php | 33 + .../Monolog/Handler/PushoverHandlerTest.php | 142 ++ .../Monolog/Handler/RavenHandlerTest.php | 135 ++ .../Monolog/Handler/RedisHandlerTest.php | 71 + .../Handler/RotatingFileHandlerTest.php | 99 ++ .../Monolog/Handler/SocketHandlerTest.php | 283 ++++ .../Monolog/Handler/StreamHandlerTest.php | 88 ++ .../Monolog/Handler/SyslogHandlerTest.php | 43 + .../tests/Monolog/Handler/TestHandlerTest.php | 56 + .../Handler/ZendMonitorHandlerTest.php | 69 + .../monolog/tests/Monolog/LoggerTest.php | 409 ++++++ .../Processor/IntrospectionProcessorTest.php | 65 + .../MemoryPeakUsageProcessorTest.php | 29 + .../Processor/MemoryUsageProcessorTest.php | 29 + .../Processor/ProcessIdProcessorTest.php | 30 + .../Monolog/Processor/UidProcessorTest.php | 27 + .../Monolog/Processor/WebProcessorTest.php | 68 + .../tests/Monolog/PsrLogCompatTest.php | 47 + .../monolog/tests/Monolog/TestCase.php | 58 + vendor/monolog/monolog/tests/bootstrap.php | 13 + vendor/php-ffmpeg/php-ffmpeg | 1 + vendor/psr/log/LICENSE | 19 + vendor/psr/log/Psr/Log/AbstractLogger.php | 120 ++ .../log/Psr/Log/InvalidArgumentException.php | 7 + vendor/psr/log/Psr/Log/LogLevel.php | 18 + .../psr/log/Psr/Log/LoggerAwareInterface.php | 17 + vendor/psr/log/Psr/Log/LoggerAwareTrait.php | 22 + vendor/psr/log/Psr/Log/LoggerInterface.php | 114 ++ vendor/psr/log/Psr/Log/LoggerTrait.php | 131 ++ vendor/psr/log/Psr/Log/NullLogger.php | 27 + .../log/Psr/Log/Test/LoggerInterfaceTest.php | 116 ++ vendor/psr/log/README.md | 45 + vendor/psr/log/composer.json | 17 + .../Symfony/Component/Process/CHANGELOG.md | 26 + .../Process/Exception/ExceptionInterface.php | 21 + .../Exception/InvalidArgumentException.php | 21 + .../Process/Exception/LogicException.php | 21 + .../Exception/ProcessFailedException.php | 49 + .../Process/Exception/RuntimeException.php | 21 + .../Component/Process/ExecutableFinder.php | 90 ++ .../process/Symfony/Component/Process/LICENSE | 19 + .../Component/Process/PhpExecutableFinder.php | 62 + .../Symfony/Component/Process/PhpProcess.php | 73 + .../Symfony/Component/Process/Process.php | 1291 +++++++++++++++++ .../Component/Process/ProcessBuilder.php | 174 +++ .../Component/Process/ProcessUtils.php | 64 + .../Symfony/Component/Process/README.md | 47 + .../Process/Tests/AbstractProcessTest.php | 641 ++++++++ .../Process/Tests/NonStopableProcess.php | 37 + .../Process/Tests/PhpExecutableFinderTest.php | 64 + .../Process/Tests/PhpProcessTest.php | 29 + .../Process/Tests/ProcessBuilderTest.php | 200 +++ .../Tests/ProcessFailedExceptionTest.php | 83 ++ .../Tests/ProcessInSigchildEnvironment.php | 22 + .../Process/Tests/ProcessTestHelper.php | 63 + .../Process/Tests/ProcessUtilsTest.php | 44 + .../Tests/SigchildDisabledProcessTest.php | 188 +++ .../Tests/SigchildEnabledProcessTest.php | 116 ++ .../Process/Tests/SignalListener.php | 16 + .../Process/Tests/SimpleProcessTest.php | 147 ++ .../Symfony/Component/Process/composer.json | 31 + .../Component/Process/phpunit.xml.dist | 28 + 240 files changed, 21421 insertions(+) create mode 100644 composer.json create mode 100644 vendor/alchemy/binary-driver/.travis.yml create mode 100644 vendor/alchemy/binary-driver/CHANGELOG.md create mode 100644 vendor/alchemy/binary-driver/LICENSE create mode 100644 vendor/alchemy/binary-driver/README.md create mode 100644 vendor/alchemy/binary-driver/composer.json create mode 100644 vendor/alchemy/binary-driver/phpunit.xml.dist create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/AbstractBinary.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/BinaryDriverTestCase.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/BinaryInterface.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Configuration.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ConfigurationAwareInterface.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ConfigurationInterface.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExceptionInterface.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExecutableNotFoundException.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExecutionFailureException.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/InvalidArgumentException.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/DebugListener.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/ListenerInterface.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/Listeners.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactory.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactoryAwareInterface.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactoryInterface.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunner.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunnerAwareInterface.php create mode 100644 vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunnerInterface.php create mode 100644 vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/AbstractBinaryTest.php create mode 100644 vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/AbstractProcessBuilderFactoryTest.php create mode 100644 vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/ConfigurationTest.php create mode 100644 vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/LTSProcessBuilderFactoryTest.php create mode 100644 vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/Listeners/DebugListenerTest.php create mode 100644 vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/Listeners/ListenersTest.php create mode 100644 vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/NONLTSProcessBuilderFactoryTest.php create mode 100644 vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/ProcessRunnerTest.php create mode 100644 vendor/alchemy/binary-driver/tests/bootstrap.php create mode 100644 vendor/autoload.php create mode 100644 vendor/composer/ClassLoader.php create mode 100644 vendor/composer/autoload_classmap.php create mode 100644 vendor/composer/autoload_namespaces.php create mode 100644 vendor/composer/autoload_real.php create mode 100644 vendor/composer/installed.json create mode 100644 vendor/doctrine/cache/.travis.yml create mode 100644 vendor/doctrine/cache/LICENSE create mode 100644 vendor/doctrine/cache/README.md create mode 100644 vendor/doctrine/cache/composer.json create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/ArrayCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/CouchbaseCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/FileCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/FilesystemCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcacheCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcachedCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/PhpFileCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/RedisCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/WinCacheCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/XcacheCache.php create mode 100644 vendor/doctrine/cache/lib/Doctrine/Common/Cache/ZendDataCache.php create mode 100644 vendor/doctrine/cache/phpunit.xml.dist create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ApcCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CouchbaseCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FileCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RiakCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/XcacheCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ZendDataCacheTest.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/DoctrineTestCase.php create mode 100644 vendor/doctrine/cache/tests/Doctrine/Tests/TestInit.php create mode 100644 vendor/evenement/evenement/.travis.yml create mode 100644 vendor/evenement/evenement/LICENSE create mode 100644 vendor/evenement/evenement/README.md create mode 100644 vendor/evenement/evenement/composer.json create mode 100644 vendor/evenement/evenement/phpunit.xml.dist create mode 100644 vendor/evenement/evenement/src/Evenement/EventEmitter.php create mode 100644 vendor/evenement/evenement/src/Evenement/EventEmitter2.php create mode 100644 vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php create mode 100644 vendor/evenement/evenement/tests/Evenement/Tests/EventEmitter2Test.php create mode 100644 vendor/evenement/evenement/tests/Evenement/Tests/EventEmitterTest.php create mode 100644 vendor/evenement/evenement/tests/Evenement/Tests/Listener.php create mode 100644 vendor/evenement/evenement/tests/bootstrap.php create mode 100644 vendor/monolog/monolog/CHANGELOG.mdown create mode 100644 vendor/monolog/monolog/LICENSE create mode 100644 vendor/monolog/monolog/README.mdown create mode 100644 vendor/monolog/monolog/composer.json create mode 100644 vendor/monolog/monolog/doc/extending.md create mode 100644 vendor/monolog/monolog/doc/sockets.md create mode 100644 vendor/monolog/monolog/doc/usage.md create mode 100644 vendor/monolog/monolog/phpunit.xml.dist create mode 100644 vendor/monolog/monolog/src/Monolog/ErrorHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php create mode 100644 vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php create mode 100644 vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php create mode 100644 vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php create mode 100644 vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php create mode 100644 vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php create mode 100644 vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php create mode 100644 vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php create mode 100644 vendor/monolog/monolog/src/Monolog/Logger.php create mode 100644 vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php create mode 100644 vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php create mode 100644 vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php create mode 100644 vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php create mode 100644 vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php create mode 100644 vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php create mode 100644 vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php create mode 100644 vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php create mode 100644 vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Functional/Handler/FirePHPHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/AmqpExchangeMock.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/Fixtures/.gitkeep create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/GelfMocks.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/LoggerTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php create mode 100644 vendor/monolog/monolog/tests/Monolog/TestCase.php create mode 100644 vendor/monolog/monolog/tests/bootstrap.php create mode 160000 vendor/php-ffmpeg/php-ffmpeg create mode 100644 vendor/psr/log/LICENSE create mode 100644 vendor/psr/log/Psr/Log/AbstractLogger.php create mode 100644 vendor/psr/log/Psr/Log/InvalidArgumentException.php create mode 100644 vendor/psr/log/Psr/Log/LogLevel.php create mode 100644 vendor/psr/log/Psr/Log/LoggerAwareInterface.php create mode 100644 vendor/psr/log/Psr/Log/LoggerAwareTrait.php create mode 100644 vendor/psr/log/Psr/Log/LoggerInterface.php create mode 100644 vendor/psr/log/Psr/Log/LoggerTrait.php create mode 100644 vendor/psr/log/Psr/Log/NullLogger.php create mode 100644 vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php create mode 100644 vendor/psr/log/README.md create mode 100644 vendor/psr/log/composer.json create mode 100644 vendor/symfony/process/Symfony/Component/Process/CHANGELOG.md create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/ExceptionInterface.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/InvalidArgumentException.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/LogicException.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/ProcessFailedException.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Exception/RuntimeException.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/ExecutableFinder.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/LICENSE create mode 100644 vendor/symfony/process/Symfony/Component/Process/PhpExecutableFinder.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/PhpProcess.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Process.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/ProcessBuilder.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/ProcessUtils.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/README.md create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/AbstractProcessTest.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/NonStopableProcess.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/PhpProcessTest.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/ProcessBuilderTest.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/ProcessFailedExceptionTest.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/ProcessTestHelper.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/ProcessUtilsTest.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/SignalListener.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/Tests/SimpleProcessTest.php create mode 100644 vendor/symfony/process/Symfony/Component/Process/composer.json create mode 100644 vendor/symfony/process/Symfony/Component/Process/phpunit.xml.dist diff --git a/composer.json b/composer.json new file mode 100644 index 0000000000..b9f18bab03 --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php-ffmpeg/php-ffmpeg": "0.3.x-dev@dev" + } +} diff --git a/vendor/alchemy/binary-driver/.travis.yml b/vendor/alchemy/binary-driver/.travis.yml new file mode 100644 index 0000000000..beea6866e6 --- /dev/null +++ b/vendor/alchemy/binary-driver/.travis.yml @@ -0,0 +1,11 @@ +language: php + +before_script: + - composer self-update + - composer install --dev --prefer-source + +php: + - 5.3.3 + - 5.3 + - 5.4 + - 5.5 diff --git a/vendor/alchemy/binary-driver/CHANGELOG.md b/vendor/alchemy/binary-driver/CHANGELOG.md new file mode 100644 index 0000000000..621ed80e84 --- /dev/null +++ b/vendor/alchemy/binary-driver/CHANGELOG.md @@ -0,0 +1,61 @@ +CHANGELOG +--------- + +* 1.5.0 (2013-06-21) + + * BC Break : ConfigurationInterface::get does not throw exceptions anymore + in case the key does not exist. Second argument is a default value to return + in case the key does not exist. + +* 1.4.1 (2013-05-23) + + * Add third parameter to BinaryInterface::command method to pass a listener or + an array of listener that will be registered just the time of the command. + +* 1.4.0 (2013-05-11) + + * Extract process run management to ProcessRunner. + * Add support for process listeners. + * Provides bundled DebugListener. + * Add BinaryInterface::command method. + * BC break : ProcessRunnerInterface::run now takes an SplObjectStorage containing + listeners as second argument. + * BC break : BinaryInterface no longer implements LoggerAwareInterface + as it is now supported by ProcessRunner. + +* 1.3.4 (2013-04-26) + + * Add BinaryDriver::run method. + +* 1.3.3 (2013-04-26) + + * Add BinaryDriver::createProcessMock method. + +* 1.3.2 (2013-04-26) + + * Add BinaryDriverTestCase for testing BinaryDriver implementations. + +* 1.3.1 (2013-04-24) + + * Add timeouts handling + +* 1.3.0 (2013-04-24) + + * Add BinaryInterface and AbstractBinary + +* 1.2.1 (2013-04-24) + + * Add ConfigurationAwareInterface + * Add ProcessBuilderAwareInterface + +* 1.2.0 (2013-04-24) + + * Add BinaryDriver\Configuration + +* 1.1.0 (2013-04-24) + + * Add support for timeouts via `setTimeout` method + +* 1.0.0 (2013-04-23) + + * First stable version. diff --git a/vendor/alchemy/binary-driver/LICENSE b/vendor/alchemy/binary-driver/LICENSE new file mode 100644 index 0000000000..e7bb314c25 --- /dev/null +++ b/vendor/alchemy/binary-driver/LICENSE @@ -0,0 +1,21 @@ +BinaryDriver is released with MIT License : + +Copyright (c) 2013 Alchemy + +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/alchemy/binary-driver/README.md b/vendor/alchemy/binary-driver/README.md new file mode 100644 index 0000000000..05b3a137f0 --- /dev/null +++ b/vendor/alchemy/binary-driver/README.md @@ -0,0 +1,190 @@ +# Binary Driver + +Binary-Driver is a set of PHP tools to build binary drivers. + +[![Build Status](https://travis-ci.org/alchemy-fr/BinaryDriver.png?branch=master)](https://travis-ci.org/alchemy-fr/BinaryDriver) + +## Why ? + +You may wonder *Why building a library while I can use `exec` or +[symfony/process](https://github.com/symfony/Process) ?*. + +Here is a simple answer : + + - If you use `exec`, `passthru`, `system`, `proc_open` or any low level process + handling in PHP, you should have a look to [symfony/process](https://github.com/symfony/Process) + component that will provide an OO portable, testable and secure interface to + deal with this. It seems easy at first approach, but if you look at this + component [unit tests](https://github.com/symfony/Process/tree/master/Tests), + you will see that handling process in a simple interface can easily become a + nightmare. + + - If you already use symfony/process, and want to build binary drivers, you + will always have the same common set of methods and objects to configure, log, + debug, and generate processes. + This library is a base to implement any binary driver with this common set of + needs. + +## AbstractBinary + +`AbstractBinary` provides an abstract class to build a binary driver. It implements +`BinaryInterface`. + +Implementation example : + +```php +use Alchemy\BinaryDriver\AbstractBinary; + +class LsDriver extends AbstractBinary +{ + public function getName() + { + return 'ls driver'; + } +} + +$parser = new LsParser(); + +$driver = Driver::load('ls'); +// will return the output of `ls -a -l` +$parser->parse($driver->command(array('-a', '-l'))); +``` + +### Binary detection troubleshooting + +If you are using Nginx with PHP-fpm, executable detection may not work because of an empty `$_ENV['path']`. +To avoid having an empty `PATH` environment variable, add the following line to your `fastcgi_params` +config file (replace `/your/current/path/` with the output of `printenv PATH`) : + +``` +fastcgi_param PATH /your/current/path +``` + +## Logging + +You can log events with a `Psr\Log\LoggerInterface` by passing it in the load +method as second argument : + +```php +$logger = new Monolog\Logger('driver'); +$driver = Driver::load('ls', $logger); +``` + +## Listeners + +You can add custom listeners on processes. +Listeners are built on top of [Evenement](https://github.com/igorw/evenement) +and must implement `Alchemy\BinaryDriver\ListenerInterface`. + +```php +use Symfony\Component\Process\Process; + +class DebugListener extends EventEmitter implements ListenerInterface +{ + public function handle($type, $data) + { + foreach (explode(PHP_EOL, $data) as $line) { + $this->emit($type === Process::ERR ? 'error' : 'out', array($line)); + } + } + + public function forwardedEvents() + { + // forward 'error' events to the BinaryInterface + return array('error'); + } +} + +$listener = new DebugListener(); + +$driver = CustomImplementation::load('php'); + +// adds listener +$driver->listen($listener); + +$driver->on('error', function ($line) { + echo '[ERROR] ' . $line . PHP_EOL; +}); + +// removes listener +$driver->unlisten($listener); +``` + +### Bundled listeners + +The debug listener is a simple listener to catch `stderr` and `stdout` outputs ; +read the implementation for customization. + +```php +use Alchemy\BinaryDriver\Listeners\DebugListener; + +$driver = CustomImplementation::load('php'); +$driver->listen(new DebugListener()); + +$driver->on('debug', function ($line) { + echo $line; +}); +``` + +## ProcessBuilderFactory + +ProcessBuilderFactory ease spawning processes by generating Symfony [Process] +(http://symfony.com/doc/master/components/process.html) objects. + +```php +use Alchemy\BinaryDriver\ProcessBuilderFactory; + +$factory = new ProcessBuilderFactory('/usr/bin/php'); + +// return a Symfony\Component\Process\Process +$process = $factory->create('-v'); + +// echoes '/usr/bin/php' '-v' +echo $process->getCommandLine(); + +$process = $factory->create(array('-r', 'echo "Hello !";')); + +// echoes '/usr/bin/php' '-r' 'echo "Hello !";' +echo $process->getCommandLine(); +``` + +## Configuration + +A simple configuration object, providing an `ArrayAccess` and `IteratorAggregate` +interface. + +```php +use Alchemy\BinaryDriver\Configuration; + +$conf = new Configuration(array('timeout' => 0)); + +echo $conf->get('timeout'); + +if ($conf->has('param')) { + $conf->remove('param'); +} + +$conf->set('timeout', 20); + +$conf->all(); +``` + +Same example using the `ArrayAccess` interface : + +```php +use Alchemy\BinaryDriver\Configuration; + +$conf = new Configuration(array('timeout' => 0)); + +echo $conf['timeout']; + +if (isset($conf['param'])) { + unset($conf['param']); +} + +$conf['timeout'] = 20; +``` + +## License + +This project is released under the MIT license. diff --git a/vendor/alchemy/binary-driver/composer.json b/vendor/alchemy/binary-driver/composer.json new file mode 100644 index 0000000000..8aa5ce4404 --- /dev/null +++ b/vendor/alchemy/binary-driver/composer.json @@ -0,0 +1,38 @@ +{ + "name": "alchemy/binary-driver", + "type": "library", + "description": "A set of tools to build binary drivers", + "keywords": ["binary", "driver"], + "license": "MIT", + "authors": [ + { + "name": "Nicolas Le Goff", + "email": "legoff.n@gmail.com" + }, + { + "name": "Romain Neutron", + "email": "imprec@gmail.com", + "homepage": "http://www.lickmychip.com/" + }, + { + "name": "Phraseanet Team", + "email": "info@alchemy.fr", + "homepage": "http://www.phraseanet.com/" + } + ], + "require": { + "php" : ">=5.3.3", + "evenement/evenement" : "~1.0", + "monolog/monolog" : "~1.3", + "psr/log" : "~1.0", + "symfony/process" : "~2.0" + }, + "require-dev": { + "phpunit/phpunit" : "~3.7" + }, + "autoload": { + "psr-0": { + "Alchemy": "src" + } + } +} diff --git a/vendor/alchemy/binary-driver/phpunit.xml.dist b/vendor/alchemy/binary-driver/phpunit.xml.dist new file mode 100644 index 0000000000..0c043a9100 --- /dev/null +++ b/vendor/alchemy/binary-driver/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + tests + + + + + vendor + tests + + + + + diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/AbstractBinary.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/AbstractBinary.php new file mode 100644 index 0000000000..ee8f8dff15 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/AbstractBinary.php @@ -0,0 +1,220 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException; +use Alchemy\BinaryDriver\Exception\ExecutionFailureException; +use Alchemy\BinaryDriver\Listeners\Listeners; +use Alchemy\BinaryDriver\Listeners\ListenerInterface; +use Evenement\EventEmitter; +use Monolog\Logger; +use Monolog\Handler\NullHandler; +use Psr\Log\LoggerInterface; +use Symfony\Component\Process\ExecutableFinder; +use Symfony\Component\Process\Process; + +abstract class AbstractBinary extends EventEmitter implements BinaryInterface +{ + /** @var ConfigurationInterface */ + protected $configuration; + + /** @var ProcessBuilderFactoryInterface */ + protected $factory; + + /** @var ProcessRunner */ + private $processRunner; + + /** @var Listeners */ + private $listenersManager; + + public function __construct(ProcessBuilderFactoryInterface $factory, LoggerInterface $logger, ConfigurationInterface $configuration) + { + $this->factory = $factory; + $this->configuration = $configuration; + $this->processRunner = new ProcessRunner($logger, $this->getName()); + $this->listenersManager = new Listeners(); + $this->applyProcessConfiguration(); + } + + /** + * {@inheritdoc} + */ + public function listen(ListenerInterface $listener) + { + $this->listenersManager->register($listener, $this); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function unlisten(ListenerInterface $listener) + { + $this->listenersManager->unregister($listener, $this); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getConfiguration() + { + return $this->configuration; + } + + /** + * {@inheritdoc} + * + * @return BinaryInterface + */ + public function setConfiguration(ConfigurationInterface $configuration) + { + $this->configuration = $configuration; + $this->applyProcessConfiguration(); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getProcessBuilderFactory() + { + return $this->factory; + } + + /** + * {@inheritdoc} + * + * @return BinaryInterface + */ + public function setProcessBuilderFactory(ProcessBuilderFactoryInterface $factory) + { + $this->factory = $factory; + $this->applyProcessConfiguration(); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getProcessRunner() + { + return $this->processRunner; + } + + /** + * {@inheritdoc} + */ + public function setProcessRunner(ProcessRunnerInterface $runner) + { + $this->processRunner = $runner; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function command($command, $bypassErrors = false, $listeners = null) + { + if (!is_array($command)) { + $command = array($command); + } + + return $this->run($this->factory->create($command), $bypassErrors, $listeners); + } + + /** + * {@inheritdoc} + */ + public static function load($binaries, LoggerInterface $logger = null, $configuration = array()) + { + $finder = new ExecutableFinder(); + $binary = null; + $binaries = is_array($binaries) ? $binaries : array($binaries); + + foreach ($binaries as $candidate) { + if (file_exists($candidate) && is_executable($candidate)) { + $binary = $candidate; + break; + } + if (null !== $binary = $finder->find($candidate)) { + break; + } + } + + if (null === $binary) { + throw new ExecutableNotFoundException(sprintf( + 'Executable not found, proposed : %s', implode(', ', $binaries) + )); + } + + if (null === $logger) { + $logger = new Logger(__NAMESPACE__ . ' logger'); + $logger->pushHandler(new NullHandler()); + } + + $configuration = $configuration instanceof ConfigurationInterface ? $configuration : new Configuration($configuration); + + return new static(new ProcessBuilderFactory($binary), $logger, $configuration); + } + + /** + * Returns the name of the driver + * + * @return string + */ + abstract public function getName(); + + /** + * Executes a process, logs events + * + * @param Process $process + * @param Boolean $bypassErrors Set to true to disable throwing ExecutionFailureExceptions + * @param ListenerInterface|array $listeners A listener or an array of listener to register for this unique run + * + * @return string The Process output + * + * @throws ExecutionFailureException in case of process failure. + */ + protected function run(Process $process, $bypassErrors = false, $listeners = null) + { + if (null !== $listeners) { + if (!is_array($listeners)) { + $listeners = array($listeners); + } + + $listenersManager = clone $this->listenersManager; + + foreach ($listeners as $listener) { + $listenersManager->register($listener, $this); + } + } else { + $listenersManager = $this->listenersManager; + } + + return $this->processRunner->run($process, $listenersManager->storage, $bypassErrors); + } + + private function applyProcessConfiguration() + { + if ($this->configuration->has('timeout')) { + $this->factory->setTimeout($this->configuration->get('timeout')); + } + + return $this; + } +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/BinaryDriverTestCase.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/BinaryDriverTestCase.php new file mode 100644 index 0000000000..3d0463dc04 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/BinaryDriverTestCase.php @@ -0,0 +1,76 @@ +getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface'); + } + + /** + * @param integer $runs The number of runs expected + * @param Boolean $success True if the process expects to be successfull + * @param string $commandLine The commandline executed + * @param string $output The process output + * @param string $error The process error output + * + * @return Process + */ + public function createProcessMock($runs = 1, $success = true, $commandLine = null, $output = null, $error = null, $callback = false) + { + $process = $this->getMockBuilder('Symfony\Component\Process\Process') + ->disableOriginalConstructor() + ->getMock(); + + $builder = $process->expects($this->exactly($runs)) + ->method('run'); + + if (true === $callback) { + $builder->with($this->isInstanceOf('Closure')); + } + + $process->expects($this->any()) + ->method('isSuccessful') + ->will($this->returnValue($success)); + + foreach (array( + 'getOutput' => $output, + 'getErrorOutput' => $error, + 'getCommandLine' => $commandLine, + ) as $command => $value) { + $process + ->expects($this->any()) + ->method($command) + ->will($this->returnValue($value)); + } + + return $process; + } + + /** + * @return LoggerInterface + */ + public function createLoggerMock() + { + return $this->getMock('Psr\Log\LoggerInterface'); + } + + /** + * @return ConfigurationInterface + */ + public function createConfigurationMock() + { + return $this->getMock('Alchemy\BinaryDriver\ConfigurationInterface'); + } +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/BinaryInterface.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/BinaryInterface.php new file mode 100644 index 0000000000..c75cb0c678 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/BinaryInterface.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +use Alchemy\BinaryDriver\Exception\ExecutableNotFoundException; +use Alchemy\BinaryDriver\Listeners\ListenerInterface; +use Psr\Log\LoggerInterface; +use Evenement\EventEmitterInterface; + +interface BinaryInterface extends ConfigurationAwareInterface, ProcessBuilderFactoryAwareInterface, ProcessRunnerAwareInterface, EventEmitterInterface +{ + /** + * Adds a listener to the binary driver + * + * @param ListenerInterface $listener + * + * @return BinaryInterface + */ + public function listen(ListenerInterface $listener); + + /** + * Removes a listener from the binary driver + * + * @param ListenerInterface $listener + * + * @return BinaryInterface + */ + public function unlisten(ListenerInterface $listener); + + /** + * Runs a command against the driver. + * + * Calling this method on a `ls` driver with the command `-a` would run `ls -a`. + * + * @param array|string $command A command or an array of command + * @param Boolean $bypassErrors If set to true, an erronous process will not throw an exception + * @param ListenerInterface|array $listeners A listener or an array of listeners to register for this unique run + * + * @return string The command output + * + * @throws ExecutionFailureException in case of process failure. + */ + public function command($command, $bypassErrors = false, $listeners = null); + + /** + * Loads a binary + * + * @param string|array $binaries A binary name or an array of binary names + * @param null||LoggerInterface $logger A Logger + * @param array|ConfigurationInterface $configuration The configuration + * + * @throws ExecutableNotFoundException In case none of the binaries were found + * + * @return BinaryInterface + */ + public static function load($binaries, LoggerInterface $logger = null, $configuration = array()); +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Configuration.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Configuration.php new file mode 100644 index 0000000000..cd0ebbb482 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Configuration.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +class Configuration implements ConfigurationInterface +{ + private $data; + + public function __construct(array $data = array()) + { + $this->data = $data; + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + return new \ArrayIterator($this->data); + } + + /** + * {@inheritdoc} + */ + public function get($key, $default = null) + { + return isset($this->data[$key]) ? $this->data[$key] : $default; + } + + /** + * {@inheritdoc} + */ + public function set($key, $value) + { + $this->data[$key] = $value; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function has($key) + { + return array_key_exists($key, $this->data); + } + + /** + * {@inheritdoc} + */ + public function remove($key) + { + $value = $this->get($key); + unset($this->data[$key]); + + return $value; + } + + /** + * {@inheritdoc} + */ + public function all() + { + return $this->data; + } + + /** + * {@inheritdoc} + */ + public function offsetExists($offset) + { + return $this->has($offset); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($offset) + { + return $this->get($offset); + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + $this->set($offset, $value); + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + $this->remove($offset); + } +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ConfigurationAwareInterface.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ConfigurationAwareInterface.php new file mode 100644 index 0000000000..3b14f9e356 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ConfigurationAwareInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +interface ConfigurationAwareInterface +{ + /** + * Returns the configuration + * + * @return ConfigurationInterface + */ + public function getConfiguration(); + + /** + * Set the configuration + * + * @param ConfigurationInterface $configuration + */ + public function setConfiguration(ConfigurationInterface $configuration); +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ConfigurationInterface.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ConfigurationInterface.php new file mode 100644 index 0000000000..71bcb885ac --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ConfigurationInterface.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +interface ConfigurationInterface extends \ArrayAccess, \IteratorAggregate +{ + /** + * Returns the value given a key from configuration + * + * @param string $key + * @param mixed $default The default value in case the key does not exist + * + * @return mixed + */ + public function get($key, $default = null); + + /** + * Set a value to configuration + * + * @param string $key The key + * @param mixed $value The value corresponding to the key + */ + public function set($key, $value); + + /** + * Tells if Configuration contains `$key` + * + * @param string $key + * + * @return Boolean + */ + public function has($key); + + /** + * Removes a value given a key + * + * @param string $key + * + * @return mixed The previous value + */ + public function remove($key); + + /** + * Returns all values set in the configuration + * + * @return array + */ + public function all(); +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExceptionInterface.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExceptionInterface.php new file mode 100644 index 0000000000..aaa1e321e9 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExceptionInterface.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver\Exception; + +interface ExceptionInterface +{ +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExecutableNotFoundException.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExecutableNotFoundException.php new file mode 100644 index 0000000000..6f267ea258 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExecutableNotFoundException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver\Exception; + +class ExecutableNotFoundException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExecutionFailureException.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExecutionFailureException.php new file mode 100644 index 0000000000..c25af9751d --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/ExecutionFailureException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver\Exception; + +class ExecutionFailureException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/InvalidArgumentException.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000..4e9cfe4b3d --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Exception/InvalidArgumentException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver\Exception; + +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/DebugListener.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/DebugListener.php new file mode 100644 index 0000000000..20773b03b7 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/DebugListener.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver\Listeners; + +use Evenement\EventEmitter; +use Symfony\Component\Process\Process; + +class DebugListener extends EventEmitter implements ListenerInterface +{ + private $prefixOut; + private $prefixErr; + private $eventOut; + private $eventErr; + + public function __construct($prefixOut = '[OUT] ', $prefixErr = '[ERROR] ', $eventOut = 'debug', $eventErr = 'debug') + { + $this->prefixOut = $prefixOut; + $this->prefixErr = $prefixErr; + $this->eventOut = $eventOut; + $this->eventErr = $eventErr; + } + + /** + * {@inheritdoc} + */ + public function handle($type, $data) + { + if (Process::ERR === $type) { + $this->emitLines($this->eventErr, $this->prefixErr, $data); + } elseif (Process::OUT === $type) { + $this->emitLines($this->eventOut, $this->prefixOut, $data); + } + } + + /** + * {@inheritdoc} + */ + public function forwardedEvents() + { + return array_unique(array($this->eventErr, $this->eventOut)); + } + + private function emitLines($event, $prefix, $lines) + { + foreach (explode("\n", $lines) as $line) { + $this->emit($event, array($prefix . $line)); + } + } +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/ListenerInterface.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/ListenerInterface.php new file mode 100644 index 0000000000..920a6d5790 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/ListenerInterface.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver\Listeners; + +use Evenement\EventEmitterInterface; + +interface ListenerInterface extends EventEmitterInterface +{ + /** + * Handle the output of a ProcessRunner + * + * @param string $type The data type, one of Process::ERR, Process::OUT constants + * @param string $data The output + */ + public function handle($type, $data); + + /** + * An array of events that should be forwarded to BinaryInterface + * + * @return array + */ + public function forwardedEvents(); +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/Listeners.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/Listeners.php new file mode 100644 index 0000000000..afb7549c02 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/Listeners/Listeners.php @@ -0,0 +1,88 @@ +storage = new SplObjectStorage(); + } + + public function __clone() + { + $storage = $this->storage; + $this->storage = new SplObjectStorage(); + $this->storage->addAll($storage); + } + + /** + * Registers a listener, pass the listener events to the target. + * + * @param ListenerInterface $listener + * @param null|EventEmitter $target + * + * @return ListenersInterface + */ + public function register(ListenerInterface $listener, EventEmitter $target = null) + { + $EElisteners = array(); + + if (null !== $target) { + $EElisteners = $this->forwardEvents($listener, $target, $listener->forwardedEvents()); + } + + $this->storage->attach($listener, $EElisteners); + + return $this; + } + + /** + * Unregisters a listener, removes the listener events from the target. + * + * @param ListenerInterface $listener + * + * @return ListenersInterface + * + * @throws InvalidArgumentException In case the listener is not registered + */ + public function unregister(ListenerInterface $listener) + { + if (!isset($this->storage[$listener])) { + throw new InvalidArgumentException('Listener is not registered.'); + } + + foreach ($this->storage[$listener] as $event => $EElistener) { + $listener->removeListener($event, $EElistener); + } + + $this->storage->detach($listener); + + return $this; + } + + private function forwardEvents($source, $target, array $events) + { + $EElisteners = array(); + + foreach ($events as $event) { + $listener = $this->createListener($event, $target); + $source->on($event, $EElisteners[$event] = $listener); + } + + return $EElisteners; + } + + private function createListener($event, $target) + { + return function () use ($event, $target) { + $target->emit($event, func_get_args()); + }; + } +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactory.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactory.php new file mode 100644 index 0000000000..9f01eebdaf --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactory.php @@ -0,0 +1,177 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +use Alchemy\BinaryDriver\Exception\InvalidArgumentException; +use Symfony\Component\Process\ProcessBuilder; + +class ProcessBuilderFactory implements ProcessBuilderFactoryInterface +{ + /** + * The binary path + * + * @var String + */ + protected $binary; + + /** + * The timeout for the generated processes + * + * @var integer|float + */ + private $timeout; + + /** + * An internal ProcessBuilder. + * + * Note that this one is used only if Symfony ProcessBuilder has method + * setPrefix (2.3) + * + * @var ProcessBuilder + */ + private $builder; + + /** + * Tells whether Symfony LTS ProcessBuilder should be emulated or not. + * + * This symfony version provided a brand new ::setPrefix method. + * + * @var Boolean + */ + public static $emulateSfLTS; + + /** + * Constructor + * + * @param String $binary The path to the binary + * + * @throws InvalidArgumentException In case binary path is invalid + */ + public function __construct($binary) + { + $this->detectEmulation(); + + if (!self::$emulateSfLTS) { + $this->builder = new ProcessBuilder(); + } + + $this->useBinary($binary); + } + + /** + * Covenient method for unit testing + * + * @return type + */ + public function getBuilder() + { + return $this->builder; + } + + /** + * Covenient method for unit testing + * + * @param ProcessBuilder $builder + * @return ProcessBuilderFactory + */ + public function setBuilder(ProcessBuilder $builder) + { + $this->builder = $builder; + + return $this; + } + + /** + * @inheritdoc + */ + public function getBinary() + { + return $this->binary; + } + + /** + * @inheritdoc + */ + public function useBinary($binary) + { + if (!is_executable($binary)) { + throw new InvalidArgumentException(sprintf('`%s` is not an executable binary', $binary)); + } + + $this->binary = $binary; + + if (!static::$emulateSfLTS) { + $this->builder->setPrefix($binary); + } + + return $this; + } + + /** + * @inheritdoc + */ + public function setTimeout($timeout) + { + $this->timeout = $timeout; + + if (!static::$emulateSfLTS) { + $this->builder->setTimeout($this->timeout); + } + + return $this; + } + + /** + * @inheritdoc + */ + public function getTimeout() + { + return $this->timeout; + } + + /** + * @inheritdoc + */ + public function create($arguments = array()) + { + if (null === $this->binary) { + throw new InvalidArgumentException('No binary set'); + } + + if (!is_array($arguments)) { + $arguments = array($arguments); + } + + if (static::$emulateSfLTS) { + array_unshift($arguments, $this->binary); + + return ProcessBuilder::create($arguments) + ->setTimeout($this->timeout) + ->getProcess(); + } else { + return $this->builder + ->setArguments($arguments) + ->getProcess(); + } + } + + private function detectEmulation() + { + if (null !== static::$emulateSfLTS) { + return $this; + } + + static::$emulateSfLTS = !method_exists('Symfony\Component\Process\ProcessBuilder', 'setPrefix'); + + return $this; + } +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactoryAwareInterface.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactoryAwareInterface.php new file mode 100644 index 0000000000..1398bb4e6e --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactoryAwareInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +interface ProcessBuilderFactoryAwareInterface +{ + /** + * Returns the current process builder factory + * + * @return ProcessBuilderFactoryInterface + */ + public function getProcessBuilderFactory(); + + /** + * Set a process builder factory + * + * @param ProcessBuilderFactoryInterface $factory + */ + public function setProcessBuilderFactory(ProcessBuilderFactoryInterface $factory); +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactoryInterface.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactoryInterface.php new file mode 100644 index 0000000000..05a22960f2 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessBuilderFactoryInterface.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +use Alchemy\BinaryDriver\Exception\InvalidArgumentException; +use Symfony\Component\Process\Process; + +interface ProcessBuilderFactoryInterface +{ + /** + * Returns a new instance of Symfony Process + * + * @param string|array $arguments An argument or an array of arguments + * + * @return Process + * + * @throws InvalidArgumentException + */ + public function create($arguments = array()); + + /** + * Returns the path to the binary that is used + * + * @return String + */ + public function getBinary(); + + /** + * Sets the path to the binary + * + * @param String $binary A path to a binary + * + * @return ProcessBuilderFactoryInterface + * + * @throws InvalidArgumentException In case binary is not executable + */ + public function useBinary($binary); + + /** + * Set the default timeout to apply on created processes. + * + * @param integer|float $timeout + * + * @return ProcessBuilderFactoryInterface + * + * @throws InvalidArgumentException In case the timeout is not valid + */ + public function setTimeout($timeout); + + /** + * Returns the current timeout applied to the created processes. + * + * @return integer|float + */ + public function getTimeout(); +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunner.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunner.php new file mode 100644 index 0000000000..2ebbcc03ef --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunner.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +use Alchemy\BinaryDriver\Exception\ExecutionFailureException; +use Psr\Log\LoggerInterface; +use SplObjectStorage; +use Symfony\Component\Process\Exception\RuntimeException; +use Symfony\Component\Process\Process; + +class ProcessRunner implements ProcessRunnerInterface +{ + /** @var LoggerInterface */ + private $logger; + + /** @var string */ + private $name; + + public function __construct(LoggerInterface $logger, $name) + { + $this->logger = $logger; + $this->name = $name; + } + + /** + * {@inheritdoc} + * + * @return ProcessRunner + */ + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + + return $this; + } + + /** + * @return LoggerInterface + */ + public function getLogger() + { + return $this->logger; + } + + /** + * {@inheritdoc} + */ + public function run(Process $process, SplObjectStorage $listeners, $bypassErrors) + { + $this->logger->info(sprintf( + '%s running command %s', $this->name, $process->getCommandLine() + )); + + try { + $process->run($this->buildCallback($listeners)); + } catch (RuntimeException $e) { + if (!$bypassErrors) { + $this->doExecutionFailure($process->getCommandLine(), $e); + } + } + + if (!$bypassErrors && !$process->isSuccessful()) { + $this->doExecutionFailure($process->getCommandLine()); + } elseif (!$process->isSuccessful()) { + $this->logger->error(sprintf( + '%s failed to execute command %s', $this->name, $process->getCommandLine() + )); + + return; + } else { + $this->logger->info(sprintf('%s executed command successfully', $this->name)); + + return $process->getOutput(); + } + } + + private function buildCallback(SplObjectStorage $listeners) + { + return function ($type, $data) use ($listeners) { + foreach ($listeners as $listener) { + $listener->handle($type, $data); + } + }; + } + + private function doExecutionFailure($command, \Exception $e = null) + { + $this->logger->error(sprintf( + '%s failed to execute command %s', $this->name, $command + )); + throw new ExecutionFailureException(sprintf( + '%s failed to execute command %s', $this->name, $command + ), $e ? $e->getCode() : null, $e ?: null); + } +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunnerAwareInterface.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunnerAwareInterface.php new file mode 100644 index 0000000000..807c33e7aa --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunnerAwareInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +interface ProcessRunnerAwareInterface +{ + /** + * Returns the current process runner + * + * @return ProcessRunnerInterface + */ + public function getProcessRunner(); + + /** + * Sets a process runner + * + * @param ProcessRunnerInterface $runner + */ + public function setProcessRunner(ProcessRunnerInterface $runner); +} diff --git a/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunnerInterface.php b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunnerInterface.php new file mode 100644 index 0000000000..6605404453 --- /dev/null +++ b/vendor/alchemy/binary-driver/src/Alchemy/BinaryDriver/ProcessRunnerInterface.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\BinaryDriver; + +use Alchemy\BinaryDriver\Exception\ExecutionFailureException; +use Psr\Log\LoggerAwareInterface; +use SplObjectStorage; +use Symfony\Component\Process\Process; + +interface ProcessRunnerInterface extends LoggerAwareInterface +{ + /** + * Executes a process, logs events + * + * @param Process $process + * @param SplObjectStorage $listeners Some listeners + * @param Boolean $bypassErrors Set to true to disable throwing ExecutionFailureExceptions + * + * @return string The Process output + * + * @throws ExecutionFailureException in case of process failure. + */ + public function run(Process $process, SplObjectStorage $listeners, $bypassErrors); +} diff --git a/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/AbstractBinaryTest.php b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/AbstractBinaryTest.php new file mode 100644 index 0000000000..dcbd2ae55c --- /dev/null +++ b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/AbstractBinaryTest.php @@ -0,0 +1,297 @@ +find('php'); + + if (null === $php) { + $this->markTestSkipped('Unable to find a php binary'); + } + + return $php; + } + + public function testSimpleLoadWithBinaryPath() + { + $php = $this->getPhpBinary(); + $imp = Implementation::load($php); + $this->assertInstanceOf('Alchemy\Tests\BinaryDriver\Implementation', $imp); + + $this->assertEquals($php, $imp->getProcessBuilderFactory()->getBinary()); + } + + public function testMultipleLoadWithBinaryPath() + { + $php = $this->getPhpBinary(); + $imp = Implementation::load(array('/zz/path/to/unexisting/command', $php)); + $this->assertInstanceOf('Alchemy\Tests\BinaryDriver\Implementation', $imp); + + $this->assertEquals($php, $imp->getProcessBuilderFactory()->getBinary()); + } + + public function testSimpleLoadWithBinaryName() + { + $php = $this->getPhpBinary(); + $imp = Implementation::load('php'); + $this->assertInstanceOf('Alchemy\Tests\BinaryDriver\Implementation', $imp); + + $this->assertEquals($php, $imp->getProcessBuilderFactory()->getBinary()); + } + + public function testMultipleLoadWithBinaryName() + { + $php = $this->getPhpBinary(); + $imp = Implementation::load(array('bachibouzouk', 'php')); + $this->assertInstanceOf('Alchemy\Tests\BinaryDriver\Implementation', $imp); + + $this->assertEquals($php, $imp->getProcessBuilderFactory()->getBinary()); + } + + /** + * @expectedException Alchemy\BinaryDriver\Exception\ExecutableNotFoundException + */ + public function testLoadWithMultiplePathExpectingAFailure() + { + Implementation::load(array('bachibouzouk', 'moribon')); + } + + /** + * @expectedException Alchemy\BinaryDriver\Exception\ExecutableNotFoundException + */ + public function testLoadWithUniquePathExpectingAFailure() + { + Implementation::load('bachibouzouk'); + } + + public function testLoadWithCustomLogger() + { + $logger = $this->getMock('Psr\Log\LoggerInterface'); + $imp = Implementation::load('php', $logger); + + $this->assertEquals($logger, $imp->getProcessRunner()->getLogger()); + } + + public function testLoadWithCustomConfigurationAsArray() + { + $conf = array('timeout' => 200); + $imp = Implementation::load('php', null, $conf); + + $this->assertEquals($conf, $imp->getConfiguration()->all()); + } + + public function testLoadWithCustomConfigurationAsObject() + { + $conf = $this->getMock('Alchemy\BinaryDriver\ConfigurationInterface'); + $imp = Implementation::load('php', null, $conf); + + $this->assertEquals($conf, $imp->getConfiguration()); + } + + public function testProcessBuilderFactoryGetterAndSetters() + { + $imp = Implementation::load('php'); + $factory = $this->getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface'); + + $imp->setProcessBuilderFactory($factory); + $this->assertEquals($factory, $imp->getProcessBuilderFactory()); + } + + public function testConfigurationGetterAndSetters() + { + $imp = Implementation::load('php'); + $conf = $this->getMock('Alchemy\BinaryDriver\ConfigurationInterface'); + + $imp->setConfiguration($conf); + $this->assertEquals($conf, $imp->getConfiguration()); + } + + public function testTimeoutIsSetOnConstruction() + { + $imp = Implementation::load('php', null, array('timeout' => 42)); + $this->assertEquals(42, $imp->getProcessBuilderFactory()->getTimeout()); + } + + public function testTimeoutIsSetOnConfigurationSetting() + { + $imp = Implementation::load('php', null); + $imp->setConfiguration(new Configuration(array('timeout' => 42))); + $this->assertEquals(42, $imp->getProcessBuilderFactory()->getTimeout()); + } + + public function testTimeoutIsSetOnProcessBuilderSetting() + { + $imp = Implementation::load('php', null, array('timeout' => 42)); + + $factory = $this->getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface'); + $factory->expects($this->once()) + ->method('setTimeout') + ->with(42); + + $imp->setProcessBuilderFactory($factory); + } + + public function testListenRegistersAListener() + { + $imp = Implementation::load('php'); + + $listeners = $this->getMockBuilder('Alchemy\BinaryDriver\Listeners\Listeners') + ->disableOriginalConstructor() + ->getMock(); + + $listener = $this->getMock('Alchemy\BinaryDriver\Listeners\ListenerInterface'); + + $listeners->expects($this->once()) + ->method('register') + ->with($this->equalTo($listener), $this->equalTo($imp)); + + $reflexion = new \ReflectionClass('Alchemy\BinaryDriver\AbstractBinary'); + $prop = $reflexion->getProperty('listenersManager'); + $prop->setAccessible(true); + $prop->setValue($imp, $listeners); + + $imp->listen($listener); + } + + /** + * @dataProvider provideCommandParameters + */ + public function testCommandRunsAProcess($parameters, $bypassErrors, $expectedParameters, $output) + { + $imp = Implementation::load('php'); + $factory = $this->getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface'); + $processRunner = $this->getMock('Alchemy\BinaryDriver\ProcessRunnerInterface'); + + $process = $this->getMockBuilder('Symfony\Component\Process\Process') + ->disableOriginalConstructor() + ->getMock(); + + $processRunner->expects($this->once()) + ->method('run') + ->with($this->equalTo($process), $this->isInstanceOf('SplObjectStorage'), $this->equalTo($bypassErrors)) + ->will($this->returnValue($output)); + + $factory->expects($this->once()) + ->method('create') + ->with($expectedParameters) + ->will($this->returnValue($process)); + + $imp->setProcessBuilderFactory($factory); + $imp->setProcessRunner($processRunner); + + $this->assertEquals($output, $imp->command($parameters, $bypassErrors)); + } + + /** + * @dataProvider provideCommandWithListenersParameters + */ + public function testCommandWithTemporaryListeners($parameters, $bypassErrors, $expectedParameters, $output, $count, $listeners) + { + $imp = Implementation::load('php'); + $factory = $this->getMock('Alchemy\BinaryDriver\ProcessBuilderFactoryInterface'); + $processRunner = $this->getMock('Alchemy\BinaryDriver\ProcessRunnerInterface'); + + $process = $this->getMockBuilder('Symfony\Component\Process\Process') + ->disableOriginalConstructor() + ->getMock(); + + $firstStorage = $secondStorage = null; + + $processRunner->expects($this->exactly(2)) + ->method('run') + ->with($this->equalTo($process), $this->isInstanceOf('SplObjectStorage'), $this->equalTo($bypassErrors)) + ->will($this->returnCallback(function ($process, $storage, $errors) use ($output, &$firstStorage, &$secondStorage) { + if (null === $firstStorage) { + $firstStorage = $storage; + } else { + $secondStorage = $storage; + } + + return $output; + })); + + $factory->expects($this->exactly(2)) + ->method('create') + ->with($expectedParameters) + ->will($this->returnValue($process)); + + $imp->setProcessBuilderFactory($factory); + $imp->setProcessRunner($processRunner); + + $this->assertEquals($output, $imp->command($parameters, $bypassErrors, $listeners)); + $this->assertCount($count, $firstStorage); + $this->assertEquals($output, $imp->command($parameters, $bypassErrors)); + $this->assertCount(0, $secondStorage); + } + + public function provideCommandWithListenersParameters() + { + $listener = $this->getMock('Alchemy\BinaryDriver\Listeners\ListenerInterface'); + $listener->expects($this->any()) + ->method('forwardedEvents') + ->will($this->returnValue(array())); + + $listener2 = $this->getMock('Alchemy\BinaryDriver\Listeners\ListenerInterface'); + $listener2->expects($this->any()) + ->method('forwardedEvents') + ->will($this->returnValue(array())); + + return array( + array('-a', false, array('-a'), 'loubda', 2, array($listener, $listener2)), + array('-a', false, array('-a'), 'loubda', 1, array($listener)), + array('-a', false, array('-a'), 'loubda', 1, $listener), + array('-a', false, array('-a'), 'loubda', 0, array()), + ); + } + + public function provideCommandParameters() + { + return array( + array('-a', false, array('-a'), 'loubda'), + array('-a', true, array('-a'), 'loubda'), + array('-a -b', false, array('-a -b'), 'loubda'), + array(array('-a'), false, array('-a'), 'loubda'), + array(array('-a'), true, array('-a'), 'loubda'), + array(array('-a', '-b'), false, array('-a', '-b'), 'loubda'), + ); + } + + public function testUnlistenUnregistersAListener() + { + $imp = Implementation::load('php'); + + $listeners = $this->getMockBuilder('Alchemy\BinaryDriver\Listeners\Listeners') + ->disableOriginalConstructor() + ->getMock(); + + $listener = $this->getMock('Alchemy\BinaryDriver\Listeners\ListenerInterface'); + + $listeners->expects($this->once()) + ->method('unregister') + ->with($this->equalTo($listener), $this->equalTo($imp)); + + $reflexion = new \ReflectionClass('Alchemy\BinaryDriver\AbstractBinary'); + $prop = $reflexion->getProperty('listenersManager'); + $prop->setAccessible(true); + $prop->setValue($imp, $listeners); + + $imp->unlisten($listener); + } +} + +class Implementation extends AbstractBinary +{ + public function getName() + { + return 'Implementation'; + } +} diff --git a/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/AbstractProcessBuilderFactoryTest.php b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/AbstractProcessBuilderFactoryTest.php new file mode 100644 index 0000000000..de0b61ce22 --- /dev/null +++ b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/AbstractProcessBuilderFactoryTest.php @@ -0,0 +1,97 @@ +markTestSkipped('Unable to detect php binary, skipping'); + } + } + + public static function setUpBeforeClass() + { + $finder = new ExecutableFinder(); + static::$phpBinary = $finder->find('php'); + } + + public function testThatBinaryIsSetOnConstruction() + { + $factory = $this->getProcessBuilderFactory(static::$phpBinary); + $this->assertEquals(static::$phpBinary, $factory->getBinary()); + } + + public function testGetSetBinary() + { + $finder = new ExecutableFinder(); + $phpUnit = $finder->find('phpunit'); + + if (null === $phpUnit) { + $this->markTestSkipped('Unable to detect phpunit binary, skipping'); + } + + $factory = $this->getProcessBuilderFactory(static::$phpBinary); + $factory->useBinary($phpUnit); + $this->assertEquals($phpUnit, $factory->getBinary()); + } + + /** + * @expectedException Alchemy\BinaryDriver\Exception\InvalidArgumentException + */ + public function testUseNonExistantBinary() + { + $factory = $this->getProcessBuilderFactory(static::$phpBinary); + $factory->useBinary('itissureitdoesnotexist'); + } + + public function testCreateShouldReturnAProcess() + { + $factory = $this->getProcessBuilderFactory(static::$phpBinary); + $process = $factory->create(); + + $this->assertInstanceOf('Symfony\Component\Process\Process', $process); + $this->assertEquals("'".static::$phpBinary."'", $process->getCommandLine()); + } + + public function testCreateWithStringArgument() + { + $factory = $this->getProcessBuilderFactory(static::$phpBinary); + $process = $factory->create('-v'); + + $this->assertInstanceOf('Symfony\Component\Process\Process', $process); + $this->assertEquals("'".static::$phpBinary."' '-v'", $process->getCommandLine()); + } + + public function testCreateWithArrayArgument() + { + $factory = $this->getProcessBuilderFactory(static::$phpBinary); + $process = $factory->create(array('-r', 'echo "Hello !";')); + + $this->assertInstanceOf('Symfony\Component\Process\Process', $process); + $this->assertEquals("'".static::$phpBinary."' '-r' 'echo \"Hello !\";'", $process->getCommandLine()); + } + + public function testCreateWithTimeout() + { + $factory = $this->getProcessBuilderFactory(static::$phpBinary); + $factory->setTimeout(200); + $process = $factory->create(array('-i')); + + $this->assertInstanceOf('Symfony\Component\Process\Process', $process); + $this->assertEquals(200, $process->getTimeout()); + } +} diff --git a/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/ConfigurationTest.php b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/ConfigurationTest.php new file mode 100644 index 0000000000..b2cd2ddd49 --- /dev/null +++ b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/ConfigurationTest.php @@ -0,0 +1,78 @@ + 'value')); + + $this->assertTrue(isset($configuration['key'])); + $this->assertEquals('value', $configuration['key']); + + $this->assertFalse(isset($configuration['key2'])); + unset($configuration['key']); + $this->assertFalse(isset($configuration['key'])); + + $configuration['key2'] = 'value2'; + $this->assertTrue(isset($configuration['key2'])); + $this->assertEquals('value2', $configuration['key2']); + } + + public function testGetOnNonExistentKeyShouldReturnDefaultValue() + { + $conf = new Configuration(); + $this->assertEquals('booba', $conf->get('hooba', 'booba')); + $this->assertEquals(null, $conf->get('hooba')); + } + + public function testSetHasGetRemove() + { + $configuration = new Configuration(array('key' => 'value')); + + $this->assertTrue($configuration->has('key')); + $this->assertEquals('value', $configuration->get('key')); + + $this->assertFalse($configuration->has('key2')); + $configuration->remove('key'); + $this->assertFalse($configuration->has('key')); + + $configuration->set('key2', 'value2'); + $this->assertTrue($configuration->has('key2')); + $this->assertEquals('value2', $configuration->get('key2')); + } + + public function testIterator() + { + $data = array( + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => 'value3', + ); + + $captured = array(); + $conf = new Configuration($data); + + foreach ($conf as $key => $value) { + $captured[$key] = $value; + } + + $this->assertEquals($data, $captured); + } + + public function testAll() + { + $data = array( + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => 'value3', + ); + + $conf = new Configuration($data); + $this->assertEquals($data, $conf->all()); + } + +} diff --git a/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/LTSProcessBuilderFactoryTest.php b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/LTSProcessBuilderFactoryTest.php new file mode 100644 index 0000000000..6875f0765a --- /dev/null +++ b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/LTSProcessBuilderFactoryTest.php @@ -0,0 +1,66 @@ +setBuilder(new LTSProcessBuilder()); + ProcessBuilderFactory::$emulateSfLTS = false; + $factory->useBinary($binary); + + return $factory; + } +} + +class LTSProcessBuilder extends ProcessBuilder +{ + private $arguments; + private $prefix; + private $timeout; + + public function __construct(array $arguments = array()) + { + $this->arguments = $arguments; + parent::__construct($arguments); + } + + public function setArguments(array $arguments) + { + $this->arguments = $arguments; + + return $this; + } + + public function setPrefix($prefix) + { + $this->prefix = $prefix; + + return $this; + } + + public function setTimeout($timeout) + { + $this->timeout = $timeout; + + return $this; + } + + public function getProcess() + { + if (!$this->prefix && !count($this->arguments)) { + throw new LogicException('You must add() command arguments before calling getProcess().'); + } + + $args = $this->prefix ? array_merge(array($this->prefix), $this->arguments) : $this->arguments; + $script = implode(' ', array_map('escapeshellarg', $args)); + + return new Process($script, null, null, null, $this->timeout); + } +} diff --git a/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/Listeners/DebugListenerTest.php b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/Listeners/DebugListenerTest.php new file mode 100644 index 0000000000..69958677da --- /dev/null +++ b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/Listeners/DebugListenerTest.php @@ -0,0 +1,33 @@ +on('debug', function ($line) use (&$lines) { + $lines[] = $line; + }); + $listener->handle(Process::ERR, "first line\nsecond line"); + $listener->handle(Process::OUT, "cool output"); + $listener->handle('unknown', "lalala"); + $listener->handle(Process::OUT, "another output\n"); + + $expected = array( + '[ERROR] first line', + '[ERROR] second line', + '[OUT] cool output', + '[OUT] another output', + '[OUT] ', + ); + + $this->assertEquals($expected, $lines); + } +} diff --git a/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/Listeners/ListenersTest.php b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/Listeners/ListenersTest.php new file mode 100644 index 0000000000..2ca21a2abf --- /dev/null +++ b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/Listeners/ListenersTest.php @@ -0,0 +1,92 @@ +register($listener); + + $n = 0; + $listener->on('received', function ($type, $data) use (&$n, &$capturedType, &$capturedData) { + $n++; + $capturedData = $data; + $capturedType = $type; + }); + + $type = 'type'; + $data = 'data'; + + $listener->handle($type, $data); + $listener->handle($type, $data); + + $listeners->unregister($listener); + + $listener->handle($type, $data); + + $this->assertEquals(3, $n); + $this->assertEquals($type, $capturedType); + $this->assertEquals($data, $capturedData); + } + + public function testRegisterAndForwardThenUnregister() + { + $listener = new TestListener(); + $target = new EventEmitter(); + + $n = 0; + $target->on('received', function ($type, $data) use (&$n, &$capturedType, &$capturedData) { + $n++; + $capturedData = $data; + $capturedType = $type; + }); + + $m = 0; + $listener->on('received', function ($type, $data) use (&$m, &$capturedType2, &$capturedData2) { + $m++; + $capturedData2 = $data; + $capturedType2 = $type; + }); + + $listeners = new Listeners(); + $listeners->register($listener, $target); + + $type = 'type'; + $data = 'data'; + + $listener->handle($type, $data); + $listener->handle($type, $data); + + $listeners->unregister($listener, $target); + + $listener->handle($type, $data); + + $this->assertEquals(2, $n); + $this->assertEquals(3, $m); + $this->assertEquals($type, $capturedType); + $this->assertEquals($data, $capturedData); + $this->assertEquals($type, $capturedType2); + $this->assertEquals($data, $capturedData2); + } +} + +class TestListener extends EventEmitter implements ListenerInterface +{ + public function handle($type, $data) + { + $this->emit('received', array($type, $data)); + } + + public function forwardedEvents() + { + return array('received'); + } +} diff --git a/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/NONLTSProcessBuilderFactoryTest.php b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/NONLTSProcessBuilderFactoryTest.php new file mode 100644 index 0000000000..fe5f343bd2 --- /dev/null +++ b/vendor/alchemy/binary-driver/tests/Alchemy/Tests/BinaryDriver/NONLTSProcessBuilderFactoryTest.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\Tests\BinaryDriver; + +use Alchemy\BinaryDriver\ProcessRunner; +use Alchemy\BinaryDriver\BinaryDriverTestCase; +use Alchemy\BinaryDriver\Exception\ExecutionFailureException; +use Alchemy\BinaryDriver\Listeners\ListenerInterface; +use Evenement\EventEmitter; +use Symfony\Component\Process\Exception\RuntimeException as ProcessRuntimeException; + +class ProcessRunnerTest extends BinaryDriverTestCase +{ + public function getProcessRunner($logger) + { + return new ProcessRunner($logger, 'test-runner'); + } + + public function testRunSuccessFullProcess() + { + $logger = $this->createLoggerMock(); + $runner = $this->getProcessRunner($logger); + + $process = $this->createProcessMock(1, true, '--helloworld--', "Kikoo Romain", null, true); + + $logger + ->expects($this->never()) + ->method('error'); + $logger + ->expects($this->exactly(2)) + ->method('info'); + + $this->assertEquals('Kikoo Romain', $runner->run($process, new \SplObjectStorage(), false)); + } + + public function testRunSuccessFullProcessBypassingErrors() + { + $logger = $this->createLoggerMock(); + $runner = $this->getProcessRunner($logger); + + $process = $this->createProcessMock(1, true, '--helloworld--', "Kikoo Romain", null, true); + + $logger + ->expects($this->never()) + ->method('error'); + $logger + ->expects($this->exactly(2)) + ->method('info'); + + $this->assertEquals('Kikoo Romain', $runner->run($process, new \SplObjectStorage(), true)); + } + + public function testRunFailingProcess() + { + $logger = $this->createLoggerMock(); + $runner = $this->getProcessRunner($logger); + + $process = $this->createProcessMock(1, false, '--helloworld--', null, null, true); + + $logger + ->expects($this->once()) + ->method('error'); + $logger + ->expects($this->once()) + ->method('info'); + + try { + $runner->run($process, new \SplObjectStorage(), false); + $this->fail('An exception should have been raised'); + } catch (ExecutionFailureException $e) { + + } + } + + public function testRunFailingProcessWithException() + { + $logger = $this->createLoggerMock(); + $runner = $this->getProcessRunner($logger); + + $exception = new ProcessRuntimeException('Process Failed'); + $process = $this->getMockBuilder('Symfony\Component\Process\Process') + ->disableOriginalConstructor() + ->getMock(); + $process->expects($this->once()) + ->method('run') + ->will($this->throwException($exception)); + + $logger + ->expects($this->once()) + ->method('error'); + $logger + ->expects($this->once()) + ->method('info'); + + try { + $runner->run($process, new \SplObjectStorage(), false); + $this->fail('An exception should have been raised'); + } catch (ExecutionFailureException $e) { + $this->assertEquals($exception, $e->getPrevious()); + } + } + + public function testRunfailingProcessBypassingErrors() + { + $logger = $this->createLoggerMock(); + $runner = $this->getProcessRunner($logger); + + $process = $this->createProcessMock(1, false, '--helloworld--', 'Hello output', null, true); + + $logger + ->expects($this->once()) + ->method('error'); + $logger + ->expects($this->once()) + ->method('info'); + + $this->assertNull($runner->run($process, new \SplObjectStorage(), true)); + } + + public function testRunFailingProcessWithExceptionBypassingErrors() + { + $logger = $this->createLoggerMock(); + $runner = $this->getProcessRunner($logger); + + $exception = new ProcessRuntimeException('Process Failed'); + $process = $this->getMockBuilder('Symfony\Component\Process\Process') + ->disableOriginalConstructor() + ->getMock(); + $process->expects($this->once()) + ->method('run') + ->will($this->throwException($exception)); + + $logger + ->expects($this->once()) + ->method('error'); + $logger + ->expects($this->once()) + ->method('info'); + + $this->assertNull($runner->run($process, new \SplObjectStorage(), true)); + } + + public function testRunSuccessFullProcessWithHandlers() + { + $logger = $this->createLoggerMock(); + $runner = $this->getProcessRunner($logger); + + $capturedCallback = null; + + $process = $this->createProcessMock(1, true, '--helloworld--', "Kikoo Romain", null, true); + $process->expects($this->once()) + ->method('run') + ->with($this->isInstanceOf('Closure')) + ->will($this->returnCallback(function ($callback) use (&$capturedCallback) { + $capturedCallback = $callback; + })); + + $logger + ->expects($this->never()) + ->method('error'); + $logger + ->expects($this->exactly(2)) + ->method('info'); + + $listener = new TestListener(); + $storage = new \SplObjectStorage(); + $storage->attach($listener); + + $capturedType = $capturedData = null; + + $listener->on('received', function ($type, $data) use (&$capturedType, &$capturedData) { + $capturedData = $data; + $capturedType = $type; + }); + + $this->assertEquals('Kikoo Romain', $runner->run($process, $storage, false)); + + $type = 'err'; + $data = 'data'; + + $capturedCallback($type, $data); + + $this->assertEquals($data, $capturedData); + $this->assertEquals($type, $capturedType); + } +} + +class TestListener extends EventEmitter implements ListenerInterface +{ + public function handle($type, $data) + { + return $this->emit('received', array($type, $data)); + } + + public function forwardedEvents() + { + return array(); + } +} diff --git a/vendor/alchemy/binary-driver/tests/bootstrap.php b/vendor/alchemy/binary-driver/tests/bootstrap.php new file mode 100644 index 0000000000..b5e2aed9bb --- /dev/null +++ b/vendor/alchemy/binary-driver/tests/bootstrap.php @@ -0,0 +1,4 @@ +add('Alchemy\Tests', __DIR__); diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 0000000000..8d31ac85a1 --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0 class loader + * + * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + */ +class ClassLoader +{ + private $prefixes = array(); + private $fallbackDirs = array(); + private $useIncludePath = false; + private $classMap = array(); + + public function getPrefixes() + { + return call_user_func_array('array_merge', $this->prefixes); + } + + public function getFallbackDirs() + { + return $this->fallbackDirs; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of classes, merging with any others previously set. + * + * @param string $prefix The classes prefix + * @param array|string $paths The location(s) of the classes + * @param bool $prepend Prepend the location(s) + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirs = array_merge( + (array) $paths, + $this->fallbackDirs + ); + } else { + $this->fallbackDirs = array_merge( + $this->fallbackDirs, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixes[$first][$prefix])) { + $this->prefixes[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixes[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixes[$first][$prefix] + ); + } else { + $this->prefixes[$first][$prefix] = array_merge( + $this->prefixes[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of classes, replacing any others previously set. + * + * @param string $prefix The classes prefix + * @param array|string $paths The location(s) of the classes + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirs = (array) $paths; + + return; + } + $this->prefixes[substr($prefix, 0, 1)][$prefix] = (array) $paths; + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + include $file; + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $classPath = strtr(substr($class, 0, $pos), '\\', DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; + $className = substr($class, $pos + 1); + } else { + // PEAR-like class name + $classPath = null; + $className = $class; + } + + $classPath .= strtr($className, '_', DIRECTORY_SEPARATOR) . '.php'; + + $first = $class[0]; + if (isset($this->prefixes[$first])) { + foreach ($this->prefixes[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { + return $dir . DIRECTORY_SEPARATOR . $classPath; + } + } + } + } + } + + foreach ($this->fallbackDirs as $dir) { + if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { + return $dir . DIRECTORY_SEPARATOR . $classPath; + } + } + + if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) { + return $file; + } + + return $this->classMap[$class] = false; + } +} diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000000..af4ad5805a --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,9 @@ + array($vendorDir . '/symfony/process'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log'), + 'Monolog' => array($vendorDir . '/monolog/monolog/src'), + 'FFMpeg' => array($vendorDir . '/php-ffmpeg/php-ffmpeg/src'), + 'Evenement' => array($vendorDir . '/evenement/evenement/src'), + 'Doctrine\\Common\\Cache\\' => array($vendorDir . '/doctrine/cache/lib'), + 'Alchemy' => array($vendorDir . '/alchemy/binary-driver/src'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 0000000000..26e208676d --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,43 @@ + $path) { + $loader->set($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + + $loader->register(true); + + return $loader; + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000000..98b72a37d6 --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,397 @@ +[ + { + "name": "evenement/evenement", + "version": "v1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/fa966683e7df3e5dd5929d984a44abfbd6bafe8d", + "reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2012-05-30 15:01:08", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Evenement": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch", + "homepage": "http://wiedler.ch/igor/" + } + ], + "description": "Événement is a very simple event dispatching library for PHP 5.3", + "keywords": [ + "event-dispatcher" + ] + }, + { + "name": "doctrine/cache", + "version": "v1.1", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "2c9761ff1d13e188d5f7378066c1ce2882d7a336" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/2c9761ff1d13e188d5f7378066c1ce2882d7a336", + "reference": "2c9761ff1d13e188d5f7378066c1ce2882d7a336", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "time": "2013-08-07 16:04:25", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Doctrine\\Common\\Cache\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "http://jmsyst.com", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ] + }, + { + "name": "psr/log", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "time": "2012-12-21 11:40:51", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ] + }, + { + "name": "symfony/process", + "version": "v2.3.4", + "version_normalized": "2.3.4.0", + "target-dir": "Symfony/Component/Process", + "source": { + "type": "git", + "url": "https://github.com/symfony/Process.git", + "reference": "1e91553e1cedd0b8fb1da6ea4f89b02e21713d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Process/zipball/1e91553e1cedd0b8fb1da6ea4f89b02e21713d5b", + "reference": "1e91553e1cedd0b8fb1da6ea4f89b02e21713d5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2013-08-22 06:42:25", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Symfony\\Component\\Process\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "http://symfony.com" + }, + { + "name": "monolog/monolog", + "version": "1.6.0", + "version_normalized": "1.6.0.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "f72392d0e6eb855118f5a84e89ac2d257c704abd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f72392d0e6eb855118f5a84e89ac2d257c704abd", + "reference": "f72392d0e6eb855118f5a84e89ac2d257c704abd", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "require-dev": { + "doctrine/couchdb": "dev-master", + "mlehner/gelf-php": "1.0.*", + "raven/raven": "0.5.*" + }, + "suggest": { + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server", + "raven/raven": "Allow sending log messages to a Sentry server" + }, + "time": "2013-07-28 22:38:30", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Monolog": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be", + "role": "Developer" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ] + }, + { + "name": "alchemy/binary-driver", + "version": "1.5.0", + "version_normalized": "1.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/alchemy-fr/BinaryDriver.git", + "reference": "b32c03d4b56ce29f783051eac55887adae654b41" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alchemy-fr/BinaryDriver/zipball/b32c03d4b56ce29f783051eac55887adae654b41", + "reference": "b32c03d4b56ce29f783051eac55887adae654b41", + "shasum": "" + }, + "require": { + "evenement/evenement": "~1.0", + "monolog/monolog": "~1.3", + "php": ">=5.3.3", + "psr/log": "~1.0", + "symfony/process": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~3.7" + }, + "time": "2013-06-21 15:51:20", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Alchemy": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Romain Neutron", + "email": "imprec@gmail.com", + "homepage": "http://www.lickmychip.com/" + }, + { + "name": "Nicolas Le Goff", + "email": "legoff.n@gmail.com" + }, + { + "name": "Phraseanet Team", + "email": "info@alchemy.fr", + "homepage": "http://www.phraseanet.com/" + } + ], + "description": "A set of tools to build binary drivers", + "keywords": [ + "binary", + "driver" + ] + }, + { + "name": "php-ffmpeg/php-ffmpeg", + "version": "0.3.x-dev", + "version_normalized": "0.3.9999999.9999999-dev", + "source": { + "type": "git", + "url": "https://github.com/alchemy-fr/PHP-FFmpeg.git", + "reference": "9fcb485d497872e674cb14eb3df1386dbda9169b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alchemy-fr/PHP-FFmpeg/zipball/9fcb485d497872e674cb14eb3df1386dbda9169b", + "reference": "9fcb485d497872e674cb14eb3df1386dbda9169b", + "shasum": "" + }, + "require": { + "alchemy/binary-driver": "~1.5", + "doctrine/cache": "~1.0", + "evenement/evenement": "~1.0", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~3.7", + "sami/sami": "~1.0", + "silex/silex": "~1.0" + }, + "suggest": { + "php-ffmpeg/extras": "A compilation of common audio & video drivers for PHP-FFMpeg" + }, + "time": "2013-08-08 10:15:15", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4-dev" + } + }, + "installation-source": "source", + "autoload": { + "psr-0": { + "FFMpeg": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Romain Neutron", + "email": "imprec@gmail.com", + "homepage": "http://www.lickmychip.com/" + }, + { + "name": "Phraseanet Team", + "email": "info@alchemy.fr", + "homepage": "http://www.phraseanet.com/" + } + ], + "description": "FFMpeg PHP, an Object Oriented library to communicate with AVconv / ffmpeg", + "keywords": [ + "audio", + "audio processing", + "avconv", + "avprobe", + "ffmpeg", + "ffprobe", + "video", + "video processing" + ] + } +] diff --git a/vendor/doctrine/cache/.travis.yml b/vendor/doctrine/cache/.travis.yml new file mode 100644 index 0000000000..ecc35406d2 --- /dev/null +++ b/vendor/doctrine/cache/.travis.yml @@ -0,0 +1,9 @@ +language: php + +php: + - 5.3 + - 5.4 + - 5.5 + +before_script: + - composer --prefer-source --dev install diff --git a/vendor/doctrine/cache/LICENSE b/vendor/doctrine/cache/LICENSE new file mode 100644 index 0000000000..4a91f0bf28 --- /dev/null +++ b/vendor/doctrine/cache/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2012 Doctrine Project + +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/doctrine/cache/README.md b/vendor/doctrine/cache/README.md new file mode 100644 index 0000000000..d315234f3d --- /dev/null +++ b/vendor/doctrine/cache/README.md @@ -0,0 +1,9 @@ +# Doctrine Cache + +Cache component extracted from the Doctrine Common project. + +## Changelog + +### v1.1 + +* Added support for MongoDB as Cache Provider diff --git a/vendor/doctrine/cache/composer.json b/vendor/doctrine/cache/composer.json new file mode 100644 index 0000000000..380540ca36 --- /dev/null +++ b/vendor/doctrine/cache/composer.json @@ -0,0 +1,29 @@ +{ + "name": "doctrine/cache", + "type": "library", + "description": "Caching library offering an object-oriented API for many cache backends", + "keywords": ["cache", "caching"], + "homepage": "http://www.doctrine-project.org", + "license": "MIT", + "authors": [ + {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, + {"name": "Roman Borschel", "email": "roman@code-factory.org"}, + {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, + {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}, + {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} + ], + "require": { + "php": ">=5.3.2" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "autoload": { + "psr-0": { "Doctrine\\Common\\Cache\\": "lib/" } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcCache.php new file mode 100644 index 0000000000..680440ba1c --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcCache.php @@ -0,0 +1,91 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * APC cache provider. + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class ApcCache extends CacheProvider +{ + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return apc_fetch($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return apc_exists($id); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + return (bool) apc_store($id, $data, (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return apc_delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return apc_clear_cache() && apc_clear_cache('user'); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $info = apc_cache_info(); + $sma = apc_sma_info(); + + return array( + Cache::STATS_HITS => $info['num_hits'], + Cache::STATS_MISSES => $info['num_misses'], + Cache::STATS_UPTIME => $info['start_time'], + Cache::STATS_MEMORY_USAGE => $info['mem_size'], + Cache::STATS_MEMORY_AVAILABLE => $sma['avail_mem'], + ); + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ArrayCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ArrayCache.php new file mode 100644 index 0000000000..e9f08a24bb --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ArrayCache.php @@ -0,0 +1,93 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Array cache driver. + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class ArrayCache extends CacheProvider +{ + /** + * @var array $data + */ + private $data = array(); + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return (isset($this->data[$id])) ? $this->data[$id] : false; + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return isset($this->data[$id]); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + $this->data[$id] = $data; + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + unset($this->data[$id]); + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + $this->data = array(); + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + return null; + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php new file mode 100644 index 0000000000..0785f263b7 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php @@ -0,0 +1,111 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Interface for cache drivers. + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Fabio B. Silva + */ +interface Cache +{ + const STATS_HITS = 'hits'; + const STATS_MISSES = 'misses'; + const STATS_UPTIME = 'uptime'; + const STATS_MEMORY_USAGE = 'memory_usage'; + const STATS_MEMORY_AVAILABLE = 'memory_available'; + /** + * Only for backward compatibility (may be removed in next major release) + * + * @deprecated + */ + const STATS_MEMORY_AVAILIABLE = 'memory_available'; + + /** + * Fetches an entry from the cache. + * + * @param string $id The id of the cache entry to fetch. + * + * @return mixed The cached data or FALSE, if no cache entry exists for the given id. + */ + function fetch($id); + + /** + * Tests if an entry exists in the cache. + * + * @param string $id The cache id of the entry to check for. + * + * @return boolean TRUE if a cache entry exists for the given cache id, FALSE otherwise. + */ + function contains($id); + + /** + * Puts data into the cache. + * + * @param string $id The cache id. + * @param mixed $data The cache entry/data. + * @param int $lifeTime The cache lifetime. + * If != 0, sets a specific lifetime for this cache entry (0 => infinite lifeTime). + * + * @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise. + */ + function save($id, $data, $lifeTime = 0); + + /** + * Deletes a cache entry. + * + * @param string $id The cache id. + * + * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise. + */ + function delete($id); + + /** + * Retrieves cached information from the data store. + * + * The server's statistics array has the following values: + * + * - hits + * Number of keys that have been requested and found present. + * + * - misses + * Number of items that have been requested and not found. + * + * - uptime + * Time that the server is running. + * + * - memory_usage + * Memory used by this server to store items. + * + * - memory_available + * Memory allowed to use for storage. + * + * @since 2.2 + * + * @return array|null An associative array with server's statistics if available, NULL otherwise. + */ + function getStats(); +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php new file mode 100644 index 0000000000..45d9acbc89 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php @@ -0,0 +1,240 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Base class for cache provider implementations. + * + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Fabio B. Silva + */ +abstract class CacheProvider implements Cache +{ + const DOCTRINE_NAMESPACE_CACHEKEY = 'DoctrineNamespaceCacheKey[%s]'; + + /** + * The namespace to prefix all cache ids with. + * + * @var string + */ + private $namespace = ''; + + /** + * The namespace version. + * + * @var string + */ + private $namespaceVersion; + + /** + * Sets the namespace to prefix all cache ids with. + * + * @param string $namespace + * + * @return void + */ + public function setNamespace($namespace) + { + $this->namespace = (string) $namespace; + } + + /** + * Retrieves the namespace that prefixes all cache ids. + * + * @return string + */ + public function getNamespace() + { + return $this->namespace; + } + + /** + * {@inheritdoc} + */ + public function fetch($id) + { + return $this->doFetch($this->getNamespacedId($id)); + } + + /** + * {@inheritdoc} + */ + public function contains($id) + { + return $this->doContains($this->getNamespacedId($id)); + } + + /** + * {@inheritdoc} + */ + public function save($id, $data, $lifeTime = 0) + { + return $this->doSave($this->getNamespacedId($id), $data, $lifeTime); + } + + /** + * {@inheritdoc} + */ + public function delete($id) + { + return $this->doDelete($this->getNamespacedId($id)); + } + + /** + * {@inheritdoc} + */ + public function getStats() + { + return $this->doGetStats(); + } + + /** + * Flushes all cache entries. + * + * @return boolean TRUE if the cache entries were successfully flushed, FALSE otherwise. + */ + public function flushAll() + { + return $this->doFlush(); + } + + /** + * Deletes all cache entries. + * + * @return boolean TRUE if the cache entries were successfully deleted, FALSE otherwise. + */ + public function deleteAll() + { + $namespaceCacheKey = $this->getNamespaceCacheKey(); + $namespaceVersion = $this->getNamespaceVersion() + 1; + + $this->namespaceVersion = $namespaceVersion; + + return $this->doSave($namespaceCacheKey, $namespaceVersion); + } + + /** + * Prefixes the passed id with the configured namespace value. + * + * @param string $id The id to namespace. + * + * @return string The namespaced id. + */ + private function getNamespacedId($id) + { + $namespaceVersion = $this->getNamespaceVersion(); + + return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion); + } + + /** + * Returns the namespace cache key. + * + * @return string + */ + private function getNamespaceCacheKey() + { + return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace); + } + + /** + * Returns the namespace version. + * + * @return string + */ + private function getNamespaceVersion() + { + if (null !== $this->namespaceVersion) { + return $this->namespaceVersion; + } + + $namespaceCacheKey = $this->getNamespaceCacheKey(); + $namespaceVersion = $this->doFetch($namespaceCacheKey); + + if (false === $namespaceVersion) { + $namespaceVersion = 1; + + $this->doSave($namespaceCacheKey, $namespaceVersion); + } + + $this->namespaceVersion = $namespaceVersion; + + return $this->namespaceVersion; + } + + /** + * Fetches an entry from the cache. + * + * @param string $id The id of the cache entry to fetch. + * + * @return string|bool The cached data or FALSE, if no cache entry exists for the given id. + */ + abstract protected function doFetch($id); + + /** + * Tests if an entry exists in the cache. + * + * @param string $id The cache id of the entry to check for. + * + * @return boolean TRUE if a cache entry exists for the given cache id, FALSE otherwise. + */ + abstract protected function doContains($id); + + /** + * Puts data into the cache. + * + * @param string $id The cache id. + * @param string $data The cache entry/data. + * @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this + * cache entry (0 => infinite lifeTime). + * + * @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise. + */ + abstract protected function doSave($id, $data, $lifeTime = 0); + + /** + * Deletes a cache entry. + * + * @param string $id The cache id. + * + * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise. + */ + abstract protected function doDelete($id); + + /** + * Flushes all cache entries. + * + * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise. + */ + abstract protected function doFlush(); + + /** + * Retrieves cached information from the data store. + * + * @since 2.2 + * + * @return array|null An associative array with server's statistics if available, NULL otherwise. + */ + abstract protected function doGetStats(); +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CouchbaseCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CouchbaseCache.php new file mode 100644 index 0000000000..c21691df96 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CouchbaseCache.php @@ -0,0 +1,121 @@ +. + */ + +namespace Doctrine\Common\Cache; + +use \Couchbase; + +/** + * Couchbase cache provider. + * + * @link www.doctrine-project.org + * @since 2.4 + * @author Michael Nitschinger + */ +class CouchbaseCache extends CacheProvider +{ + /** + * @var Couchbase|null + */ + private $couchbase; + + /** + * Sets the Couchbase instance to use. + * + * @param Couchbase $couchbase + * + * @return void + */ + public function setCouchbase(Couchbase $couchbase) + { + $this->couchbase = $couchbase; + } + + /** + * Gets the Couchbase instance used by the cache. + * + * @return Couchbase|null + */ + public function getCouchbase() + { + return $this->couchbase; + } + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return $this->couchbase->get($id) ?: false; + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return (null !== $this->couchbase->get($id)); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + if ($lifeTime > 30 * 24 * 3600) { + $lifeTime = time() + $lifeTime; + } + return $this->couchbase->set($id, $data, (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return $this->couchbase->delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return $this->couchbase->flush(); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $stats = $this->couchbase->getStats(); + $servers = $this->couchbase->getServers(); + $server = explode(":", $servers[0]); + $key = $server[0] . ":" . "11210"; + $stats = $stats[$key]; + return array( + Cache::STATS_HITS => $stats['get_hits'], + Cache::STATS_MISSES => $stats['get_misses'], + Cache::STATS_UPTIME => $stats['uptime'], + Cache::STATS_MEMORY_USAGE => $stats['bytes'], + Cache::STATS_MEMORY_AVAILABLE => $stats['limit_maxbytes'], + ); + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FileCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FileCache.php new file mode 100644 index 0000000000..1aa4d79118 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FileCache.php @@ -0,0 +1,158 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Base file cache driver. + * + * @since 2.3 + * @author Fabio B. Silva + */ +abstract class FileCache extends CacheProvider +{ + /** + * The cache directory. + * + * @var string + */ + protected $directory; + + /** + * The cache file extension. + * + * @var string|null + */ + protected $extension; + + /** + * Constructor. + * + * @param string $directory The cache directory. + * @param string|null $extension The cache file extension. + * + * @throws \InvalidArgumentException + */ + public function __construct($directory, $extension = null) + { + if ( ! is_dir($directory) && ! @mkdir($directory, 0777, true)) { + throw new \InvalidArgumentException(sprintf( + 'The directory "%s" does not exist and could not be created.', + $directory + )); + } + + if ( ! is_writable($directory)) { + throw new \InvalidArgumentException(sprintf( + 'The directory "%s" is not writable.', + $directory + )); + } + + $this->directory = realpath($directory); + $this->extension = $extension ?: $this->extension; + } + + /** + * Gets the cache directory. + * + * @return string + */ + public function getDirectory() + { + return $this->directory; + } + + /** + * Gets the cache file extension. + * + * @return string|null + */ + public function getExtension() + { + return $this->extension; + } + + /** + * @param string $id + * + * @return string + */ + protected function getFilename($id) + { + $hash = hash('sha256', $id); + $path = implode(str_split($hash, 16), DIRECTORY_SEPARATOR); + $path = $this->directory . DIRECTORY_SEPARATOR . $path; + $id = preg_replace('@[\\\/:"*?<>|]+@', '', $id); + + return $path . DIRECTORY_SEPARATOR . $id . $this->extension; + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return @unlink($this->getFilename($id)); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + foreach ($this->getIterator() as $name => $file) { + @unlink($name); + } + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $usage = 0; + foreach ($this->getIterator() as $name => $file) { + $usage += $file->getSize(); + } + + $free = disk_free_space($this->directory); + + return array( + Cache::STATS_HITS => null, + Cache::STATS_MISSES => null, + Cache::STATS_UPTIME => null, + Cache::STATS_MEMORY_USAGE => $usage, + Cache::STATS_MEMORY_AVAILABLE => $free, + ); + } + + /** + * @return \Iterator + */ + private function getIterator() + { + $pattern = '/^.+\\' . $this->extension . '$/i'; + $iterator = new \RecursiveDirectoryIterator($this->directory); + $iterator = new \RecursiveIteratorIterator($iterator); + return new \RegexIterator($iterator, $pattern); + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FilesystemCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FilesystemCache.php new file mode 100644 index 0000000000..5c5a46e944 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/FilesystemCache.php @@ -0,0 +1,113 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Filesystem cache driver. + * + * @since 2.3 + * @author Fabio B. Silva + */ +class FilesystemCache extends FileCache +{ + const EXTENSION = '.doctrinecache.data'; + + /** + * {@inheritdoc} + */ + protected $extension = self::EXTENSION; + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + $data = ''; + $lifetime = -1; + $filename = $this->getFilename($id); + + if ( ! is_file($filename)) { + return false; + } + + $resource = fopen($filename, "r"); + + if (false !== ($line = fgets($resource))) { + $lifetime = (integer) $line; + } + + if ($lifetime !== 0 && $lifetime < time()) { + fclose($resource); + + return false; + } + + while (false !== ($line = fgets($resource))) { + $data .= $line; + } + + fclose($resource); + + return unserialize($data); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + $lifetime = -1; + $filename = $this->getFilename($id); + + if ( ! is_file($filename)) { + return false; + } + + $resource = fopen($filename, "r"); + + if (false !== ($line = fgets($resource))) { + $lifetime = (integer) $line; + } + + fclose($resource); + + return $lifetime === 0 || $lifetime > time(); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + if ($lifeTime > 0) { + $lifeTime = time() + $lifeTime; + } + + $data = serialize($data); + $filename = $this->getFilename($id); + $filepath = pathinfo($filename, PATHINFO_DIRNAME); + + if ( ! is_dir($filepath)) { + mkdir($filepath, 0777, true); + } + + return file_put_contents($filename, $lifeTime . PHP_EOL . $data); + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcacheCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcacheCache.php new file mode 100644 index 0000000000..f839a65918 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcacheCache.php @@ -0,0 +1,121 @@ +. + */ + +namespace Doctrine\Common\Cache; + +use \Memcache; + +/** + * Memcache cache provider. + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class MemcacheCache extends CacheProvider +{ + /** + * @var Memcache|null + */ + private $memcache; + + /** + * Sets the memcache instance to use. + * + * @param Memcache $memcache + * + * @return void + */ + public function setMemcache(Memcache $memcache) + { + $this->memcache = $memcache; + } + + /** + * Gets the memcache instance used by the cache. + * + * @return Memcache|null + */ + public function getMemcache() + { + return $this->memcache; + } + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return $this->memcache->get($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return (bool) $this->memcache->get($id); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + if ($lifeTime > 30 * 24 * 3600) { + $lifeTime = time() + $lifeTime; + } + return $this->memcache->set($id, $data, 0, (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return $this->memcache->delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return $this->memcache->flush(); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $stats = $this->memcache->getStats(); + return array( + Cache::STATS_HITS => $stats['get_hits'], + Cache::STATS_MISSES => $stats['get_misses'], + Cache::STATS_UPTIME => $stats['uptime'], + Cache::STATS_MEMORY_USAGE => $stats['bytes'], + Cache::STATS_MEMORY_AVAILABLE => $stats['limit_maxbytes'], + ); + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcachedCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcachedCache.php new file mode 100644 index 0000000000..f7e5500a1c --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/MemcachedCache.php @@ -0,0 +1,124 @@ +. + */ + +namespace Doctrine\Common\Cache; + +use \Memcached; + +/** + * Memcached cache provider. + * + * @link www.doctrine-project.org + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class MemcachedCache extends CacheProvider +{ + /** + * @var Memcached|null + */ + private $memcached; + + /** + * Sets the memcache instance to use. + * + * @param Memcached $memcached + * + * @return void + */ + public function setMemcached(Memcached $memcached) + { + $this->memcached = $memcached; + } + + /** + * Gets the memcached instance used by the cache. + * + * @return Memcached|null + */ + public function getMemcached() + { + return $this->memcached; + } + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return $this->memcached->get($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return (false !== $this->memcached->get($id)); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + if ($lifeTime > 30 * 24 * 3600) { + $lifeTime = time() + $lifeTime; + } + return $this->memcached->set($id, $data, (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return $this->memcached->delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return $this->memcached->flush(); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $stats = $this->memcached->getStats(); + $servers = $this->memcached->getServerList(); + $key = $servers[0]['host'] . ':' . $servers[0]['port']; + $stats = $stats[$key]; + return array( + Cache::STATS_HITS => $stats['get_hits'], + Cache::STATS_MISSES => $stats['get_misses'], + Cache::STATS_UPTIME => $stats['uptime'], + Cache::STATS_MEMORY_USAGE => $stats['bytes'], + Cache::STATS_MEMORY_AVAILABLE => $stats['limit_maxbytes'], + ); + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/PhpFileCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/PhpFileCache.php new file mode 100644 index 0000000000..83c6b52d88 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/PhpFileCache.php @@ -0,0 +1,107 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Php file cache driver. + * + * @since 2.3 + * @author Fabio B. Silva + */ +class PhpFileCache extends FileCache +{ + const EXTENSION = '.doctrinecache.php'; + + /** + * {@inheritdoc} + */ + protected $extension = self::EXTENSION; + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + $filename = $this->getFilename($id); + + if ( ! is_file($filename)) { + return false; + } + + $value = include $filename; + + if ($value['lifetime'] !== 0 && $value['lifetime'] < time()) { + return false; + } + + return $value['data']; + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + $filename = $this->getFilename($id); + + if ( ! is_file($filename)) { + return false; + } + + $value = include $filename; + + return $value['lifetime'] === 0 || $value['lifetime'] > time(); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + if ($lifeTime > 0) { + $lifeTime = time() + $lifeTime; + } + + if (is_object($data) && ! method_exists($data, '__set_state')) { + throw new \InvalidArgumentException( + "Invalid argument given, PhpFileCache only allows objects that implement __set_state() " . + "and fully support var_export(). You can use the FilesystemCache to save arbitrary object " . + "graphs using serialize()/deserialize()." + ); + } + + $filename = $this->getFilename($id); + $filepath = pathinfo($filename, PATHINFO_DIRNAME); + + if ( ! is_dir($filepath)) { + mkdir($filepath, 0777, true); + } + + $value = array( + 'lifetime' => $lifeTime, + 'data' => $data + ); + + $value = var_export($value, true); + $code = sprintf('. + */ + +namespace Doctrine\Common\Cache; + +use Redis; + +/** + * Redis cache provider. + * + * @link www.doctrine-project.org + * @since 2.2 + * @author Osman Ungur + */ +class RedisCache extends CacheProvider +{ + /** + * @var Redis|null + */ + private $redis; + + /** + * Sets the redis instance to use. + * + * @param Redis $redis + * + * @return void + */ + public function setRedis(Redis $redis) + { + $redis->setOption(Redis::OPT_SERIALIZER, $this->getSerializerValue()); + $this->redis = $redis; + } + + /** + * Gets the redis instance used by the cache. + * + * @return Redis|null + */ + public function getRedis() + { + return $this->redis; + } + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return $this->redis->get($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return $this->redis->exists($id); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + if ($lifeTime > 0) { + return $this->redis->setex($id, $lifeTime, $data); + } + return $this->redis->set($id, $data); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return $this->redis->delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return $this->redis->flushDB(); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $info = $this->redis->info(); + return array( + Cache::STATS_HITS => false, + Cache::STATS_MISSES => false, + Cache::STATS_UPTIME => $info['uptime_in_seconds'], + Cache::STATS_MEMORY_USAGE => $info['used_memory'], + Cache::STATS_MEMORY_AVAILABLE => false + ); + } + + /** + * Returns the serializer constant to use. If Redis is compiled with + * igbinary support, that is used. Otherwise the default PHP serializer is + * used. + * + * @return integer One of the Redis::SERIALIZER_* constants + */ + protected function getSerializerValue() + { + return defined('Redis::SERIALIZER_IGBINARY') ? Redis::SERIALIZER_IGBINARY : Redis::SERIALIZER_PHP; + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php new file mode 100644 index 0000000000..b8dbfd5673 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php @@ -0,0 +1,250 @@ +. + */ + +namespace Doctrine\Common\Cache; + +use Riak\Bucket; +use Riak\Connection; +use Riak\Input; +use Riak\Exception; +use Riak\Object; + +/** + * Riak cache provider. + * + * @link www.doctrine-project.org + * @since 1.1 + * @author Guilherme Blanco + */ +class RiakCache extends CacheProvider +{ + const EXPIRES_HEADER = 'X-Riak-Meta-Expires'; + + /** + * @var \Riak\Bucket + */ + private $bucket; + + /** + * Sets the riak bucket instance to use. + * + * @param \Riak\Bucket $bucket + */ + public function __construct(Bucket $bucket) + { + $this->bucket = $bucket; + } + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + try { + $response = $this->bucket->get(urlencode($id)); + + // No objects found + if ( ! $response->hasObject()) { + return false; + } + + // Check for attempted siblings + $object = ($response->hasSiblings()) + ? $this->resolveConflict($id, $response->getVClock(), $response->getObjectList()) + : $response->getFirstObject(); + + // Check for expired object + if ($this->isExpired($object)) { + $this->bucket->delete($object); + + return false; + } + + return unserialize($object->getContent()); + } catch (Exception\RiakException $e) { + // Covers: + // - Riak\ConnectionException + // - Riak\CommunicationException + // - Riak\UnexpectedResponseException + // - Riak\NotFoundException + } + + return false; + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + try { + // We only need the HEAD, not the entire object + $input = new Input\GetInput(); + + $input->setReturnHead(true); + + $response = $this->bucket->get(urlencode($id), $input); + + // No objects found + if ( ! $response->hasObject()) { + return false; + } + + $object = $response->getFirstObject(); + + // Check for expired object + if ($this->isExpired($object)) { + $this->bucket->delete($object); + + return false; + } + + return true; + } catch (Exception\RiakException $e) { + // Do nothing + } + + return false; + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + try { + $object = new Object(urlencode($id)); + + $object->setContent(serialize($data)); + + if ($lifeTime > 0) { + $object->addMetadata(self::EXPIRES_HEADER, (string) (time() + $lifeTime)); + } + + $this->bucket->put($object); + + return true; + } catch (Exception\RiakException $e) { + // Do nothing + } + + return false; + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + try { + $this->bucket->delete(urlencode($id)); + + return true; + } catch (Exception\BadArgumentsException $e) { + // Key did not exist on cluster already + } catch (Exception\RiakException $e) { + // Covers: + // - Riak\Exception\ConnectionException + // - Riak\Exception\CommunicationException + // - Riak\Exception\UnexpectedResponseException + } + + return false; + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + try { + $keyList = $this->bucket->getKeyList(); + + foreach ($keyList as $key) { + $this->bucket->delete($key); + } + + return true; + } catch (Exception\RiakException $e) { + // Do nothing + } + + return false; + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + // Only exposed through HTTP stats API, not Protocol Buffers API + return null; + } + + /** + * Check if a given Riak Object have expired. + * + * @param \Riak\Object $object + * + * @return boolean + */ + private function isExpired(Object $object) + { + $metadataMap = $object->getMetadataMap(); + + return isset($metadataMap[self::EXPIRES_HEADER]) + && $metadataMap[self::EXPIRES_HEADER] < time(); + } + + /** + * On-read conflict resolution. Applied approach here is last write wins. + * Specific needs may override this method to apply alternate conflict resolutions. + * + * {@internal Riak does not attempt to resolve a write conflict, and store + * it as sibling of conflicted one. By following this approach, it is up to + * the next read to resolve the conflict. When this happens, your fetched + * object will have a list of siblings (read as a list of objects). + * In our specific case, we do not care about the intermediate ones since + * they are all the same read from storage, and we do apply a last sibling + * (last write) wins logic. + * If by any means our resolution generates another conflict, it'll up to + * next read to properly solve it.} + * + * @param string $id + * @param string $vClock + * @param array $objectList + * + * @return \Riak\Object + */ + protected function resolveConflict($id, $vClock, array $objectList) + { + // Our approach here is last-write wins + $winner = $objectList[count($objectList)]; + + $putInput = new Input\PutInput(); + $putInput->setVClock($vClock); + + $mergedObject = new Object(urlencode($id)); + $mergedObject->setContent($winner->getContent()); + + $this->bucket->put($mergedObject, $putInput); + + return $mergedObject; + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/WinCacheCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/WinCacheCache.php new file mode 100644 index 0000000000..ae32772930 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/WinCacheCache.php @@ -0,0 +1,91 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * WinCache cache provider. + * + * @link www.doctrine-project.org + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class WinCacheCache extends CacheProvider +{ + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return wincache_ucache_get($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return wincache_ucache_exists($id); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + return (bool) wincache_ucache_set($id, $data, (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return wincache_ucache_delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return wincache_ucache_clear(); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $info = wincache_ucache_info(); + $meminfo = wincache_ucache_meminfo(); + + return array( + Cache::STATS_HITS => $info['total_hit_count'], + Cache::STATS_MISSES => $info['total_miss_count'], + Cache::STATS_UPTIME => $info['total_cache_uptime'], + Cache::STATS_MEMORY_USAGE => $meminfo['memory_total'], + Cache::STATS_MEMORY_AVAILABLE => $meminfo['memory_free'], + ); + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/XcacheCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/XcacheCache.php new file mode 100644 index 0000000000..833b02a89b --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/XcacheCache.php @@ -0,0 +1,109 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Xcache cache driver. + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class XcacheCache extends CacheProvider +{ + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return $this->doContains($id) ? unserialize(xcache_get($id)) : false; + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return xcache_isset($id); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + return xcache_set($id, serialize($data), (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return xcache_unset($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + $this->checkAuthorization(); + + xcache_clear_cache(XC_TYPE_VAR, 0); + + return true; + } + + /** + * Checks that xcache.admin.enable_auth is Off. + * + * @return void + * + * @throws \BadMethodCallException When xcache.admin.enable_auth is On. + */ + protected function checkAuthorization() + { + if (ini_get('xcache.admin.enable_auth')) { + throw new \BadMethodCallException('To use all features of \Doctrine\Common\Cache\XcacheCache, you must set "xcache.admin.enable_auth" to "Off" in your php.ini.'); + } + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $this->checkAuthorization(); + + $info = xcache_info(XC_TYPE_VAR, 0); + return array( + Cache::STATS_HITS => $info['hits'], + Cache::STATS_MISSES => $info['misses'], + Cache::STATS_UPTIME => null, + Cache::STATS_MEMORY_USAGE => $info['size'], + Cache::STATS_MEMORY_AVAILABLE => $info['avail'], + ); + } +} diff --git a/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ZendDataCache.php b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ZendDataCache.php new file mode 100644 index 0000000000..6e35ac8236 --- /dev/null +++ b/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ZendDataCache.php @@ -0,0 +1,83 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Zend Data Cache cache driver. + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Ralph Schindler + * @author Guilherme Blanco + */ +class ZendDataCache extends CacheProvider +{ + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return zend_shm_cache_fetch($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return (false !== zend_shm_cache_fetch($id)); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + return zend_shm_cache_store($id, $data, $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return zend_shm_cache_delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + $namespace = $this->getNamespace(); + if (empty($namespace)) { + return zend_shm_cache_clear(); + } + return zend_shm_cache_clear($namespace); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + return null; + } +} diff --git a/vendor/doctrine/cache/phpunit.xml.dist b/vendor/doctrine/cache/phpunit.xml.dist new file mode 100644 index 0000000000..900378bf36 --- /dev/null +++ b/vendor/doctrine/cache/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + ./tests/Doctrine/ + + + + + + ./lib/Doctrine/ + + + + + + performance + + + diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ApcCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ApcCacheTest.php new file mode 100644 index 0000000000..df81262010 --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ApcCacheTest.php @@ -0,0 +1,20 @@ +markTestSkipped('The ' . __CLASS__ .' requires the use of APC'); + } + } + + protected function _getCacheDriver() + { + return new ApcCache(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php new file mode 100644 index 0000000000..6cad8915b6 --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php @@ -0,0 +1,21 @@ +_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertNull($stats); + } +} \ No newline at end of file diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CacheTest.php new file mode 100644 index 0000000000..8d0e16edfc --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CacheTest.php @@ -0,0 +1,103 @@ +_getCacheDriver(); + + // Test save + $cache->save('test_key', 'testing this out'); + + // Test contains to test that save() worked + $this->assertTrue($cache->contains('test_key')); + + // Test fetch + $this->assertEquals('testing this out', $cache->fetch('test_key')); + + // Test delete + $cache->save('test_key2', 'test2'); + $cache->delete('test_key2'); + $this->assertFalse($cache->contains('test_key2')); + } + + public function testObjects() + { + $cache = $this->_getCacheDriver(); + + // Fetch/save test with objects (Is cache driver serializes/unserializes objects correctly ?) + $cache->save('test_object_key', new \ArrayObject()); + $this->assertTrue($cache->fetch('test_object_key') instanceof \ArrayObject); + } + + public function testDeleteAll() + { + $cache = $this->_getCacheDriver(); + $cache->save('test_key1', '1'); + $cache->save('test_key2', '2'); + $cache->deleteAll(); + + $this->assertFalse($cache->contains('test_key1')); + $this->assertFalse($cache->contains('test_key2')); + } + + public function testFlushAll() + { + $cache = $this->_getCacheDriver(); + $cache->save('test_key1', '1'); + $cache->save('test_key2', '2'); + $cache->flushAll(); + + $this->assertFalse($cache->contains('test_key1')); + $this->assertFalse($cache->contains('test_key2')); + } + + public function testNamespace() + { + $cache = $this->_getCacheDriver(); + $cache->setNamespace('test_'); + $cache->save('key1', 'test'); + + $this->assertTrue($cache->contains('key1')); + + $cache->setNamespace('test2_'); + + $this->assertFalse($cache->contains('key1')); + } + + /** + * @group DCOM-43 + */ + public function testGetStats() + { + $cache = $this->_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertArrayHasKey(Cache::STATS_HITS, $stats); + $this->assertArrayHasKey(Cache::STATS_MISSES, $stats); + $this->assertArrayHasKey(Cache::STATS_UPTIME, $stats); + $this->assertArrayHasKey(Cache::STATS_MEMORY_USAGE, $stats); + $this->assertArrayHasKey(Cache::STATS_MEMORY_AVAILABLE, $stats); + } + + /** + * Make sure that all supported caches return "false" instead of "null" to be compatible + * with ORM integration. + */ + public function testFalseOnFailedFetch() + { + $cache = $this->_getCacheDriver(); + $result = $cache->fetch('nonexistent_key'); + $this->assertFalse($result); + $this->assertNotNull($result); + } + + /** + * @return \Doctrine\Common\Cache\CacheProvider + */ + abstract protected function _getCacheDriver(); +} diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CouchbaseCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CouchbaseCacheTest.php new file mode 100644 index 0000000000..40d5a6934b --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/CouchbaseCacheTest.php @@ -0,0 +1,47 @@ +couchbase = new Couchbase('127.0.0.1', 'Administrator', 'password', 'default'); + } catch(Exception $ex) { + $this->markTestSkipped('Could not instantiate the Couchbase cache because of: ' . $ex); + } + } else { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of the couchbase extension'); + } + } + + public function testNoExpire() + { + $cache = $this->_getCacheDriver(); + $cache->save('noexpire', 'value', 0); + sleep(1); + $this->assertTrue($cache->contains('noexpire'), 'Couchbase provider should support no-expire'); + } + + public function testLongLifetime() + { + $cache = $this->_getCacheDriver(); + $cache->save('key', 'value', 30 * 24 * 3600 + 1); + + $this->assertTrue($cache->contains('key'), 'Couchbase provider should support TTL > 30 days'); + } + + protected function _getCacheDriver() + { + $driver = new CouchbaseCache(); + $driver->setCouchbase($this->couchbase); + return $driver; + } +} \ No newline at end of file diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FileCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FileCacheTest.php new file mode 100644 index 0000000000..6f9df8158e --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FileCacheTest.php @@ -0,0 +1,107 @@ +driver = $this->getMock( + 'Doctrine\Common\Cache\FileCache', + array('doFetch', 'doContains', 'doSave'), + array(), '', false + ); + } + + public function getProviderFileName() + { + return array( + //The characters :\/<>"*?| are not valid in Windows filenames. + array('key:1', 'key1'), + array('key\2', 'key2'), + array('key/3', 'key3'), + array('key<4', 'key4'), + array('key>5', 'key5'), + array('key"6', 'key6'), + array('key*7', 'key7'), + array('key?8', 'key8'), + array('key|9', 'key9'), + array('key[0]','key[0]'), + ); + } + + /** + * @dataProvider getProviderFileName + */ + public function testInvalidFilename($key, $expected) + { + $cache = $this->driver; + $method = new \ReflectionMethod($cache, 'getFilename'); + + $method->setAccessible(true); + + $value = $method->invoke($cache, $key); + $actual = pathinfo($value, PATHINFO_FILENAME); + + $this->assertEquals($expected, $actual); + } + + public function testFilenameCollision() + { + $data['key:0'] = 'key0'; + $data['key\0'] = 'key0'; + $data['key/0'] = 'key0'; + $data['key<0'] = 'key0'; + $data['key>0'] = 'key0'; + $data['key"0'] = 'key0'; + $data['key*0'] = 'key0'; + $data['key?0'] = 'key0'; + $data['key|0'] = 'key0'; + + $paths = array(); + $cache = $this->driver; + $method = new \ReflectionMethod($cache, 'getFilename'); + + $method->setAccessible(true); + + foreach ($data as $key => $expected) { + $path = $method->invoke($cache, $key); + $actual = pathinfo($path, PATHINFO_FILENAME); + + $this->assertNotContains($path, $paths); + $this->assertEquals($expected, $actual); + + $paths[] = $path; + } + } + + public function testFilenameShouldCreateThePathWithFourSubDirectories() + { + $cache = $this->driver; + $method = new \ReflectionMethod($cache, 'getFilename'); + $key = 'item-key'; + $expectedDir[] = '84e0e2e893febb73'; + $expectedDir[] = '7a0fee0c89d53f4b'; + $expectedDir[] = 'b7fcb44c57cdf3d3'; + $expectedDir[] = '2ce7363f5d597760'; + $expectedDir = implode(DIRECTORY_SEPARATOR, $expectedDir); + + $method->setAccessible(true); + + $path = $method->invoke($cache, $key); + $filename = pathinfo($path, PATHINFO_FILENAME); + $dirname = pathinfo($path, PATHINFO_DIRNAME); + + $this->assertEquals('item-key', $filename); + $this->assertEquals(DIRECTORY_SEPARATOR . $expectedDir, $dirname); + $this->assertEquals(DIRECTORY_SEPARATOR . $expectedDir . DIRECTORY_SEPARATOR . $key, $path); + } +} \ No newline at end of file diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php new file mode 100644 index 0000000000..ff243ceeff --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php @@ -0,0 +1,102 @@ +assertFalse(is_dir($dir)); + + $this->driver = new FilesystemCache($dir); + $this->assertTrue(is_dir($dir)); + + return $this->driver; + } + + public function testLifetime() + { + $cache = $this->_getCacheDriver(); + + // Test save + $cache->save('test_key', 'testing this out', 10); + + // Test contains to test that save() worked + $this->assertTrue($cache->contains('test_key')); + + // Test fetch + $this->assertEquals('testing this out', $cache->fetch('test_key')); + + // access private methods + $getFilename = new \ReflectionMethod($cache, 'getFilename'); + $getNamespacedId = new \ReflectionMethod($cache, 'getNamespacedId'); + + $getFilename->setAccessible(true); + $getNamespacedId->setAccessible(true); + + $id = $getNamespacedId->invoke($cache, 'test_key'); + $filename = $getFilename->invoke($cache, $id); + + $data = ''; + $lifetime = 0; + $resource = fopen($filename, "r"); + + if (false !== ($line = fgets($resource))) { + $lifetime = (integer) $line; + } + + while (false !== ($line = fgets($resource))) { + $data .= $line; + } + + $this->assertNotEquals(0, $lifetime, "previous lifetime could not be loaded"); + + // update lifetime + $lifetime = $lifetime - 20; + file_put_contents($filename, $lifetime . PHP_EOL . $data); + + // test expired data + $this->assertFalse($cache->contains('test_key')); + $this->assertFalse($cache->fetch('test_key')); + } + + public function testGetStats() + { + $cache = $this->_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertNull($stats[Cache::STATS_HITS]); + $this->assertNull($stats[Cache::STATS_MISSES]); + $this->assertNull($stats[Cache::STATS_UPTIME]); + $this->assertEquals(0, $stats[Cache::STATS_MEMORY_USAGE]); + $this->assertGreaterThan(0, $stats[Cache::STATS_MEMORY_AVAILABLE]); + } + + public function tearDown() + { + $dir = $this->driver->getDirectory(); + $ext = $this->driver->getExtension(); + $iterator = new \RecursiveDirectoryIterator($dir); + + foreach (new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST) as $file) { + if ($file->isFile()) { + @unlink($file->getRealPath()); + } else { + @rmdir($file->getRealPath()); + } + } + } + +} diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php new file mode 100644 index 0000000000..36c180c935 --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php @@ -0,0 +1,45 @@ +_memcache = new \Memcache; + $ok = @$this->_memcache->connect('localhost', 11211); + if (!$ok) { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of memcache'); + } + } else { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of memcache'); + } + } + + public function testNoExpire() { + $cache = $this->_getCacheDriver(); + $cache->save('noexpire', 'value', 0); + sleep(1); + $this->assertTrue($cache->contains('noexpire'), 'Memcache provider should support no-expire'); + } + + public function testLongLifetime() + { + $cache = $this->_getCacheDriver(); + $cache->save('key', 'value', 30 * 24 * 3600 + 1); + $this->assertTrue($cache->contains('key'), 'Memcache provider should support TTL > 30 days'); + } + + protected function _getCacheDriver() + { + $driver = new MemcacheCache(); + $driver->setMemcache($this->_memcache); + return $driver; + } + +} diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php new file mode 100644 index 0000000000..ecbe5a6001 --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php @@ -0,0 +1,48 @@ +memcached = new \Memcached(); + $this->memcached->setOption(\Memcached::OPT_COMPRESSION, false); + $this->memcached->addServer('127.0.0.1', 11211); + + $fh = @fsockopen('127.0.0.1', 11211); + if (!$fh) { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of memcache'); + } + } else { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of memcache'); + } + } + + public function testNoExpire() { + $cache = $this->_getCacheDriver(); + $cache->save('noexpire', 'value', 0); + sleep(1); + $this->assertTrue($cache->contains('noexpire'), 'Memcache provider should support no-expire'); + } + + public function testLongLifetime() + { + $cache = $this->_getCacheDriver(); + $cache->save('key', 'value', 30 * 24 * 3600 + 1); + + $this->assertTrue($cache->contains('key'), 'Memcached provider should support TTL > 30 days'); + } + + protected function _getCacheDriver() + { + $driver = new MemcachedCache(); + $driver->setMemcached($this->memcached); + return $driver; + } +} diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php new file mode 100644 index 0000000000..1f13b27431 --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php @@ -0,0 +1,154 @@ +assertFalse(is_dir($dir)); + + $this->driver = new PhpFileCache($dir); + $this->assertTrue(is_dir($dir)); + + return $this->driver; + } + + public function testObjects() + { + $this->markTestSkipped('PhpFileCache does not support saving objects that dont implement __set_state()'); + } + + public function testLifetime() + { + $cache = $this->_getCacheDriver(); + + // Test save + $cache->save('test_key', 'testing this out', 10); + + // Test contains to test that save() worked + $this->assertTrue($cache->contains('test_key')); + + // Test fetch + $this->assertEquals('testing this out', $cache->fetch('test_key')); + + // access private methods + $getFilename = new \ReflectionMethod($cache, 'getFilename'); + $getNamespacedId = new \ReflectionMethod($cache, 'getNamespacedId'); + + $getFilename->setAccessible(true); + $getNamespacedId->setAccessible(true); + + $id = $getNamespacedId->invoke($cache, 'test_key'); + $path = $getFilename->invoke($cache, $id); + $value = include $path; + + // update lifetime + $value['lifetime'] = $value['lifetime'] - 20; + file_put_contents($path, 'assertFalse($cache->contains('test_key')); + $this->assertFalse($cache->fetch('test_key')); + } + + public function testImplementsSetState() + { + $cache = $this->_getCacheDriver(); + + // Test save + $cache->save('test_set_state', new SetStateClass(array(1,2,3))); + + //Test __set_state call + $this->assertCount(0, SetStateClass::$values); + + // Test fetch + $value = $cache->fetch('test_set_state'); + $this->assertInstanceOf('Doctrine\Tests\Common\Cache\SetStateClass', $value); + $this->assertEquals(array(1,2,3), $value->getValue()); + + //Test __set_state call + $this->assertCount(1, SetStateClass::$values); + + // Test contains + $this->assertTrue($cache->contains('test_set_state')); + } + + public function testNotImplementsSetState() + { + $cache = $this->_getCacheDriver(); + + $this->setExpectedException('InvalidArgumentException'); + $cache->save('test_not_set_state', new NotSetStateClass(array(1,2,3))); + } + + public function testGetStats() + { + $cache = $this->_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertNull($stats[Cache::STATS_HITS]); + $this->assertNull($stats[Cache::STATS_MISSES]); + $this->assertNull($stats[Cache::STATS_UPTIME]); + $this->assertEquals(0, $stats[Cache::STATS_MEMORY_USAGE]); + $this->assertGreaterThan(0, $stats[Cache::STATS_MEMORY_AVAILABLE]); + } + + public function tearDown() + { + if (!$this->driver) { + return; + } + + $dir = $this->driver->getDirectory(); + $ext = $this->driver->getExtension(); + $iterator = new \RecursiveDirectoryIterator($dir); + + foreach (new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST) as $file) { + if ($file->isFile()) { + @unlink($file->getRealPath()); + } else { + @rmdir($file->getRealPath()); + } + } + } + +} + +class NotSetStateClass +{ + private $value; + + public function __construct($value) + { + $this->value = $value; + } + + public function getValue() + { + return $this->value; + } +} + +class SetStateClass extends NotSetStateClass +{ + public static $values = array(); + + public static function __set_state($data) + { + self::$values = $data; + return new self($data['value']); + } +} diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php new file mode 100644 index 0000000000..45bbc752af --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php @@ -0,0 +1,30 @@ +_redis = new \Redis(); + $ok = @$this->_redis->connect('127.0.0.1'); + if (!$ok) { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of redis'); + } + } else { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of redis'); + } + } + + protected function _getCacheDriver() + { + $driver = new RedisCache(); + $driver->setRedis($this->_redis); + return $driver; + } +} diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RiakCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RiakCacheTest.php new file mode 100644 index 0000000000..dce8cc00e2 --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/RiakCacheTest.php @@ -0,0 +1,64 @@ +markTestSkipped('The ' . __CLASS__ .' requires the use of Riak'); + } + + try { + $this->connection = new Connection('127.0.0.1', 8087); + $this->bucket = new Bucket($this->connection, 'test'); + } catch (Exception\RiakException $e) { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of Riak'); + } + } + + /** + * {@inheritdoc} + */ + public function testGetStats() + { + $cache = $this->_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertNull($stats); + } + + /** + * Retrieve RiakCache instance. + * + * @return \Doctrine\Common\Cache\RiakCache + */ + protected function _getCacheDriver() + { + return new RiakCache($this->bucket); + } +} diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php new file mode 100644 index 0000000000..cb363df956 --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php @@ -0,0 +1,20 @@ +markTestSkipped('The ' . __CLASS__ .' requires the use of Wincache'); + } + } + + protected function _getCacheDriver() + { + return new WincacheCache(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/XcacheCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/XcacheCacheTest.php new file mode 100644 index 0000000000..6259848776 --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/XcacheCacheTest.php @@ -0,0 +1,20 @@ +markTestSkipped('The ' . __CLASS__ .' requires the use of xcache'); + } + } + + protected function _getCacheDriver() + { + return new XcacheCache(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ZendDataCacheTest.php b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ZendDataCacheTest.php new file mode 100644 index 0000000000..cd66e1578f --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/Common/Cache/ZendDataCacheTest.php @@ -0,0 +1,28 @@ +markTestSkipped('The ' . __CLASS__ .' requires the use of Zend Data Cache which only works in apache2handler SAPI'); + } + } + + public function testGetStats() + { + $cache = $this->_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertNull($stats); + } + + protected function _getCacheDriver() + { + return new ZendDataCache(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/cache/tests/Doctrine/Tests/DoctrineTestCase.php b/vendor/doctrine/cache/tests/Doctrine/Tests/DoctrineTestCase.php new file mode 100644 index 0000000000..e8323d2940 --- /dev/null +++ b/vendor/doctrine/cache/tests/Doctrine/Tests/DoctrineTestCase.php @@ -0,0 +1,10 @@ +on('user.create', function (User $user) use ($logger) { + $logger->log(sprintf("User '%s' was created.", $user->getLogin())); +}); +``` + +### Emitting Events + +```php +emit('user.create', array($user)); +``` + +Tests +----- + + $ phpunit + +License +------- +MIT, see LICENSE. diff --git a/vendor/evenement/evenement/composer.json b/vendor/evenement/evenement/composer.json new file mode 100644 index 0000000000..5426833cd4 --- /dev/null +++ b/vendor/evenement/evenement/composer.json @@ -0,0 +1,20 @@ +{ + "name": "evenement/evenement", + "description": "Événement is a very simple event dispatching library for PHP 5.3", + "keywords": ["event-dispatcher"], + "license": "MIT", + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-0": { + "Evenement": "src" + } + } +} diff --git a/vendor/evenement/evenement/phpunit.xml.dist b/vendor/evenement/evenement/phpunit.xml.dist new file mode 100644 index 0000000000..8be0651849 --- /dev/null +++ b/vendor/evenement/evenement/phpunit.xml.dist @@ -0,0 +1,25 @@ + + + + + + ./tests/Evenement/ + + + + + + ./src/ + + + diff --git a/vendor/evenement/evenement/src/Evenement/EventEmitter.php b/vendor/evenement/evenement/src/Evenement/EventEmitter.php new file mode 100644 index 0000000000..df591c8576 --- /dev/null +++ b/vendor/evenement/evenement/src/Evenement/EventEmitter.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 Evenement; + +class EventEmitter implements EventEmitterInterface +{ + protected $listeners = array(); + + public function on($event, $listener) + { + if (!is_callable($listener)) { + throw new \InvalidArgumentException('The provided listener was not a valid callable.'); + } + + if (!isset($this->listeners[$event])) { + $this->listeners[$event] = array(); + } + + $this->listeners[$event][] = $listener; + } + + public function once($event, $listener) + { + $that = $this; + + $onceListener = function () use ($that, &$onceListener, $event, $listener) { + $that->removeListener($event, $onceListener); + + call_user_func_array($listener, func_get_args()); + }; + + $this->on($event, $onceListener); + } + + public function removeListener($event, $listener) + { + if (isset($this->listeners[$event])) { + if (false !== $index = array_search($listener, $this->listeners[$event], true)) { + unset($this->listeners[$event][$index]); + } + } + } + + public function removeAllListeners($event = null) + { + if ($event !== null) { + unset($this->listeners[$event]); + } else { + $this->listeners = array(); + } + } + + public function listeners($event) + { + return isset($this->listeners[$event]) ? $this->listeners[$event] : array(); + } + + public function emit($event, array $arguments = array()) + { + foreach ($this->listeners($event) as $listener) { + call_user_func_array($listener, $arguments); + } + } +} diff --git a/vendor/evenement/evenement/src/Evenement/EventEmitter2.php b/vendor/evenement/evenement/src/Evenement/EventEmitter2.php new file mode 100644 index 0000000000..b051609986 --- /dev/null +++ b/vendor/evenement/evenement/src/Evenement/EventEmitter2.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Evenement; + +class EventEmitter2 extends EventEmitter +{ + protected $options; + protected $anyListeners = array(); + + public function __construct(array $options = array()) + { + $this->options = array_merge(array( + 'delimiter' => '.', + ), $options); + } + + public function onAny($listener) + { + $this->anyListeners[] = $listener; + } + + public function offAny($listener) + { + if (false !== $index = array_search($listener, $this->anyListeners, true)) { + unset($this->anyListeners[$index]); + } + } + + public function many($event, $timesToListen, $listener) + { + $that = $this; + + $timesListened = 0; + + if ($timesToListen == 0) { + return; + } + + if ($timesToListen < 0) { + throw new \OutOfRangeException('You cannot listen less than zero times.'); + } + + $manyListener = function () use ($that, &$timesListened, &$manyListener, $event, $timesToListen, $listener) { + if (++$timesListened == $timesToListen) { + $that->removeListener($event, $manyListener); + } + + call_user_func_array($listener, func_get_args()); + }; + + $this->on($event, $manyListener); + } + + public function emit($event, array $arguments = array()) + { + foreach ($this->anyListeners as $listener) { + call_user_func_array($listener, $arguments); + } + + parent::emit($event, $arguments); + } + + public function listeners($event) + { + $matchedListeners = array(); + + foreach ($this->listeners as $name => $listeners) { + foreach ($listeners as $listener) { + if ($this->matchEventName($event, $name)) { + $matchedListeners[] = $listener; + } + } + } + + return $matchedListeners; + } + + protected function matchEventName($matchPattern, $eventName) + { + $patternParts = explode($this->options['delimiter'], $matchPattern); + $nameParts = explode($this->options['delimiter'], $eventName); + + if (count($patternParts) != count($nameParts)) { + return false; + } + + $size = min(count($patternParts), count($nameParts)); + for ($i = 0; $i < $size; $i++) { + $patternPart = $patternParts[$i]; + $namePart = $nameParts[$i]; + + if ('*' === $patternPart || '*' === $namePart) { + continue; + } + + if ($namePart === $patternPart) { + continue; + } + + return false; + } + + return true; + } +} diff --git a/vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php b/vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php new file mode 100644 index 0000000000..665a9478c3 --- /dev/null +++ b/vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Evenement; + +interface EventEmitterInterface +{ + public function on($event, $listener); + public function once($event, $listener); + public function removeListener($event, $listener); + public function removeAllListeners($event = null); + public function listeners($event); + public function emit($event, array $arguments = array()); +} diff --git a/vendor/evenement/evenement/tests/Evenement/Tests/EventEmitter2Test.php b/vendor/evenement/evenement/tests/Evenement/Tests/EventEmitter2Test.php new file mode 100644 index 0000000000..7be4290452 --- /dev/null +++ b/vendor/evenement/evenement/tests/Evenement/Tests/EventEmitter2Test.php @@ -0,0 +1,160 @@ +emitter = new EventEmitter2(); + } + + // matching tests from + // test/wildcardEvents/addListener.js + + public function testWildcardMatching7() + { + $listenerCalled = 0; + + $listener = function () use (&$listenerCalled) { + $listenerCalled++; + }; + + $this->emitter->on('*.test', $listener); + $this->emitter->on('*.*', $listener); + $this->emitter->on('*', $listener); + + $this->emitter->emit('other.emit'); + $this->emitter->emit('foo.test'); + + $this->assertSame(3, $listenerCalled); + } + + public function testWildcardMatching8() + { + $listenerCalled = 0; + + $listener = function () use (&$listenerCalled) { + $listenerCalled++; + }; + + $this->emitter->on('foo.test', $listener); + $this->emitter->on('*.*', $listener); + $this->emitter->on('*', $listener); + + $this->emitter->emit('*.*'); + $this->emitter->emit('foo.test'); + $this->emitter->emit('*'); + + $this->assertSame(5, $listenerCalled); + } + + public function testOnAny() + { + $this->emitter->onAny(function () {}); + } + + public function testOnAnyWithEmit() + { + $listenerCalled = 0; + + $this->emitter->onAny(function () use (&$listenerCalled) { + $listenerCalled++; + }); + + $this->assertSame(0, $listenerCalled); + + $this->emitter->emit('foo'); + + $this->assertSame(1, $listenerCalled); + + $this->emitter->emit('bar'); + + $this->assertSame(2, $listenerCalled); + } + + public function testoffAnyWithEmit() + { + $listenerCalled = 0; + + $listener = function () use (&$listenerCalled) { + $listenerCalled++; + }; + + $this->emitter->onAny($listener); + $this->emitter->offAny($listener); + + $this->assertSame(0, $listenerCalled); + $this->emitter->emit('foo'); + $this->assertSame(0, $listenerCalled); + } + + /** + * @dataProvider provideMany + */ + public function testMany($amount) + { + $listenerCalled = 0; + + $this->emitter->many('foo', $amount, function () use (&$listenerCalled) { + $listenerCalled++; + }); + + for ($i = 0; $i < $amount; $i++) { + $this->assertSame($i, $listenerCalled); + $this->emitter->emit('foo'); + } + + $this->emitter->emit('foo'); + $this->assertSame($amount, $listenerCalled); + } + + public function provideMany() + { + return array( + array(0), + array(1), + array(2), + array(3), + array(4), + array(400), + ); + } + + /** + * @expectedException OutOfRangeException + */ + public function testManyWithLessThanZeroTtl() + { + $this->emitter->many('foo', -1, function () {}); + $this->emitter->emit('foo'); + } +} diff --git a/vendor/evenement/evenement/tests/Evenement/Tests/EventEmitterTest.php b/vendor/evenement/evenement/tests/Evenement/Tests/EventEmitterTest.php new file mode 100644 index 0000000000..3f6be1dd68 --- /dev/null +++ b/vendor/evenement/evenement/tests/Evenement/Tests/EventEmitterTest.php @@ -0,0 +1,236 @@ +emitter = new EventEmitter(); + } + + public function testAddListenerWithLambda() + { + $this->emitter->on('foo', function () {}); + } + + public function testAddListenerWithMethod() + { + $listener = new Listener(); + $this->emitter->on('foo', array($listener, 'onFoo')); + } + + public function testAddListenerWithStaticMethod() + { + $this->emitter->on('bar', array('Evenement\Tests\Listener', 'onBar')); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testAddListenerWithInvalidListener() + { + $this->emitter->on('foo', 'not a callable'); + } + + public function testOnce() + { + $listenerCalled = 0; + + $this->emitter->once('foo', function () use (&$listenerCalled) { + $listenerCalled++; + }); + + $this->assertSame(0, $listenerCalled); + + $this->emitter->emit('foo'); + + $this->assertSame(1, $listenerCalled); + + $this->emitter->emit('foo'); + + $this->assertSame(1, $listenerCalled); + } + + public function testEmitWithoutArguments() + { + $listenerCalled = false; + + $this->emitter->on('foo', function () use (&$listenerCalled) { + $listenerCalled = true; + }); + + $this->assertSame(false, $listenerCalled); + $this->emitter->emit('foo'); + $this->assertSame(true, $listenerCalled); + } + + public function testEmitWithOneArgument() + { + $test = $this; + + $listenerCalled = false; + + $this->emitter->on('foo', function ($value) use (&$listenerCalled, $test) { + $listenerCalled = true; + + $test->assertSame('bar', $value); + }); + + $this->assertSame(false, $listenerCalled); + $this->emitter->emit('foo', array('bar')); + $this->assertSame(true, $listenerCalled); + } + + public function testEmitWithTwoArguments() + { + $test = $this; + + $listenerCalled = false; + + $this->emitter->on('foo', function ($arg1, $arg2) use (&$listenerCalled, $test) { + $listenerCalled = true; + + $test->assertSame('bar', $arg1); + $test->assertSame('baz', $arg2); + }); + + $this->assertSame(false, $listenerCalled); + $this->emitter->emit('foo', array('bar', 'baz')); + $this->assertSame(true, $listenerCalled); + } + + public function testEmitWithNoListeners() + { + $this->emitter->emit('foo'); + $this->emitter->emit('foo', array('bar')); + $this->emitter->emit('foo', array('bar', 'baz')); + } + + public function testEmitWithTwoListeners() + { + $listenersCalled = 0; + + $this->emitter->on('foo', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->emitter->on('foo', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->assertSame(2, $listenersCalled); + } + + public function testRemoveListenerMatching() + { + $listenersCalled = 0; + + $listener = function () use (&$listenersCalled) { + $listenersCalled++; + }; + + $this->emitter->on('foo', $listener); + $this->emitter->removeListener('foo', $listener); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->assertSame(0, $listenersCalled); + } + + public function testRemoveListenerNotMatching() + { + $listenersCalled = 0; + + $listener = function () use (&$listenersCalled) { + $listenersCalled++; + }; + + $this->emitter->on('foo', $listener); + $this->emitter->removeListener('bar', $listener); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->assertSame(1, $listenersCalled); + } + + public function testRemoveAllListenersMatching() + { + $listenersCalled = 0; + + $this->emitter->on('foo', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->emitter->removeAllListeners('foo'); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->assertSame(0, $listenersCalled); + } + + public function testRemoveAllListenersNotMatching() + { + $listenersCalled = 0; + + $this->emitter->on('foo', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->emitter->removeAllListeners('bar'); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->assertSame(1, $listenersCalled); + } + + public function testRemoveAllListenersWithoutArguments() + { + $listenersCalled = 0; + + $this->emitter->on('foo', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->emitter->on('bar', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->emitter->removeAllListeners(); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->emitter->emit('bar'); + $this->assertSame(0, $listenersCalled); + } +} diff --git a/vendor/evenement/evenement/tests/Evenement/Tests/Listener.php b/vendor/evenement/evenement/tests/Evenement/Tests/Listener.php new file mode 100644 index 0000000000..7032442aa8 --- /dev/null +++ b/vendor/evenement/evenement/tests/Evenement/Tests/Listener.php @@ -0,0 +1,38 @@ +add('Evenement\Tests', __DIR__); diff --git a/vendor/monolog/monolog/CHANGELOG.mdown b/vendor/monolog/monolog/CHANGELOG.mdown new file mode 100644 index 0000000000..2df1e0f1aa --- /dev/null +++ b/vendor/monolog/monolog/CHANGELOG.mdown @@ -0,0 +1,110 @@ +### 1.6.0 (2013-07-29) + + * Added HipChatHandler to send logs to a HipChat chat room + * Added ErrorLogHandler to send logs to PHP's error_log function + * Added NewRelicHandler to send logs to NewRelic's service + * Added Monolog\ErrorHandler helper class to register a Logger as exception/error/fatal handler + * Added ChannelLevelActivationStrategy for the FingersCrossedHandler to customize levels by channel + * Added stack traces output when normalizing exceptions (json output & co) + * Added Monolog\Logger::API constant (currently 1) + * Added support for ChromePHP's v4.0 extension + * Added support for message priorities in PushoverHandler, see $highPriorityLevel and $emergencyLevel + * Added support for sending messages to multiple users at once with the PushoverHandler + * Fixed RavenHandler's support for batch sending of messages (when behind a Buffer or FingersCrossedHandler) + * Fixed normalization of Traversables with very large data sets, only the first 1000 items are shown now + * Fixed issue in RotatingFileHandler when an open_basedir restriction is active + * Fixed minor issues in RavenHandler and bumped the API to Raven 0.5.0 + * Fixed SyslogHandler issue when many were used concurrently with different facilities + +### 1.5.0 (2013-04-23) + + * Added ProcessIdProcessor to inject the PID in log records + * Added UidProcessor to inject a unique identifier to all log records of one request/run + * Added support for previous exceptions in the LineFormatter exception serialization + * Added Monolog\Logger::getLevels() to get all available levels + * Fixed ChromePHPHandler so it avoids sending headers larger than Chrome can handle + +### 1.4.1 (2013-04-01) + + * Fixed exception formatting in the LineFormatter to be more minimalistic + * Fixed RavenHandler's handling of context/extra data, requires Raven client >0.1.0 + * Fixed log rotation in RotatingFileHandler to work with long running scripts spanning multiple days + * Fixed WebProcessor array access so it checks for data presence + * Fixed Buffer, Group and FingersCrossed handlers to make use of their processors + +### 1.4.0 (2013-02-13) + + * Added RedisHandler to log to Redis via the Predis library or the phpredis extension + * Added ZendMonitorHandler to log to the Zend Server monitor + * Added the possibility to pass arrays of handlers and processors directly in the Logger constructor + * Added `$useSSL` option to the PushoverHandler which is enabled by default + * Fixed ChromePHPHandler and FirePHPHandler issue when multiple instances are used simultaneously + * Fixed header injection capability in the NativeMailHandler + +### 1.3.1 (2013-01-11) + + * Fixed LogstashFormatter to be usable with stream handlers + * Fixed GelfMessageFormatter levels on Windows + +### 1.3.0 (2013-01-08) + + * Added PSR-3 compliance, the `Monolog\Logger` class is now an instance of `Psr\Log\LoggerInterface` + * Added PsrLogMessageProcessor that you can selectively enable for full PSR-3 compliance + * Added LogstashFormatter (combine with SocketHandler or StreamHandler to send logs to Logstash) + * Added PushoverHandler to send mobile notifications + * Added CouchDBHandler and DoctrineCouchDBHandler + * Added RavenHandler to send data to Sentry servers + * Added support for the new MongoClient class in MongoDBHandler + * Added microsecond precision to log records' timestamps + * Added `$flushOnOverflow` param to BufferHandler to flush by batches instead of losing + the oldest entries + * Fixed normalization of objects with cyclic references + +### 1.2.1 (2012-08-29) + + * Added new $logopts arg to SyslogHandler to provide custom openlog options + * Fixed fatal error in SyslogHandler + +### 1.2.0 (2012-08-18) + + * Added AmqpHandler (for use with AMQP servers) + * Added CubeHandler + * Added NativeMailerHandler::addHeader() to send custom headers in mails + * Added the possibility to specify more than one recipient in NativeMailerHandler + * Added the possibility to specify float timeouts in SocketHandler + * Added NOTICE and EMERGENCY levels to conform with RFC 5424 + * Fixed the log records to use the php default timezone instead of UTC + * Fixed BufferHandler not being flushed properly on PHP fatal errors + * Fixed normalization of exotic resource types + * Fixed the default format of the SyslogHandler to avoid duplicating datetimes in syslog + +### 1.1.0 (2012-04-23) + + * Added Monolog\Logger::isHandling() to check if a handler will + handle the given log level + * Added ChromePHPHandler + * Added MongoDBHandler + * Added GelfHandler (for use with Graylog2 servers) + * Added SocketHandler (for use with syslog-ng for example) + * Added NormalizerFormatter + * Added the possibility to change the activation strategy of the FingersCrossedHandler + * Added possibility to show microseconds in logs + * Added `server` and `referer` to WebProcessor output + +### 1.0.2 (2011-10-24) + + * Fixed bug in IE with large response headers and FirePHPHandler + +### 1.0.1 (2011-08-25) + + * Added MemoryPeakUsageProcessor and MemoryUsageProcessor + * Added Monolog\Logger::getName() to get a logger's channel name + +### 1.0.0 (2011-07-06) + + * Added IntrospectionProcessor to get info from where the logger was called + * Fixed WebProcessor in CLI + +### 1.0.0-RC1 (2011-07-01) + + * Initial release diff --git a/vendor/monolog/monolog/LICENSE b/vendor/monolog/monolog/LICENSE new file mode 100644 index 0000000000..5df1c397f7 --- /dev/null +++ b/vendor/monolog/monolog/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) Jordi Boggiano + +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/monolog/monolog/README.mdown b/vendor/monolog/monolog/README.mdown new file mode 100644 index 0000000000..9d20546996 --- /dev/null +++ b/vendor/monolog/monolog/README.mdown @@ -0,0 +1,248 @@ +Monolog - Logging for PHP 5.3+ [![Build Status](https://secure.travis-ci.org/Seldaek/monolog.png)](http://travis-ci.org/Seldaek/monolog) +============================== + +[![Total Downloads](https://poser.pugx.org/monolog/monolog/downloads.png)](https://packagist.org/packages/monolog/monolog) +[![Latest Stable Version](https://poser.pugx.org/monolog/monolog/v/stable.png)](https://packagist.org/packages/monolog/monolog) + + +Monolog sends your logs to files, sockets, inboxes, databases and various +web services. See the complete list of handlers below. Special handlers +allow you to build advanced logging strategies. + +This library implements the [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +interface that you can type-hint against in your own libraries to keep +a maximum of interoperability. You can also use it in your applications to +make sure you can always use another compatible logger at a later time. + +Usage +----- + +```php +pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING)); + +// add records to the log +$log->addWarning('Foo'); +$log->addError('Bar'); +``` + +Core Concepts +------------- + +Every `Logger` instance has a channel (name) and a stack of handlers. Whenever +you add a record to the logger, it traverses the handler stack. Each handler +decides whether it handled fully the record, and if so, the propagation of the +record ends there. + +This allows for flexible logging setups, for example having a `StreamHandler` at +the bottom of the stack that will log anything to disk, and on top of that add +a `MailHandler` that will send emails only when an error message is logged. +Handlers also have a `$bubble` property which defines whether they block the +record or not if they handled it. In this example, setting the `MailHandler`'s +`$bubble` argument to true means that all records will propagate to the +`StreamHandler`, even the errors that are handled by the `MailHandler`. + +You can create many `Logger`s, each defining a channel (e.g.: db, request, +router, ..) and each of them combining various handlers, which can be shared +or not. The channel is reflected in the logs and allows you to easily see or +filter records. + +Each Handler also has a Formatter, a default one with settings that make sense +will be created if you don't set one. The formatters normalize and format +incoming records so that they can be used by the handlers to output useful +information. + +Custom severity levels are not available. Only the eight +[RFC 5424](http://tools.ietf.org/html/rfc5424) levels (debug, info, notice, +warning, error, critical, alert, emergency) are present for basic filtering +purposes, but for sorting and other use cases that would require +flexibility, you should add Processors to the Logger that can add extra +information (tags, user ip, ..) to the records before they are handled. + +Log Levels +---------- + +Monolog supports all 8 logging levels defined in +[RFC 5424](http://tools.ietf.org/html/rfc5424), but unless you specifically +need syslog compatibility, it is advised to only use DEBUG, INFO, WARNING, +ERROR, CRITICAL, ALERT. + +- **DEBUG** (100): Detailed debug information. + +- **INFO** (200): Interesting events. Examples: User logs in, SQL logs. + +- NOTICE (250): Normal but significant events. + +- **WARNING** (300): Exceptional occurrences that are not errors. Examples: + Use of deprecated APIs, poor use of an API, undesirable things that are not + necessarily wrong. + +- **ERROR** (400): Runtime errors that do not require immediate action but + should typically be logged and monitored. + +- **CRITICAL** (500): Critical conditions. Example: Application component + unavailable, unexpected exception. + +- **ALERT** (550): Action must be taken immediately. Example: Entire website + down, database unavailable, etc. This should trigger the SMS alerts and wake + you up. + +- EMERGENCY (600): Emergency: system is unusable. + +Docs +==== + +**See the `doc` directory for more detailed documentation. +The following is only a list of all parts that come with Monolog.** + +Handlers +-------- + +### Log to files and syslog + +- _StreamHandler_: Logs records into any PHP stream, use this for log files. +- _RotatingFileHandler_: Logs records to a file and creates one logfile per day. + It will also delete files older than `$maxFiles`. You should use + [logrotate](http://linuxcommand.org/man_pages/logrotate8.html) for high profile + setups though, this is just meant as a quick and dirty solution. +- _SyslogHandler_: Logs records to the syslog. +- _ErrorLogHandler_: Logs records to PHP's + [`error_log()`](http://docs.php.net/manual/en/function.error-log.php) function. + +### Send alerts and emails + +- _NativeMailerHandler_: Sends emails using PHP's + [`mail()`](http://php.net/manual/en/function.mail.php) function. +- _SwiftMailerHandler_: Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance. +- _PushoverHandler_: Sends mobile notifications via the [Pushover](https://www.pushover.net/) API. +- _HipChatHandler_: Logs records to a [HipChat](http://hipchat.com) chat room using its API. + +### Log specific servers and networked logging + +- _SocketHandler_: Logs records to [sockets](http://php.net/fsockopen), use this + for UNIX and TCP sockets. See an [example](https://github.com/Seldaek/monolog/blob/master/doc/sockets.md). +- _AmqpHandler_: Logs records to an [amqp](http://www.amqp.org/) compatible + server. Requires the [php-amqp](http://pecl.php.net/package/amqp) extension (1.0+). +- _GelfHandler_: Logs records to a [Graylog2](http://www.graylog2.org) server. +- _CubeHandler_: Logs records to a [Cube](http://square.github.com/cube/) server. +- _RavenHandler_: Logs records to a [Sentry](http://getsentry.com/) server using + [raven](https://packagist.org/packages/raven/raven). +- _ZendMonitorHandler_: Logs records to the Zend Monitor present in Zend Server. +- _NewRelicHandler_: Logs records to a [NewRelic](http://newrelic.com/) application. + +### Logging in development + +- _FirePHPHandler_: Handler for [FirePHP](http://www.firephp.org/), providing + inline `console` messages within [FireBug](http://getfirebug.com/). +- _ChromePHPHandler_: Handler for [ChromePHP](http://www.chromephp.com/), providing + inline `console` messages within Chrome. + +### Log to databases + +- _RedisHandler_: Logs records to a [redis](http://redis.io) server. +- _MongoDBHandler_: Handler to write records in MongoDB via a + [Mongo](http://pecl.php.net/package/mongo) extension connection. +- _CouchDBHandler_: Logs records to a CouchDB server. +- _DoctrineCouchDBHandler_: Logs records to a CouchDB server via the Doctrine CouchDB ODM. + +### Wrappers / Special Handlers + +- _FingersCrossedHandler_: A very interesting wrapper. It takes a logger as + parameter and will accumulate log records of all levels until a record + exceeds the defined severity level. At which point it delivers all records, + including those of lower severity, to the handler it wraps. This means that + until an error actually happens you will not see anything in your logs, but + when it happens you will have the full information, including debug and info + records. This provides you with all the information you need, but only when + you need it. +- _NullHandler_: Any record it can handle will be thrown away. This can be used + to put on top of an existing handler stack to disable it temporarily. +- _BufferHandler_: This handler will buffer all the log records it receives + until `close()` is called at which point it will call `handleBatch()` on the + handler it wraps with all the log messages at once. This is very useful to + send an email with all records at once for example instead of having one mail + for every log record. +- _GroupHandler_: This handler groups other handlers. Every record received is + sent to all the handlers it is configured with. +- _TestHandler_: Used for testing, it records everything that is sent to it and + has accessors to read out the information. + +Formatters +---------- + +- _LineFormatter_: Formats a log record into a one-line string. +- _NormalizerFormatter_: Normalizes objects/resources down to strings so a record can easily be serialized/encoded. +- _JsonFormatter_: Encodes a log record into json. +- _WildfireFormatter_: Used to format log records into the Wildfire/FirePHP protocol, only useful for the FirePHPHandler. +- _ChromePHPFormatter_: Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler. +- _GelfFormatter_: Used to format log records into Gelf message instances, only useful for the GelfHandler. +- _LogstashFormatter_: Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/1.1.5/). + +Processors +---------- + +- _IntrospectionProcessor_: Adds the line/file/class/method from which the log call originated. +- _WebProcessor_: Adds the current request URI, request method and client IP to a log record. +- _MemoryUsageProcessor_: Adds the current memory usage to a log record. +- _MemoryPeakUsageProcessor_: Adds the peak memory usage to a log record. +- _ProcessIdProcessor_: Adds the process id to a log record. +- _UidProcessor_: Adds a unique identifier to a log record. + +Utilities +--------- + +- _ErrorHandler_: The `Monolog\ErrorHandler` class allows you to easily register + a Logger instance as an exception handler, error handler or fatal error handler. +- _ErrorLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain log + level is reached. +- _ChannelLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain + log level is reached, depending on which channel received the log record. + +About +===== + +Requirements +------------ + +- Any flavor of PHP 5.3 or above should do +- [optional] PHPUnit 3.5+ to execute the test suite (phpunit --version) + +Submitting bugs and feature requests +------------------------------------ + +Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/monolog/issues) + +Frameworks Integration +---------------------- + +- Frameworks and libraries using [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) + can be used very easily with Monolog since it implements the interface. +- [Symfony2](http://symfony.com) comes out of the box with Monolog. +- [Silex](http://silex.sensiolabs.org/) comes out of the box with Monolog. +- [Laravel4](http://laravel.com/) comes out of the box with Monolog. +- [PPI](http://www.ppi.io/) comes out of the box with Monolog. +- [CakePHP](http://cakephp.org/) is usable with Monolog via the [cakephp-monolog](https://github.com/jadb/cakephp-monolog) plugin. +- [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer. + +Author +------ + +Jordi Boggiano - -
+See also the list of [contributors](https://github.com/Seldaek/monolog/contributors) which participated in this project. + +License +------- + +Monolog is licensed under the MIT License - see the `LICENSE` file for details + +Acknowledgements +---------------- + +This library is heavily inspired by Python's [Logbook](http://packages.python.org/Logbook/) +library, although most concepts have been adjusted to fit to the PHP world. diff --git a/vendor/monolog/monolog/composer.json b/vendor/monolog/monolog/composer.json new file mode 100644 index 0000000000..c89e1886c7 --- /dev/null +++ b/vendor/monolog/monolog/composer.json @@ -0,0 +1,39 @@ +{ + "name": "monolog/monolog", + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "keywords": ["log", "logging", "psr-3"], + "homepage": "http://github.com/Seldaek/monolog", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "require-dev": { + "mlehner/gelf-php": "1.0.*", + "raven/raven": "0.5.*", + "doctrine/couchdb": "dev-master" + }, + "suggest": { + "mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server", + "raven/raven": "Allow sending log messages to a Sentry server", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server" + }, + "autoload": { + "psr-0": {"Monolog": "src/"} + }, + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + } +} diff --git a/vendor/monolog/monolog/doc/extending.md b/vendor/monolog/monolog/doc/extending.md new file mode 100644 index 0000000000..fcd7af2b39 --- /dev/null +++ b/vendor/monolog/monolog/doc/extending.md @@ -0,0 +1,76 @@ +Extending Monolog +================= + +Monolog is fully extensible, allowing you to adapt your logger to your needs. + +Writing your own handler +------------------------ + +Monolog provides many built-in handlers. But if the one you need does not +exist, you can write it and use it in your logger. The only requirement is +to implement `Monolog\Handler\HandlerInterface`. + +Let's write a PDOHandler to log records to a database. We will extend the +abstract class provided by Monolog to keep things DRY. + +```php +pdo = $pdo; + parent::__construct($level, $bubble); + } + + protected function write(array $record) + { + if (!$this->initialized) { + $this->initialize(); + } + + $this->statement->execute(array( + 'channel' => $record['channel'], + 'level' => $record['level'], + 'message' => $record['formatted'], + 'time' => $record['datetime']->format('U'), + )); + } + + private function initialize() + { + $this->pdo->exec( + 'CREATE TABLE IF NOT EXISTS monolog ' + .'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)' + ); + $this->statement = $this->pdo->prepare( + 'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)' + ); + + $this->initialized = true; + } +} +``` + +You can now use this handler in your logger: + +```php +pushHandler(new PDOHandler(new PDO('sqlite:logs.sqlite')); + +// You can now use your logger +$logger->addInfo('My logger is now ready'); +``` + +The `Monolog\Handler\AbstractProcessingHandler` class provides most of the +logic needed for the handler, including the use of processors and the formatting +of the record (which is why we use ``$record['formatted']`` instead of ``$record['message']``). diff --git a/vendor/monolog/monolog/doc/sockets.md b/vendor/monolog/monolog/doc/sockets.md new file mode 100644 index 0000000000..fad30a9f4b --- /dev/null +++ b/vendor/monolog/monolog/doc/sockets.md @@ -0,0 +1,37 @@ +Sockets Handler +=============== + +This handler allows you to write your logs to sockets using [fsockopen](http://php.net/fsockopen) +or [pfsockopen](http://php.net/pfsockopen). + +Persistent sockets are mainly useful in web environments where you gain some performance not closing/opening +the connections between requests. + +Basic Example +------------- + +```php +setPersistent(true); + +// Now add the handler +$logger->pushHandler($handler, Logger::DEBUG); + +// You can now use your logger +$logger->addInfo('My logger is now ready'); + +``` + +In this example, using syslog-ng, you should see the log on the log server: + + cweb1 [2012-02-26 00:12:03] my_logger.INFO: My logger is now ready [] [] + diff --git a/vendor/monolog/monolog/doc/usage.md b/vendor/monolog/monolog/doc/usage.md new file mode 100644 index 0000000000..07efa78a44 --- /dev/null +++ b/vendor/monolog/monolog/doc/usage.md @@ -0,0 +1,158 @@ +Using Monolog +============= + +Installation +------------ + +Monolog is available on Packagist ([monolog/monolog](http://packagist.org/packages/monolog/monolog)) +and as such installable via [Composer](http://getcomposer.org/). + +If you do not use Composer, you can grab the code from GitHub, and use any +PSR-0 compatible autoloader (e.g. the [Symfony2 ClassLoader component](https://github.com/symfony/ClassLoader)) +to load Monolog classes. + +Configuring a logger +-------------------- + +Here is a basic setup to log to a file and to firephp on the DEBUG level: + +```php +pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG)); +$logger->pushHandler(new FirePHPHandler()); + +// You can now use your logger +$logger->addInfo('My logger is now ready'); +``` + +Let's explain it. The first step is to create the logger instance which will +be used in your code. The argument is a channel name, which is useful when +you use several loggers (see below for more details about it). + +The logger itself does not know how to handle a record. It delegates it to +some handlers. The code above registers two handlers in the stack to allow +handling records in two different ways. + +Note that the FirePHPHandler is called first as it is added on top of the +stack. This allows you to temporarily add a logger with bubbling disabled if +you want to override other configured loggers. + +Adding extra data in the records +-------------------------------- + +Monolog provides two different ways to add extra informations along the simple +textual message. + +### Using the logging context + +The first way is the context, allowing to pass an array of data along the +record: + +```php +addInfo('Adding a new user', array('username' => 'Seldaek')); +``` + +Simple handlers (like the StreamHandler for instance) will simply format +the array to a string but richer handlers can take advantage of the context +(FirePHP is able to display arrays in pretty way for instance). + +### Using processors + +The second way is to add extra data for all records by using a processor. +Processors can be any callable. They will get the record as parameter and +must return it after having eventually changed the `extra` part of it. Let's +write a processor adding some dummy data in the record: + +```php +pushProcessor(function ($record) { + $record['extra']['dummy'] = 'Hello world!'; + + return $record; +}); +``` + +Monolog provides some built-in processors that can be used in your project. +Look at the README file for the list. + +> Tip: processors can also be registered on a specific handler instead of + the logger to apply only for this handler. + +Leveraging channels +------------------- + +Channels are a great way to identify to which part of the application a record +is related. This is useful in big applications (and is leveraged by +MonologBundle in Symfony2). + +Picture two loggers sharing a handler that writes to a single log file. +Channels would allow you to identify the logger that issued every record. +You can easily grep through the log files filtering this or that channel. + +```php +pushHandler($stream); +$logger->pushHandler($firephp); + +// Create a logger for the security-related stuff with a different channel +$securityLogger = new Logger('security'); +$securityLogger->pushHandler($stream); +$securityLogger->pushHandler($firephp); +``` + +Customizing log format +---------------------- + +In Monolog it's easy to customize the format of the logs written into files, +sockets, mails, databases and other handlers. Most of the handlers use the + +```php +$record['formatted'] +``` + +value to be automatically put into the log device. This value depends on the +formatter settings. You can choose between predefined formatter classes or +write your own (e.g. a multiline text file for human-readable output). + +To configure a predefined formatter class, just set it as the handler's field: + +```php +// the default date format is "Y-m-d H:i:s" +$dateFormat = "Y n j, g:i a"; +// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n" +$output = "%datetime% > %level_name% > %message% %context% %extra%\n"; +// finally, create a formatter +$formatter = new LineFormatter($output, $dateFormat); + +// Create a handler +$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG); +$stream->setFormatter($formatter); +// bind it to a logger object +$securityLogger = new Logger('security'); +$securityLogger->pushHandler($stream); +``` + +You may also reuse the same formatter between multiple handlers and share those +handlers between multiple loggers. diff --git a/vendor/monolog/monolog/phpunit.xml.dist b/vendor/monolog/monolog/phpunit.xml.dist new file mode 100644 index 0000000000..175457071b --- /dev/null +++ b/vendor/monolog/monolog/phpunit.xml.dist @@ -0,0 +1,15 @@ + + + + + + tests/Monolog/ + + + + + + src/Monolog/ + + + diff --git a/vendor/monolog/monolog/src/Monolog/ErrorHandler.php b/vendor/monolog/monolog/src/Monolog/ErrorHandler.php new file mode 100644 index 0000000000..aa5a278a62 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/ErrorHandler.php @@ -0,0 +1,209 @@ + + * + * 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; + +/** + * Monolog error handler + * + * A facility to enable logging of runtime errors, exceptions and fatal errors. + * + * Quick setup: ErrorHandler::register($logger); + * + * @author Jordi Boggiano + */ +class ErrorHandler +{ + private $logger; + + private $previousExceptionHandler; + private $uncaughtExceptionLevel; + + private $previousErrorHandler; + private $errorLevelMap; + + private $fatalLevel; + private $reservedMemory; + private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR); + + public function __construct(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * Registers a new ErrorHandler for a given Logger + * + * By default it will handle errors, exceptions and fatal errors + * + * @param LoggerInterface $logger + * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling + * @param int|false $exceptionLevel a LogLevel::* constant, or false to disable exception handling + * @param int|false $fatalLevel a LogLevel::* constant, or false to disable fatal error handling + * @return ErrorHandler + */ + public static function register(LoggerInterface $logger, $errorLevelMap = array(), $exceptionLevel = null, $fatalLevel = null) + { + $handler = new static($logger); + if ($errorLevelMap !== false) { + $handler->registerErrorHandler($errorLevelMap); + } + if ($exceptionLevel !== false) { + $handler->registerExceptionHandler($exceptionLevel); + } + if ($fatalLevel !== false) { + $handler->registerFatalHandler($fatalLevel); + } + + return $handler; + } + + public function registerExceptionHandler($level = null, $callPrevious = true) + { + $prev = set_exception_handler(array($this, 'handleException')); + $this->uncaughtExceptionLevel = $level === null ? LogLevel::ERROR : $level; + if ($callPrevious && $prev) { + $this->previousExceptionHandler = $prev; + } + } + + public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1) + { + $prev = set_error_handler(array($this, 'handleError'), $errorTypes); + $this->errorLevelMap = $this->defaultErrorLevelMap(); + // merging the map into the defaults by hand because array_merge + // trips up on numeric keys + foreach ($levelMap as $key => $val) { + $this->errorLevelMap[$key] = $val; + } + if ($callPrevious) { + $this->previousErrorHandler = $prev ?: true; + } + } + + public function registerFatalHandler($level = null, $reservedMemorySize = 20) + { + register_shutdown_function(array($this, 'handleFatalError')); + + $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize); + $this->fatalLevel = $level === null ? LogLevel::ALERT : $level; + } + + protected function defaultErrorLevelMap() + { + return array( + E_ERROR => LogLevel::CRITICAL, + E_WARNING => LogLevel::WARNING, + E_PARSE => LogLevel::ALERT, + E_NOTICE => LogLevel::NOTICE, + E_CORE_ERROR => LogLevel::CRITICAL, + E_CORE_WARNING => LogLevel::WARNING, + E_COMPILE_ERROR => LogLevel::ALERT, + E_COMPILE_WARNING => LogLevel::WARNING, + E_USER_ERROR => LogLevel::ERROR, + E_USER_WARNING => LogLevel::WARNING, + E_USER_NOTICE => LogLevel::NOTICE, + E_STRICT => LogLevel::NOTICE, + E_RECOVERABLE_ERROR => LogLevel::ERROR, + E_DEPRECATED => LogLevel::NOTICE, + E_USER_DEPRECATED => LogLevel::NOTICE, + ); + } + + /** + * @private + */ + public function handleException(\Exception $e) + { + $this->logger->log($this->uncaughtExceptionLevel, 'Uncaught exception', array('exception' => $e)); + + if ($this->previousExceptionHandler) { + call_user_func($this->previousExceptionHandler, $e); + } + } + + /** + * @private + */ + public function handleError($code, $message, $file = '', $line = 0, $context = array()) + { + if (!(error_reporting() & $code)) { + return; + } + + $level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL; + $this->logger->log($level, self::codeToString($code).': '.$message, array('file' => $file, 'line' => $line)); + + if ($this->previousErrorHandler === true) { + return false; + } elseif ($this->previousErrorHandler) { + return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context); + } + } + + /** + * @private + */ + public function handleFatalError() + { + $this->reservedMemory = null; + + $lastError = error_get_last(); + if ($lastError && in_array($lastError['type'], self::$fatalErrors)) { + $this->logger->log( + $this->fatalLevel, + 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], + array('file' => $lastError['file'], 'line' => $lastError['line']) + ); + } + } + + private static function codeToString($code) + { + switch ($code) { + case E_ERROR: + return 'E_ERROR'; + case E_WARNING: + return 'E_WARNING'; + case E_PARSE: + return 'E_PARSE'; + case E_NOTICE: + return 'E_NOTICE'; + case E_CORE_ERROR: + return 'E_CORE_ERROR'; + case E_CORE_WARNING: + return 'E_CORE_WARNING'; + case E_COMPILE_ERROR: + return 'E_COMPILE_ERROR'; + case E_COMPILE_WARNING: + return 'E_COMPILE_WARNING'; + case E_USER_ERROR: + return 'E_USER_ERROR'; + case E_USER_WARNING: + return 'E_USER_WARNING'; + case E_USER_NOTICE: + return 'E_USER_NOTICE'; + case E_STRICT: + return 'E_STRICT'; + case E_RECOVERABLE_ERROR: + return 'E_RECOVERABLE_ERROR'; + case E_DEPRECATED: + return 'E_DEPRECATED'; + case E_USER_DEPRECATED: + return 'E_USER_DEPRECATED'; + } + + return 'Unknown PHP error'; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php new file mode 100644 index 0000000000..56d3e278a5 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php @@ -0,0 +1,79 @@ + + * + * 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; + +/** + * Formats a log message according to the ChromePHP array format + * + * @author Christophe Coevoet + */ +class ChromePHPFormatter implements FormatterInterface +{ + /** + * Translates Monolog log levels to Wildfire levels. + */ + private $logLevels = array( + Logger::DEBUG => 'log', + Logger::INFO => 'info', + Logger::NOTICE => 'info', + Logger::WARNING => 'warn', + Logger::ERROR => 'error', + Logger::CRITICAL => 'error', + Logger::ALERT => 'error', + Logger::EMERGENCY => 'error', + ); + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + // Retrieve the line and file if set and remove them from the formatted extra + $backtrace = 'unknown'; + if (isset($record['extra']['file']) && isset($record['extra']['line'])) { + $backtrace = $record['extra']['file'].' : '.$record['extra']['line']; + unset($record['extra']['file']); + unset($record['extra']['line']); + } + + $message = array('message' => $record['message']); + if ($record['context']) { + $message['context'] = $record['context']; + } + if ($record['extra']) { + $message['extra'] = $record['extra']; + } + if (count($message) === 1) { + $message = reset($message); + } + + return array( + $record['channel'], + $message, + $backtrace, + $this->logLevels[$record['level']], + ); + } + + public function formatBatch(array $records) + { + $formatted = array(); + + foreach ($records as $record) { + $formatted[] = $this->format($record); + } + + return $formatted; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php b/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php new file mode 100644 index 0000000000..b5de751112 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Interface for formatters + * + * @author Jordi Boggiano + */ +interface FormatterInterface +{ + /** + * Formats a log record. + * + * @param array $record A record to format + * @return mixed The formatted record + */ + public function format(array $record); + + /** + * Formats a set of log records. + * + * @param array $records A set of records to format + * @return mixed The formatted set of records + */ + public function formatBatch(array $records); +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php new file mode 100644 index 0000000000..aa01f491eb --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php @@ -0,0 +1,94 @@ + + * + * 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 Gelf\Message; + +/** + * Serializes a log message to GELF + * @see http://www.graylog2.org/about/gelf + * + * @author Matt Lehner + */ +class GelfMessageFormatter extends NormalizerFormatter +{ + /** + * @var string the name of the system for the Gelf log message + */ + protected $systemName; + + /** + * @var string a prefix for 'extra' fields from the Monolog record (optional) + */ + protected $extraPrefix; + + /** + * @var string a prefix for 'context' fields from the Monolog record (optional) + */ + protected $contextPrefix; + + /** + * Translates Monolog log levels to Graylog2 log priorities. + */ + private $logLevels = array( + Logger::DEBUG => 7, + Logger::INFO => 6, + Logger::NOTICE => 5, + Logger::WARNING => 4, + Logger::ERROR => 3, + Logger::CRITICAL => 2, + Logger::ALERT => 1, + Logger::EMERGENCY => 0, + ); + + public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_') + { + parent::__construct('U.u'); + + $this->systemName = $systemName ?: gethostname(); + + $this->extraPrefix = $extraPrefix; + $this->contextPrefix = $contextPrefix; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + $record = parent::format($record); + $message = new Message(); + $message + ->setTimestamp($record['datetime']) + ->setShortMessage((string) $record['message']) + ->setFacility($record['channel']) + ->setHost($this->systemName) + ->setLine(isset($record['extra']['line']) ? $record['extra']['line'] : null) + ->setFile(isset($record['extra']['file']) ? $record['extra']['file'] : null) + ->setLevel($this->logLevels[$record['level']]); + + // Do not duplicate these values in the additional fields + unset($record['extra']['line']); + unset($record['extra']['file']); + + foreach ($record['extra'] as $key => $val) { + $message->setAdditional($this->extraPrefix . $key, is_scalar($val) ? $val : $this->toJson($val)); + } + + foreach ($record['context'] as $key => $val) { + $message->setAdditional($this->contextPrefix . $key, is_scalar($val) ? $val : $this->toJson($val)); + } + + return $message; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php new file mode 100644 index 0000000000..822af0ea43 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Encodes whatever record data is passed to it as json + * + * This can be useful to log to databases or remote APIs + * + * @author Jordi Boggiano + */ +class JsonFormatter implements FormatterInterface +{ + /** + * {@inheritdoc} + */ + public function format(array $record) + { + return json_encode($record); + } + + /** + * {@inheritdoc} + */ + public function formatBatch(array $records) + { + return json_encode($records); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php new file mode 100644 index 0000000000..a96fb27d90 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Formats incoming records into a one-line string + * + * This is especially useful for logging to files + * + * @author Jordi Boggiano + * @author Christophe Coevoet + */ +class LineFormatter extends NormalizerFormatter +{ + const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; + + protected $format; + + /** + * @param string $format The format of the message + * @param string $dateFormat The format of the timestamp: one supported by DateTime::format + */ + public function __construct($format = null, $dateFormat = null) + { + $this->format = $format ?: static::SIMPLE_FORMAT; + parent::__construct($dateFormat); + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + $vars = parent::format($record); + + $output = $this->format; + foreach ($vars['extra'] as $var => $val) { + if (false !== strpos($output, '%extra.'.$var.'%')) { + $output = str_replace('%extra.'.$var.'%', $this->convertToString($val), $output); + unset($vars['extra'][$var]); + } + } + foreach ($vars as $var => $val) { + $output = str_replace('%'.$var.'%', $this->convertToString($val), $output); + } + + return $output; + } + + public function formatBatch(array $records) + { + $message = ''; + foreach ($records as $record) { + $message .= $this->format($record); + } + + return $message; + } + + protected function normalize($data) + { + if (is_bool($data) || is_null($data)) { + return var_export($data, true); + } + + if ($data instanceof \Exception) { + $previousText = ''; + if ($previous = $data->getPrevious()) { + do { + $previousText .= ', '.get_class($previous).': '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine(); + } while ($previous = $previous->getPrevious()); + } + + return '[object] ('.get_class($data).': '.$data->getMessage().' at '.$data->getFile().':'.$data->getLine().$previousText.')'; + } + + return parent::normalize($data); + } + + protected function convertToString($data) + { + if (null === $data || is_scalar($data)) { + return (string) $data; + } + + $data = $this->normalize($data); + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return $this->toJson($data); + } + + return str_replace('\\/', '/', json_encode($data)); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php new file mode 100644 index 0000000000..7aa8ad33cb --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Serializes a log message to Logstash Event Format + * + * @see http://logstash.net/ + * @see https://github.com/logstash/logstash/blob/master/lib/logstash/event.rb + * + * @author Tim Mower + */ +class LogstashFormatter extends NormalizerFormatter +{ + /** + * @var string the name of the system for the Logstash log message, used to fill the @source field + */ + protected $systemName; + + /** + * @var string an application name for the Logstash log message, used to fill the @type field + */ + protected $applicationName; + + /** + * @var string a prefix for 'extra' fields from the Monolog record (optional) + */ + protected $extraPrefix; + + /** + * @var string a prefix for 'context' fields from the Monolog record (optional) + */ + protected $contextPrefix; + + /** + * @param string $applicationName the application that sends the data, used as the "type" field of logstash + * @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine + * @param string $extraPrefix prefix for extra keys inside logstash "fields" + * @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_ + */ + public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_') + { + //log stash requires a ISO 8601 format date + parent::__construct('c'); + + $this->systemName = $systemName ?: gethostname(); + $this->applicationName = $applicationName; + + $this->extraPrefix = $extraPrefix; + $this->contextPrefix = $contextPrefix; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + $record = parent::format($record); + $message = array( + '@timestamp' => $record['datetime'], + '@message' => $record['message'], + '@tags' => array($record['channel']), + '@source' => $this->systemName + ); + + if ($this->applicationName) { + $message['@type'] = $this->applicationName; + } + $message['@fields'] = array(); + $message['@fields']['channel'] = $record['channel']; + $message['@fields']['level'] = $record['level']; + + if (isset($record['extra']['server'])) { + $message['@source_host'] = $record['extra']['server']; + } + if (isset($record['extra']['url'])) { + $message['@source_path'] = $record['extra']['url']; + } + foreach ($record['extra'] as $key => $val) { + $message['@fields'][$this->extraPrefix . $key] = $val; + } + + foreach ($record['context'] as $key => $val) { + $message['@fields'][$this->contextPrefix . $key] = $val; + } + + return json_encode($message) . "\n"; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php new file mode 100644 index 0000000000..765fed4566 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php @@ -0,0 +1,137 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Exception; + +/** + * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets + * + * @author Jordi Boggiano + */ +class NormalizerFormatter implements FormatterInterface +{ + const SIMPLE_DATE = "Y-m-d H:i:s"; + + protected $dateFormat; + + /** + * @param string $dateFormat The format of the timestamp: one supported by DateTime::format + */ + public function __construct($dateFormat = null) + { + $this->dateFormat = $dateFormat ?: static::SIMPLE_DATE; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + return $this->normalize($record); + } + + /** + * {@inheritdoc} + */ + public function formatBatch(array $records) + { + foreach ($records as $key => $record) { + $records[$key] = $this->format($record); + } + + return $records; + } + + protected function normalize($data) + { + if (null === $data || is_scalar($data)) { + return $data; + } + + if (is_array($data) || $data instanceof \Traversable) { + $normalized = array(); + + $count = 1; + foreach ($data as $key => $value) { + if ($count++ >= 1000) { + $normalized['...'] = 'Over 1000 items, aborting normalization'; + break; + } + $normalized[$key] = $this->normalize($value); + } + + return $normalized; + } + + if ($data instanceof \DateTime) { + return $data->format($this->dateFormat); + } + + if (is_object($data)) { + if ($data instanceof Exception) { + return $this->normalizeException($data); + } + + return sprintf("[object] (%s: %s)", get_class($data), $this->toJson($data, true)); + } + + if (is_resource($data)) { + return '[resource]'; + } + + return '[unknown('.gettype($data).')]'; + } + + protected function normalizeException(Exception $e) + { + $data = array( + 'class' => get_class($e), + 'message' => $e->getMessage(), + 'file' => $e->getFile().':'.$e->getLine(), + ); + + $trace = $e->getTrace(); + array_shift($trace); + foreach ($trace as $frame) { + if (isset($frame['file'])) { + $data['trace'][] = $frame['file'].':'.$frame['line']; + } else { + $data['trace'][] = json_encode($frame); + } + } + + if ($previous = $e->getPrevious()) { + $data['previous'] = $this->normalizeException($previous); + } + + return $data; + } + + protected function toJson($data, $ignoreErrors = false) + { + // suppress json_encode errors since it's twitchy with some inputs + if ($ignoreErrors) { + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return @json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + return @json_encode($data); + } + + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + return json_encode($data); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php new file mode 100644 index 0000000000..b3e9b18644 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php @@ -0,0 +1,102 @@ + + * + * 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; + +/** + * Serializes a log message according to Wildfire's header requirements + * + * @author Eric Clemmons (@ericclemmons) + * @author Christophe Coevoet + * @author Kirill chEbba Chebunin + */ +class WildfireFormatter extends NormalizerFormatter +{ + /** + * Translates Monolog log levels to Wildfire levels. + */ + private $logLevels = array( + Logger::DEBUG => 'LOG', + Logger::INFO => 'INFO', + Logger::NOTICE => 'INFO', + Logger::WARNING => 'WARN', + Logger::ERROR => 'ERROR', + Logger::CRITICAL => 'ERROR', + Logger::ALERT => 'ERROR', + Logger::EMERGENCY => 'ERROR', + ); + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + // Retrieve the line and file if set and remove them from the formatted extra + $file = $line = ''; + if (isset($record['extra']['file'])) { + $file = $record['extra']['file']; + unset($record['extra']['file']); + } + if (isset($record['extra']['line'])) { + $line = $record['extra']['line']; + unset($record['extra']['line']); + } + + $record = $this->normalize($record); + $message = array('message' => $record['message']); + $handleError = false; + if ($record['context']) { + $message['context'] = $record['context']; + $handleError = true; + } + if ($record['extra']) { + $message['extra'] = $record['extra']; + $handleError = true; + } + if (count($message) === 1) { + $message = reset($message); + } + + // Create JSON object describing the appearance of the message in the console + $json = $this->toJson(array( + array( + 'Type' => $this->logLevels[$record['level']], + 'File' => $file, + 'Line' => $line, + 'Label' => $record['channel'], + ), + $message, + ), $handleError); + + // The message itself is a serialization of the above JSON object + it's length + return sprintf( + '%s|%s|', + strlen($json), + $json + ); + } + + public function formatBatch(array $records) + { + throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter'); + } + + protected function normalize($data) + { + if (is_object($data) && !$data instanceof \DateTime) { + return $data; + } + + return parent::normalize($data); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php new file mode 100644 index 0000000000..2ea9f5599b --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php @@ -0,0 +1,174 @@ + + * + * 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\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; + +/** + * Base Handler class providing the Handler structure + * + * @author Jordi Boggiano + */ +abstract class AbstractHandler implements HandlerInterface +{ + protected $level = Logger::DEBUG; + protected $bubble = false; + + /** + * @var FormatterInterface + */ + protected $formatter; + protected $processors = array(); + + /** + * @param integer $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 + */ + public function __construct($level = Logger::DEBUG, $bubble = true) + { + $this->level = $level; + $this->bubble = $bubble; + } + + /** + * {@inheritdoc} + */ + public function isHandling(array $record) + { + return $record['level'] >= $this->level; + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + foreach ($records as $record) { + $this->handle($record); + } + } + + /** + * Closes the handler. + * + * This will be called automatically when the object is destroyed + */ + public function close() + { + } + + /** + * {@inheritdoc} + */ + public function pushProcessor($callback) + { + if (!is_callable($callback)) { + throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given'); + } + array_unshift($this->processors, $callback); + } + + /** + * {@inheritdoc} + */ + public function popProcessor() + { + if (!$this->processors) { + throw new \LogicException('You tried to pop from an empty processor stack.'); + } + + return array_shift($this->processors); + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + $this->formatter = $formatter; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + if (!$this->formatter) { + $this->formatter = $this->getDefaultFormatter(); + } + + return $this->formatter; + } + + /** + * Sets minimum logging level at which this handler will be triggered. + * + * @param integer $level + */ + public function setLevel($level) + { + $this->level = $level; + } + + /** + * Gets minimum logging level at which this handler will be triggered. + * + * @return integer + */ + public function getLevel() + { + return $this->level; + } + + /** + * Sets the bubbling behavior. + * + * @param Boolean $bubble True means that bubbling is not permitted. + * False means that this handler allows bubbling. + */ + public function setBubble($bubble) + { + $this->bubble = $bubble; + } + + /** + * Gets the bubbling behavior. + * + * @return Boolean True means that bubbling is not permitted. + * False means that this handler allows bubbling. + */ + public function getBubble() + { + return $this->bubble; + } + + public function __destruct() + { + try { + $this->close(); + } catch (\Exception $e) { + // do nothing + } + } + + /** + * Gets the default formatter. + * + * @return FormatterInterface + */ + protected function getDefaultFormatter() + { + return new LineFormatter(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php new file mode 100644 index 0000000000..e1e5b89311 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Base Handler class providing the Handler structure + * + * Classes extending it should (in most cases) only implement write($record) + * + * @author Jordi Boggiano + * @author Christophe Coevoet + */ +abstract class AbstractProcessingHandler extends AbstractHandler +{ + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if ($record['level'] < $this->level) { + return false; + } + + $record = $this->processRecord($record); + + $record['formatted'] = $this->getFormatter()->format($record); + + $this->write($record); + + return false === $this->bubble; + } + + /** + * Writes the record down to the log of the implementing handler + * + * @param array $record + * @return void + */ + abstract protected function write(array $record); + + /** + * Processes a record. + * + * @param array $record + * @return array + */ + protected function processRecord(array $record) + { + if ($this->processors) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + } + + return $record; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php new file mode 100644 index 0000000000..00703436c5 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php @@ -0,0 +1,69 @@ + + * + * 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\Formatter\JsonFormatter; + +class AmqpHandler extends AbstractProcessingHandler +{ + /** + * @var \AMQPExchange $exchange + */ + protected $exchange; + + /** + * @param \AMQPExchange $exchange AMQP exchange, ready for use + * @param string $exchangeName + * @param int $level + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(\AMQPExchange $exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true) + { + $this->exchange = $exchange; + $this->exchange->setName($exchangeName); + + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $data = $record["formatted"]; + + $routingKey = sprintf( + '%s.%s', + substr($record['level_name'], 0, 4), + $record['channel'] + ); + + $this->exchange->publish( + $data, + strtolower($routingKey), + 0, + array( + 'delivery_mode' => 2, + 'Content-type' => 'application/json' + ) + ); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new JsonFormatter(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php new file mode 100644 index 0000000000..e9a4dc358b --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php @@ -0,0 +1,98 @@ + + * + * 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; + +/** + * Buffers all records until closing the handler and then pass them as batch. + * + * This is useful for a MailHandler to send only one mail per request instead of + * sending one per log message. + * + * @author Christophe Coevoet + */ +class BufferHandler extends AbstractHandler +{ + protected $handler; + protected $bufferSize = 0; + protected $bufferLimit; + protected $flushOnOverflow; + protected $buffer = array(); + + /** + * @param HandlerInterface $handler Handler. + * @param integer $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. + * @param integer $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 + */ + public function __construct(HandlerInterface $handler, $bufferSize = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false) + { + parent::__construct($level, $bubble); + $this->handler = $handler; + $this->bufferLimit = (int) $bufferSize; + $this->flushOnOverflow = $flushOnOverflow; + + // __destructor() doesn't get called on Fatal errors + register_shutdown_function(array($this, 'close')); + } + + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if ($record['level'] < $this->level) { + return false; + } + + if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) { + if ($this->flushOnOverflow) { + $this->flush(); + } else { + array_shift($this->buffer); + $this->bufferSize--; + } + } + + if ($this->processors) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + } + + $this->buffer[] = $record; + $this->bufferSize++; + + return false === $this->bubble; + } + + public function flush() + { + if ($this->bufferSize === 0) { + return; + } + + $this->handler->handleBatch($this->buffer); + $this->bufferSize = 0; + $this->buffer = array(); + } + + /** + * {@inheritdoc} + */ + public function close() + { + $this->flush(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php new file mode 100644 index 0000000000..705400b15c --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php @@ -0,0 +1,183 @@ + + * + * 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\ChromePHPFormatter; +use Monolog\Logger; + +/** + * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) + * + * @author Christophe Coevoet + */ +class ChromePHPHandler extends AbstractProcessingHandler +{ + /** + * Version of the extension + */ + const VERSION = '4.0'; + + /** + * Header name + */ + const HEADER_NAME = 'X-ChromeLogger-Data'; + + protected static $initialized = false; + + /** + * Tracks whether we sent too much data + * + * Chrome limits the headers to 256KB, so when we sent 240KB we stop sending + * + * @var Boolean + */ + protected static $overflowed = false; + + protected static $json = array( + 'version' => self::VERSION, + 'columns' => array('label', 'log', 'backtrace', 'type'), + 'rows' => array(), + ); + + protected static $sendHeaders = true; + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + $messages = array(); + + foreach ($records as $record) { + if ($record['level'] < $this->level) { + continue; + } + $messages[] = $this->processRecord($record); + } + + if (!empty($messages)) { + $messages = $this->getFormatter()->formatBatch($messages); + self::$json['rows'] = array_merge(self::$json['rows'], $messages); + $this->send(); + } + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new ChromePHPFormatter(); + } + + /** + * Creates & sends header for a record + * + * @see sendHeader() + * @see send() + * @param array $record + */ + protected function write(array $record) + { + self::$json['rows'][] = $record['formatted']; + + $this->send(); + } + + /** + * Sends the log header + * + * @see sendHeader() + */ + protected function send() + { + if (self::$overflowed) { + return; + } + + if (!self::$initialized) { + self::$sendHeaders = $this->headersAccepted(); + self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + + self::$initialized = true; + } + + $json = @json_encode(self::$json); + $data = base64_encode(utf8_encode($json)); + if (strlen($data) > 240*1024) { + self::$overflowed = true; + + $record = array( + 'message' => 'Incomplete logs, chrome header size limit reached', + 'context' => array(), + 'level' => Logger::WARNING, + 'level_name' => Logger::getLevelName(Logger::WARNING), + 'channel' => 'monolog', + 'datetime' => new \DateTime(), + 'extra' => array(), + ); + self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); + $json = @json_encode(self::$json); + $data = base64_encode(utf8_encode($json)); + } + + $this->sendHeader(self::HEADER_NAME, $data); + } + + /** + * Send header string to the client + * + * @param string $header + * @param string $content + */ + protected function sendHeader($header, $content) + { + if (!headers_sent() && self::$sendHeaders) { + header(sprintf('%s: %s', $header, $content)); + } + } + + /** + * Verifies if the headers are accepted by the current user agent + * + * @return Boolean + */ + protected function headersAccepted() + { + return !isset($_SERVER['HTTP_USER_AGENT']) + || preg_match('{\bChrome/\d+[\.\d+]*\b}', $_SERVER['HTTP_USER_AGENT']); + } + + /** + * BC getter for the sendHeaders property that has been made static + */ + public function __get($property) + { + if ('sendHeaders' !== $property) { + throw new \InvalidArgumentException('Undefined property '.$property); + } + + return static::$sendHeaders; + } + + /** + * BC setter for the sendHeaders property that has been made static + */ + public function __set($property, $value) + { + if ('sendHeaders' !== $property) { + throw new \InvalidArgumentException('Undefined property '.$property); + } + + static::$sendHeaders = $value; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php new file mode 100644 index 0000000000..4877b345d6 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php @@ -0,0 +1,72 @@ + + * + * 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\JsonFormatter; +use Monolog\Logger; + +/** + * CouchDB handler + * + * @author Markus Bachmann + */ +class CouchDBHandler extends AbstractProcessingHandler +{ + private $options; + + public function __construct(array $options = array(), $level = Logger::DEBUG, $bubble = true) + { + $this->options = array_merge(array( + 'host' => 'localhost', + 'port' => 5984, + 'dbname' => 'logger', + 'username' => null, + 'password' => null, + ), $options); + + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $basicAuth = null; + if ($this->options['username']) { + $basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']); + } + + $url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname']; + $context = stream_context_create(array( + 'http' => array( + 'method' => 'POST', + 'content' => $record['formatted'], + 'ignore_errors' => true, + 'max_redirects' => 0, + 'header' => 'Content-type: application/json', + ) + )); + + if (false === @file_get_contents($url, null, $context)) { + throw new \RuntimeException(sprintf('Could not connect to %s', $url)); + } + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new JsonFormatter(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php new file mode 100644 index 0000000000..0b2f21be0c --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php @@ -0,0 +1,145 @@ + + * + * 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; + +/** + * Logs to Cube. + * + * @link http://square.github.com/cube/ + * @author Wan Chen + */ +class CubeHandler extends AbstractProcessingHandler +{ + private $udpConnection = null; + private $httpConnection = null; + private $scheme = null; + private $host = null; + private $port = null; + private $acceptedSchemes = array('http', 'udp'); + + /** + * Create a Cube handler + * + * @throws UnexpectedValueException when given url is not a valid url. + * A valid url must consists of three parts : protocol://host:port + * Only valid protocol used by Cube are http and udp + */ + public function __construct($url, $level = Logger::DEBUG, $bubble = true) + { + $urlInfos = parse_url($url); + + if (!isset($urlInfos['scheme']) || !isset($urlInfos['host']) || !isset($urlInfos['port'])) { + throw new \UnexpectedValueException('URL "'.$url.'" is not valid'); + } + + if (!in_array($urlInfos['scheme'], $this->acceptedSchemes)) { + throw new \UnexpectedValueException( + 'Invalid protocol (' . $urlInfos['scheme'] . ').' + . ' Valid options are ' . implode(', ', $this->acceptedSchemes)); + } + + $this->scheme = $urlInfos['scheme']; + $this->host = $urlInfos['host']; + $this->port = $urlInfos['port']; + + parent::__construct($level, $bubble); + } + + /** + * Establish a connection to an UDP socket + * + * @throws LogicException when unable to connect to the socket + */ + protected function connectUdp() + { + if (!extension_loaded('sockets')) { + throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler'); + } + + $this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0); + if (!$this->udpConnection) { + throw new \LogicException('Unable to create a socket'); + } + + if (!socket_connect($this->udpConnection, $this->host, $this->port)) { + throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port); + } + } + + /** + * Establish a connection to a http server + */ + protected function connectHttp() + { + if (!extension_loaded('curl')) { + throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler'); + } + + $this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put'); + + if (!$this->httpConnection) { + throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port); + } + + curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST"); + curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $date = $record['datetime']; + + $data = array('time' => $date->format('Y-m-d\TH:i:s.u')); + unset($record['datetime']); + + if (isset($record['context']['type'])) { + $data['type'] = $record['context']['type']; + unset($record['context']['type']); + } else { + $data['type'] = $record['channel']; + } + + $data['data'] = $record['context']; + $data['data']['level'] = $record['level']; + + $this->{'write'.$this->scheme}(json_encode($data)); + } + + private function writeUdp($data) + { + if (!$this->udpConnection) { + $this->connectUdp(); + } + + socket_send($this->udpConnection, $data, strlen($data), 0); + } + + private function writeHttp($data) + { + if (!$this->httpConnection) { + $this->connectHttp(); + } + + curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']'); + curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/json', + 'Content-Length: ' . strlen('['.$data.']')) + ); + + return curl_exec($this->httpConnection); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php new file mode 100644 index 0000000000..b91ffec905 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -0,0 +1,45 @@ + + * + * 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\Formatter\NormalizerFormatter; +use Doctrine\CouchDB\CouchDBClient; + +/** + * CouchDB handler for Doctrine CouchDB ODM + * + * @author Markus Bachmann + */ +class DoctrineCouchDBHandler extends AbstractProcessingHandler +{ + private $client; + + public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubble = true) + { + $this->client = $client; + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $this->client->postDocument($record['formatted']); + } + + protected function getDefaultFormatter() + { + return new NormalizerFormatter; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php new file mode 100644 index 0000000000..477c56546a --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php @@ -0,0 +1,46 @@ + + * + * 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; + +/** + * Stores to PHP error_log() handler. + * + * @author Elan Ruusamäe + */ +class ErrorLogHandler extends AbstractProcessingHandler +{ + protected $messageType; + + /** + * @param integer $messageType Says where the error should go. + * @param integer $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 + */ + public function __construct($messageType = 0, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + if (!in_array($messageType, array(0, 4))) { + throw new \InvalidArgumentException('Only message types 0 and 4 are supported'); + } + $this->messageType = $messageType; + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + error_log((string) $record['formatted'], $this->messageType); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php new file mode 100644 index 0000000000..c3e42efefa --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler\FingersCrossed; + +/** + * Interface for activation strategies for the FingersCrossedHandler. + * + * @author Johannes M. Schmitt + */ +interface ActivationStrategyInterface +{ + /** + * Returns whether the given record activates the handler. + * + * @param array $record + * @return Boolean + */ + public function isHandlerActivated(array $record); +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php new file mode 100644 index 0000000000..646d57a8c8 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -0,0 +1,57 @@ + +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ + +namespace Monolog\Handler\FingersCrossed; + +/** + * Channel and Error level based monolog activation strategy. Allows to trigger activation + * based on level per channel. e.g. trigger activation on level 'ERROR' by default, except + * for records of the 'sql' channel; those should trigger activation on level 'WARN'. + * + * Example: + * + * + * $activationStrategy = new ChannelLevelActivationStrategy( + * Logger::CRITICAL, + * array( + * 'request' => Logger::ALERT, + * 'sensitive' => Logger::ERROR, + * ) + * ); + * $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy); + * + * + * @author Mike Meessen + */ +class ChannelLevelActivationStrategy implements ActivationStrategyInterface +{ + private $defaultActionLevel; + private $channelToActionLevel; + + /** + * @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any + * @param array $categoryToActionLevel An array that maps channel names to action levels. + */ + public function __construct($defaultActionLevel, $channelToActionLevel = array()) + { + $this->defaultActionLevel = $defaultActionLevel; + $this->channelToActionLevel = $channelToActionLevel; + } + + public function isHandlerActivated(array $record) + { + if (isset($this->channelToActionLevel[$record['channel']])) { + return $record['level'] >= $this->channelToActionLevel[$record['channel']]; + } + + return $record['level'] >= $this->defaultActionLevel; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php new file mode 100644 index 0000000000..7cd8ef1b62 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler\FingersCrossed; + +/** + * Error level based activation strategy. + * + * @author Johannes M. Schmitt + */ +class ErrorLevelActivationStrategy implements ActivationStrategyInterface +{ + private $actionLevel; + + public function __construct($actionLevel) + { + $this->actionLevel = $actionLevel; + } + + public function isHandlerActivated(array $record) + { + return $record['level'] >= $this->actionLevel; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php new file mode 100644 index 0000000000..bc51e4e3be --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; +use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; +use Monolog\Logger; + +/** + * Buffers all records until a certain level is reached + * + * The advantage of this approach is that you don't get any clutter in your log files. + * Only requests which actually trigger an error (or whatever your actionLevel is) will be + * in the logs, but they will contain all records, not only those above the level threshold. + * + * You can find the various activation strategies in the + * Monolog\Handler\FingersCrossed\ namespace. + * + * @author Jordi Boggiano + */ +class FingersCrossedHandler extends AbstractHandler +{ + protected $handler; + protected $activationStrategy; + protected $buffering = true; + protected $bufferSize; + protected $buffer = array(); + protected $stopBuffering; + + /** + * @param callable|HandlerInterface $handler Handler or factory callable($record, $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) + */ + public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true) + { + if (null === $activationStrategy) { + $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING); + } + + // convert simple int activationStrategy to an object + if (!$activationStrategy instanceof ActivationStrategyInterface) { + $activationStrategy = new ErrorLevelActivationStrategy($activationStrategy); + } + + $this->handler = $handler; + $this->activationStrategy = $activationStrategy; + $this->bufferSize = $bufferSize; + $this->bubble = $bubble; + $this->stopBuffering = $stopBuffering; + } + + /** + * {@inheritdoc} + */ + public function isHandling(array $record) + { + return true; + } + + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if ($this->processors) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + } + + if ($this->buffering) { + $this->buffer[] = $record; + if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) { + array_shift($this->buffer); + } + if ($this->activationStrategy->isHandlerActivated($record)) { + if ($this->stopBuffering) { + $this->buffering = false; + } + if (!$this->handler instanceof HandlerInterface) { + if (!is_callable($this->handler)) { + throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object"); + } + $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->buffer = array(); + } + } else { + $this->handler->handle($record); + } + + return false === $this->bubble; + } + + /** + * Resets the state of the handler. Stops forwarding records to the wrapped handler. + */ + public function reset() + { + $this->buffering = true; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php new file mode 100644 index 0000000000..46a039ad72 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php @@ -0,0 +1,184 @@ + + * + * 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\WildfireFormatter; + +/** + * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol. + * + * @author Eric Clemmons (@ericclemmons) + */ +class FirePHPHandler extends AbstractProcessingHandler +{ + /** + * WildFire JSON header message format + */ + const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'; + + /** + * FirePHP structure for parsing messages & their presentation + */ + const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'; + + /** + * Must reference a "known" plugin, otherwise headers won't display in FirePHP + */ + const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3'; + + /** + * Header prefix for Wildfire to recognize & parse headers + */ + const HEADER_PREFIX = 'X-Wf'; + + /** + * Whether or not Wildfire vendor-specific headers have been generated & sent yet + */ + protected static $initialized = false; + + /** + * Shared static message index between potentially multiple handlers + * @var int + */ + protected static $messageIndex = 1; + + protected static $sendHeaders = true; + + /** + * Base header creation function used by init headers & record headers + * + * @param array $meta Wildfire Plugin, Protocol & Structure Indexes + * @param string $message Log message + * @return array Complete header string ready for the client as key and message as value + */ + protected function createHeader(array $meta, $message) + { + $header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta)); + + return array($header => $message); + } + + /** + * Creates message header from record + * + * @see createHeader() + * @param array $record + * @return string + */ + protected function createRecordHeader(array $record) + { + // Wildfire is extensible to support multiple protocols & plugins in a single request, + // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake. + return $this->createHeader( + array(1, 1, 1, self::$messageIndex++), + $record['formatted'] + ); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new WildfireFormatter(); + } + + /** + * Wildfire initialization headers to enable message parsing + * + * @see createHeader() + * @see sendHeader() + * @return array + */ + protected function getInitHeaders() + { + // Initial payload consists of required headers for Wildfire + return array_merge( + $this->createHeader(array('Protocol', 1), self::PROTOCOL_URI), + $this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI), + $this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI) + ); + } + + /** + * Send header string to the client + * + * @param string $header + * @param string $content + */ + protected function sendHeader($header, $content) + { + if (!headers_sent() && self::$sendHeaders) { + header(sprintf('%s: %s', $header, $content)); + } + } + + /** + * Creates & sends header for a record, ensuring init headers have been sent prior + * + * @see sendHeader() + * @see sendInitHeaders() + * @param array $record + */ + protected function write(array $record) + { + // WildFire-specific headers must be sent prior to any messages + if (!self::$initialized) { + self::$sendHeaders = $this->headersAccepted(); + + foreach ($this->getInitHeaders() as $header => $content) { + $this->sendHeader($header, $content); + } + + self::$initialized = true; + } + + $header = $this->createRecordHeader($record); + $this->sendHeader(key($header), current($header)); + } + + /** + * Verifies if the headers are accepted by the current user agent + * + * @return Boolean + */ + protected function headersAccepted() + { + return !isset($_SERVER['HTTP_USER_AGENT']) + || preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT']) + || isset($_SERVER['HTTP_X_FIREPHP_VERSION']); + } + + /** + * BC getter for the sendHeaders property that has been made static + */ + public function __get($property) + { + if ('sendHeaders' !== $property) { + throw new \InvalidArgumentException('Undefined property '.$property); + } + + return static::$sendHeaders; + } + + /** + * BC setter for the sendHeaders property that has been made static + */ + public function __set($property, $value) + { + if ('sendHeaders' !== $property) { + throw new \InvalidArgumentException('Undefined property '.$property); + } + + static::$sendHeaders = $value; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php new file mode 100644 index 0000000000..34d48e7506 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Gelf\IMessagePublisher; +use Monolog\Logger; +use Monolog\Handler\AbstractProcessingHandler; +use Monolog\Formatter\GelfMessageFormatter; + +/** + * Handler to send messages to a Graylog2 (http://www.graylog2.org) server + * + * @author Matt Lehner + */ +class GelfHandler extends AbstractProcessingHandler +{ + /** + * @var Gelf\IMessagePublisher the publisher object that sends the message to the server + */ + protected $publisher; + + /** + * @param Gelf\IMessagePublisher $publisher a publisher object + * @param integer $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 + */ + public function __construct(IMessagePublisher $publisher, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + + $this->publisher = $publisher; + } + + /** + * {@inheritdoc} + */ + public function close() + { + $this->publisher = null; + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $this->publisher->publish($record['formatted']); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new GelfMessageFormatter(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php new file mode 100644 index 0000000000..99384d35f1 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Forwards records to multiple handlers + * + * @author Lenar Lõhmus + */ +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 + */ + public function __construct(array $handlers, $bubble = true) + { + foreach ($handlers as $handler) { + if (!$handler instanceof HandlerInterface) { + throw new \InvalidArgumentException('The first argument of the GroupHandler must be an array of HandlerInterface instances.'); + } + } + + $this->handlers = $handlers; + $this->bubble = $bubble; + } + + /** + * {@inheritdoc} + */ + public function isHandling(array $record) + { + foreach ($this->handlers as $handler) { + if ($handler->isHandling($record)) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if ($this->processors) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + } + + foreach ($this->handlers as $handler) { + $handler->handle($record); + } + + return false === $this->bubble; + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + foreach ($this->handlers as $handler) { + $handler->handleBatch($records); + } + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php new file mode 100644 index 0000000000..ac15d7decb --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php @@ -0,0 +1,88 @@ + + * + * 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 that all Monolog Handlers must implement + * + * @author Jordi Boggiano + */ +interface HandlerInterface +{ + /** + * Checks whether the given record will be handled by this handler. + * + * This is mostly done for performance reasons, to avoid calling processors for nothing. + * + * Handlers should still check the record levels within handle(), returning false in isHandling() + * is no guarantee that handle() will not be called, and isHandling() might not be called + * for a given record. + * + * @param array $record + * + * @return Boolean + */ + public function isHandling(array $record); + + /** + * Handles a record. + * + * All records may be passed to this method, and the handler should discard + * those that it does not want to handle. + * + * The return value of this function controls the bubbling process of the handler stack. + * Unless the bubbling is interrupted (by returning true), the Logger class will keep on + * 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. + * False means the record was either not processed or that this handler allows bubbling. + */ + public function handle(array $record); + + /** + * Handles a set of records at once. + * + * @param array $records The records to handle (an array of record arrays) + */ + public function handleBatch(array $records); + + /** + * Adds a processor in the stack. + * + * @param callable $callback + */ + public function pushProcessor($callback); + + /** + * Removes the processor on top of the stack and returns it. + * + * @return callable + */ + public function popProcessor(); + + /** + * Sets the formatter. + * + * @param FormatterInterface $formatter + */ + public function setFormatter(FormatterInterface $formatter); + + /** + * Gets the formatter. + * + * @return FormatterInterface + */ + public function getFormatter(); +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php new file mode 100644 index 0000000000..e1402a0357 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php @@ -0,0 +1,153 @@ + + * + * 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; + +/** + * Sends notifications through the hipchat api to a hipchat room + * + * Notes: + * API token - HipChat API token + * Room - HipChat Room Id or name, where messages are sent + * Name - Name used to send the message (from) + * notify - Should the message trigger a notification in the clients + * + * @author Rafael Dohms + * @see https://www.hipchat.com/docs/api + */ +class HipChatHandler extends SocketHandler +{ + /** + * @var string + */ + private $token; + + /** + * @var array + */ + private $room; + + /** + * @var string + */ + private $name; + + /** + * @var boolean + */ + private $notify; + + /** + * @param string $token HipChat API Token + * @param string $room The room that should be alerted of the message (Id or Name) + * @param string $name Name used in the "from" field + * @param bool $notify Trigger a notification in clients or not + * @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. + */ + public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true) + { + $connectionString = $useSSL ? 'ssl://api.hipchat.com:443' : 'api.hipchat.com:80'; + parent::__construct($connectionString, $level, $bubble); + + $this->token = $token; + $this->name = $name; + $this->notify = $notify; + $this->room = $room; + } + + /** + * {@inheritdoc} + * + * @param array $record + * @return string + */ + protected function generateDataStream($record) + { + $content = $this->buildContent($record); + + return $this->buildHeader($content) . $content; + } + + /** + * Builds the body of API call + * + * @param array $record + * @return string + */ + private function buildContent($record) + { + $dataArray = array( + 'from' => $this->name, + 'room_id' => $this->room, + 'notify' => $this->notify, + 'message' => $record['formatted'], + 'message_format' => 'text', + 'color' => $this->getAlertColor($record['level']), + ); + + return http_build_query($dataArray); + } + + /** + * Builds the header of the API Call + * + * @param string $content + * @return string + */ + private function buildHeader($content) + { + $header = "POST /v1/rooms/message?format=json&auth_token=".$this->token." HTTP/1.1\r\n"; + $header .= "Host: api.hipchat.com\r\n"; + $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $header .= "Content-Length: " . strlen($content) . "\r\n"; + $header .= "\r\n"; + + return $header; + } + + /** + * Assigns a color to each level of log records. + * + * @param integer $level + * @return string + */ + protected function getAlertColor($level) + { + switch (true) { + case $level >= Logger::ERROR: + return 'red'; + case $level >= Logger::WARNING: + return 'yellow'; + case $level >= Logger::INFO: + return 'green'; + case $level == Logger::DEBUG: + return 'gray'; + default: + return 'yellow'; + } + } + + /** + * {@inheritdoc} + * + * @param array $record + */ + public function write(array $record) + { + parent::write($record); + $this->closeSocket(); + } + +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php new file mode 100644 index 0000000000..86292727f3 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Base class for all mail handlers + * + * @author Gyula Sallai + */ +abstract class MailHandler extends AbstractProcessingHandler +{ + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + $messages = array(); + + foreach ($records as $record) { + if ($record['level'] < $this->level) { + continue; + } + $messages[] = $this->processRecord($record); + } + + if (!empty($messages)) { + $this->send((string) $this->getFormatter()->formatBatch($messages), $messages); + } + } + + /** + * Send a mail with the given content + * + * @param string $content + * @param array $records the array of log records that formed this content + */ + abstract protected function send($content, array $records); + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $this->send((string) $record['formatted'], array($record)); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php b/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php new file mode 100644 index 0000000000..0cb21cd227 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Exception can be thrown if an extension for an handler is missing + * + * @author Christian Bergau + */ +class MissingExtensionException extends \Exception +{ + +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php new file mode 100644 index 0000000000..5a59201a11 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php @@ -0,0 +1,55 @@ + + * + * 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\Formatter\NormalizerFormatter; + +/** + * Logs to a MongoDB database. + * + * usage example: + * + * $log = new Logger('application'); + * $mongodb = new MongoDBHandler(new \Mongo("mongodb://localhost:27017"), "logs", "prod"); + * $log->pushHandler($mongodb); + * + * @author Thomas Tourlourat + */ +class MongoDBHandler extends AbstractProcessingHandler +{ + private $mongoCollection; + + public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true) + { + if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) { + throw new \InvalidArgumentException('MongoClient or Mongo instance required'); + } + + $this->mongoCollection = $mongo->selectCollection($database, $collection); + + parent::__construct($level, $bubble); + } + + protected function write(array $record) + { + $this->mongoCollection->save($record["formatted"]); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new NormalizerFormatter(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php new file mode 100644 index 0000000000..c7ac63a0e8 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php @@ -0,0 +1,68 @@ + + * + * 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; + +/** + * NativeMailerHandler uses the mail() function to send the emails + * + * @author Christophe Coevoet + */ +class NativeMailerHandler extends MailHandler +{ + protected $to; + protected $subject; + protected $headers = array( + 'Content-type: text/plain; charset=utf-8' + ); + + /** + * @param string|array $to The receiver of the mail + * @param string $subject The subject of the mail + * @param string $from The sender of the mail + * @param integer $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 + */ + public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true) + { + parent::__construct($level, $bubble); + $this->to = is_array($to) ? $to : array($to); + $this->subject = $subject; + $this->addHeader(sprintf('From: %s', $from)); + } + + /** + * @param string|array $headers Custom added headers + */ + public function addHeader($headers) + { + foreach ((array) $headers as $header) { + if (strpos($header, "\n") !== false || strpos($header, "\r") !== false) { + throw new \InvalidArgumentException('Headers can not contain newline characters for security reasons'); + } + $this->headers[] = $header; + } + } + + /** + * {@inheritdoc} + */ + protected function send($content, array $records) + { + $content = wordwrap($content, 70); + $headers = implode("\r\n", $this->headers) . "\r\n"; + foreach ($this->to as $to) { + mail($to, $this->subject, $content, $headers); + } + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php new file mode 100644 index 0000000000..0b83b968e8 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php @@ -0,0 +1,61 @@ + + * + * 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 to record a log on a NewRelic application + * + * @see https://newrelic.com/docs/php/new-relic-for-php + */ +class NewRelicHandler extends AbstractProcessingHandler +{ + /** + * {@inheritDoc} + */ + public function __construct($level = Logger::ERROR, $bubble = true) + { + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + if (!$this->isNewRelicEnabled()) { + throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler'); + } + + if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) { + newrelic_notice_error($record['message'], $record['context']['exception']); + unset($record['context']['exception']); + } else { + newrelic_notice_error($record['message']); + } + + foreach ($record['context'] as $key => $parameter) { + newrelic_add_custom_parameter($key, $parameter); + } + } + + /** + * Checks whether the NewRelic extension is enabled in the system. + * + * @return bool + */ + protected function isNewRelicEnabled() + { + return extension_loaded('newrelic'); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php new file mode 100644 index 0000000000..3754e45dbc --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php @@ -0,0 +1,45 @@ + + * + * 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; + +/** + * Blackhole + * + * Any record it can handle will be thrown away. This can be used + * to put on top of an existing stack to override it temporarily. + * + * @author Jordi Boggiano + */ +class NullHandler extends AbstractHandler +{ + /** + * @param integer $level The minimum logging level at which this handler will be triggered + */ + public function __construct($level = Logger::DEBUG) + { + parent::__construct($level, false); + } + + /** + * {@inheritdoc} + */ + public function handle(array $record) + { + if ($record['level'] < $this->level) { + return false; + } + + return true; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php new file mode 100644 index 0000000000..c4da70e44f --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php @@ -0,0 +1,120 @@ + + * + * 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; + +/** + * Sends notifications through the pushover api to mobile phones + * + * @author Sebastian Göttschkes + * @see https://www.pushover.net/api + */ +class PushoverHandler extends SocketHandler +{ + private $token; + private $users; + private $title; + private $user; + + private $highPriorityLevel; + private $emergencyLevel; + + /** + * @param string $token Pushover api token + * @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 integer $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 + * the pushover.net app owner. OpenSSL is required for this option. + * @param integer $highPriorityLevel The minimum logging level at which this handler will start + * sending "high priority" requests to the Pushover API + * @param integer $emergencyLevel The minimum logging level at which this handler will start + * sending "emergency" requests to the Pushover API + */ + public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY) + { + $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80'; + parent::__construct($connectionString, $level, $bubble); + + $this->token = $token; + $this->users = (array) $users; + $this->title = $title ?: gethostname(); + $this->highPriorityLevel = $highPriorityLevel; + $this->emergencyLevel = $emergencyLevel; + } + + protected function generateDataStream($record) + { + $content = $this->buildContent($record); + + return $this->buildHeader($content) . $content; + } + + private function buildContent($record) + { + // Pushover has a limit of 512 characters on title and message combined. + $maxMessageLength = 512 - strlen($this->title); + $message = substr($record['message'], 0, $maxMessageLength); + $timestamp = $record['datetime']->getTimestamp(); + + $dataArray = array( + 'token' => $this->token, + 'user' => $this->user, + 'message' => $message, + 'title' => $this->title, + 'timestamp' => $timestamp + ); + + if ($record['level'] >= $this->emergencyLevel) { + $dataArray['priority'] = 2; + } elseif ($record['level'] >= $this->highPriorityLevel) { + $dataArray['priority'] = 1; + } + + return http_build_query($dataArray); + } + + private function buildHeader($content) + { + $header = "POST /1/messages.json HTTP/1.1\r\n"; + $header .= "Host: api.pushover.net\r\n"; + $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $header .= "Content-Length: " . strlen($content) . "\r\n"; + $header .= "\r\n"; + + return $header; + } + + public function write(array $record) + { + foreach ($this->users as $user) { + $this->user = $user; + + parent::write($record); + $this->closeSocket(); + } + + $this->user = null; + } + + public function setHighPriorityLevel($value) + { + $this->highPriorityLevel = $value; + } + + public function setEmergencyLevel($value) + { + $this->emergencyLevel = $value; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php new file mode 100644 index 0000000000..8835e666ed --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php @@ -0,0 +1,167 @@ + + * + * 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\Formatter\FormatterInterface; +use Monolog\Logger; +use Monolog\Handler\AbstractProcessingHandler; +use Raven_Client; + +/** + * Handler to send messages to a Sentry (https://github.com/dcramer/sentry) server + * using raven-php (https://github.com/getsentry/raven-php) + * + * @author Marc Abramowitz + */ +class RavenHandler extends AbstractProcessingHandler +{ + /** + * Translates Monolog log levels to Raven log levels. + */ + private $logLevels = array( + Logger::DEBUG => Raven_Client::DEBUG, + Logger::INFO => Raven_Client::INFO, + Logger::NOTICE => Raven_Client::INFO, + Logger::WARNING => Raven_Client::WARNING, + Logger::ERROR => Raven_Client::ERROR, + Logger::CRITICAL => Raven_Client::FATAL, + Logger::ALERT => Raven_Client::FATAL, + Logger::EMERGENCY => Raven_Client::FATAL, + ); + + /** + * @var Raven_Client the client object that sends the message to the server + */ + protected $ravenClient; + + /** + * @var LineFormatter The formatter to use for the logs generated via handleBatch() + */ + protected $batchFormatter; + + /** + * @param Raven_Client $ravenClient + * @param integer $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 + */ + public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + + $this->ravenClient = $ravenClient; + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + $level = $this->level; + + // filter records based on their level + $records = array_filter($records, function($record) use ($level) { + return $record['level'] >= $level; + }); + + if (!$records) { + return; + } + + // the record with the highest severity is the "main" one + $record = array_reduce($records, function($highest, $record) { + if ($record['level'] >= $highest['level']) { + $highest = $record; + + return $highest; + } + }); + + // the other ones are added as a context item + $logs = array(); + foreach ($records as $r) { + $logs[] = $this->processRecord($r); + } + + if ($logs) { + $record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs); + } + + $this->handle($record); + } + + /** + * Sets the formatter for the logs generated by handleBatch(). + * + * @param FormatterInterface $formatter + */ + public function setBatchFormatter(FormatterInterface $formatter) + { + $this->batchFormatter = $formatter; + } + + /** + * Gets the formatter for the logs generated by handleBatch(). + * + * @return FormatterInterface + */ + public function getBatchFormatter() + { + if (!$this->batchFormatter) { + $this->batchFormatter = $this->getDefaultBatchFormatter(); + } + + return $this->batchFormatter; + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $options = array(); + $options['level'] = $this->logLevels[$record['level']]; + if (!empty($record['context'])) { + $options['extra']['context'] = $record['context']; + } + if (!empty($record['extra'])) { + $options['extra']['extra'] = $record['extra']; + } + + if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) { + $options['extra']['message'] = $record['formatted']; + $this->ravenClient->captureException($record['context']['exception'], $options); + + return; + } + + $this->ravenClient->captureMessage($record['formatted'], array(), $options); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new LineFormatter('[%channel%] %message%'); + } + + /** + * Gets the default formatter for the logs generated by handleBatch(). + * + * @return FormatterInterface + */ + protected function getDefaultBatchFormatter() + { + return new LineFormatter(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php new file mode 100644 index 0000000000..51a8e7df80 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php @@ -0,0 +1,58 @@ + + * + * 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\Formatter\LineFormatter; + +/** + * Logs to a Redis key using rpush + * + * usage example: + * + * $log = new Logger('application'); + * $redis = new RedisHandler(new Predis\Client("tcp://localhost:6379"), "logs", "prod"); + * $log->pushHandler($redis); + * + * @author Thomas Tourlourat + */ +class RedisHandler extends AbstractProcessingHandler +{ + private $redisClient; + private $redisKey; + + # redis instance, key to use + public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true) + { + if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) { + throw new \InvalidArgumentException('Predis\Client or Redis instance required'); + } + + $this->redisClient = $redis; + $this->redisKey = $key; + + parent::__construct($level, $bubble); + } + + protected function write(array $record) + { + $this->redisClient->rpush($this->redisKey, $record["formatted"]); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new LineFormatter(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php new file mode 100644 index 0000000000..0850134d51 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php @@ -0,0 +1,124 @@ + + * + * 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; + +/** + * Stores logs to files that are rotated every day and a limited number of files are kept. + * + * This rotation is only intended to be used as a workaround. Using logrotate to + * handle the rotation is strongly encouraged when you can use it. + * + * @author Christophe Coevoet + * @author Jordi Boggiano + */ +class RotatingFileHandler extends StreamHandler +{ + protected $filename; + protected $maxFiles; + protected $mustRotate; + protected $nextRotation; + + /** + * @param string $filename + * @param integer $maxFiles The maximal amount of files to keep (0 means unlimited) + * @param integer $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 + */ + public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true) + { + $this->filename = $filename; + $this->maxFiles = (int) $maxFiles; + $this->nextRotation = new \DateTime('tomorrow'); + + parent::__construct($this->getTimedFilename(), $level, $bubble); + } + + /** + * {@inheritdoc} + */ + public function close() + { + parent::close(); + + if (true === $this->mustRotate) { + $this->rotate(); + } + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + // on the first record written, if the log is new, we should rotate (once per day) + if (null === $this->mustRotate) { + $this->mustRotate = !file_exists($this->url); + } + + if ($this->nextRotation < $record['datetime']) { + $this->mustRotate = true; + $this->close(); + } + + parent::write($record); + } + + /** + * Rotates the files. + */ + protected function rotate() + { + // update filename + $this->url = $this->getTimedFilename(); + $this->nextRotation = new \DateTime('tomorrow'); + + // skip GC of old logs if files are unlimited + if (0 === $this->maxFiles) { + return; + } + + $fileInfo = pathinfo($this->filename); + $glob = $fileInfo['dirname'].'/'.$fileInfo['filename'].'-*'; + if (!empty($fileInfo['extension'])) { + $glob .= '.'.$fileInfo['extension']; + } + $logFiles = glob($glob); + if ($this->maxFiles >= count($logFiles)) { + // no files to remove + return; + } + + // Sorting the files by name to remove the older ones + usort($logFiles, function($a, $b) { + return strcmp($b, $a); + }); + + foreach (array_slice($logFiles, $this->maxFiles) as $file) { + if (is_writable($file)) { + unlink($file); + } + } + } + + protected function getTimedFilename() + { + $fileInfo = pathinfo($this->filename); + $timedFilename = $fileInfo['dirname'].'/'.$fileInfo['filename'].'-'.date('Y-m-d'); + if (!empty($fileInfo['extension'])) { + $timedFilename .= '.'.$fileInfo['extension']; + } + + return $timedFilename; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php new file mode 100644 index 0000000000..4faa327d63 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php @@ -0,0 +1,285 @@ + + * + * 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; + +/** + * Stores to any socket - uses fsockopen() or pfsockopen(). + * + * @author Pablo de Leon Belloc + * @see http://php.net/manual/en/function.fsockopen.php + */ +class SocketHandler extends AbstractProcessingHandler +{ + private $connectionString; + private $connectionTimeout; + private $resource; + private $timeout = 0; + private $persistent = false; + private $errno; + private $errstr; + + /** + * @param string $connectionString Socket connection string + * @param integer $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 + */ + public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + $this->connectionString = $connectionString; + $this->connectionTimeout = (float) ini_get('default_socket_timeout'); + } + + /** + * Connect (if necessary) and write to the socket + * + * @param array $record + * + * @throws \UnexpectedValueException + * @throws \RuntimeException + */ + public function write(array $record) + { + $this->connectIfNotConnected(); + $data = $this->generateDataStream($record); + $this->writeToSocket($data); + } + + /** + * We will not close a PersistentSocket instance so it can be reused in other requests. + */ + public function close() + { + if (!$this->isPersistent()) { + $this->closeSocket(); + } + } + + /** + * Close socket, if open + */ + public function closeSocket() + { + if (is_resource($this->resource)) { + fclose($this->resource); + $this->resource = null; + } + } + + /** + * Set socket connection to nbe persistent. It only has effect before the connection is initiated. + * + * @param type $boolean + */ + public function setPersistent($boolean) + { + $this->persistent = (boolean) $boolean; + } + + /** + * Set connection timeout. Only has effect before we connect. + * + * @param float $seconds + * + * @see http://php.net/manual/en/function.fsockopen.php + */ + public function setConnectionTimeout($seconds) + { + $this->validateTimeout($seconds); + $this->connectionTimeout = (float) $seconds; + } + + /** + * Set write timeout. Only has effect before we connect. + * + * @param float $seconds + * + * @see http://php.net/manual/en/function.stream-set-timeout.php + */ + public function setTimeout($seconds) + { + $this->validateTimeout($seconds); + $this->timeout = (float) $seconds; + } + + /** + * Get current connection string + * + * @return string + */ + public function getConnectionString() + { + return $this->connectionString; + } + + /** + * Get persistent setting + * + * @return boolean + */ + public function isPersistent() + { + return $this->persistent; + } + + /** + * Get current connection timeout setting + * + * @return float + */ + public function getConnectionTimeout() + { + return $this->connectionTimeout; + } + + /** + * Get current in-transfer timeout + * + * @return float + */ + public function getTimeout() + { + return $this->timeout; + } + + /** + * Check to see if the socket is currently available. + * + * UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details. + * + * @return boolean + */ + public function isConnected() + { + return is_resource($this->resource) + && !feof($this->resource); // on TCP - other party can close connection. + } + + /** + * Wrapper to allow mocking + */ + protected function pfsockopen() + { + return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout); + } + + /** + * Wrapper to allow mocking + */ + protected function fsockopen() + { + return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout); + } + + /** + * Wrapper to allow mocking + * + * @see http://php.net/manual/en/function.stream-set-timeout.php + */ + protected function streamSetTimeout() + { + $seconds = floor($this->timeout); + $microseconds = round(($this->timeout - $seconds)*1e6); + + return stream_set_timeout($this->resource, $seconds, $microseconds); + } + + /** + * Wrapper to allow mocking + */ + protected function fwrite($data) + { + return @fwrite($this->resource, $data); + } + + /** + * Wrapper to allow mocking + */ + protected function streamGetMetadata() + { + return stream_get_meta_data($this->resource); + } + + private function validateTimeout($value) + { + $ok = filter_var($value, FILTER_VALIDATE_FLOAT); + if ($ok === false || $value < 0) { + throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)"); + } + } + + private function connectIfNotConnected() + { + if ($this->isConnected()) { + return; + } + $this->connect(); + } + + protected function generateDataStream($record) + { + return (string) $record['formatted']; + } + + private function connect() + { + $this->createSocketResource(); + $this->setSocketTimeout(); + } + + private function createSocketResource() + { + if ($this->isPersistent()) { + $resource = $this->pfsockopen(); + } else { + $resource = $this->fsockopen(); + } + if (!$resource) { + throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)"); + } + $this->resource = $resource; + } + + private function setSocketTimeout() + { + if (!$this->streamSetTimeout()) { + throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()"); + } + } + + private function writeToSocket($data) + { + $length = strlen($data); + $sent = 0; + while ($this->isConnected() && $sent < $length) { + if (0 == $sent) { + $chunk = $this->fwrite($data); + } else { + $chunk = $this->fwrite(substr($data, $sent)); + } + if ($chunk === false) { + throw new \RuntimeException("Could not write to socket"); + } + $sent += $chunk; + $socketInfo = $this->streamGetMetadata(); + if ($socketInfo['timed_out']) { + throw new \RuntimeException("Write timed-out"); + } + } + if (!$this->isConnected() && $sent < $length) { + throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)"); + } + } + +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php new file mode 100644 index 0000000000..96ce7fc0c0 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php @@ -0,0 +1,76 @@ + + * + * 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; + +/** + * Stores to any stream resource + * + * Can be used to store into php://stderr, remote and local files, etc. + * + * @author Jordi Boggiano + */ +class StreamHandler extends AbstractProcessingHandler +{ + protected $stream; + protected $url; + + /** + * @param string $stream + * @param integer $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 + */ + public function __construct($stream, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + if (is_resource($stream)) { + $this->stream = $stream; + } else { + $this->url = $stream; + } + } + + /** + * {@inheritdoc} + */ + public function close() + { + if (is_resource($this->stream)) { + fclose($this->stream); + } + $this->stream = null; + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + if (null === $this->stream) { + if (!$this->url) { + throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().'); + } + $errorMessage = null; + set_error_handler(function ($code, $msg) use (&$errorMessage) { + $errorMessage = preg_replace('{^fopen\(.*?\): }', '', $msg); + }); + $this->stream = fopen($this->url, 'a'); + restore_error_handler(); + if (!is_resource($this->stream)) { + $this->stream = null; + throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$errorMessage, $this->url)); + } + } + fwrite($this->stream, (string) $record['formatted']); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php new file mode 100644 index 0000000000..ca03ccaa9a --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php @@ -0,0 +1,55 @@ + + * + * 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; + +/** + * SwiftMailerHandler uses Swift_Mailer to send the emails + * + * @author Gyula Sallai + */ +class SwiftMailerHandler extends MailHandler +{ + protected $mailer; + protected $message; + + /** + * @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 integer $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 + */ + public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true) + { + parent::__construct($level, $bubble); + $this->mailer = $mailer; + if (!$message instanceof \Swift_Message && is_callable($message)) { + $message = call_user_func($message); + } + if (!$message instanceof \Swift_Message) { + throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it'); + } + $this->message = $message; + } + + /** + * {@inheritdoc} + */ + protected function send($content, array $records) + { + $message = clone $this->message; + $message->setBody($content); + + $this->mailer->send($message); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php new file mode 100644 index 0000000000..924ccf47d7 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php @@ -0,0 +1,127 @@ + + * + * 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\Formatter\LineFormatter; + +/** + * Logs to syslog service. + * + * usage example: + * + * $log = new Logger('application'); + * $syslog = new SyslogHandler('myfacility', 'local6'); + * $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%"); + * $syslog->setFormatter($formatter); + * $log->pushHandler($syslog); + * + * @author Sven Paulus + */ +class SyslogHandler extends AbstractProcessingHandler +{ + protected $ident; + protected $logopts; + protected $facility; + + /** + * Translates Monolog log levels to syslog log priorities. + */ + private $logLevels = array( + Logger::DEBUG => LOG_DEBUG, + Logger::INFO => LOG_INFO, + Logger::NOTICE => LOG_NOTICE, + Logger::WARNING => LOG_WARNING, + Logger::ERROR => LOG_ERR, + Logger::CRITICAL => LOG_CRIT, + Logger::ALERT => LOG_ALERT, + Logger::EMERGENCY => LOG_EMERG, + ); + + /** + * List of valid log facility names. + */ + private $facilities = array( + 'auth' => LOG_AUTH, + 'authpriv' => LOG_AUTHPRIV, + 'cron' => LOG_CRON, + 'daemon' => LOG_DAEMON, + 'kern' => LOG_KERN, + 'lpr' => LOG_LPR, + 'mail' => LOG_MAIL, + 'news' => LOG_NEWS, + 'syslog' => LOG_SYSLOG, + 'user' => LOG_USER, + 'uucp' => LOG_UUCP, + ); + + /** + * @param string $ident + * @param mixed $facility + * @param integer $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 + */ + public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID) + { + parent::__construct($level, $bubble); + + if (!defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->facilities['local0'] = LOG_LOCAL0; + $this->facilities['local1'] = LOG_LOCAL1; + $this->facilities['local2'] = LOG_LOCAL2; + $this->facilities['local3'] = LOG_LOCAL3; + $this->facilities['local4'] = LOG_LOCAL4; + $this->facilities['local5'] = LOG_LOCAL5; + $this->facilities['local6'] = LOG_LOCAL6; + $this->facilities['local7'] = LOG_LOCAL7; + } + + // convert textual description of facility to syslog constant + if (array_key_exists(strtolower($facility), $this->facilities)) { + $facility = $this->facilities[strtolower($facility)]; + } elseif (!in_array($facility, array_values($this->facilities), true)) { + throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given'); + } + + $this->ident = $ident; + $this->logopts = $logopts; + $this->facility = $facility; + } + + /** + * {@inheritdoc} + */ + public function close() + { + closelog(); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + if (!openlog($this->ident, $this->logopts, $this->facility)) { + throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"'); + } + syslog($this->logLevels[$record['level']], (string) $record['formatted']); + } + + /** + * {@inheritdoc} + */ + protected function getDefaultFormatter() + { + return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%'); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php new file mode 100644 index 0000000000..085d9e1719 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php @@ -0,0 +1,140 @@ + + * + * 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; + +/** + * Used for testing purposes. + * + * It records all records and gives you access to them for verification. + * + * @author Jordi Boggiano + */ +class TestHandler extends AbstractProcessingHandler +{ + protected $records = array(); + protected $recordsByLevel = array(); + + public function getRecords() + { + return $this->records; + } + + public function hasEmergency($record) + { + return $this->hasRecord($record, Logger::EMERGENCY); + } + + public function hasAlert($record) + { + return $this->hasRecord($record, Logger::ALERT); + } + + public function hasCritical($record) + { + return $this->hasRecord($record, Logger::CRITICAL); + } + + public function hasError($record) + { + return $this->hasRecord($record, Logger::ERROR); + } + + public function hasWarning($record) + { + return $this->hasRecord($record, Logger::WARNING); + } + + public function hasNotice($record) + { + return $this->hasRecord($record, Logger::NOTICE); + } + + public function hasInfo($record) + { + return $this->hasRecord($record, Logger::INFO); + } + + public function hasDebug($record) + { + return $this->hasRecord($record, Logger::DEBUG); + } + + public function hasEmergencyRecords() + { + return isset($this->recordsByLevel[Logger::EMERGENCY]); + } + + public function hasAlertRecords() + { + return isset($this->recordsByLevel[Logger::ALERT]); + } + + public function hasCriticalRecords() + { + return isset($this->recordsByLevel[Logger::CRITICAL]); + } + + public function hasErrorRecords() + { + return isset($this->recordsByLevel[Logger::ERROR]); + } + + public function hasWarningRecords() + { + return isset($this->recordsByLevel[Logger::WARNING]); + } + + public function hasNoticeRecords() + { + return isset($this->recordsByLevel[Logger::NOTICE]); + } + + public function hasInfoRecords() + { + return isset($this->recordsByLevel[Logger::INFO]); + } + + public function hasDebugRecords() + { + return isset($this->recordsByLevel[Logger::DEBUG]); + } + + protected function hasRecord($record, $level) + { + if (!isset($this->recordsByLevel[$level])) { + return false; + } + + if (is_array($record)) { + $record = $record['message']; + } + + foreach ($this->recordsByLevel[$level] as $rec) { + if ($rec['message'] === $record) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $this->recordsByLevel[$record['level']][] = $record; + $this->records[] = $record; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php new file mode 100644 index 0000000000..f22cf21874 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php @@ -0,0 +1,95 @@ + + * + * 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\NormalizerFormatter; +use Monolog\Logger; + +/** + * Handler sending logs to Zend Monitor + * + * @author Christian Bergau + */ +class ZendMonitorHandler extends AbstractProcessingHandler +{ + /** + * Monolog level / ZendMonitor Custom Event priority map + * + * @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, + ); + + /** + * Construct + * + * @param int $level + * @param bool $bubble + * @throws MissingExtensionException + */ + 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'); + } + parent::__construct($level, $bubble); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) + { + $this->writeZendMonitorCustomEvent( + $this->levelMap[$record['level']], + $record['message'], + $record['formatted'] + ); + } + + /** + * Write a record to Zend Monitor + * + * @param int $level + * @param string $message + * @param array $formatted + */ + protected function writeZendMonitorCustomEvent($level, $message, $formatted) + { + zend_monitor_custom_event($level, $message, $formatted); + } + + /** + * {@inheritdoc} + */ + public function getDefaultFormatter() + { + return new NormalizerFormatter(); + } + + /** + * Get the level map + * + * @return array + */ + public function getLevelMap() + { + return $this->levelMap; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Logger.php b/vendor/monolog/monolog/src/Monolog/Logger.php new file mode 100644 index 0000000000..65f9257505 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Logger.php @@ -0,0 +1,574 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use Monolog\Handler\HandlerInterface; +use Monolog\Handler\StreamHandler; +use Psr\Log\LoggerInterface; +use Psr\Log\InvalidArgumentException; + +/** + * Monolog log channel + * + * It contains a stack of Handlers and a stack of Processors, + * and uses them to store records that are added to it. + * + * @author Jordi Boggiano + */ +class Logger implements LoggerInterface +{ + /** + * Detailed debug information + */ + const DEBUG = 100; + + /** + * Interesting events + * + * Examples: User logs in, SQL logs. + */ + const INFO = 200; + + /** + * Uncommon events + */ + const NOTICE = 250; + + /** + * Exceptional occurrences that are not errors + * + * Examples: Use of deprecated APIs, poor use of an API, + * undesirable things that are not necessarily wrong. + */ + const WARNING = 300; + + /** + * Runtime errors + */ + const ERROR = 400; + + /** + * Critical conditions + * + * Example: Application component unavailable, unexpected exception. + */ + const CRITICAL = 500; + + /** + * Action must be taken immediately + * + * Example: Entire website down, database unavailable, etc. + * This should trigger the SMS alerts and wake you up. + */ + const ALERT = 550; + + /** + * Urgent alert. + */ + const EMERGENCY = 600; + + /** + * Monolog API version + * + * This is only bumped when API breaks are done and should + * follow the major version of the library + * + * @var int + */ + const API = 1; + + protected static $levels = array( + 100 => 'DEBUG', + 200 => 'INFO', + 250 => 'NOTICE', + 300 => 'WARNING', + 400 => 'ERROR', + 500 => 'CRITICAL', + 550 => 'ALERT', + 600 => 'EMERGENCY', + ); + + /** + * @var DateTimeZone + */ + protected static $timezone; + + protected $name; + + /** + * The handler stack + * + * @var array of Monolog\Handler\HandlerInterface + */ + protected $handlers; + + /** + * Processors that will process all log records + * + * To process records of a single handler instead, add the processor on that specific handler + * + * @var array of callables + */ + protected $processors; + + /** + * @param string $name The logging channel + * @param array $handlers Optional stack of handlers, the first one in the array is called first, etc. + * @param array $processors Optional array of processors + */ + public function __construct($name, array $handlers = array(), array $processors = array()) + { + $this->name = $name; + $this->handlers = $handlers; + $this->processors = $processors; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Pushes a handler on to the stack. + * + * @param HandlerInterface $handler + */ + public function pushHandler(HandlerInterface $handler) + { + array_unshift($this->handlers, $handler); + } + + /** + * Pops a handler from the stack + * + * @return HandlerInterface + */ + public function popHandler() + { + if (!$this->handlers) { + throw new \LogicException('You tried to pop from an empty handler stack.'); + } + + return array_shift($this->handlers); + } + + /** + * Adds a processor on to the stack. + * + * @param callable $callback + */ + public function pushProcessor($callback) + { + if (!is_callable($callback)) { + throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given'); + } + array_unshift($this->processors, $callback); + } + + /** + * Removes the processor on top of the stack and returns it. + * + * @return callable + */ + public function popProcessor() + { + if (!$this->processors) { + throw new \LogicException('You tried to pop from an empty processor stack.'); + } + + return array_shift($this->processors); + } + + /** + * Adds a log record. + * + * @param integer $level The logging level + * @param string $message The log message + * @param array $context The log context + * @return Boolean Whether the record has been processed + */ + public function addRecord($level, $message, array $context = array()) + { + if (!$this->handlers) { + $this->pushHandler(new StreamHandler('php://stderr', static::DEBUG)); + } + + if (!static::$timezone) { + static::$timezone = new \DateTimeZone(date_default_timezone_get() ?: 'UTC'); + } + + $record = array( + 'message' => (string) $message, + 'context' => $context, + 'level' => $level, + 'level_name' => static::getLevelName($level), + 'channel' => $this->name, + 'datetime' => \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone)->setTimezone(static::$timezone), + 'extra' => array(), + ); + // check if any handler will handle this message + $handlerKey = null; + foreach ($this->handlers as $key => $handler) { + if ($handler->isHandling($record)) { + $handlerKey = $key; + break; + } + } + // none found + if (null === $handlerKey) { + return false; + } + + // found at least one, process message and dispatch it + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + while (isset($this->handlers[$handlerKey]) && + false === $this->handlers[$handlerKey]->handle($record)) { + $handlerKey++; + } + + return true; + } + + /** + * 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 + */ + public function addDebug($message, array $context = array()) + { + return $this->addRecord(static::DEBUG, $message, $context); + } + + /** + * 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 + */ + public function addInfo($message, array $context = array()) + { + return $this->addRecord(static::INFO, $message, $context); + } + + /** + * 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 + */ + public function addNotice($message, array $context = array()) + { + return $this->addRecord(static::NOTICE, $message, $context); + } + + /** + * 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 + */ + public function addWarning($message, array $context = array()) + { + return $this->addRecord(static::WARNING, $message, $context); + } + + /** + * 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 + */ + public function addError($message, array $context = array()) + { + return $this->addRecord(static::ERROR, $message, $context); + } + + /** + * 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 + */ + public function addCritical($message, array $context = array()) + { + return $this->addRecord(static::CRITICAL, $message, $context); + } + + /** + * 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 + */ + public function addAlert($message, array $context = array()) + { + return $this->addRecord(static::ALERT, $message, $context); + } + + /** + * 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 + */ + public function addEmergency($message, array $context = array()) + { + return $this->addRecord(static::EMERGENCY, $message, $context); + } + + /** + * Gets all supported logging levels. + * + * @return array Assoc array with human-readable level names => level codes. + */ + public static function getLevels() + { + return array_flip(static::$levels); + } + + /** + * Gets the name of the logging level. + * + * @param integer $level + * @return string + */ + public static function getLevelName($level) + { + if (!isset(static::$levels[$level])) { + throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels))); + } + + return static::$levels[$level]; + } + + /** + * Checks whether the Logger has a handler that listens on the given level + * + * @param integer $level + * @return Boolean + */ + public function isHandling($level) + { + $record = array( + 'level' => $level, + ); + + foreach ($this->handlers as $handler) { + if ($handler->isHandling($record)) { + return true; + } + } + + return false; + } + + /** + * 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 + */ + public function log($level, $message, array $context = array()) + { + if (is_string($level) && defined(__CLASS__.'::'.strtoupper($level))) { + $level = constant(__CLASS__.'::'.strtoupper($level)); + } + + return $this->addRecord($level, $message, $context); + } + + /** + * Adds a log record at the DEBUG level. + * + * 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 + */ + public function debug($message, array $context = array()) + { + return $this->addRecord(static::DEBUG, $message, $context); + } + + /** + * Adds a log record at the INFO level. + * + * 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 + */ + public function info($message, array $context = array()) + { + return $this->addRecord(static::INFO, $message, $context); + } + + /** + * Adds a log record at the INFO level. + * + * 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 + */ + public function notice($message, array $context = array()) + { + return $this->addRecord(static::NOTICE, $message, $context); + } + + /** + * Adds a log record at the WARNING level. + * + * 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 + */ + public function warn($message, array $context = array()) + { + return $this->addRecord(static::WARNING, $message, $context); + } + + /** + * Adds a log record at the WARNING level. + * + * 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 + */ + public function warning($message, array $context = array()) + { + return $this->addRecord(static::WARNING, $message, $context); + } + + /** + * Adds a log record at the ERROR level. + * + * 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 + */ + public function err($message, array $context = array()) + { + return $this->addRecord(static::ERROR, $message, $context); + } + + /** + * Adds a log record at the ERROR level. + * + * 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 + */ + public function error($message, array $context = array()) + { + return $this->addRecord(static::ERROR, $message, $context); + } + + /** + * Adds a log record at the CRITICAL level. + * + * 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 + */ + public function crit($message, array $context = array()) + { + return $this->addRecord(static::CRITICAL, $message, $context); + } + + /** + * Adds a log record at the CRITICAL level. + * + * 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 + */ + public function critical($message, array $context = array()) + { + return $this->addRecord(static::CRITICAL, $message, $context); + } + + /** + * Adds a log record at the ALERT level. + * + * 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 + */ + public function alert($message, array $context = array()) + { + return $this->addRecord(static::ALERT, $message, $context); + } + + /** + * Adds a log record at the EMERGENCY level. + * + * 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 + */ + public function emerg($message, array $context = array()) + { + return $this->addRecord(static::EMERGENCY, $message, $context); + } + + /** + * Adds a log record at the EMERGENCY level. + * + * 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 + */ + public function emergency($message, array $context = array()) + { + return $this->addRecord(static::EMERGENCY, $message, $context); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php new file mode 100644 index 0000000000..b126218ee4 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Injects line/file:class/function where the log message came from + * + * Warning: This only works if the handler processes the logs directly. + * If you put the processor on a handler that is behind a FingersCrossedHandler + * for example, the processor will only be called once the trigger level is reached, + * and all the log records will have the same file/line/.. data from the call that + * triggered the FingersCrossedHandler. + * + * @author Jordi Boggiano + */ +class IntrospectionProcessor +{ + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + $trace = debug_backtrace(); + + // skip first since it's always the current method + array_shift($trace); + // the call_user_func call is also skipped + array_shift($trace); + + $i = 0; + while (isset($trace[$i]['class']) && false !== strpos($trace[$i]['class'], 'Monolog\\')) { + $i++; + } + + // we should have the call source now + $record['extra'] = array_merge( + $record['extra'], + array( + 'file' => isset($trace[$i-1]['file']) ? $trace[$i-1]['file'] : null, + 'line' => isset($trace[$i-1]['line']) ? $trace[$i-1]['line'] : null, + 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null, + 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null, + ) + ); + + return $record; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php new file mode 100644 index 0000000000..e48672bf2e --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.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\Processor; + +/** + * Injects memory_get_peak_usage in all records + * + * @see Monolog\Processor\MemoryProcessor::__construct() for options + * @author Rob Jensen + */ +class MemoryPeakUsageProcessor extends MemoryProcessor +{ + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + $bytes = memory_get_peak_usage($this->realUsage); + $formatted = self::formatBytes($bytes); + + $record['extra'] = array_merge( + $record['extra'], + array( + 'memory_peak_usage' => $formatted, + ) + ); + + return $record; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php new file mode 100644 index 0000000000..7551043e12 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Some methods that are common for all memory processors + * + * @author Rob Jensen + */ +abstract class MemoryProcessor +{ + protected $realUsage; + + /** + * @param boolean $realUsage + */ + public function __construct($realUsage = true) + { + $this->realUsage = (boolean) $realUsage; + } + + /** + * Formats bytes into a human readable string + * + * @param int $bytes + * @return string + */ + protected static function formatBytes($bytes) + { + $bytes = (int) $bytes; + + if ($bytes > 1024*1024) { + return round($bytes/1024/1024, 2).' MB'; + } elseif ($bytes > 1024) { + return round($bytes/1024, 2).' KB'; + } + + return $bytes . ' B'; + } + +} diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php new file mode 100644 index 0000000000..2c4a8079f0 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.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\Processor; + +/** + * Injects memory_get_usage in all records + * + * @see Monolog\Processor\MemoryProcessor::__construct() for options + * @author Rob Jensen + */ +class MemoryUsageProcessor extends MemoryProcessor +{ + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + $bytes = memory_get_usage($this->realUsage); + $formatted = self::formatBytes($bytes); + + $record['extra'] = array_merge( + $record['extra'], + array( + 'memory_usage' => $formatted, + ) + ); + + return $record; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php new file mode 100644 index 0000000000..9bd5e5eaa1 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.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\Processor; + +/** + * Adds value of getmypid into records + * + * @author Andreas Hörnicke + */ +class ProcessIdProcessor +{ + private static $pid; + + public function __construct() + { + if (null === self::$pid) { + self::$pid = getmypid(); + } + } + + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + $record['extra']['process_id'] = self::$pid; + + return $record; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php new file mode 100644 index 0000000000..b63fcccce3 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Processes a record's message according to PSR-3 rules + * + * It replaces {foo} with the value from $context['foo'] + * + * @author Jordi Boggiano + */ +class PsrLogMessageProcessor +{ + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + if (false === strpos($record['message'], '{')) { + return $record; + } + + $replacements = array(); + foreach ($record['context'] as $key => $val) { + $replacements['{'.$key.'}'] = $val; + } + + $record['message'] = strtr($record['message'], $replacements); + + return $record; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php new file mode 100644 index 0000000000..80270d08ad --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Adds a unique identifier into records + * + * @author Simon Mönch + */ +class UidProcessor +{ + private $uid; + + public function __construct($length = 7) + { + if (!is_int($length) || $length > 32 || $length < 1) { + throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32'); + } + + $this->uid = substr(hash('md5', uniqid('', true)), 0, $length); + } + + public function __invoke(array $record) + { + $record['extra']['uid'] = $this->uid; + + return $record; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php new file mode 100644 index 0000000000..9916cc087f --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.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\Processor; + +/** + * Injects url/method and remote IP of the current web request in all records + * + * @author Jordi Boggiano + */ +class WebProcessor +{ + protected $serverData; + + /** + * @param mixed $serverData array or object w/ ArrayAccess that provides access to the $_SERVER data + */ + public function __construct($serverData = null) + { + if (null === $serverData) { + $this->serverData =& $_SERVER; + } elseif (is_array($serverData) || $serverData instanceof \ArrayAccess) { + $this->serverData = $serverData; + } else { + throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.'); + } + } + + /** + * @param array $record + * @return array + */ + public function __invoke(array $record) + { + // skip processing if for some reason request data + // is not present (CLI or wonky SAPIs) + if (!isset($this->serverData['REQUEST_URI'])) { + return $record; + } + + $record['extra'] = array_merge( + $record['extra'], + array( + 'url' => $this->serverData['REQUEST_URI'], + 'ip' => isset($this->serverData['REMOTE_ADDR']) ? $this->serverData['REMOTE_ADDR'] : null, + 'http_method' => isset($this->serverData['REQUEST_METHOD']) ? $this->serverData['REQUEST_METHOD'] : null, + 'server' => isset($this->serverData['SERVER_NAME']) ? $this->serverData['SERVER_NAME'] : null, + 'referrer' => isset($this->serverData['HTTP_REFERER']) ? $this->serverData['HTTP_REFERER'] : null, + ) + ); + + return $record; + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php new file mode 100644 index 0000000000..a9a3f301f8 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.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; + +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 new file mode 100644 index 0000000000..e7f7334e2c --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php @@ -0,0 +1,158 @@ + + * + * 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/GelfMessageFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php new file mode 100644 index 0000000000..a1db166af5 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -0,0 +1,158 @@ + + * + * 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\Formatter\GelfMessageFormatter; + +class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!class_exists("Gelf\Message")) { + $this->markTestSkipped("mlehner/gelf-php 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(3, $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 + */ + 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 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']); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php new file mode 100644 index 0000000000..ba6152c943 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php @@ -0,0 +1,41 @@ + + * + * 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::format + */ + public function testFormat() + { + $formatter = new JsonFormatter(); + $record = $this->getRecord(); + $this->assertEquals(json_encode($record), $formatter->format($record)); + } + + /** + * @covers Monolog\Formatter\JsonFormatter::formatBatch + */ + public function testFormatBatch() + { + $formatter = new JsonFormatter(); + $records = array( + $this->getRecord(Logger::WARNING), + $this->getRecord(Logger::DEBUG), + ); + $this->assertEquals(json_encode($records), $formatter->formatBatch($records)); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php new file mode 100644 index 0000000000..fa3fa59d03 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php @@ -0,0 +1,164 @@ + + * + * 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', + ) + )); + $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foo {"foo":"bar","baz":"qux"} []'."\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 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: {})","baz":[],"res":"[resource]"}'."\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: 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: Foo at '.substr($path, 1, -1).':'.(__LINE__-8).', LogicException: 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); + } +} + +class TestFoo +{ + public $foo = 'foo'; +} + +class TestBar +{ + public function __toString() + { + return 'bar'; + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php new file mode 100644 index 0000000000..6b012deaa7 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php @@ -0,0 +1,160 @@ + + * + * 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\Formatter\LogstashFormatter; + +class LogstashFormatterTest extends \PHPUnit_Framework_TestCase +{ + + /** + * @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+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']); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php new file mode 100644 index 0000000000..7477871284 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -0,0 +1,182 @@ + + * + * 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 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', + ), + )); + + $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: {})', + 'baz' => array(), + 'res' => '[resource]', + ), + 'context' => array( + 'foo' => 'bar', + 'baz' => 'qux', + ) + ), $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(), + 'file' => $e2->getFile().':'.$e2->getLine(), + ) + ), $formatted); + } + + 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); + } +} + +class TestFooNorm +{ + public $foo = 'foo'; +} + +class TestBarNorm +{ + public function __toString() + { + return 'bar'; + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php b/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php new file mode 100644 index 0000000000..0b07e330fd --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php @@ -0,0 +1,111 @@ + + * + * 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)); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Functional/Handler/FirePHPHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Functional/Handler/FirePHPHandlerTest.php new file mode 100644 index 0000000000..65b530970e --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Functional/Handler/FirePHPHandlerTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +spl_autoload_register(function($class) { + $file = __DIR__.'/../../../../src/'.strtr($class, '\\', '/').'.php'; + if (file_exists($file)) { + require $file; + + return true; + } +}); + +use Monolog\Logger; +use Monolog\Handler\FirePHPHandler; +use Monolog\Handler\ChromePHPHandler; + +$logger = new Logger('firephp'); +$logger->pushHandler(new FirePHPHandler); +$logger->pushHandler(new ChromePHPHandler()); + +$logger->addDebug('Debug'); +$logger->addInfo('Info'); +$logger->addWarning('Warning'); +$logger->addError('Error'); diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php new file mode 100644 index 0000000000..01d522fa41 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php @@ -0,0 +1,104 @@ + + * + * 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::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 new file mode 100644 index 0000000000..3485bdf34a --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php @@ -0,0 +1,79 @@ + + * + * 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' => '', + ))); + $handledRecord = null; + $handler->expects($this->once()) + ->method('write') + ->will($this->returnCallback(function($record) use (&$handledRecord) { + $handledRecord = $record; + })) + ; + $handler->handle($this->getRecord()); + $this->assertEquals(5, count($handledRecord['extra'])); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/AmqpExchangeMock.php b/vendor/monolog/monolog/tests/Monolog/Handler/AmqpExchangeMock.php new file mode 100644 index 0000000000..3415c82c4f --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/AmqpExchangeMock.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +class AmqpExchangeMock extends \AMQPExchange +{ + protected $messages = array(); + + public function __construct() + { + } + + public function publish($message, $routing_key, $params = 0, $attributes = array()) + { + $this->messages[] = array($message, $routing_key, $params, $attributes); + + return true; + } + + public function getMessages() + { + return $this->messages; + } + + public function setName($name) + { + return true; + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php new file mode 100644 index 0000000000..7369091696 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php @@ -0,0 +1,74 @@ + + * + * 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\RotatingFileHandler + */ +class AmqpHandlerTest extends TestCase +{ + public function setUp() + { + 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"); + } + } + + public function testHandle() + { + $exchange = $this->getExchange(); + + $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); + + $messages = $exchange->getMessages(); + $this->assertCount(1, $messages); + $messages[0][0] = json_decode($messages[0][0], true); + unset($messages[0][0]['datetime']); + $this->assertEquals($expected, $messages[0]); + } + + protected function getExchange() + { + return new AmqpExchangeMock(); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php new file mode 100644 index 0000000000..beb08cf8a0 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php @@ -0,0 +1,149 @@ + + * + * 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 +{ + /** + * @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 testDestructPropagatesRecords() + { + $test = new TestHandler(); + $handler = new BufferHandler($test); + $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->__destruct(); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasDebugRecords()); + } + + /** + * @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 new file mode 100644 index 0000000000..9fa4d50682 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -0,0 +1,139 @@ + + * + * 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(); + } + + public function testHeaders() + { + $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 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::$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 new file mode 100644 index 0000000000..78a1d15cdc --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php @@ -0,0 +1,41 @@ + + * + * 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)); + + $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(), + ); + + $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/DoctrineCouchDBHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php new file mode 100644 index 0000000000..d67da90aec --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php @@ -0,0 +1,52 @@ + + * + * 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/FingersCrossedHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php new file mode 100644 index 0000000000..7713e6a93b --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php @@ -0,0 +1,189 @@ + + * + * 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; + +class FingersCrossedHandlerTest extends TestCase +{ + /** + * @covers Monolog\Handler\FingersCrossedHandler::__construct + * @covers Monolog\Handler\FingersCrossedHandler::handle + */ + 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)); + $this->assertTrue($test->hasInfoRecords()); + $this->assertTrue(count($test->getRecords()) === 3); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + */ + public function testHandleStopsBufferingAfterTrigger() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test); + $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Logger::DEBUG)); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasDebugRecords()); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + * @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)); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasDebugRecords()); + $this->assertFalse($test->hasInfoRecords()); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + */ + 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)); + $this->assertTrue($test->hasWarningRecords()); + $this->assertTrue($test->hasDebugRecords()); + $this->assertFalse($test->hasInfoRecords()); + } + + /** + * @covers Monolog\Handler\FingersCrossedHandler::handle + */ + 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 + */ + 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 + * @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\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\FingersCrossedHandler::handle + */ + 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']); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php new file mode 100644 index 0000000000..2b7b76d984 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php @@ -0,0 +1,94 @@ + + * + * 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(); + } + + 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::$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 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php new file mode 100644 index 0000000000..8e9b9f8ad4 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php @@ -0,0 +1,94 @@ + + * + * 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\GelfMessageFormatter; + +class GelfHandlerTest extends TestCase +{ + public function setUp() + { + if (!class_exists("Gelf\MessagePublisher") || !class_exists("Gelf\Message")) { + $this->markTestSkipped("mlehner/gelf-php not installed"); + } + + require_once __DIR__ . '/GelfMocks.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 MockMessagePublisher('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/GelfMocks.php b/vendor/monolog/monolog/tests/Monolog/Handler/GelfMocks.php new file mode 100644 index 0000000000..dda8711406 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/GelfMocks.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\Handler; + +use Gelf\MessagePublisher; +use Gelf\Message; + +class MockMessagePublisher 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 new file mode 100644 index 0000000000..c6298a6e6e --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php @@ -0,0 +1,89 @@ + + * + * 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']); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php new file mode 100644 index 0000000000..c393cf42ab --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php @@ -0,0 +1,110 @@ + + * + * 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; + 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; + } + + /** + * @depends testWriteHeader + */ + public function testWriteContent($content) + { + $this->assertRegexp('/from=Monolog&room_id=room1¬ify=0&message=test1&message_format=text&color=red$/', $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); + } + + /** + * @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'), + ); + } + + private function createHandler($token = 'myToken', $room = 'room1', $name = 'Monolog', $notify = false) + { + $constructorArgs = array($token, $room, $name, $notify, Logger::DEBUG); + $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()); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php new file mode 100644 index 0000000000..6754f3d623 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php @@ -0,0 +1,75 @@ + + * + * 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 new file mode 100644 index 0000000000..fbaab9bc3d --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php @@ -0,0 +1,26 @@ + + * + * 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) + { + $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 new file mode 100644 index 0000000000..ce3433e17b --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.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\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')); + $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 new file mode 100644 index 0000000000..50ceace0f0 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php @@ -0,0 +1,43 @@ + + * + * 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 NativeMailerHandlerTest extends TestCase +{ + /** + * @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")); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php new file mode 100644 index 0000000000..bc7bcab8ad --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php @@ -0,0 +1,65 @@ + + * + * 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 NewRelicHandlerTest extends TestCase +{ + /** + * @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 testThehandlerCanAddParamsToTheNewRelicTrace() + { + $handler = new StubNewRelicHandler(); + $handler->handle($this->getRecord(Logger::ERROR, 'log message', array('a' => 'b'))); + } +} + +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_add_custom_parameter() +{ + return true; +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php new file mode 100644 index 0000000000..292df78c7f --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php @@ -0,0 +1,33 @@ + + * + * 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/PushoverHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php new file mode 100644 index 0000000000..a7d24d2a14 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php @@ -0,0 +1,142 @@ + + * + * 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', Logger::EMERGENCY); + $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$/', $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=2POST/', $content); + $this->assertRegexp('/token=myToken&user=userB&message=test1&title=Monolog×tamp=\d{10}&priority=2$/', $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 new file mode 100644 index 0000000000..9c13c3f4ad --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php @@ -0,0 +1,135 @@ + + * + * 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\RavenHandler; + +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 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(); + + $logFormatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); + $logFormatter->expects($this->once())->method('formatBatch'); + + $formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface'); + $formatter->expects($this->once())->method('format'); + + $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 testGetSetBatchFormatter() + { + $ravenClient = $this->getRavenClient(); + $handler = $this->getHandler($ravenClient); + + $handler->setBatchFormatter($formatter = new LineFormatter()); + $this->assertSame($formatter, $handler->getBatchFormatter()); + } + + 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 new file mode 100644 index 0000000000..3629f8a247 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php @@ -0,0 +1,71 @@ + + * + * 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); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php new file mode 100644 index 0000000000..f4cefda178 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -0,0 +1,99 @@ + + * + * 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\RotatingFileHandler + */ +class RotatingFileHandlerTest extends TestCase +{ + public function setUp() + { + $dir = __DIR__.'/Fixtures'; + chmod($dir, 0777); + if (!is_writable($dir)) { + $this->markTestSkipped($dir.' must be writeable to test the RotatingFileHandler.'); + } + } + + 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) + { + touch($old1 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400).'.rot'); + touch($old2 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 2).'.rot'); + touch($old3 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 3).'.rot'); + touch($old4 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 4).'.rot'); + + $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot'; + + if ($createFile) { + touch($log); + } + + $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2); + $handler->setFormatter($this->getIdentityFormatter()); + $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() + { + return array( + 'Rotation is triggered when the file of the current day is not present' + => array(true), + 'Rotation is not triggered when the file is already present' + => array(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); + } + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php new file mode 100644 index 0000000000..c642bea8b9 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php @@ -0,0 +1,283 @@ + + * + * 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 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)); + } + + 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 new file mode 100644 index 0000000000..63d4fef6d4 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php @@ -0,0 +1,88 @@ + + * + * 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 testClose() + { + $handle = fopen('php://memory', 'a+'); + $handler = new StreamHandler($handle); + $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()); + } + + /** + * @expectedException LogicException + * @covers Monolog\Handler\StreamHandler::__construct + * @covers Monolog\Handler\StreamHandler::write + */ + public function testWriteMissingResource() + { + $handler = new StreamHandler(null); + $handler->handle($this->getRecord()); + } + + /** + * @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('/foo/bar/baz/'.rand(0, 10000)); + $handler->handle($this->getRecord()); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php new file mode 100644 index 0000000000..98219ac12d --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php @@ -0,0 +1,43 @@ + + * + * 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/TestHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php new file mode 100644 index 0000000000..801d80a9a2 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php @@ -0,0 +1,56 @@ + + * + * 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->{'has'.$method}($record)); + $this->assertFalse($handler->{'has'.$method.'Records'}()); + $handler->handle($record); + + $this->assertFalse($handler->{'has'.$method}('bar')); + $this->assertTrue($handler->{'has'.$method}($record)); + $this->assertTrue($handler->{'has'.$method}('test'.$method)); + $this->assertTrue($handler->{'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/ZendMonitorHandlerTest.php b/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php new file mode 100644 index 0000000000..416039e65d --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -0,0 +1,69 @@ + + * + * 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 new file mode 100644 index 0000000000..8bcbbf90a1 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/LoggerTest.php @@ -0,0 +1,409 @@ + + * + * 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::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::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 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), + ); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php new file mode 100644 index 0000000000..9adbe1742b --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php @@ -0,0 +1,65 @@ + + * + * 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; +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(58, $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(64, $record['extra']['line']); + $this->assertEquals(null, $record['extra']['class']); + $this->assertEquals('Acme\tester', $record['extra']['function']); + } +} + +namespace Acme; + +class Tester +{ + public function test($handler, $record) + { + $handler->handle($record); + } +} + +function tester($handler, $record) +{ + $handler->handle($record); +} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php new file mode 100644 index 0000000000..4bdf22c363 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php @@ -0,0 +1,29 @@ + + * + * 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']); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php new file mode 100644 index 0000000000..a30d6de630 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php @@ -0,0 +1,29 @@ + + * + * 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']); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php new file mode 100644 index 0000000000..458d2a33a6 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php @@ -0,0 +1,30 @@ + + * + * 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/UidProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php new file mode 100644 index 0000000000..7ced62ca0e --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php @@ -0,0 +1,27 @@ + + * + * 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']); + } +} diff --git a/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php b/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php new file mode 100644 index 0000000000..04a5422136 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php @@ -0,0 +1,68 @@ + + * + * 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', + ); + + $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']); + } + + 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']); + } + + /** + * @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 new file mode 100644 index 0000000000..ab89944962 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php @@ -0,0 +1,47 @@ + + * + * 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/TestCase.php b/vendor/monolog/monolog/tests/Monolog/TestCase.php new file mode 100644 index 0000000000..1067b91974 --- /dev/null +++ b/vendor/monolog/monolog/tests/Monolog/TestCase.php @@ -0,0 +1,58 @@ + + * + * 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/monolog/monolog/tests/bootstrap.php b/vendor/monolog/monolog/tests/bootstrap.php new file mode 100644 index 0000000000..189f4a68f7 --- /dev/null +++ b/vendor/monolog/monolog/tests/bootstrap.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +$loader = require_once __DIR__ . "/../vendor/autoload.php"; +$loader->add('Monolog\\', __DIR__); diff --git a/vendor/php-ffmpeg/php-ffmpeg b/vendor/php-ffmpeg/php-ffmpeg new file mode 160000 index 0000000000..9fcb485d49 --- /dev/null +++ b/vendor/php-ffmpeg/php-ffmpeg @@ -0,0 +1 @@ +Subproject commit 9fcb485d497872e674cb14eb3df1386dbda9169b diff --git a/vendor/psr/log/LICENSE b/vendor/psr/log/LICENSE new file mode 100644 index 0000000000..474c952b4b --- /dev/null +++ b/vendor/psr/log/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 PHP Framework Interoperability Group + +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/psr/log/Psr/Log/AbstractLogger.php b/vendor/psr/log/Psr/Log/AbstractLogger.php new file mode 100644 index 0000000000..00f9034521 --- /dev/null +++ b/vendor/psr/log/Psr/Log/AbstractLogger.php @@ -0,0 +1,120 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + * @return null + */ + public function alert($message, array $context = array()) + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + * @return null + */ + public function critical($message, array $context = array()) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param array $context + * @return null + */ + public function error($message, array $context = array()) + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + * @return null + */ + public function warning($message, array $context = array()) + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * @return null + */ + public function notice($message, array $context = array()) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * @return null + */ + public function info($message, array $context = array()) + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * @return null + */ + public function debug($message, array $context = array()) + { + $this->log(LogLevel::DEBUG, $message, $context); + } +} diff --git a/vendor/psr/log/Psr/Log/InvalidArgumentException.php b/vendor/psr/log/Psr/Log/InvalidArgumentException.php new file mode 100644 index 0000000000..67f852d1db --- /dev/null +++ b/vendor/psr/log/Psr/Log/InvalidArgumentException.php @@ -0,0 +1,7 @@ +logger = $logger; + } +} diff --git a/vendor/psr/log/Psr/Log/LoggerInterface.php b/vendor/psr/log/Psr/Log/LoggerInterface.php new file mode 100644 index 0000000000..476bb962af --- /dev/null +++ b/vendor/psr/log/Psr/Log/LoggerInterface.php @@ -0,0 +1,114 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + * @return null + */ + public function alert($message, array $context = array()) + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + * @return null + */ + public function critical($message, array $context = array()) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param array $context + * @return null + */ + public function error($message, array $context = array()) + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + * @return null + */ + public function warning($message, array $context = array()) + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * @return null + */ + public function notice($message, array $context = array()) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * @return null + */ + public function info($message, array $context = array()) + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * @return null + */ + public function debug($message, array $context = array()) + { + $this->log(LogLevel::DEBUG, $message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * @return null + */ + 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 new file mode 100644 index 0000000000..553a3c593a --- /dev/null +++ b/vendor/psr/log/Psr/Log/NullLogger.php @@ -0,0 +1,27 @@ +logger) { }` + * blocks. + */ +class NullLogger extends AbstractLogger +{ + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * @return null + */ + public function log($level, $message, array $context = array()) + { + // noop + } +} diff --git a/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php b/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php new file mode 100644 index 0000000000..a932815111 --- /dev/null +++ b/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php @@ -0,0 +1,116 @@ + " + * + * Example ->error('Foo') would yield "error Foo" + * + * @return string[] + */ + abstract function getLogs(); + + public function testImplements() + { + $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); + } + + /** + * @dataProvider provideLevelsAndMessages + */ + public function testLogsAtAllLevels($level, $message) + { + $logger = $this->getLogger(); + $logger->{$level}($message, array('user' => 'Bob')); + $logger->log($level, $message, array('user' => 'Bob')); + + $expected = array( + $level.' message of level '.$level.' with context: Bob', + $level.' message of level '.$level.' with context: Bob', + ); + $this->assertEquals($expected, $this->getLogs()); + } + + public function provideLevelsAndMessages() + { + return array( + LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'), + LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'), + LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'), + LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'), + LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'), + LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'), + LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'), + LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'), + ); + } + + /** + * @expectedException Psr\Log\InvalidArgumentException + */ + public function testThrowsOnInvalidLevel() + { + $logger = $this->getLogger(); + $logger->log('invalid level', 'Foo'); + } + + public function testContextReplacement() + { + $logger = $this->getLogger(); + $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar')); + + $expected = array('info {Message {nothing} Bob Bar a}'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testObjectCastToString() + { + $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString')); + $dummy->expects($this->once()) + ->method('__toString') + ->will($this->returnValue('DUMMY')); + + $this->getLogger()->warning($dummy); + } + + public function testContextCanContainAnything() + { + $context = array( + 'bool' => true, + 'null' => null, + 'string' => 'Foo', + 'int' => 0, + 'float' => 0.5, + 'nested' => array('with object' => new DummyTest), + 'object' => new \DateTime, + 'resource' => fopen('php://memory', 'r'), + ); + + $this->getLogger()->warning('Crazy context data', $context); + } + + public function testContextExceptionKeyCanBeExceptionOrOtherValues() + { + $this->getLogger()->warning('Random message', array('exception' => 'oops')); + $this->getLogger()->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail'))); + } +} + +class DummyTest +{ +} \ No newline at end of file diff --git a/vendor/psr/log/README.md b/vendor/psr/log/README.md new file mode 100644 index 0000000000..574bc1cb2a --- /dev/null +++ b/vendor/psr/log/README.md @@ -0,0 +1,45 @@ +PSR Log +======= + +This repository holds all interfaces/classes/traits related to +[PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md). + +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. + +Usage +----- + +If you need a logger, you can use the interface like this: + +```php +logger = $logger; + } + + public function doSomething() + { + if ($this->logger) { + $this->logger->info('Doing work'); + } + + // do something useful + } +} +``` + +You can then pick one of the implementations of the interface to get a logger. + +If you want to implement the interface, you can require this package and +implement `Psr\Log\LoggerInterface` in your code. Please read the +[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +for details. diff --git a/vendor/psr/log/composer.json b/vendor/psr/log/composer.json new file mode 100644 index 0000000000..6bdcc2194b --- /dev/null +++ b/vendor/psr/log/composer.json @@ -0,0 +1,17 @@ +{ + "name": "psr/log", + "description": "Common interface for logging libraries", + "keywords": ["psr", "psr-3", "log"], + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/CHANGELOG.md b/vendor/symfony/process/Symfony/Component/Process/CHANGELOG.md new file mode 100644 index 0000000000..3bad982fcb --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/CHANGELOG.md @@ -0,0 +1,26 @@ +CHANGELOG +========= + +2.3.0 +----- + + * added ProcessUtils::escapeArgument() to fix the bug in escapeshellarg() function on Windows + * added Process::signal() + * added Process::getPid() + * added support for a TTY mode + +2.2.0 +----- + + * added ProcessBuilder::setArguments() to reset the arguments on a builder + * added a way to retrieve the standard and error output incrementally + * added Process:restart() + +2.1.0 +----- + + * added support for non-blocking processes (start(), wait(), isRunning(), stop()) + * enhanced Windows compatibility + * added Process::getExitCodeText() that returns a string representation for + the exit code returned by the process + * added ProcessBuilder diff --git a/vendor/symfony/process/Symfony/Component/Process/Exception/ExceptionInterface.php b/vendor/symfony/process/Symfony/Component/Process/Exception/ExceptionInterface.php new file mode 100644 index 0000000000..75c1c9e5d8 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Exception; + +/** + * Marker Interface for the Process Component. + * + * @author Johannes M. Schmitt + */ +interface ExceptionInterface +{ +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Exception/InvalidArgumentException.php b/vendor/symfony/process/Symfony/Component/Process/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000..926ee2118b --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Exception; + +/** + * InvalidArgumentException for the Process Component. + * + * @author Romain Neutron + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Exception/LogicException.php b/vendor/symfony/process/Symfony/Component/Process/Exception/LogicException.php new file mode 100644 index 0000000000..be3d490dde --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Exception/LogicException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Exception; + +/** + * LogicException for the Process Component. + * + * @author Romain Neutron + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Exception/ProcessFailedException.php b/vendor/symfony/process/Symfony/Component/Process/Exception/ProcessFailedException.php new file mode 100644 index 0000000000..890935933b --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Exception/ProcessFailedException.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Exception; + +use Symfony\Component\Process\Process; + +/** + * Exception for failed processes. + * + * @author Johannes M. Schmitt + */ +class ProcessFailedException extends RuntimeException +{ + private $process; + + public function __construct(Process $process) + { + if ($process->isSuccessful()) { + throw new InvalidArgumentException('Expected a failed process, but the given process was successful.'); + } + + parent::__construct( + sprintf( + 'The command "%s" failed.'."\nExit Code: %s(%s)\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", + $process->getCommandLine(), + $process->getExitCode(), + $process->getExitCodeText(), + $process->getOutput(), + $process->getErrorOutput() + ) + ); + + $this->process = $process; + } + + public function getProcess() + { + return $this->process; + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Exception/RuntimeException.php b/vendor/symfony/process/Symfony/Component/Process/Exception/RuntimeException.php new file mode 100644 index 0000000000..adead2536b --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Exception/RuntimeException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Exception; + +/** + * RuntimeException for the Process Component. + * + * @author Johannes M. Schmitt + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/process/Symfony/Component/Process/ExecutableFinder.php b/vendor/symfony/process/Symfony/Component/Process/ExecutableFinder.php new file mode 100644 index 0000000000..5cc99c7692 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/ExecutableFinder.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process; + +/** + * Generic executable finder. + * + * @author Fabien Potencier + * @author Johannes M. Schmitt + */ +class ExecutableFinder +{ + private $suffixes = array('.exe', '.bat', '.cmd', '.com'); + + /** + * Replaces default suffixes of executable. + * + * @param array $suffixes + */ + public function setSuffixes(array $suffixes) + { + $this->suffixes = $suffixes; + } + + /** + * Adds new possible suffix to check for executable. + * + * @param string $suffix + */ + public function addSuffix($suffix) + { + $this->suffixes[] = $suffix; + } + + /** + * Finds an executable by name. + * + * @param string $name The executable name (without the extension) + * @param string $default The default to return if no executable is found + * @param array $extraDirs Additional dirs to check into + * + * @return string The executable path or default value + */ + public function find($name, $default = null, array $extraDirs = array()) + { + if (ini_get('open_basedir')) { + $searchPath = explode(PATH_SEPARATOR, getenv('open_basedir')); + $dirs = array(); + foreach ($searchPath as $path) { + if (is_dir($path)) { + $dirs[] = $path; + } else { + $file = str_replace(dirname($path), '', $path); + if ($file == $name && is_executable($path)) { + return $path; + } + } + } + } else { + $dirs = array_merge( + explode(PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')), + $extraDirs + ); + } + + $suffixes = array(''); + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $pathExt = getenv('PATHEXT'); + $suffixes = $pathExt ? explode(PATH_SEPARATOR, $pathExt) : $this->suffixes; + } + foreach ($suffixes as $suffix) { + foreach ($dirs as $dir) { + if (is_file($file = $dir.DIRECTORY_SEPARATOR.$name.$suffix) && (defined('PHP_WINDOWS_VERSION_BUILD') || is_executable($file))) { + return $file; + } + } + } + + return $default; + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/LICENSE b/vendor/symfony/process/Symfony/Component/Process/LICENSE new file mode 100644 index 0000000000..88a57f8d8d --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2013 Fabien Potencier + +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/symfony/process/Symfony/Component/Process/PhpExecutableFinder.php b/vendor/symfony/process/Symfony/Component/Process/PhpExecutableFinder.php new file mode 100644 index 0000000000..6c9b8a1149 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/PhpExecutableFinder.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 Symfony\Component\Process; + +/** + * An executable finder specifically designed for the PHP executable. + * + * @author Fabien Potencier + * @author Johannes M. Schmitt + */ +class PhpExecutableFinder +{ + private $executableFinder; + + public function __construct() + { + $this->executableFinder = new ExecutableFinder(); + } + + /** + * Finds The PHP executable. + * + * @return string|false The PHP executable path or false if it cannot be found + */ + public function find() + { + // PHP_BINARY return the current sapi executable + if (defined('PHP_BINARY') && PHP_BINARY && ('cli' === PHP_SAPI) && is_file(PHP_BINARY)) { + return PHP_BINARY; + } + + if ($php = getenv('PHP_PATH')) { + if (!is_executable($php)) { + return false; + } + + return $php; + } + + if ($php = getenv('PHP_PEAR_PHP_BIN')) { + if (is_executable($php)) { + return $php; + } + } + + $dirs = array(PHP_BINDIR); + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $dirs[] = 'C:\xampp\php\\'; + } + + return $this->executableFinder->find('php', false, $dirs); + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/PhpProcess.php b/vendor/symfony/process/Symfony/Component/Process/PhpProcess.php new file mode 100644 index 0000000000..d146057e08 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/PhpProcess.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 Symfony\Component\Process; + +use Symfony\Component\Process\Exception\RuntimeException; + +/** + * PhpProcess runs a PHP script in an independent process. + * + * $p = new PhpProcess(''); + * $p->run(); + * print $p->getOutput()."\n"; + * + * @author Fabien Potencier + * + * @api + */ +class PhpProcess extends Process +{ + private $executableFinder; + + /** + * Constructor. + * + * @param string $script The PHP script to run (as a string) + * @param string $cwd The working directory + * @param array $env The environment variables + * @param integer $timeout The timeout in seconds + * @param array $options An array of options for proc_open + * + * @api + */ + public function __construct($script, $cwd = null, array $env = array(), $timeout = 60, array $options = array()) + { + parent::__construct(null, $cwd, $env, $script, $timeout, $options); + + $this->executableFinder = new PhpExecutableFinder(); + } + + /** + * Sets the path to the PHP binary to use. + * + * @api + */ + public function setPhpBinary($php) + { + $this->setCommandLine($php); + } + + /** + * {@inheritdoc} + */ + public function start($callback = null) + { + if (null === $this->getCommandLine()) { + if (false === $php = $this->executableFinder->find()) { + throw new RuntimeException('Unable to find the PHP executable.'); + } + $this->setCommandLine($php); + } + + parent::start($callback); + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Process.php b/vendor/symfony/process/Symfony/Component/Process/Process.php new file mode 100644 index 0000000000..6d0b3c537b --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Process.php @@ -0,0 +1,1291 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process; + +use Symfony\Component\Process\Exception\InvalidArgumentException; +use Symfony\Component\Process\Exception\LogicException; +use Symfony\Component\Process\Exception\RuntimeException; + +/** + * Process is a thin wrapper around proc_* functions to ease + * start independent PHP processes. + * + * @author Fabien Potencier + * + * @api + */ +class Process +{ + const ERR = 'err'; + const OUT = 'out'; + + const STATUS_READY = 'ready'; + const STATUS_STARTED = 'started'; + const STATUS_TERMINATED = 'terminated'; + + const STDIN = 0; + const STDOUT = 1; + const STDERR = 2; + + // Timeout Precision in seconds. + const TIMEOUT_PRECISION = 0.2; + + private $callback; + private $commandline; + private $cwd; + private $env; + private $stdin; + private $starttime; + private $timeout; + private $options; + private $exitcode; + private $fallbackExitcode; + private $processInformation; + private $stdout; + private $stderr; + private $enhanceWindowsCompatibility; + private $enhanceSigchildCompatibility; + private $pipes; + private $process; + private $status = self::STATUS_READY; + private $incrementalOutputOffset; + private $incrementalErrorOutputOffset; + private $tty; + + private $fileHandles; + private $readBytes; + + private static $sigchild; + + /** + * Exit codes translation table. + * + * User-defined errors must use exit codes in the 64-113 range. + * + * @var array + */ + public static $exitCodes = array( + 0 => 'OK', + 1 => 'General error', + 2 => 'Misuse of shell builtins', + + 126 => 'Invoked command cannot execute', + 127 => 'Command not found', + 128 => 'Invalid exit argument', + + // signals + 129 => 'Hangup', + 130 => 'Interrupt', + 131 => 'Quit and dump core', + 132 => 'Illegal instruction', + 133 => 'Trace/breakpoint trap', + 134 => 'Process aborted', + 135 => 'Bus error: "access to undefined portion of memory object"', + 136 => 'Floating point exception: "erroneous arithmetic operation"', + 137 => 'Kill (terminate immediately)', + 138 => 'User-defined 1', + 139 => 'Segmentation violation', + 140 => 'User-defined 2', + 141 => 'Write to pipe with no one reading', + 142 => 'Signal raised by alarm', + 143 => 'Termination (request to terminate)', + // 144 - not defined + 145 => 'Child process terminated, stopped (or continued*)', + 146 => 'Continue if stopped', + 147 => 'Stop executing temporarily', + 148 => 'Terminal stop signal', + 149 => 'Background process attempting to read from tty ("in")', + 150 => 'Background process attempting to write to tty ("out")', + 151 => 'Urgent data available on socket', + 152 => 'CPU time limit exceeded', + 153 => 'File size limit exceeded', + 154 => 'Signal raised by timer counting virtual time: "virtual timer expired"', + 155 => 'Profiling timer expired', + // 156 - not defined + 157 => 'Pollable event', + // 158 - not defined + 159 => 'Bad syscall', + ); + + /** + * Constructor. + * + * @param string $commandline The command line to run + * @param string $cwd The working directory + * @param array $env The environment variables or null to inherit + * @param string $stdin The STDIN content + * @param integer $timeout The timeout in seconds + * @param array $options An array of options for proc_open + * + * @throws RuntimeException When proc_open is not installed + * + * @api + */ + public function __construct($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()) + { + if (!function_exists('proc_open')) { + throw new RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.'); + } + + $this->commandline = $commandline; + $this->cwd = $cwd; + + // on windows, if the cwd changed via chdir(), proc_open defaults to the dir where php was started + // on gnu/linux, PHP builds with --enable-maintainer-zts are also affected + // @see : https://bugs.php.net/bug.php?id=51800 + // @see : https://bugs.php.net/bug.php?id=50524 + + if (null === $this->cwd && (defined('ZEND_THREAD_SAFE') || defined('PHP_WINDOWS_VERSION_BUILD'))) { + $this->cwd = getcwd(); + } + if (null !== $env) { + $this->setEnv($env); + } else { + $this->env = null; + } + $this->stdin = $stdin; + $this->setTimeout($timeout); + $this->enhanceWindowsCompatibility = true; + $this->enhanceSigchildCompatibility = !defined('PHP_WINDOWS_VERSION_BUILD') && $this->isSigchildEnabled(); + $this->options = array_replace(array('suppress_errors' => true, 'binary_pipes' => true), $options); + } + + public function __destruct() + { + // stop() will check if we have a process running. + $this->stop(); + } + + public function __clone() + { + $this->resetProcessData(); + } + + /** + * Runs the process. + * + * The callback receives the type of output (out or err) and + * some bytes from the output in real-time. It allows to have feedback + * from the independent process during execution. + * + * The STDOUT and STDERR are also available after the process is finished + * via the getOutput() and getErrorOutput() methods. + * + * @param callback|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @return integer The exit status code + * + * @throws RuntimeException When process can't be launch or is stopped + * + * @api + */ + public function run($callback = null) + { + $this->start($callback); + + return $this->wait(); + } + + /** + * Starts the process and returns after sending the STDIN. + * + * This method blocks until all STDIN data is sent to the process then it + * returns while the process runs in the background. + * + * The termination of the process can be awaited with wait(). + * + * The callback receives the type of output (out or err) and some bytes from + * the output in real-time while writing the standard input to the process. + * It allows to have feedback from the independent process during execution. + * If there is no callback passed, the wait() method can be called + * with true as a second parameter then the callback will get all data occurred + * in (and since) the start call. + * + * @param callback|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @throws RuntimeException When process can't be launch or is stopped + * @throws RuntimeException When process is already running + */ + public function start($callback = null) + { + if ($this->isRunning()) { + throw new RuntimeException('Process is already running'); + } + + $this->resetProcessData(); + $this->starttime = microtime(true); + $this->callback = $this->buildCallback($callback); + $descriptors = $this->getDescriptors(); + + $commandline = $this->commandline; + + if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->enhanceWindowsCompatibility) { + $commandline = 'cmd /V:ON /E:ON /C "'.$commandline.'"'; + if (!isset($this->options['bypass_shell'])) { + $this->options['bypass_shell'] = true; + } + } + + $this->process = proc_open($commandline, $descriptors, $this->pipes, $this->cwd, $this->env, $this->options); + + if (!is_resource($this->process)) { + throw new RuntimeException('Unable to launch a new process.'); + } + $this->status = self::STATUS_STARTED; + + foreach ($this->pipes as $pipe) { + stream_set_blocking($pipe, false); + } + + $this->writePipes(); + $this->updateStatus(false); + $this->checkTimeout(); + } + + /** + * Restarts the process. + * + * Be warned that the process is cloned before being started. + * + * @param callable $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @return Process The new process + * + * @throws \RuntimeException When process can't be launch or is stopped + * @throws \RuntimeException When process is already running + * + * @see start() + */ + public function restart($callback = null) + { + if ($this->isRunning()) { + throw new RuntimeException('Process is already running'); + } + + $process = clone $this; + $process->start($callback); + + return $process; + } + + /** + * Waits for the process to terminate. + * + * The callback receives the type of output (out or err) and some bytes + * from the output in real-time while writing the standard input to the process. + * It allows to have feedback from the independent process during execution. + * + * @param callback|null $callback A valid PHP callback + * + * @return integer The exitcode of the process + * + * @throws \RuntimeException When process timed out + * @throws \RuntimeException When process stopped after receiving signal + */ + public function wait($callback = null) + { + $this->updateStatus(false); + if (null !== $callback) { + $this->callback = $this->buildCallback($callback); + } + while ($this->pipes || (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles)) { + $this->checkTimeout(); + $this->readPipes(true); + } + $this->updateStatus(false); + if ($this->processInformation['signaled']) { + if ($this->isSigchildEnabled()) { + throw new RuntimeException('The process has been signaled.'); + } + + throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig'])); + } + + $time = 0; + while ($this->isRunning() && $time < 1000000) { + $time += 1000; + usleep(1000); + } + + if ($this->processInformation['signaled']) { + if ($this->isSigchildEnabled()) { + throw new RuntimeException('The process has been signaled.'); + } + + throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig'])); + } + + return $this->exitcode; + } + + /** + * Returns the Pid (process identifier), if applicable. + * + * @return integer|null The process id if running, null otherwise + * + * @throws RuntimeException In case --enable-sigchild is activated + */ + public function getPid() + { + if ($this->isSigchildEnabled()) { + throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.'); + } + + $this->updateStatus(false); + + return $this->isRunning() ? $this->processInformation['pid'] : null; + } + + /** + * Sends a posix signal to the process. + * + * @param integer $signal A valid posix signal (see http://www.php.net/manual/en/pcntl.constants.php) + * @return Process + * + * @throws LogicException In case the process is not running + * @throws RuntimeException In case --enable-sigchild is activated + * @throws RuntimeException In case of failure + */ + public function signal($signal) + { + if (!$this->isRunning()) { + throw new LogicException('Can not send signal on a non running process.'); + } + + if ($this->isSigchildEnabled()) { + throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); + } + + if (true !== @proc_terminate($this->process, $signal)) { + throw new RuntimeException(sprintf('Error while sending signal `%d`.', $signal)); + } + + return $this; + } + + /** + * Returns the current output of the process (STDOUT). + * + * @return string The process output + * + * @api + */ + public function getOutput() + { + $this->readPipes(false); + + return $this->stdout; + } + + /** + * Returns the output incrementally. + * + * In comparison with the getOutput method which always return the whole + * output, this one returns the new output since the last call. + * + * @return string The process output since the last call + */ + public function getIncrementalOutput() + { + $data = $this->getOutput(); + + $latest = substr($data, $this->incrementalOutputOffset); + $this->incrementalOutputOffset = strlen($data); + + return $latest; + } + + /** + * Returns the current error output of the process (STDERR). + * + * @return string The process error output + * + * @api + */ + public function getErrorOutput() + { + $this->readPipes(false); + + return $this->stderr; + } + + /** + * Returns the errorOutput incrementally. + * + * In comparison with the getErrorOutput method which always return the + * whole error output, this one returns the new error output since the last + * call. + * + * @return string The process error output since the last call + */ + public function getIncrementalErrorOutput() + { + $data = $this->getErrorOutput(); + + $latest = substr($data, $this->incrementalErrorOutputOffset); + $this->incrementalErrorOutputOffset = strlen($data); + + return $latest; + } + + /** + * Returns the exit code returned by the process. + * + * @return integer The exit status code + * + * @throws RuntimeException In case --enable-sigchild is activated and the sigchild compatibility mode is disabled + * + * @api + */ + public function getExitCode() + { + if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) { + throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method'); + } + + $this->updateStatus(false); + + return $this->exitcode; + } + + /** + * Returns a string representation for the exit code returned by the process. + * + * This method relies on the Unix exit code status standardization + * and might not be relevant for other operating systems. + * + * @return string A string representation for the exit status code + * + * @see http://tldp.org/LDP/abs/html/exitcodes.html + * @see http://en.wikipedia.org/wiki/Unix_signal + */ + public function getExitCodeText() + { + $exitcode = $this->getExitCode(); + + return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error'; + } + + /** + * Checks if the process ended successfully. + * + * @return Boolean true if the process ended successfully, false otherwise + * + * @api + */ + public function isSuccessful() + { + return 0 === $this->getExitCode(); + } + + /** + * Returns true if the child process has been terminated by an uncaught signal. + * + * It always returns false on Windows. + * + * @return Boolean + * + * @throws RuntimeException In case --enable-sigchild is activated + * + * @api + */ + public function hasBeenSignaled() + { + if ($this->isSigchildEnabled()) { + throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved'); + } + + $this->updateStatus(false); + + return $this->processInformation['signaled']; + } + + /** + * Returns the number of the signal that caused the child process to terminate its execution. + * + * It is only meaningful if hasBeenSignaled() returns true. + * + * @return integer + * + * @throws RuntimeException In case --enable-sigchild is activated + * + * @api + */ + public function getTermSignal() + { + if ($this->isSigchildEnabled()) { + throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved'); + } + + $this->updateStatus(false); + + return $this->processInformation['termsig']; + } + + /** + * Returns true if the child process has been stopped by a signal. + * + * It always returns false on Windows. + * + * @return Boolean + * + * @api + */ + public function hasBeenStopped() + { + $this->updateStatus(false); + + return $this->processInformation['stopped']; + } + + /** + * Returns the number of the signal that caused the child process to stop its execution. + * + * It is only meaningful if hasBeenStopped() returns true. + * + * @return integer + * + * @api + */ + public function getStopSignal() + { + $this->updateStatus(false); + + return $this->processInformation['stopsig']; + } + + /** + * Checks if the process is currently running. + * + * @return Boolean true if the process is currently running, false otherwise + */ + public function isRunning() + { + if (self::STATUS_STARTED !== $this->status) { + return false; + } + + $this->updateStatus(false); + + return $this->processInformation['running']; + } + + /** + * Checks if the process has been started with no regard to the current state. + * + * @return Boolean true if status is ready, false otherwise + */ + public function isStarted() + { + return $this->status != self::STATUS_READY; + } + + /** + * Checks if the process is terminated. + * + * @return Boolean true if process is terminated, false otherwise + */ + public function isTerminated() + { + $this->updateStatus(false); + + return $this->status == self::STATUS_TERMINATED; + } + + /** + * Gets the process status. + * + * The status is one of: ready, started, terminated. + * + * @return string The current process status + */ + public function getStatus() + { + $this->updateStatus(false); + + return $this->status; + } + + /** + * Stops the process. + * + * @param integer|float $timeout The timeout in seconds + * @param integer $signal A posix signal to send in case the process has not stop at timeout, default is SIGKILL + * + * @return integer The exit-code of the process + * + * @throws RuntimeException if the process got signaled + */ + public function stop($timeout = 10, $signal = null) + { + $timeoutMicro = microtime(true) + $timeout; + if ($this->isRunning()) { + proc_terminate($this->process); + do { + usleep(1000); + } while ($this->isRunning() && microtime(true) < $timeoutMicro); + + if ($this->isRunning() && !$this->isSigchildEnabled()) { + if (null !== $signal || defined('SIGKILL')) { + $this->signal($signal ?: SIGKILL); + } + } + + $this->updateStatus(false); + } + $this->status = self::STATUS_TERMINATED; + + return $this->exitcode; + } + + /** + * Adds a line to the STDOUT stream. + * + * @param string $line The line to append + */ + public function addOutput($line) + { + $this->stdout .= $line; + } + + /** + * Adds a line to the STDERR stream. + * + * @param string $line The line to append + */ + public function addErrorOutput($line) + { + $this->stderr .= $line; + } + + /** + * Gets the command line to be executed. + * + * @return string The command to execute + */ + public function getCommandLine() + { + return $this->commandline; + } + + /** + * Sets the command line to be executed. + * + * @param string $commandline The command to execute + * + * @return self The current Process instance + */ + public function setCommandLine($commandline) + { + $this->commandline = $commandline; + + return $this; + } + + /** + * Gets the process timeout. + * + * @return integer|null The timeout in seconds or null if it's disabled + */ + public function getTimeout() + { + return $this->timeout; + } + + /** + * Sets the process timeout. + * + * To disable the timeout, set this value to null. + * + * @param float|null $timeout The timeout in seconds + * + * @return self The current Process instance + * + * @throws InvalidArgumentException if the timeout is negative + */ + public function setTimeout($timeout) + { + if (null === $timeout) { + $this->timeout = null; + + return $this; + } + + $timeout = (float) $timeout; + + if ($timeout < 0) { + throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.'); + } + + $this->timeout = $timeout; + + return $this; + } + + /** + * Enables or disables the TTY mode. + * + * @param boolean $tty True to enabled and false to disable + * + * @return self The current Process instance + */ + public function setTty($tty) + { + $this->tty = (Boolean) $tty; + + return $this; + } + + /** + * Checks if the TTY mode is enabled. + * + * @return Boolean true if the TTY mode is enabled, false otherwise + */ + public function isTty() + { + return $this->tty; + } + + /** + * Gets the working directory. + * + * @return string The current working directory + */ + public function getWorkingDirectory() + { + // This is for BC only + if (null === $this->cwd) { + // getcwd() will return false if any one of the parent directories does not have + // the readable or search mode set, even if the current directory does + return getcwd() ?: null; + } + + return $this->cwd; + } + + /** + * Sets the current working directory. + * + * @param string $cwd The new working directory + * + * @return self The current Process instance + */ + public function setWorkingDirectory($cwd) + { + $this->cwd = $cwd; + + return $this; + } + + /** + * Gets the environment variables. + * + * @return array The current environment variables + */ + public function getEnv() + { + return $this->env; + } + + /** + * Sets the environment variables. + * + * An environment variable value should be a string. + * If it is an array, the variable is ignored. + * + * That happens in PHP when 'argv' is registered into + * the $_ENV array for instance. + * + * @param array $env The new environment variables + * + * @return self The current Process instance + */ + public function setEnv(array $env) + { + // Process can not handle env values that are arrays + $env = array_filter($env, function ($value) { if (!is_array($value)) { return true; } }); + + $this->env = array(); + foreach ($env as $key => $value) { + $this->env[(binary) $key] = (binary) $value; + } + + return $this; + } + + /** + * Gets the contents of STDIN. + * + * @return string The current contents + */ + public function getStdin() + { + return $this->stdin; + } + + /** + * Sets the contents of STDIN. + * + * @param string $stdin The new contents + * + * @return self The current Process instance + */ + public function setStdin($stdin) + { + $this->stdin = $stdin; + + return $this; + } + + /** + * Gets the options for proc_open. + * + * @return array The current options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Sets the options for proc_open. + * + * @param array $options The new options + * + * @return self The current Process instance + */ + public function setOptions(array $options) + { + $this->options = $options; + + return $this; + } + + /** + * Gets whether or not Windows compatibility is enabled. + * + * This is true by default. + * + * @return Boolean + */ + public function getEnhanceWindowsCompatibility() + { + return $this->enhanceWindowsCompatibility; + } + + /** + * Sets whether or not Windows compatibility is enabled. + * + * @param Boolean $enhance + * + * @return self The current Process instance + */ + public function setEnhanceWindowsCompatibility($enhance) + { + $this->enhanceWindowsCompatibility = (Boolean) $enhance; + + return $this; + } + + /** + * Returns whether sigchild compatibility mode is activated or not. + * + * @return Boolean + */ + public function getEnhanceSigchildCompatibility() + { + return $this->enhanceSigchildCompatibility; + } + + /** + * Activates sigchild compatibility mode. + * + * Sigchild compatibility mode is required to get the exit code and + * determine the success of a process when PHP has been compiled with + * the --enable-sigchild option + * + * @param Boolean $enhance + * + * @return self The current Process instance + */ + public function setEnhanceSigchildCompatibility($enhance) + { + $this->enhanceSigchildCompatibility = (Boolean) $enhance; + + return $this; + } + + /** + * Performs a check between the timeout definition and the time the process started. + * + * In case you run a background process (with the start method), you should + * trigger this method regularly to ensure the process timeout + * + * @throws RuntimeException In case the timeout was reached + */ + public function checkTimeout() + { + if (0 < $this->timeout && $this->timeout < microtime(true) - $this->starttime) { + $this->stop(0); + + throw new RuntimeException('The process timed-out.'); + } + } + + /** + * Creates the descriptors needed by the proc_open. + * + * @return array + */ + private function getDescriptors() + { + //Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big. + //Workaround for this problem is to use temporary files instead of pipes on Windows platform. + //@see https://bugs.php.net/bug.php?id=51800 + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->fileHandles = array( + self::STDOUT => tmpfile(), + ); + if (false === $this->fileHandles[self::STDOUT]) { + throw new RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable'); + } + $this->readBytes = array( + self::STDOUT => 0, + ); + + return array(array('pipe', 'r'), $this->fileHandles[self::STDOUT], array('pipe', 'w')); + } + + if ($this->tty) { + $descriptors = array( + array('file', '/dev/tty', 'r'), + array('file', '/dev/tty', 'w'), + array('file', '/dev/tty', 'w'), + ); + } else { + $descriptors = array( + array('pipe', 'r'), // stdin + array('pipe', 'w'), // stdout + array('pipe', 'w'), // stderr + ); + } + + if ($this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { + // last exit code is output on the fourth pipe and caught to work around --enable-sigchild + $descriptors = array_merge($descriptors, array(array('pipe', 'w'))); + + $this->commandline = '('.$this->commandline.') 3>/dev/null; code=$?; echo $code >&3; exit $code'; + } + + return $descriptors; + } + + /** + * Builds up the callback used by wait(). + * + * The callbacks adds all occurred output to the specific buffer and calls + * the user callback (if present) with the received output. + * + * @param callback|null $callback The user defined PHP callback + * + * @return callback A PHP callable + */ + protected function buildCallback($callback) + { + $that = $this; + $out = self::OUT; + $err = self::ERR; + $callback = function ($type, $data) use ($that, $callback, $out, $err) { + if ($out == $type) { + $that->addOutput($data); + } else { + $that->addErrorOutput($data); + } + + if (null !== $callback) { + call_user_func($callback, $type, $data); + } + }; + + return $callback; + } + + /** + * Updates the status of the process, reads pipes. + * + * @param Boolean $blocking Whether to use a clocking read call. + */ + protected function updateStatus($blocking) + { + if (self::STATUS_STARTED !== $this->status) { + return; + } + + $this->readPipes($blocking); + + $this->processInformation = proc_get_status($this->process); + $this->captureExitCode(); + if (!$this->processInformation['running']) { + $this->close(); + $this->status = self::STATUS_TERMINATED; + } + } + + /** + * Returns whether PHP has been compiled with the '--enable-sigchild' option or not. + * + * @return Boolean + */ + protected function isSigchildEnabled() + { + if (null !== self::$sigchild) { + return self::$sigchild; + } + + ob_start(); + phpinfo(INFO_GENERAL); + + return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild'); + } + + /** + * Handles the windows file handles fallbacks. + * + * @param Boolean $closeEmptyHandles if true, handles that are empty will be assumed closed + */ + private function processFileHandles($closeEmptyHandles = false) + { + $fh = $this->fileHandles; + foreach ($fh as $type => $fileHandle) { + fseek($fileHandle, $this->readBytes[$type]); + $data = fread($fileHandle, 8192); + if (strlen($data) > 0) { + $this->readBytes[$type] += strlen($data); + call_user_func($this->callback, $type == 1 ? self::OUT : self::ERR, $data); + } + if (false === $data || ($closeEmptyHandles && '' === $data && feof($fileHandle))) { + fclose($fileHandle); + unset($this->fileHandles[$type]); + } + } + } + + /** + * Returns true if a system call has been interrupted. + * + * @return Boolean + */ + private function hasSystemCallBeenInterrupted() + { + $lastError = error_get_last(); + + // stream_select returns false when the `select` system call is interrupted by an incoming signal + return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call'); + } + + /** + * Reads pipes, executes callback. + * + * @param Boolean $blocking Whether to use blocking calls or not. + */ + private function readPipes($blocking) + { + if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles) { + $this->processFileHandles(!$this->pipes); + } + + if ($this->pipes) { + $r = $this->pipes; + $w = null; + $e = null; + + // let's have a look if something changed in streams + if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? ceil(self::TIMEOUT_PRECISION * 1E6) : 0)) { + // if a system call has been interrupted, forget about it, let's try again + // otherwise, an error occured, let's reset pipes + if (!$this->hasSystemCallBeenInterrupted()) { + $this->pipes = array(); + } + + return; + } + + // nothing has changed + if (0 === $n) { + return; + } + + $this->processReadPipes($r); + } + } + + /** + * Writes data to pipes. + * + * @param Boolean $blocking Whether to use blocking calls or not. + */ + private function writePipes() + { + if ($this->tty) { + $this->status = self::STATUS_TERMINATED; + + return; + } + + if (null === $this->stdin) { + fclose($this->pipes[0]); + unset($this->pipes[0]); + + return; + } + + $writePipes = array($this->pipes[0]); + unset($this->pipes[0]); + $stdinLen = strlen($this->stdin); + $stdinOffset = 0; + + while ($writePipes) { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->processFileHandles(); + } + + $r = $this->pipes; + $w = $writePipes; + $e = null; + + if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? ceil(static::TIMEOUT_PRECISION * 1E6) : 0)) { + // if a system call has been interrupted, forget about it, let's try again + if ($this->hasSystemCallBeenInterrupted()) { + continue; + } + break; + } + + // nothing has changed, let's wait until the process is ready + if (0 === $n) { + continue; + } + + if ($w) { + $written = fwrite($writePipes[0], (binary) substr($this->stdin, $stdinOffset), 8192); + if (false !== $written) { + $stdinOffset += $written; + } + if ($stdinOffset >= $stdinLen) { + fclose($writePipes[0]); + $writePipes = null; + } + } + + $this->processReadPipes($r); + } + } + + /** + * Processes read pipes, executes callback on it. + * + * @param array $pipes + */ + private function processReadPipes(array $pipes) + { + foreach ($pipes as $pipe) { + $type = array_search($pipe, $this->pipes); + $data = fread($pipe, 8192); + + if (strlen($data) > 0) { + // last exit code is output and caught to work around --enable-sigchild + if (3 == $type) { + $this->fallbackExitcode = (int) $data; + } else { + call_user_func($this->callback, $type == 1 ? self::OUT : self::ERR, $data); + } + } + if (false === $data || feof($pipe)) { + fclose($pipe); + unset($this->pipes[$type]); + } + } + } + + /** + * Captures the exitcode if mentioned in the process informations. + */ + private function captureExitCode() + { + if (isset($this->processInformation['exitcode']) && -1 != $this->processInformation['exitcode']) { + $this->exitcode = $this->processInformation['exitcode']; + } + } + + + /** + * Closes process resource, closes file handles, sets the exitcode. + * + * @return Integer The exitcode + */ + private function close() + { + foreach ($this->pipes as $pipe) { + fclose($pipe); + } + + $this->pipes = null; + $exitcode = -1; + + if (is_resource($this->process)) { + $exitcode = proc_close($this->process); + } + + $this->exitcode = $this->exitcode !== null ? $this->exitcode : -1; + $this->exitcode = -1 != $exitcode ? $exitcode : $this->exitcode; + + if (-1 == $this->exitcode && null !== $this->fallbackExitcode) { + $this->exitcode = $this->fallbackExitcode; + } elseif (-1 === $this->exitcode && $this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) { + // if process has been signaled, no exitcode but a valid termsig, apply unix convention + $this->exitcode = 128 + $this->processInformation['termsig']; + } + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + foreach ($this->fileHandles as $fileHandle) { + fclose($fileHandle); + } + $this->fileHandles = array(); + } + + return $this->exitcode; + } + + /** + * Resets data related to the latest run of the process. + */ + private function resetProcessData() + { + $this->starttime = null; + $this->callback = null; + $this->exitcode = null; + $this->fallbackExitcode = null; + $this->processInformation = null; + $this->stdout = null; + $this->stderr = null; + $this->pipes = null; + $this->process = null; + $this->status = self::STATUS_READY; + $this->fileHandles = null; + $this->readBytes = null; + $this->incrementalOutputOffset = 0; + $this->incrementalErrorOutputOffset = 0; + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/ProcessBuilder.php b/vendor/symfony/process/Symfony/Component/Process/ProcessBuilder.php new file mode 100644 index 0000000000..ddd064a2b8 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/ProcessBuilder.php @@ -0,0 +1,174 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process; + +use Symfony\Component\Process\Exception\InvalidArgumentException; +use Symfony\Component\Process\Exception\LogicException; + +/** + * Process builder. + * + * @author Kris Wallsmith + */ +class ProcessBuilder +{ + private $arguments; + private $cwd; + private $env; + private $stdin; + private $timeout; + private $options; + private $inheritEnv; + private $prefix; + + public function __construct(array $arguments = array()) + { + $this->arguments = $arguments; + + $this->timeout = 60; + $this->options = array(); + $this->env = array(); + $this->inheritEnv = true; + } + + public static function create(array $arguments = array()) + { + return new static($arguments); + } + + /** + * Adds an unescaped argument to the command string. + * + * @param string $argument A command argument + * + * @return ProcessBuilder + */ + public function add($argument) + { + $this->arguments[] = $argument; + + return $this; + } + + /** + * Adds an unescaped prefix to the command string. + * + * The prefix is preserved when reseting arguments. + * + * @param string $prefix A command prefix + * + * @return ProcessBuilder + */ + public function setPrefix($prefix) + { + $this->prefix = $prefix; + + return $this; + } + + /** + * @param array $arguments + * + * @return ProcessBuilder + */ + public function setArguments(array $arguments) + { + $this->arguments = $arguments; + + return $this; + } + + public function setWorkingDirectory($cwd) + { + $this->cwd = $cwd; + + return $this; + } + + public function inheritEnvironmentVariables($inheritEnv = true) + { + $this->inheritEnv = $inheritEnv; + + return $this; + } + + public function setEnv($name, $value) + { + $this->env[$name] = $value; + + return $this; + } + + public function setInput($stdin) + { + $this->stdin = $stdin; + + return $this; + } + + /** + * Sets the process timeout. + * + * To disable the timeout, set this value to null. + * + * @param float|null + * + * @return ProcessBuilder + * + * @throws InvalidArgumentException + */ + public function setTimeout($timeout) + { + if (null === $timeout) { + $this->timeout = null; + + return $this; + } + + $timeout = (float) $timeout; + + if ($timeout < 0) { + throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.'); + } + + $this->timeout = $timeout; + + return $this; + } + + public function setOption($name, $value) + { + $this->options[$name] = $value; + + return $this; + } + + public function getProcess() + { + if (!$this->prefix && !count($this->arguments)) { + throw new LogicException('You must add() command arguments before calling getProcess().'); + } + + $options = $this->options; + + $arguments = $this->prefix ? array_merge(array($this->prefix), $this->arguments) : $this->arguments; + $script = implode(' ', array_map(array(__NAMESPACE__.'\\ProcessUtils', 'escapeArgument'), $arguments)); + + if ($this->inheritEnv) { + $env = $this->env ? $this->env + $_ENV : null; + } else { + $env = $this->env; + } + + return new Process($script, $this->cwd, $env, $this->stdin, $this->timeout, $options); + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/ProcessUtils.php b/vendor/symfony/process/Symfony/Component/Process/ProcessUtils.php new file mode 100644 index 0000000000..4a5b7d6073 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/ProcessUtils.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process; + +/** + * ProcessUtils is a bunch of utility methods. + * + * This class contains static methods only and is not meant to be instantiated. + * + * @author Martin Hasoň + */ +class ProcessUtils +{ + /** + * This class should not be instantiated + */ + private function __construct() + { + } + + /** + * Escapes a string to be used as a shell argument. + * + * @param string $argument The argument that will be escaped + * + * @return string The escaped argument + */ + public static function escapeArgument($argument) + { + //Fix for PHP bug #43784 escapeshellarg removes % from given string + //Fix for PHP bug #49446 escapeshellarg dosn`t work on windows + //@see https://bugs.php.net/bug.php?id=43784 + //@see https://bugs.php.net/bug.php?id=49446 + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + if ('' === $argument) { + return escapeshellarg($argument); + } + + $escapedArgument = ''; + foreach (preg_split('/([%"])/i', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) { + if ('"' === $part) { + $escapedArgument .= '\\"'; + } elseif ('%' === $part) { + $escapedArgument .= '^%'; + } else { + $escapedArgument .= escapeshellarg($part); + } + } + + return $escapedArgument; + } + + return escapeshellarg($argument); + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/README.md b/vendor/symfony/process/Symfony/Component/Process/README.md new file mode 100644 index 0000000000..7b9f30757b --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/README.md @@ -0,0 +1,47 @@ +Process Component +================= + +Process executes commands in sub-processes. + +In this example, we run a simple directory listing and get the result back: + + use Symfony\Component\Process\Process; + + $process = new Process('ls -lsa'); + $process->setTimeout(3600); + $process->run(); + if (!$process->isSuccessful()) { + throw new RuntimeException($process->getErrorOutput()); + } + + print $process->getOutput(); + +You can think that this is easy to achieve with plain PHP but it's not especially +if you want to take care of the subtle differences between the different platforms. + +And if you want to be able to get some feedback in real-time, just pass an +anonymous function to the ``run()`` method and you will get the output buffer +as it becomes available: + + use Symfony\Component\Process\Process; + + $process = new Process('ls -lsa'); + $process->run(function ($type, $buffer) { + if ('err' === $type) { + echo 'ERR > '.$buffer; + } else { + echo 'OUT > '.$buffer; + } + }); + +That's great if you want to execute a long running command (like rsync-ing files to a +remote server) and give feedback to the user in real-time. + +Resources +--------- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/XXX/ + $ composer.phar install --dev + $ phpunit diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/AbstractProcessTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/AbstractProcessTest.php new file mode 100644 index 0000000000..d0228f0e55 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/AbstractProcessTest.php @@ -0,0 +1,641 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +use Symfony\Component\Process\Process; +use Symfony\Component\Process\Exception\RuntimeException; + +/** + * @author Robert Schönthal + */ +abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase +{ + /** + * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException + */ + public function testNegativeTimeoutFromConstructor() + { + $this->getProcess('', null, null, null, -1); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException + */ + public function testNegativeTimeoutFromSetter() + { + $p = $this->getProcess(''); + $p->setTimeout(-1); + } + + public function testNullTimeout() + { + $p = $this->getProcess(''); + $p->setTimeout(10); + $p->setTimeout(null); + + $this->assertNull($p->getTimeout()); + } + + public function testStopWithTimeoutIsActuallyWorking() + { + $this->verifyPosixIsEnabled(); + + // exec is mandatory here since we send a signal to the process + // see https://github.com/symfony/symfony/issues/5030 about prepending + // command with exec + $p = $this->getProcess('exec php '.__DIR__.'/NonStopableProcess.php 3'); + $p->start(); + usleep(100000); + $start = microtime(true); + $p->stop(1.1, SIGKILL); + while ($p->isRunning()) { + usleep(1000); + } + $duration = microtime(true) - $start; + + $this->assertLessThan(1.8, $duration); + } + + public function testCallbacksAreExecutedWithStart() + { + $data = ''; + + $process = $this->getProcess('echo "foo";sleep 1;echo "foo"'); + $process->start(function ($type, $buffer) use (&$data) { + $data .= $buffer; + }); + + $start = microtime(true); + while ($process->isRunning()) { + usleep(10000); + } + + $this->assertEquals("foo\nfoo\n", $data); + } + + /** + * tests results from sub processes + * + * @dataProvider responsesCodeProvider + */ + public function testProcessResponses($expected, $getter, $code) + { + $p = $this->getProcess(sprintf('php -r %s', escapeshellarg($code))); + $p->run(); + + $this->assertSame($expected, $p->$getter()); + } + + /** + * tests results from sub processes + * + * @dataProvider pipesCodeProvider + */ + public function testProcessPipes($code, $size) + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Test hangs on Windows & PHP due to https://bugs.php.net/bug.php?id=60120 and https://bugs.php.net/bug.php?id=51800'); + } + + $expected = str_repeat(str_repeat('*', 1024), $size) . '!'; + $expectedLength = (1024 * $size) + 1; + + $p = $this->getProcess(sprintf('php -r %s', escapeshellarg($code))); + $p->setStdin($expected); + $p->run(); + + $this->assertEquals($expectedLength, strlen($p->getOutput())); + $this->assertEquals($expectedLength, strlen($p->getErrorOutput())); + } + + public function chainedCommandsOutputProvider() + { + return array( + array("1\n1\n", ';', '1'), + array("2\n2\n", '&&', '2'), + ); + } + + /** + * + * @dataProvider chainedCommandsOutputProvider + */ + public function testChainedCommandsOutput($expected, $operator, $input) + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Does it work on windows ?'); + } + + $process = $this->getProcess(sprintf('echo %s %s echo %s', $input, $operator, $input)); + $process->run(); + $this->assertEquals($expected, $process->getOutput()); + } + + public function testCallbackIsExecutedForOutput() + { + $p = $this->getProcess(sprintf('php -r %s', escapeshellarg('echo \'foo\';'))); + + $called = false; + $p->run(function ($type, $buffer) use (&$called) { + $called = $buffer === 'foo'; + }); + + $this->assertTrue($called, 'The callback should be executed with the output'); + } + + public function testGetErrorOutput() + { + $p = new Process(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }'))); + + $p->run(); + $this->assertEquals(3, preg_match_all('/ERROR/', $p->getErrorOutput(), $matches)); + } + + public function testGetIncrementalErrorOutput() + { + $p = new Process(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { usleep(50000); file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }'))); + + $p->start(); + while ($p->isRunning()) { + $this->assertLessThanOrEqual(1, preg_match_all('/ERROR/', $p->getIncrementalErrorOutput(), $matches)); + usleep(20000); + } + } + + public function testGetOutput() + { + $p = new Process(sprintf('php -r %s', escapeshellarg('$n=0;while ($n<3) {echo \' foo \';$n++;}'))); + + $p->run(); + $this->assertEquals(3, preg_match_all('/foo/', $p->getOutput(), $matches)); + } + + public function testGetIncrementalOutput() + { + $p = new Process(sprintf('php -r %s', escapeshellarg('$n=0;while ($n<3) { echo \' foo \'; usleep(50000); $n++; }'))); + + $p->start(); + while ($p->isRunning()) { + $this->assertLessThanOrEqual(1, preg_match_all('/foo/', $p->getIncrementalOutput(), $matches)); + usleep(20000); + } + } + + public function testExitCodeCommandFailed() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Windows does not support POSIX exit code'); + } + + // such command run in bash return an exitcode 127 + $process = $this->getProcess('nonexistingcommandIhopeneversomeonewouldnameacommandlikethis'); + $process->run(); + + $this->assertGreaterThan(0, $process->getExitCode()); + } + + public function testTTYCommand() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Windows does have /dev/tty support'); + } + + $process = $this->getProcess('echo "foo" >> /dev/null'); + $process->setTTY(true); + $process->run(); + + $this->assertSame(Process::STATUS_TERMINATED, $process->getStatus()); + } + + public function testExitCodeText() + { + $process = $this->getProcess(''); + $r = new \ReflectionObject($process); + $p = $r->getProperty('exitcode'); + $p->setAccessible(true); + + $p->setValue($process, 2); + $this->assertEquals('Misuse of shell builtins', $process->getExitCodeText()); + } + + public function testStartIsNonBlocking() + { + $process = $this->getProcess('php -r "sleep(4);"'); + $start = microtime(true); + $process->start(); + $end = microtime(true); + $this->assertLessThan(1 , $end-$start); + } + + public function testUpdateStatus() + { + $process = $this->getProcess('php -h'); + $process->run(); + $this->assertTrue(strlen($process->getOutput()) > 0); + } + + public function testGetExitCodeIsNullOnStart() + { + $process = $this->getProcess('php -r "usleep(200000);"'); + $this->assertNull($process->getExitCode()); + $process->start(); + $this->assertNull($process->getExitCode()); + $process->wait(); + $this->assertEquals(0, $process->getExitCode()); + } + + public function testGetExitCodeIsNullOnWhenStartingAgain() + { + $process = $this->getProcess('php -r "usleep(200000);"'); + $process->run(); + $this->assertEquals(0, $process->getExitCode()); + $process->start(); + $this->assertNull($process->getExitCode()); + $process->wait(); + $this->assertEquals(0, $process->getExitCode()); + } + + public function testGetExitCode() + { + $process = $this->getProcess('php -m'); + $process->run(); + $this->assertEquals(0, $process->getExitCode()); + } + + public function testStatus() + { + $process = $this->getProcess('php -r "usleep(500000);"'); + $this->assertFalse($process->isRunning()); + $this->assertFalse($process->isStarted()); + $this->assertFalse($process->isTerminated()); + $this->assertSame(Process::STATUS_READY, $process->getStatus()); + $process->start(); + $this->assertTrue($process->isRunning()); + $this->assertTrue($process->isStarted()); + $this->assertFalse($process->isTerminated()); + $this->assertSame(Process::STATUS_STARTED, $process->getStatus()); + $process->wait(); + $this->assertFalse($process->isRunning()); + $this->assertTrue($process->isStarted()); + $this->assertTrue($process->isTerminated()); + $this->assertSame(Process::STATUS_TERMINATED, $process->getStatus()); + } + + public function testStop() + { + $process = $this->getProcess('php -r "sleep(4);"'); + $process->start(); + $this->assertTrue($process->isRunning()); + $process->stop(); + $this->assertFalse($process->isRunning()); + } + + public function testIsSuccessful() + { + $process = $this->getProcess('php -m'); + $process->run(); + $this->assertTrue($process->isSuccessful()); + } + + public function testIsSuccessfulOnlyAfterTerminated() + { + $process = $this->getProcess('sleep 1'); + $process->start(); + while ($process->isRunning()) { + $this->assertFalse($process->isSuccessful()); + usleep(300000); + } + + $this->assertTrue($process->isSuccessful()); + } + + public function testIsNotSuccessful() + { + $process = $this->getProcess('php -r "sleep(4);"'); + $process->start(); + $this->assertTrue($process->isRunning()); + $process->stop(); + $this->assertFalse($process->isSuccessful()); + } + + public function testProcessIsNotSignaled() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Windows does not support POSIX signals'); + } + + $process = $this->getProcess('php -m'); + $process->run(); + $this->assertFalse($process->hasBeenSignaled()); + } + + public function testProcessWithoutTermSignalIsNotSignaled() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Windows does not support POSIX signals'); + } + + $process = $this->getProcess('php -m'); + $process->run(); + $this->assertFalse($process->hasBeenSignaled()); + } + + public function testProcessWithoutTermSignal() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Windows does not support POSIX signals'); + } + + $process = $this->getProcess('php -m'); + $process->run(); + $this->assertEquals(0, $process->getTermSignal()); + } + + public function testProcessIsSignaledIfStopped() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Windows does not support POSIX signals'); + } + + $process = $this->getProcess('php -r "sleep(4);"'); + $process->start(); + $process->stop(); + $this->assertTrue($process->hasBeenSignaled()); + } + + public function testProcessWithTermSignal() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Windows does not support POSIX signals'); + } + + // SIGTERM is only defined if pcntl extension is present + $termSignal = defined('SIGTERM') ? SIGTERM : 15; + + $process = $this->getProcess('php -r "sleep(4);"'); + $process->start(); + $process->stop(); + + $this->assertEquals($termSignal, $process->getTermSignal()); + } + + public function testProcessThrowsExceptionWhenExternallySignaled() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('Windows does not support POSIX signals'); + } + + if (!function_exists('posix_kill')) { + $this->markTestSkipped('posix_kill is required for this test'); + } + + $termSignal = defined('SIGKILL') ? SIGKILL : 9; + + $process = $this->getProcess('exec php -r "while (true) {}"'); + $process->start(); + posix_kill($process->getPid(), $termSignal); + + $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'The process has been signaled with signal "9".'); + $process->wait(); + } + + public function testRestart() + { + $process1 = $this->getProcess('php -r "echo getmypid();"'); + $process1->run(); + $process2 = $process1->restart(); + + usleep(300000); // wait for output + + // Ensure that both processed finished and the output is numeric + $this->assertFalse($process1->isRunning()); + $this->assertFalse($process2->isRunning()); + $this->assertTrue(is_numeric($process1->getOutput())); + $this->assertTrue(is_numeric($process2->getOutput())); + + // Ensure that restart returned a new process by check that the output is different + $this->assertNotEquals($process1->getOutput(), $process2->getOutput()); + } + + public function testPhpDeadlock() + { + $this->markTestSkipped('Can course php to hang'); + + // Sleep doesn't work as it will allow the process to handle signals and close + // file handles from the other end. + $process = $this->getProcess('php -r "while (true) {}"'); + $process->start(); + + // PHP will deadlock when it tries to cleanup $process + } + + public function testRunProcessWithTimeout() + { + $timeout = 0.5; + $process = $this->getProcess('sleep 3'); + $process->setTimeout($timeout); + $start = microtime(true); + try { + $process->run(); + $this->fail('A RuntimeException should have been raised'); + } catch (RuntimeException $e) { + + } + $duration = microtime(true) - $start; + + $this->assertLessThan($timeout + Process::TIMEOUT_PRECISION, $duration); + } + + public function testCheckTimeoutOnStartedProcess() + { + $timeout = 0.5; + $precision = 100000; + $process = $this->getProcess('sleep 3'); + $process->setTimeout($timeout); + $start = microtime(true); + + $process->start(); + + try { + while ($process->isRunning()) { + $process->checkTimeout(); + usleep($precision); + } + $this->fail('A RuntimeException should have been raised'); + } catch (RuntimeException $e) { + + } + $duration = microtime(true) - $start; + + $this->assertLessThan($timeout + $precision, $duration); + $this->assertFalse($process->isSuccessful()); + } + + public function testGetPid() + { + $process = $this->getProcess('php -r "sleep(1);"'); + $process->start(); + $this->assertGreaterThan(0, $process->getPid()); + $process->stop(); + } + + public function testGetPidIsNullBeforeStart() + { + $process = $this->getProcess('php -r "sleep(1);"'); + $this->assertNull($process->getPid()); + } + + public function testGetPidIsNullAfterRun() + { + $process = $this->getProcess('php -m'); + $process->run(); + $this->assertNull($process->getPid()); + } + + public function testSignal() + { + $this->verifyPosixIsEnabled(); + + $process = $this->getProcess('exec php -f ' . __DIR__ . '/SignalListener.php'); + $process->start(); + usleep(500000); + $process->signal(SIGUSR1); + + while ($process->isRunning() && false === strpos($process->getoutput(), 'Caught SIGUSR1')) { + usleep(10000); + } + + $this->assertEquals('Caught SIGUSR1', $process->getOutput()); + } + + public function testExitCodeIsAvailableAfterSignal() + { + $this->verifyPosixIsEnabled(); + + $process = $this->getProcess('sleep 4'); + $process->start(); + $process->signal(SIGKILL); + + while ($process->isRunning()) { + usleep(10000); + } + + $this->assertFalse($process->isRunning()); + $this->assertTrue($process->hasBeenSignaled()); + $this->assertFalse($process->isSuccessful()); + $this->assertEquals(137, $process->getExitCode()); + } + + /** + * @expectedException Symfony\Component\Process\Exception\LogicException + */ + public function testSignalProcessNotRunning() + { + $this->verifyPosixIsEnabled(); + $process = $this->getProcess('php -m'); + $process->signal(SIGHUP); + } + + private function verifyPosixIsEnabled() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('POSIX signals do not work on windows'); + } + if (!defined('SIGUSR1')) { + $this->markTestSkipped('The pcntl extension is not enabled'); + } + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testSignalWithWrongIntSignal() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('POSIX signals do not work on windows'); + } + + $process = $this->getProcess('php -r "sleep(3);"'); + $process->start(); + $process->signal(-4); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testSignalWithWrongNonIntSignal() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->markTestSkipped('POSIX signals do not work on windows'); + } + + $process = $this->getProcess('php -r "sleep(3);"'); + $process->start(); + $process->signal('Céphalopodes'); + } + + public function responsesCodeProvider() + { + return array( + //expected output / getter / code to execute + //array(1,'getExitCode','exit(1);'), + //array(true,'isSuccessful','exit();'), + array('output', 'getOutput', 'echo \'output\';'), + ); + } + + public function pipesCodeProvider() + { + $variations = array( + 'fwrite(STDOUT, $in = file_get_contents(\'php://stdin\')); fwrite(STDERR, $in);', + 'include \''.__DIR__.'/ProcessTestHelper.php\';', + ); + + $codes = array(); + foreach (array(1, 16, 64, 1024, 4096) as $size) { + foreach ($variations as $code) { + $codes[] = array($code, $size); + } + } + + return $codes; + } + + /** + * provides default method names for simple getter/setter + */ + public function methodProvider() + { + $defaults = array( + array('CommandLine'), + array('Timeout'), + array('WorkingDirectory'), + array('Env'), + array('Stdin'), + array('Options') + ); + + return $defaults; + } + + /** + * @param string $commandline + * @param null $cwd + * @param array $env + * @param null $stdin + * @param integer $timeout + * @param array $options + * + * @return Process + */ + abstract protected function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()); +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/NonStopableProcess.php b/vendor/symfony/process/Symfony/Component/Process/Tests/NonStopableProcess.php new file mode 100644 index 0000000000..a4db838256 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/NonStopableProcess.php @@ -0,0 +1,37 @@ + (microtime(true) - $start)) { + usleep(1000); +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php new file mode 100644 index 0000000000..99c4a1e7c9 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +use Symfony\Component\Process\PhpExecutableFinder; + +/** + * @author Robert Schönthal + */ +class PhpExecutableFinderTest extends \PHPUnit_Framework_TestCase +{ + /** + * tests find() with the env var PHP_PATH + */ + public function testFindWithPhpPath() + { + if (defined('PHP_BINARY')) { + $this->markTestSkipped('The PHP binary is easily available as of PHP 5.4'); + } + + $f = new PhpExecutableFinder(); + + $current = $f->find(); + + //not executable PHP_PATH + putenv('PHP_PATH=/not/executable/php'); + $this->assertFalse($f->find(), '::find() returns false for not executable php'); + + //executable PHP_PATH + putenv('PHP_PATH='.$current); + $this->assertEquals($f->find(), $current, '::find() returns the executable php'); + } + + /** + * tests find() with default executable + */ + public function testFindWithSuffix() + { + if (defined('PHP_BINARY')) { + $this->markTestSkipped('The PHP binary is easily available as of PHP 5.4'); + } + + putenv('PHP_PATH='); + putenv('PHP_PEAR_PHP_BIN='); + $f = new PhpExecutableFinder(); + + $current = $f->find(); + + //TODO maybe php executable is custom or even windows + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->assertTrue(is_executable($current)); + $this->assertTrue((bool) preg_match('/'.addSlashes(DIRECTORY_SEPARATOR).'php\.(exe|bat|cmd|com)$/i', $current), '::find() returns the executable php with suffixes'); + } + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/PhpProcessTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/PhpProcessTest.php new file mode 100644 index 0000000000..df66ad624b --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/PhpProcessTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +use Symfony\Component\Process\PhpProcess; + +class PhpProcessTest extends \PHPUnit_Framework_TestCase +{ + public function testNonBlockingWorks() + { + $expected = 'hello world!'; + $process = new PhpProcess(<<start(); + $process->wait(); + $this->assertEquals($expected, $process->getOutput()); + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessBuilderTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessBuilderTest.php new file mode 100644 index 0000000000..4c88b55ce1 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessBuilderTest.php @@ -0,0 +1,200 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +use Symfony\Component\Process\ProcessBuilder; + +class ProcessBuilderTest extends \PHPUnit_Framework_TestCase +{ + public function testInheritEnvironmentVars() + { + $snapshot = $_ENV; + $_ENV = $expected = array('foo' => 'bar'); + + $pb = new ProcessBuilder(); + $pb->add('foo')->inheritEnvironmentVariables(); + $proc = $pb->getProcess(); + + $this->assertNull($proc->getEnv(), '->inheritEnvironmentVariables() copies $_ENV'); + + $_ENV = $snapshot; + } + + public function testProcessShouldInheritAndOverrideEnvironmentVars() + { + $snapshot = $_ENV; + $_ENV = array('foo' => 'bar', 'bar' => 'baz'); + $expected = array('foo' => 'foo', 'bar' => 'baz'); + + $pb = new ProcessBuilder(); + $pb->add('foo')->inheritEnvironmentVariables() + ->setEnv('foo', 'foo'); + $proc = $pb->getProcess(); + + $this->assertEquals($expected, $proc->getEnv(), '->inheritEnvironmentVariables() copies $_ENV'); + + $_ENV = $snapshot; + } + + public function testProcessBuilderShouldNotPassEnvArrays() + { + $snapshot = $_ENV; + $_ENV = array('a' => array('b', 'c'), 'd' => 'e', 'f' => 'g'); + $expected = array('d' => 'e', 'f' => 'g'); + + $pb = new ProcessBuilder(); + $pb->add('a')->inheritEnvironmentVariables() + ->setEnv('d', 'e'); + $proc = $pb->getProcess(); + + $this->assertEquals($expected, $proc->getEnv(), '->inheritEnvironmentVariables() removes array values from $_ENV'); + + $_ENV = $snapshot; + } + + public function testInheritEnvironmentVarsByDefault() + { + $pb = new ProcessBuilder(); + $proc = $pb->add('foo')->getProcess(); + + $this->assertNull($proc->getEnv()); + } + + public function testNotReplaceExplicitlySetVars() + { + $snapshot = $_ENV; + $_ENV = array('foo' => 'bar'); + $expected = array('foo' => 'baz'); + + $pb = new ProcessBuilder(); + $pb + ->setEnv('foo', 'baz') + ->inheritEnvironmentVariables() + ->add('foo') + ; + $proc = $pb->getProcess(); + + $this->assertEquals($expected, $proc->getEnv(), '->inheritEnvironmentVariables() copies $_ENV'); + + $_ENV = $snapshot; + } + + /** + * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException + */ + public function testNegativeTimeoutFromSetter() + { + $pb = new ProcessBuilder(); + $pb->setTimeout(-1); + } + + public function testNullTimeout() + { + $pb = new ProcessBuilder(); + $pb->setTimeout(10); + $pb->setTimeout(null); + + $r = new \ReflectionObject($pb); + $p = $r->getProperty('timeout'); + $p->setAccessible(true); + + $this->assertNull($p->getValue($pb)); + } + + public function testShouldSetArguments() + { + $pb = new ProcessBuilder(array('initial')); + $pb->setArguments(array('second')); + + $proc = $pb->getProcess(); + + $this->assertContains("second", $proc->getCommandLine()); + } + + public function testPrefixIsPrependedToAllGeneratedProcess() + { + $pb = new ProcessBuilder(); + $pb->setPrefix('/usr/bin/php'); + + $proc = $pb->setArguments(array('-v'))->getProcess(); + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->assertEquals('"/usr/bin/php" "-v"', $proc->getCommandLine()); + } else { + $this->assertEquals("'/usr/bin/php' '-v'", $proc->getCommandLine()); + } + + $proc = $pb->setArguments(array('-i'))->getProcess(); + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->assertEquals('"/usr/bin/php" "-i"', $proc->getCommandLine()); + } else { + $this->assertEquals("'/usr/bin/php' '-i'", $proc->getCommandLine()); + } + } + + public function testShouldEscapeArguments() + { + $pb = new ProcessBuilder(array('%path%', 'foo " bar')); + $proc = $pb->getProcess(); + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->assertSame('^%"path"^% "foo "\\"" bar"', $proc->getCommandLine()); + } else { + $this->assertSame("'%path%' 'foo \" bar'", $proc->getCommandLine()); + } + } + + public function testShouldEscapeArgumentsAndPrefix() + { + $pb = new ProcessBuilder(array('arg')); + $pb->setPrefix('%prefix%'); + $proc = $pb->getProcess(); + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->assertSame('^%"prefix"^% "arg"', $proc->getCommandLine()); + } else { + $this->assertSame("'%prefix%' 'arg'", $proc->getCommandLine()); + } + } + + /** + * @expectedException \Symfony\Component\Process\Exception\LogicException + */ + public function testShouldThrowALogicExceptionIfNoPrefixAndNoArgument() + { + ProcessBuilder::create()->getProcess(); + } + + public function testShouldNotThrowALogicExceptionIfNoArgument() + { + $process = ProcessBuilder::create() + ->setPrefix('/usr/bin/php') + ->getProcess(); + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->assertEquals('"/usr/bin/php"', $process->getCommandLine()); + } else { + $this->assertEquals("'/usr/bin/php'", $process->getCommandLine()); + } + } + + public function testShouldNotThrowALogicExceptionIfNoPrefix() + { + $process = ProcessBuilder::create(array('/usr/bin/php')) + ->getProcess(); + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->assertEquals('"/usr/bin/php"', $process->getCommandLine()); + } else { + $this->assertEquals("'/usr/bin/php'", $process->getCommandLine()); + } + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessFailedExceptionTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessFailedExceptionTest.php new file mode 100644 index 0000000000..5da55e75ec --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessFailedExceptionTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +use Symfony\Component\Process\Exception\ProcessFailedException; + +/** + * @author Sebastian Marek + */ +class ProcessFailedExceptionTest extends \PHPUnit_Framework_TestCase +{ + /** + * tests ProcessFailedException throws exception if the process was successful + */ + public function testProcessFailedExceptionThrowsException() + { + $process = $this->getMock( + 'Symfony\Component\Process\Process', + array('isSuccessful'), + array('php') + ); + $process->expects($this->once()) + ->method('isSuccessful') + ->will($this->returnValue(true)); + + $this->setExpectedException( + '\InvalidArgumentException', + 'Expected a failed process, but the given process was successful.' + ); + + new ProcessFailedException($process); + } + + /** + * tests ProcessFailedException uses information from process output + * to generate exception message + */ + public function testProcessFailedExceptionPopulatesInformationFromProcessOutput() + { + $cmd = 'php'; + $exitCode = 1; + $exitText = 'General error'; + $output = "Command output"; + $errorOutput = "FATAL: Unexpected error"; + + $process = $this->getMock( + 'Symfony\Component\Process\Process', + array('isSuccessful', 'getOutput', 'getErrorOutput', 'getExitCode', 'getExitCodeText'), + array($cmd) + ); + $process->expects($this->once()) + ->method('isSuccessful') + ->will($this->returnValue(false)); + $process->expects($this->once()) + ->method('getOutput') + ->will($this->returnValue($output)); + $process->expects($this->once()) + ->method('getErrorOutput') + ->will($this->returnValue($errorOutput)); + $process->expects($this->once()) + ->method('getExitCode') + ->will($this->returnValue($exitCode)); + $process->expects($this->once()) + ->method('getExitCodeText') + ->will($this->returnValue($exitText)); + + $exception = new ProcessFailedException($process); + + $this->assertEquals( + "The command \"$cmd\" failed.\nExit Code: $exitCode($exitText)\n\nOutput:\n================\n{$output}\n\nError Output:\n================\n{$errorOutput}", + $exception->getMessage() + ); + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php new file mode 100644 index 0000000000..3977bcdcf1 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +use Symfony\Component\Process\Process; + +class ProcessInSigchildEnvironment extends Process +{ + protected function isSigchildEnabled() + { + return true; + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessTestHelper.php b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessTestHelper.php new file mode 100644 index 0000000000..25cfb41f93 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessTestHelper.php @@ -0,0 +1,63 @@ + 0) { + $written = fwrite(STDOUT, (binary) $out, 1024); + if (false === $written) { + die(ERR_WRITE_FAILED); + } + $out = (binary) substr($out, $written); + } + if (null === $read && strlen($out) < 1) { + $write = array_diff($write, array(STDOUT)); + } + + if (in_array(STDERR, $w) && strlen($err) > 0) { + $written = fwrite(STDERR, (binary) $err, 1024); + if (false === $written) { + die(ERR_WRITE_FAILED); + } + $err = (binary) substr($err, $written); + } + if (null === $read && strlen($err) < 1) { + $write = array_diff($write, array(STDERR)); + } + + if ($r) { + $str = fread(STDIN, 1024); + if (false !== $str) { + $out .= $str; + $err .= $str; + } + if (false === $str || feof(STDIN)) { + $read = null; + if (!feof(STDIN)) { + die(ERR_READ_FAILED); + } + } + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessUtilsTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessUtilsTest.php new file mode 100644 index 0000000000..603fac53e7 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/ProcessUtilsTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +use Symfony\Component\Process\ProcessUtils; + +class ProcessUtilsTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider dataArguments + */ + public function testEscapeArgument($result, $argument) + { + $this->assertSame($result, ProcessUtils::escapeArgument($argument)); + } + + public function dataArguments() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + return array( + array('"foo bar"', 'foo bar'), + array('^%"path"^%', '%path%'), + array('"<|>"\\"" "\\""\'f"', '<|>" "\'f'), + array('""', ''), + ); + } + + return array( + array("'foo bar'", 'foo bar'), + array("'%path%'", '%path%'), + array("'<|>\" \"'\\''f'", '<|>" "\'f'), + array("''", ''), + ); + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php new file mode 100644 index 0000000000..29f3cd9a04 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php @@ -0,0 +1,188 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +class SigchildDisabledProcessTest extends AbstractProcessTest +{ + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetExitCode() + { + parent::testGetExitCode(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetExitCodeIsNullOnStart() + { + parent::testGetExitCodeIsNullOnStart(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetExitCodeIsNullOnWhenStartingAgain() + { + parent::testGetExitCodeIsNullOnWhenStartingAgain(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testExitCodeCommandFailed() + { + parent::testExitCodeCommandFailed(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testProcessIsSignaledIfStopped() + { + parent::testProcessIsSignaledIfStopped(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testProcessWithTermSignal() + { + parent::testProcessWithTermSignal(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testProcessIsNotSignaled() + { + parent::testProcessIsNotSignaled(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testProcessWithoutTermSignal() + { + parent::testProcessWithoutTermSignal(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testCheckTimeoutOnStartedProcess() + { + parent::testCheckTimeoutOnStartedProcess(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetPid() + { + parent::testGetPid(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetPidIsNullBeforeStart() + { + parent::testGetPidIsNullBeforeStart(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetPidIsNullAfterRun() + { + parent::testGetPidIsNullAfterRun(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testExitCodeText() + { + $process = $this->getProcess('qdfsmfkqsdfmqmsd'); + $process->run(); + + $process->getExitCodeText(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testIsSuccessful() + { + parent::testIsSuccessful(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testIsSuccessfulOnlyAfterTerminated() + { + parent::testIsSuccessfulOnlyAfterTerminated(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testIsNotSuccessful() + { + parent::testIsNotSuccessful(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testSignal() + { + parent::testSignal(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testProcessWithoutTermSignalIsNotSignaled() + { + parent::testProcessWithoutTermSignalIsNotSignaled(); + } + + public function testStopWithTimeoutIsActuallyWorking() + { + $this->markTestSkipped('Stopping with signal is not supported in sigchild environment'); + } + + public function testProcessThrowsExceptionWhenExternallySignaled() + { + $this->markTestSkipped('Retrieving Pid is not supported in sigchild environment'); + } + + public function testExitCodeIsAvailableAfterSignal() + { + $this->markTestSkipped('Signal is not supported in sigchild environment'); + } + + /** + * {@inheritdoc} + */ + protected function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()) + { + $process = new ProcessInSigchildEnvironment($commandline, $cwd, $env, $stdin, $timeout, $options); + $process->setEnhanceSigchildCompatibility(false); + + return $process; + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php b/vendor/symfony/process/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php new file mode 100644 index 0000000000..296b00dfcb --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +class SigchildEnabledProcessTest extends AbstractProcessTest +{ + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testProcessIsSignaledIfStopped() + { + parent::testProcessIsSignaledIfStopped(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testProcessWithTermSignal() + { + parent::testProcessWithTermSignal(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testProcessIsNotSignaled() + { + parent::testProcessIsNotSignaled(); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + */ + public function testProcessWithoutTermSignal() + { + parent::testProcessWithoutTermSignal(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetPid() + { + parent::testGetPid(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetPidIsNullBeforeStart() + { + parent::testGetPidIsNullBeforeStart(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testGetPidIsNullAfterRun() + { + parent::testGetPidIsNullAfterRun(); + } + + public function testExitCodeText() + { + $process = $this->getProcess('qdfsmfkqsdfmqmsd'); + $process->run(); + + $this->assertInternalType('string', $process->getExitCodeText()); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testSignal() + { + parent::testSignal(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testProcessWithoutTermSignalIsNotSignaled() + { + parent::testProcessWithoutTermSignalIsNotSignaled(); + } + + public function testProcessThrowsExceptionWhenExternallySignaled() + { + $this->markTestSkipped('Retrieving Pid is not supported in sigchild environment'); + } + + public function testExitCodeIsAvailableAfterSignal() + { + $this->markTestSkipped('Signal is not supported in sigchild environment'); + } + + /** + * {@inheritdoc} + */ + protected function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()) + { + $process = new ProcessInSigchildEnvironment($commandline, $cwd, $env, $stdin, $timeout, $options); + $process->setEnhanceSigchildCompatibility(true); + + return $process; + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/Tests/SignalListener.php b/vendor/symfony/process/Symfony/Component/Process/Tests/SignalListener.php new file mode 100644 index 0000000000..0bf191e371 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/Tests/SignalListener.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Tests; + +use Symfony\Component\Process\Process; + +class SimpleProcessTest extends AbstractProcessTest +{ + private $enabledSigchild = false; + + public function setUp() + { + ob_start(); + phpinfo(INFO_GENERAL); + + $this->enabledSigchild = false !== strpos(ob_get_clean(), '--enable-sigchild'); + } + + public function testGetExitCode() + { + $this->skipIfPHPSigchild(); + parent::testGetExitCode(); + } + + public function testExitCodeCommandFailed() + { + $this->skipIfPHPSigchild(); + parent::testExitCodeCommandFailed(); + } + + public function testProcessIsSignaledIfStopped() + { + $this->skipIfPHPSigchild(); + parent::testProcessIsSignaledIfStopped(); + } + + public function testProcessWithTermSignal() + { + $this->skipIfPHPSigchild(); + parent::testProcessWithTermSignal(); + } + + public function testProcessIsNotSignaled() + { + $this->skipIfPHPSigchild(); + parent::testProcessIsNotSignaled(); + } + + public function testProcessWithoutTermSignal() + { + $this->skipIfPHPSigchild(); + parent::testProcessWithoutTermSignal(); + } + + public function testExitCodeText() + { + $this->skipIfPHPSigchild(); + parent::testExitCodeText(); + } + + public function testIsSuccessful() + { + $this->skipIfPHPSigchild(); + parent::testIsSuccessful(); + } + + public function testIsNotSuccessful() + { + $this->skipIfPHPSigchild(); + parent::testIsNotSuccessful(); + } + + public function testGetPid() + { + $this->skipIfPHPSigchild(); + parent::testGetPid(); + } + + public function testGetPidIsNullBeforeStart() + { + $this->skipIfPHPSigchild(); + parent::testGetPidIsNullBeforeStart(); + } + + public function testGetPidIsNullAfterRun() + { + $this->skipIfPHPSigchild(); + parent::testGetPidIsNullAfterRun(); + } + + public function testSignal() + { + $this->skipIfPHPSigchild(); + parent::testSignal(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\LogicException + */ + public function testSignalProcessNotRunning() + { + $this->skipIfPHPSigchild(); + parent::testSignalProcessNotRunning(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testSignalWithWrongIntSignal() + { + $this->skipIfPHPSigchild(); + parent::testSignalWithWrongIntSignal(); + } + + /** + * @expectedException Symfony\Component\Process\Exception\RuntimeException + */ + public function testSignalWithWrongNonIntSignal() + { + $this->skipIfPHPSigchild(); + parent::testSignalWithWrongNonIntSignal(); + } + + /** + * {@inheritdoc} + */ + protected function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()) + { + return new Process($commandline, $cwd, $env, $stdin, $timeout, $options); + } + + private function skipIfPHPSigchild() + { + if ($this->enabledSigchild) { + $this->markTestSkipped('Your PHP has been compiled with --enable-sigchild, this test can not be executed'); + } + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/composer.json b/vendor/symfony/process/Symfony/Component/Process/composer.json new file mode 100644 index 0000000000..427e63b87f --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/composer.json @@ -0,0 +1,31 @@ +{ + "name": "symfony/process", + "type": "library", + "description": "Symfony Process Component", + "keywords": [], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3" + }, + "autoload": { + "psr-0": { "Symfony\\Component\\Process\\": "" } + }, + "target-dir": "Symfony/Component/Process", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + } +} diff --git a/vendor/symfony/process/Symfony/Component/Process/phpunit.xml.dist b/vendor/symfony/process/Symfony/Component/Process/phpunit.xml.dist new file mode 100644 index 0000000000..9d5830f9e2 --- /dev/null +++ b/vendor/symfony/process/Symfony/Component/Process/phpunit.xml.dist @@ -0,0 +1,28 @@ + + + + + + ./Tests/ + + + + + + ./ + + ./Tests + + + +