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.
+
+[](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+ [](http://travis-ci.org/Seldaek/monolog)
+==============================
+
+[](https://packagist.org/packages/monolog/monolog)
+[](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
+
+
+
+