From b89e036fb2fd6237d58eba4dd3653ba366cbc3fb Mon Sep 17 00:00:00 2001 From: Jair Junior Date: Sun, 23 Oct 2016 16:37:01 -0200 Subject: [PATCH] Initial commit. Initial commit. --- .gitignore | 21 + README.md | 80 + app/.htaccess | 7 + app/AppCache.php | 7 + app/AppKernel.php | 58 + .../Version20161023151839.php | 38 + app/Resources/views/base.html.twig | 13 + app/Resources/views/default/index.html.twig | 76 + app/autoload.php | 11 + app/config/config.yml | 74 + app/config/config_dev.yml | 34 + app/config/config_prod.yml | 21 + app/config/config_test.yml | 16 + app/config/parameters.yml.dist | 19 + app/config/routing.yml | 9 + app/config/routing_dev.yml | 14 + app/config/security.yml | 24 + app/config/services.yml | 17 + bin/console | 27 + bin/symfony_requirements | 146 + challenge.md | 25 + composer.json | 70 + composer.lock | 4354 +++++++++++++++++ doc.html | 1753 +++++++ doc.md | 198 + phpunit.xml.dist | 31 + src/.htaccess | 7 + src/AppBundle/AppBundle.php | 9 + .../Command/MessageProcessorCommand.php | 154 + src/AppBundle/Controller/BaseController.php | 79 + .../Controller/DestinationController.php | 164 + .../Controller/MessageController.php | 130 + src/AppBundle/Entity/Destination.php | 73 + src/AppBundle/Entity/Message.php | 106 + .../EventListener/ExceptionSubscriber.php | 91 + src/AppBundle/Form/DestinationType.php | 30 + src/AppBundle/Form/MessageType.php | 38 + src/AppBundle/Problem/Problem.php | 76 + src/AppBundle/Problem/ProblemException.php | 24 + src/AppBundle/Problem/ResponseFactory.php | 26 + src/AppBundle/Test/HookTestCase.php | 106 + .../Controller/DestinationControllerTest.php | 226 + .../Controller/MessageControllerTest.php | 185 + var/SymfonyRequirements.php | 819 ++++ var/cache/.gitkeep | 0 var/logs/.gitkeep | 0 var/sessions/.gitkeep | 0 web/.htaccess | 68 + web/app.php | 18 + web/app_dev.php | 30 + web/apple-touch-icon.png | Bin 0 -> 2092 bytes web/config.php | 215 + web/favicon.ico | Bin 0 -> 6518 bytes web/robots.txt | 5 + 54 files changed, 9822 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 app/.htaccess create mode 100644 app/AppCache.php create mode 100644 app/AppKernel.php create mode 100644 app/DoctrineMigrations/Version20161023151839.php create mode 100644 app/Resources/views/base.html.twig create mode 100644 app/Resources/views/default/index.html.twig create mode 100644 app/autoload.php create mode 100644 app/config/config.yml create mode 100644 app/config/config_dev.yml create mode 100644 app/config/config_prod.yml create mode 100644 app/config/config_test.yml create mode 100644 app/config/parameters.yml.dist create mode 100644 app/config/routing.yml create mode 100644 app/config/routing_dev.yml create mode 100644 app/config/security.yml create mode 100644 app/config/services.yml create mode 100644 bin/console create mode 100644 bin/symfony_requirements create mode 100644 challenge.md create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 doc.html create mode 100644 doc.md create mode 100644 phpunit.xml.dist create mode 100644 src/.htaccess create mode 100644 src/AppBundle/AppBundle.php create mode 100644 src/AppBundle/Command/MessageProcessorCommand.php create mode 100644 src/AppBundle/Controller/BaseController.php create mode 100644 src/AppBundle/Controller/DestinationController.php create mode 100644 src/AppBundle/Controller/MessageController.php create mode 100644 src/AppBundle/Entity/Destination.php create mode 100644 src/AppBundle/Entity/Message.php create mode 100644 src/AppBundle/EventListener/ExceptionSubscriber.php create mode 100644 src/AppBundle/Form/DestinationType.php create mode 100644 src/AppBundle/Form/MessageType.php create mode 100644 src/AppBundle/Problem/Problem.php create mode 100644 src/AppBundle/Problem/ProblemException.php create mode 100644 src/AppBundle/Problem/ResponseFactory.php create mode 100644 src/AppBundle/Test/HookTestCase.php create mode 100644 tests/AppBundle/Controller/DestinationControllerTest.php create mode 100644 tests/AppBundle/Controller/MessageControllerTest.php create mode 100644 var/SymfonyRequirements.php create mode 100644 var/cache/.gitkeep create mode 100644 var/logs/.gitkeep create mode 100644 var/sessions/.gitkeep create mode 100644 web/.htaccess create mode 100644 web/app.php create mode 100644 web/app_dev.php create mode 100644 web/apple-touch-icon.png create mode 100644 web/config.php create mode 100644 web/favicon.ico create mode 100644 web/robots.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af3326f --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +/app/config/parameters.yml +/build/ +/phpunit.xml +/var/* +!/var/cache +/var/cache/* +!var/cache/.gitkeep +!/var/logs +/var/logs/* +!var/logs/.gitkeep +!/var/sessions +/var/sessions/* +!var/sessions/.gitkeep +!var/SymfonyRequirements.php +/vendor/ +/web/bundles/ +/composer.phar +/.idea/ +/README.pdf +/README.docx +/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..29f56a5 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# HOOTSUITE Challenge # + +## Challenge ## +[challenge.md]() + + +## What I did ## +I made a small project to simulate a webhook that receives messages and forward to previously defined destinations. +It was developed in PHP/Symfony3. +The project was made based in REST concepts and it answers the GET, POST, DELETE, PUT and PATCH requisitions. +The endpoints where tested using PHP Unit. +All requisitions to the webhook service are answered and should be made in JSON format. + +## Considerations about security ## +Due to the short time, I didn’t implement neither validation to requests nor to sign the messages sent. Either I didn’t require HTTPS urls but it should be mandatory in a production environment. +Of course, in a production environment I’d use or RSA or ECC signature. I wouldn’t like to use HMAC as it’s use symmetric keys we need another step to ensure the keys are transferred in a secured way to the other side of endpoint. +Another option is authenticating requests to webhook based in credentials using JSON Web Tokens. The token can be transferred both in a “plain” way over HTTPS or either over a OAUTH layer of security. +The service also verifies if a valid URL was given and it won’t send messages to URLs that resolves to a private address. + +## Considerations about scalability ## +Instead this project that relies in a centralized MySql the server can’t handle millions of connections, but it was developed with scalability in mind. +When a message is posted to the webhook it is added to a queue based on the destination. +The project has a worker module that consumes and process these messages and you can run multiple workers, each one processing one queue (one destination). The message ordering for each destination is guaranteed. You can also run a single worker to process all queues. +Each work can run in an independent server but it needs to connect to the same database server. +As it’s a small project (proof of concept only) I didn’t added validation to ensure you started only one worker for each queue. If you add more than one, the message ordering will not be guaranteed. +In another word, this project can scale as soon you have multiple destinations. +In a production environment, I’d use probably a queue server like RabbitMQ. + +## First ## +Download composer and install the required dependencies with + + php composer.phar install + +## Instructions to run the server ## +1. Configure the database definitions in `./app/config/parameters.yml` +2. Create the database using the command `php ./bin/console doctrine:database:create` +3. Create database schema using the command `php ./bin/console doctrine:migrations:migrate` +4. Run the Symfony built In server using the command `php ./bin/console server:run` +The server will start listening in `http://127.0.0.1:8000` + +## PHPUnit ## +There are PHPUnit tests in the `./tests` folder. +You can run those with the command: `./vendor/bin/phpunit` +Attention: Run the tests will erase the database. + +## Webhook Requisitions (documentation) ## +The webhook documentation are located in both `doc.md` and `doc.html` files. +After start the server you can also read the documentation in `http://127.0.0.1:8000/doc`. +**All requests and responses should be made in JSON format.** + +## Starting the message processor ## +The message processor can be started with the command + + php ./bin/console message-processor + +The service will start, process the messages and exit. +### Options: ### + + --persistent +If set, the service will run in a persistent mode, it won’t exit until it’s cancelled. + + --destination=DESTINATION +Indicates that the service should only process messages from the DESTINATION (destination id) queue. If this option isn’t set, the service will process messages from all queues. + + --retry=RETRY +Indicates how many times (RETRY) the service will retry to deliver a message (in case of error) before removes it. Default = 3. + + --retry-delay=RETRY-DELAY +Indicates how many time, in seconds (RETRY-DELAY), the service should wait before retry to deliver a message (in case of error). Default = 1. + +**Attention:** The message processor will remove automatically messages that aren’t delivered for more than 24h.  + +## Extra information ## +When you run the Symfony built in server, it automatically set environment as DEVELOPMENT, so in case of error it’ll return the full debug stack to the client. It doesn’t happen if environment is set to PRODUCTION. +As I didn’t use a queue server I decided to add GET and DELETE method to the “messages” endpoint, so we can check and eventually remove messages from the queue. The messages will remain in the queue only before they are processed. +If you remove a destination, it’ll automatically removes all the messages to this destination that hasn’t been already processed. +I really love backend programming and I really would like to be part of HootSuite team. +For me programming isn’t a job, is a pleasure. + + diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..fb1de45 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,7 @@ + + Require all denied + + + Order deny,allow + Deny from all + diff --git a/app/AppCache.php b/app/AppCache.php new file mode 100644 index 0000000..639ec2c --- /dev/null +++ b/app/AppCache.php @@ -0,0 +1,7 @@ +getEnvironment(), ['dev', 'test'], true)) { + $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle(); + $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); + $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); + $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); + } + + return $bundles; + } + + public function getRootDir() + { + return __DIR__; + } + + public function getCacheDir() + { + return dirname(__DIR__).'/var/cache/'.$this->getEnvironment(); + } + + public function getLogDir() + { + return dirname(__DIR__).'/var/logs'; + } + + public function registerContainerConfiguration(LoaderInterface $loader) + { + $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml'); + } +} diff --git a/app/DoctrineMigrations/Version20161023151839.php b/app/DoctrineMigrations/Version20161023151839.php new file mode 100644 index 0000000..5682322 --- /dev/null +++ b/app/DoctrineMigrations/Version20161023151839.php @@ -0,0 +1,38 @@ +abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql('CREATE TABLE destination (id INT AUTO_INCREMENT NOT NULL, url VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'); + $this->addSql('CREATE TABLE message (id INT AUTO_INCREMENT NOT NULL, destination_id INT NOT NULL, content_type VARCHAR(255) NOT NULL, msg_body LONGTEXT NOT NULL, created_at DATETIME NOT NULL, INDEX IDX_B6BD307F816C6140 (destination_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'); + $this->addSql('ALTER TABLE message ADD CONSTRAINT FK_B6BD307F816C6140 FOREIGN KEY (destination_id) REFERENCES destination (id) ON DELETE CASCADE'); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + // this down() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql('ALTER TABLE message DROP FOREIGN KEY FK_B6BD307F816C6140'); + $this->addSql('DROP TABLE destination'); + $this->addSql('DROP TABLE message'); + } +} diff --git a/app/Resources/views/base.html.twig b/app/Resources/views/base.html.twig new file mode 100644 index 0000000..bafd28d --- /dev/null +++ b/app/Resources/views/base.html.twig @@ -0,0 +1,13 @@ + + + + + {% block title %}Welcome!{% endblock %} + {% block stylesheets %}{% endblock %} + + + + {% block body %}{% endblock %} + {% block javascripts %}{% endblock %} + + diff --git a/app/Resources/views/default/index.html.twig b/app/Resources/views/default/index.html.twig new file mode 100644 index 0000000..aa88ca9 --- /dev/null +++ b/app/Resources/views/default/index.html.twig @@ -0,0 +1,76 @@ +{% extends 'base.html.twig' %} + +{% block body %} +
+
+
+

Welcome to Symfony {{ constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION') }}

+
+ +
+

+ + + Your application is now ready. You can start working on it at: + {{ base_dir }} +

+
+ + + +
+
+{% endblock %} + +{% block stylesheets %} + +{% endblock %} diff --git a/app/autoload.php b/app/autoload.php new file mode 100644 index 0000000..31321fa --- /dev/null +++ b/app/autoload.php @@ -0,0 +1,11 @@ +getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev'); +$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod'; + +if ($debug) { + Debug::enable(); +} + +$kernel = new AppKernel($env, $debug); +$application = new Application($kernel); +$application->run($input); diff --git a/bin/symfony_requirements b/bin/symfony_requirements new file mode 100644 index 0000000..a7bf65a --- /dev/null +++ b/bin/symfony_requirements @@ -0,0 +1,146 @@ +#!/usr/bin/env php +getPhpIniConfigPath(); + +echo_title('Symfony Requirements Checker'); + +echo '> PHP is using the following php.ini file:'.PHP_EOL; +if ($iniPath) { + echo_style('green', ' '.$iniPath); +} else { + echo_style('yellow', ' WARNING: No configuration file (php.ini) used by PHP!'); +} + +echo PHP_EOL.PHP_EOL; + +echo '> Checking Symfony requirements:'.PHP_EOL.' '; + +$messages = array(); +foreach ($symfonyRequirements->getRequirements() as $req) { + if ($helpText = get_error_message($req, $lineSize)) { + echo_style('red', 'E'); + $messages['error'][] = $helpText; + } else { + echo_style('green', '.'); + } +} + +$checkPassed = empty($messages['error']); + +foreach ($symfonyRequirements->getRecommendations() as $req) { + if ($helpText = get_error_message($req, $lineSize)) { + echo_style('yellow', 'W'); + $messages['warning'][] = $helpText; + } else { + echo_style('green', '.'); + } +} + +if ($checkPassed) { + echo_block('success', 'OK', 'Your system is ready to run Symfony projects'); +} else { + echo_block('error', 'ERROR', 'Your system is not ready to run Symfony projects'); + + echo_title('Fix the following mandatory requirements', 'red'); + + foreach ($messages['error'] as $helpText) { + echo ' * '.$helpText.PHP_EOL; + } +} + +if (!empty($messages['warning'])) { + echo_title('Optional recommendations to improve your setup', 'yellow'); + + foreach ($messages['warning'] as $helpText) { + echo ' * '.$helpText.PHP_EOL; + } +} + +echo PHP_EOL; +echo_style('title', 'Note'); +echo ' The command console could use a different php.ini file'.PHP_EOL; +echo_style('title', '~~~~'); +echo ' than the one used with your web server. To be on the'.PHP_EOL; +echo ' safe side, please check the requirements from your web'.PHP_EOL; +echo ' server using the '; +echo_style('yellow', 'web/config.php'); +echo ' script.'.PHP_EOL; +echo PHP_EOL; + +exit($checkPassed ? 0 : 1); + +function get_error_message(Requirement $requirement, $lineSize) +{ + if ($requirement->isFulfilled()) { + return; + } + + $errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL.' ').PHP_EOL; + $errorMessage .= ' > '.wordwrap($requirement->getHelpText(), $lineSize - 5, PHP_EOL.' > ').PHP_EOL; + + return $errorMessage; +} + +function echo_title($title, $style = null) +{ + $style = $style ?: 'title'; + + echo PHP_EOL; + echo_style($style, $title.PHP_EOL); + echo_style($style, str_repeat('~', strlen($title)).PHP_EOL); + echo PHP_EOL; +} + +function echo_style($style, $message) +{ + // ANSI color codes + $styles = array( + 'reset' => "\033[0m", + 'red' => "\033[31m", + 'green' => "\033[32m", + 'yellow' => "\033[33m", + 'error' => "\033[37;41m", + 'success' => "\033[37;42m", + 'title' => "\033[34m", + ); + $supports = has_color_support(); + + echo($supports ? $styles[$style] : '').$message.($supports ? $styles['reset'] : ''); +} + +function echo_block($style, $title, $message) +{ + $message = ' '.trim($message).' '; + $width = strlen($message); + + echo PHP_EOL.PHP_EOL; + + echo_style($style, str_repeat(' ', $width)); + echo PHP_EOL; + echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT)); + echo PHP_EOL; + echo_style($style, $message); + echo PHP_EOL; + echo_style($style, str_repeat(' ', $width)); + echo PHP_EOL; +} + +function has_color_support() +{ + static $support; + + if (null === $support) { + if (DIRECTORY_SEPARATOR == '\\') { + $support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI'); + } else { + $support = function_exists('posix_isatty') && @posix_isatty(STDOUT); + } + } + + return $support; +} diff --git a/challenge.md b/challenge.md new file mode 100644 index 0000000..2b9f18d --- /dev/null +++ b/challenge.md @@ -0,0 +1,25 @@ +# From HootSuite # + +As more and more integration takes place between SaaS providers, other SaaS providers and their customers, webhooks have become an invaluable way of sharing events. These events simplify data-synchronization and extensibility. + +**Project:** +Write a webhook calling service that will reliably POST data to destination URLs in the order POST message requests are received. + +The service should support the following remote requests via REST +register a new destination (URL) returning its id +list registered destinations [{id, URL},...] +delete a destination by id +POST a message to this destination (id, msg-body, content-type): this causes the server to POST the given msg-body to the URL associated with that id. + +**Behaviour:** +If the destination URL is not responding (e.g. the servier is down) or returns a non-200 response, your service should resend the message at a later time +Messages not sent within 24 hours can be be deleted +Messages that failed to send should retried 3 or more times before they are deleted +Message ordering to a destination should be preserved, even when there are pending message retries for that destination +Feel free to add more metadata to the destination (id, URL,) if it helps your implementation + +**To Consider:** +is your API using the standard REST-ful conventions for the 4 operations? +how can I scale out this service across multiple servers while preserving per-destination ordering? +how well does your service support concurrency for multiple destinations while preserving per-destination ordering? +how secure is this? should you require HTTPS urls? should the content be signed with something like an HMAC? Should any url be allowed (e.g. one that has or resolves to a private IP address?) \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4fa6039 --- /dev/null +++ b/composer.json @@ -0,0 +1,70 @@ +{ + "name": "jair/.checkout", + "license": "proprietary", + "type": "project", + "autoload": { + "psr-4": { + "": "src/" + }, + "classmap": [ + "app/AppKernel.php", + "app/AppCache.php" + ] + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "require": { + "php": ">=5.5.9", + "symfony/symfony": "3.1.*", + "doctrine/orm": "^2.5", + "doctrine/doctrine-bundle": "^1.6", + "doctrine/doctrine-cache-bundle": "^1.2", + "symfony/swiftmailer-bundle": "^2.3", + "symfony/monolog-bundle": "^2.8", + "symfony/polyfill-apcu": "^1.0", + "sensio/distribution-bundle": "^5.0", + "sensio/framework-extra-bundle": "^3.0.2", + "incenteev/composer-parameter-handler": "^2.0", + "doctrine/doctrine-migrations-bundle": "v1.2.0", + "phpunit/phpunit": "4.8.27", + "symfony/phpunit-bridge": "v3.1.5", + "doctrine/doctrine-fixtures-bundle": "2.3.0", + "jms/serializer-bundle": "1.1.0", + "willdurand/hateoas-bundle": "1.2.0", + "nelmio/api-doc-bundle": "2.13.0", + "fabpot/goutte": "v3.1.2" + }, + "require-dev": { + "sensio/generator-bundle": "^3.0" + }, + "scripts": { + "symfony-scripts": [ + "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget" + ], + "post-install-cmd": [ + "@symfony-scripts" + ], + "post-update-cmd": [ + "@symfony-scripts" + ] + }, + "extra": { + "symfony-app-dir": "app", + "symfony-bin-dir": "bin", + "symfony-var-dir": "var", + "symfony-web-dir": "web", + "symfony-tests-dir": "tests", + "symfony-assets-install": "relative", + "incenteev-parameters": { + "file": "app/config/parameters.yml" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..7ad9efa --- /dev/null +++ b/composer.lock @@ -0,0 +1,4354 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "9e8022fafae04ea371a8a68cf3aa62b7", + "packages": [ + { + "name": "doctrine/annotations", + "version": "v1.2.7", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": ">=5.3.2" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Annotations\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2015-08-31T12:32:49+00:00" + }, + { + "name": "doctrine/cache", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6", + "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6", + "shasum": "" + }, + "require": { + "php": "~5.5|~7.0" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|~5.0", + "predis/predis": "~1.0", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2015-12-31T16:37:02+00:00" + }, + { + "name": "doctrine/collections", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a", + "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Collections\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "array", + "collections", + "iterator" + ], + "time": "2015-04-14T22:21:58+00:00" + }, + { + "name": "doctrine/common", + "version": "v2.6.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "a579557bc689580c19fee4e27487a67fe60defc0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0", + "reference": "a579557bc689580c19fee4e27487a67fe60defc0", + "shasum": "" + }, + "require": { + "doctrine/annotations": "1.*", + "doctrine/cache": "1.*", + "doctrine/collections": "1.*", + "doctrine/inflector": "1.*", + "doctrine/lexer": "1.*", + "php": "~5.5|~7.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|~5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common Library for Doctrine projects", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "collections", + "eventmanager", + "persistence", + "spl" + ], + "time": "2015-12-25T13:18:31+00:00" + }, + { + "name": "doctrine/data-fixtures", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/data-fixtures.git", + "reference": "bd44f6b6e40247b6530bc8abe802e4e4d914976a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/bd44f6b6e40247b6530bc8abe802e4e4d914976a", + "reference": "bd44f6b6e40247b6530bc8abe802e4e4d914976a", + "shasum": "" + }, + "require": { + "doctrine/common": "~2.2", + "php": ">=5.3.2" + }, + "conflict": { + "doctrine/orm": "< 2.4" + }, + "require-dev": { + "doctrine/orm": "~2.4" + }, + "suggest": { + "doctrine/mongodb-odm": "For loading MongoDB ODM fixtures", + "doctrine/orm": "For loading ORM fixtures", + "doctrine/phpcr-odm": "For loading PHPCR ODM fixtures" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\DataFixtures": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Data Fixtures for all Doctrine Object Managers", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database" + ], + "time": "2015-03-30T12:14:13+00:00" + }, + { + "name": "doctrine/dbal", + "version": "v2.5.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/9f8c05cd5225a320d56d4bfdb4772f10d045a0c9", + "reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9", + "shasum": "" + }, + "require": { + "doctrine/common": ">=2.4,<2.7-dev", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "symfony/console": "2.*||^3.0" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "bin": [ + "bin/doctrine-dbal" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\DBAL\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Database Abstraction Layer", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "persistence", + "queryobject" + ], + "time": "2016-09-09T19:13:33+00:00" + }, + { + "name": "doctrine/doctrine-bundle", + "version": "1.6.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineBundle.git", + "reference": "dd40b0a7fb16658cda9def9786992b8df8a49be7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/dd40b0a7fb16658cda9def9786992b8df8a49be7", + "reference": "dd40b0a7fb16658cda9def9786992b8df8a49be7", + "shasum": "" + }, + "require": { + "doctrine/dbal": "~2.3", + "doctrine/doctrine-cache-bundle": "~1.0", + "jdorn/sql-formatter": "~1.1", + "php": ">=5.3.2", + "symfony/console": "~2.3|~3.0", + "symfony/dependency-injection": "~2.3|~3.0", + "symfony/doctrine-bridge": "~2.2|~3.0", + "symfony/framework-bundle": "~2.3|~3.0" + }, + "require-dev": { + "doctrine/orm": "~2.3", + "phpunit/phpunit": "~4", + "satooshi/php-coveralls": "~0.6.1", + "symfony/phpunit-bridge": "~2.7|~3.0", + "symfony/property-info": "~2.8|~3.0", + "symfony/validator": "~2.2|~3.0", + "symfony/yaml": "~2.2|~3.0", + "twig/twig": "~1.10" + }, + "suggest": { + "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", + "symfony/web-profiler-bundle": "To use the data collector." + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\DoctrineBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Doctrine Project", + "homepage": "http://www.doctrine-project.org/" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony DoctrineBundle", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "orm", + "persistence" + ], + "time": "2016-08-10T15:35:22+00:00" + }, + { + "name": "doctrine/doctrine-cache-bundle", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineCacheBundle.git", + "reference": "18c600a9b82f6454d2e81ca4957cdd56a1cf3504" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineCacheBundle/zipball/18c600a9b82f6454d2e81ca4957cdd56a1cf3504", + "reference": "18c600a9b82f6454d2e81ca4957cdd56a1cf3504", + "shasum": "" + }, + "require": { + "doctrine/cache": "^1.4.2", + "doctrine/inflector": "~1.0", + "php": ">=5.3.2", + "symfony/doctrine-bridge": "~2.2|~3.0" + }, + "require-dev": { + "instaclick/coding-standard": "~1.1", + "instaclick/object-calisthenics-sniffs": "dev-master", + "instaclick/symfony2-coding-standard": "dev-remaster", + "phpunit/phpunit": "~4", + "predis/predis": "~0.8", + "satooshi/php-coveralls": "~0.6.1", + "squizlabs/php_codesniffer": "~1.5", + "symfony/console": "~2.2|~3.0", + "symfony/finder": "~2.2|~3.0", + "symfony/framework-bundle": "~2.2|~3.0", + "symfony/phpunit-bridge": "~2.7|~3.0", + "symfony/security-acl": "~2.3|~3.0", + "symfony/validator": "~2.2|~3.0", + "symfony/yaml": "~2.2|~3.0" + }, + "suggest": { + "symfony/security-acl": "For using this bundle to cache ACLs" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\DoctrineCacheBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Fabio B. Silva", + "email": "fabio.bat.silva@gmail.com" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@hotmail.com" + }, + { + "name": "Doctrine Project", + "homepage": "http://www.doctrine-project.org/" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Bundle for Doctrine Cache", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2016-01-26T17:28:51+00:00" + }, + { + "name": "doctrine/doctrine-fixtures-bundle", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineFixturesBundle.git", + "reference": "0f1a2f91b349e10f5c343f75ab71d23aace5b029" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/0f1a2f91b349e10f5c343f75ab71d23aace5b029", + "reference": "0f1a2f91b349e10f5c343f75ab71d23aace5b029", + "shasum": "" + }, + "require": { + "doctrine/data-fixtures": "~1.0", + "doctrine/doctrine-bundle": "~1.0", + "php": ">=5.3.2", + "symfony/doctrine-bridge": "~2.3|~3.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\FixturesBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Doctrine Project", + "homepage": "http://www.doctrine-project.org" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony DoctrineFixturesBundle", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "Fixture", + "persistence" + ], + "time": "2015-11-04T21:23:23+00:00" + }, + { + "name": "doctrine/doctrine-migrations-bundle", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", + "reference": "0b89ee55bceb53c60bc4ba32924ac5053e377abb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/0b89ee55bceb53c60bc4ba32924ac5053e377abb", + "reference": "0b89ee55bceb53c60bc4ba32924ac5053e377abb", + "shasum": "" + }, + "require": { + "doctrine/doctrine-bundle": "~1.0", + "doctrine/migrations": "^1.1", + "php": ">=5.4.0", + "symfony/framework-bundle": "~2.3|~3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\MigrationsBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Doctrine Project", + "homepage": "http://www.doctrine-project.org" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony DoctrineMigrationsBundle", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "dbal", + "migrations", + "schema" + ], + "time": "2016-06-30T19:26:35+00:00" + }, + { + "name": "doctrine/inflector", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "90b2128806bfde671b6952ab8bea493942c1fdae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae", + "reference": "90b2128806bfde671b6952ab8bea493942c1fdae", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Inflector\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2015-11-06T14:35:42+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14T21:17:01+00:00" + }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09T13:34:57+00:00" + }, + { + "name": "doctrine/migrations", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/migrations.git", + "reference": "0d0ff5da10c5d30846da32060bd9e357abf70a05" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/0d0ff5da10c5d30846da32060bd9e357abf70a05", + "reference": "0d0ff5da10c5d30846da32060bd9e357abf70a05", + "shasum": "" + }, + "require": { + "doctrine/dbal": "~2.2", + "ocramius/proxy-manager": "^1.0|^2.0", + "php": "^5.5|^7.0", + "symfony/console": "~2.3|~3.0", + "symfony/yaml": "~2.3|~3.0" + }, + "require-dev": { + "doctrine/coding-standard": "dev-master", + "doctrine/orm": "2.*", + "jdorn/sql-formatter": "~1.1", + "johnkary/phpunit-speedtrap": "~1.0@dev", + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "~4.7", + "satooshi/php-coveralls": "0.6.*" + }, + "suggest": { + "jdorn/sql-formatter": "Allows to generate formatted SQL with the diff command." + }, + "bin": [ + "bin/doctrine-migrations" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "v1.5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\DBAL\\Migrations\\": "lib/Doctrine/DBAL/Migrations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Michael Simonson", + "email": "contact@mikesimonson.com" + } + ], + "description": "Database Schema migrations using Doctrine DBAL", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "migrations" + ], + "time": "2016-03-14T12:29:11+00:00" + }, + { + "name": "doctrine/orm", + "version": "v2.5.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/doctrine2.git", + "reference": "73e4be7c7b3ba26f96b781a40b33feba4dfa6d45" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/73e4be7c7b3ba26f96b781a40b33feba4dfa6d45", + "reference": "73e4be7c7b3ba26f96b781a40b33feba4dfa6d45", + "shasum": "" + }, + "require": { + "doctrine/cache": "~1.4", + "doctrine/collections": "~1.2", + "doctrine/common": ">=2.5-dev,<2.7-dev", + "doctrine/dbal": ">=2.5-dev,<2.6-dev", + "doctrine/instantiator": "~1.0.1", + "ext-pdo": "*", + "php": ">=5.4", + "symfony/console": "~2.5|~3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "symfony/yaml": "~2.3|~3.0" + }, + "suggest": { + "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + }, + "bin": [ + "bin/doctrine", + "bin/doctrine.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\ORM\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Object-Relational-Mapper for PHP", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "orm" + ], + "time": "2016-09-10T18:51:13+00:00" + }, + { + "name": "fabpot/goutte", + "version": "v3.1.2", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/Goutte.git", + "reference": "3cbc6ed222422a28400e470050f14928a153207e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/3cbc6ed222422a28400e470050f14928a153207e", + "reference": "3cbc6ed222422a28400e470050f14928a153207e", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "php": ">=5.5.0", + "symfony/browser-kit": "~2.1|~3.0", + "symfony/css-selector": "~2.1|~3.0", + "symfony/dom-crawler": "~2.1|~3.0" + }, + "type": "application", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Goutte\\": "Goutte" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "A simple PHP Web Scraper", + "homepage": "https://github.com/FriendsOfPHP/Goutte", + "keywords": [ + "scraper" + ], + "time": "2015-11-05T12:58:44+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.2.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ebf29dee597f02f09f4d5bbecc68230ea9b08f60", + "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.3.1", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.0", + "psr/log": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2016-10-08T15:01:37+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579", + "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-05-18T16:56:05+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "PSR-7 message implementation", + "keywords": [ + "http", + "message", + "stream", + "uri" + ], + "time": "2016-06-24T23:00:38+00:00" + }, + { + "name": "incenteev/composer-parameter-handler", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/Incenteev/ParameterHandler.git", + "reference": "d7ce7f06136109e81d1cb9d57066c4d4a99cf1cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Incenteev/ParameterHandler/zipball/d7ce7f06136109e81d1cb9d57066c4d4a99cf1cc", + "reference": "d7ce7f06136109e81d1cb9d57066c4d4a99cf1cc", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/yaml": "~2.3|~3.0" + }, + "require-dev": { + "composer/composer": "1.0.*@dev", + "phpspec/prophecy-phpunit": "~1.0", + "symfony/filesystem": "~2.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Incenteev\\ParameterHandler\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Composer script handling your ignored parameter file", + "homepage": "https://github.com/Incenteev/ParameterHandler", + "keywords": [ + "parameters management" + ], + "time": "2015-11-10T17:04:01+00:00" + }, + { + "name": "jdorn/sql-formatter", + "version": "v1.2.17", + "source": { + "type": "git", + "url": "https://github.com/jdorn/sql-formatter.git", + "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jdorn/sql-formatter/zipball/64990d96e0959dff8e059dfcdc1af130728d92bc", + "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "lib" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Dorn", + "email": "jeremy@jeremydorn.com", + "homepage": "http://jeremydorn.com/" + } + ], + "description": "a PHP SQL highlighting library", + "homepage": "https://github.com/jdorn/sql-formatter/", + "keywords": [ + "highlight", + "sql" + ], + "time": "2014-01-12T16:20:24+00:00" + }, + { + "name": "jms/metadata", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/metadata.git", + "reference": "22b72455559a25777cfd28c4ffda81ff7639f353" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/22b72455559a25777cfd28c4ffda81ff7639f353", + "reference": "22b72455559a25777cfd28c4ffda81ff7639f353", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "doctrine/cache": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Metadata\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache" + ], + "authors": [ + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Class/method/property metadata management in PHP", + "keywords": [ + "annotations", + "metadata", + "xml", + "yaml" + ], + "time": "2014-07-12T07:13:19+00:00" + }, + { + "name": "jms/parser-lib", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/parser-lib.git", + "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/parser-lib/zipball/c509473bc1b4866415627af0e1c6cc8ac97fa51d", + "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d", + "shasum": "" + }, + "require": { + "phpoption/phpoption": ">=0.9,<2.0-dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "JMS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "description": "A library for easily creating recursive-descent parsers.", + "time": "2012-11-18T18:08:43+00:00" + }, + { + "name": "jms/serializer", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/serializer.git", + "reference": "705d0b4633b9c44e6253aa18306b3972282cd3a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/705d0b4633b9c44e6253aa18306b3972282cd3a3", + "reference": "705d0b4633b9c44e6253aa18306b3972282cd3a3", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "doctrine/instantiator": "^1.0.3", + "jms/metadata": "~1.1", + "jms/parser-lib": "1.*", + "php": ">=5.5.0", + "phpcollection/phpcollection": "~0.1", + "phpoption/phpoption": "^1.1" + }, + "conflict": { + "twig/twig": "<1.12" + }, + "require-dev": { + "doctrine/orm": "~2.1", + "doctrine/phpcr-odm": "^1.3|^2.0", + "jackalope/jackalope-doctrine-dbal": "^1.1.5", + "phpunit/phpunit": "^4.8|^5.0", + "propel/propel1": "~1.7", + "symfony/filesystem": "^2.1", + "symfony/form": "~2.1", + "symfony/translation": "^2.1", + "symfony/validator": "^2.2", + "symfony/yaml": "^2.1", + "twig/twig": "~1.12|~2.0" + }, + "suggest": { + "symfony/yaml": "Required if you'd like to serialize data to YAML format." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-0": { + "JMS\\Serializer": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", + "homepage": "http://jmsyst.com/libs/serializer", + "keywords": [ + "deserialization", + "jaxb", + "json", + "serialization", + "xml" + ], + "time": "2016-08-23T17:20:24+00:00" + }, + { + "name": "jms/serializer-bundle", + "version": "1.1.0", + "target-dir": "JMS/SerializerBundle", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/JMSSerializerBundle.git", + "reference": "3e396c980545350c2efb65a50041d2a9f9d6562e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/JMSSerializerBundle/zipball/3e396c980545350c2efb65a50041d2a9f9d6562e", + "reference": "3e396c980545350c2efb65a50041d2a9f9d6562e", + "shasum": "" + }, + "require": { + "jms/serializer": "^1.0.0", + "php": ">=5.4.0", + "phpoption/phpoption": "^1.1.0", + "symfony/framework-bundle": "~2.3|~3.0" + }, + "require-dev": { + "doctrine/doctrine-bundle": "*", + "doctrine/orm": "*", + "symfony/browser-kit": "*", + "symfony/class-loader": "*", + "symfony/css-selector": "*", + "symfony/finder": "*", + "symfony/form": "*", + "symfony/process": "*", + "symfony/stopwatch": "*", + "symfony/twig-bundle": "*", + "symfony/validator": "*", + "symfony/yaml": "*" + }, + "suggest": { + "jms/di-extra-bundle": "Required to get lazy loading (de)serialization visitors, ~1.3" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-0": { + "JMS\\SerializerBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Allows you to easily serialize, and deserialize data of any complexity", + "homepage": "http://jmsyst.com/bundles/JMSSerializerBundle", + "keywords": [ + "deserialization", + "jaxb", + "json", + "serialization", + "xml" + ], + "time": "2015-11-10T12:26:42+00:00" + }, + { + "name": "michelf/php-markdown", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/michelf/php-markdown.git", + "reference": "156e56ee036505ec637d761ee62dc425d807183c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/michelf/php-markdown/zipball/156e56ee036505ec637d761ee62dc425d807183c", + "reference": "156e56ee036505ec637d761ee62dc425d807183c", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-lib": "1.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Michelf": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Michel Fortin", + "email": "michel.fortin@michelf.ca", + "homepage": "https://michelf.ca/", + "role": "Developer" + }, + { + "name": "John Gruber", + "homepage": "https://daringfireball.net/" + } + ], + "description": "PHP Markdown", + "homepage": "https://michelf.ca/projects/php-markdown/", + "keywords": [ + "markdown" + ], + "time": "2015-12-24T01:37:31+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.21.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f42fbdfd53e306bda545845e4dbfd3e72edb4952", + "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "~5.3" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "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", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2016-07-29T03:23:52+00:00" + }, + { + "name": "nelmio/api-doc-bundle", + "version": "2.13.0", + "target-dir": "Nelmio/ApiDocBundle", + "source": { + "type": "git", + "url": "https://github.com/nelmio/NelmioApiDocBundle.git", + "reference": "a3a9bb3b700f3ebaed95390292dad23f8141afa0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/a3a9bb3b700f3ebaed95390292dad23f8141afa0", + "reference": "a3a9bb3b700f3ebaed95390292dad23f8141afa0", + "shasum": "" + }, + "require": { + "michelf/php-markdown": "~1.4", + "php": ">=5.3", + "symfony/console": "~2.3|~3.0", + "symfony/framework-bundle": "~2.3|~3.0", + "symfony/twig-bundle": "~2.3|~3.0" + }, + "conflict": { + "jms/serializer": "<0.12", + "jms/serializer-bundle": "<0.11", + "symfony/symfony": "~2.7.8", + "twig/twig": "<1.12" + }, + "require-dev": { + "doctrine/doctrine-bundle": "~1.5", + "doctrine/orm": "~2.3", + "dunglas/api-bundle": "~1.0@dev", + "friendsofsymfony/rest-bundle": "~1.0|~2.0", + "jms/serializer-bundle": ">=0.11", + "sensio/framework-extra-bundle": "~3.0", + "symfony/browser-kit": "~2.3|~3.0", + "symfony/css-selector": "~2.3|~3.0", + "symfony/finder": "~2.3|~3.0", + "symfony/form": "~2.3|~3.0", + "symfony/phpunit-bridge": "~2.7|~3.0", + "symfony/serializer": "~2.7|~3.0", + "symfony/validator": "~2.3|~3.0", + "symfony/yaml": "~2.3|~3.0" + }, + "suggest": { + "dunglas/api-bundle": "For making use of resources definitions of DunglasApiBundle.", + "friendsofsymfony/rest-bundle": "For making use of REST information in the doc.", + "jms/serializer": "For making use of serializer information in the doc.", + "symfony/form": "For using form definitions as input.", + "symfony/validator": "For making use of validator information in the doc." + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.13-dev" + } + }, + "autoload": { + "psr-0": { + "Nelmio\\ApiDocBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nelmio", + "homepage": "http://nelm.io" + }, + { + "name": "Symfony Community", + "homepage": "https://github.com/nelmio/NelmioApiDocBundle/contributors" + } + ], + "description": "Generates documentation for your REST API from annotations", + "keywords": [ + "api", + "doc", + "documentation", + "rest" + ], + "time": "2016-06-13T09:12:09+00:00" + }, + { + "name": "ocramius/proxy-manager", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/Ocramius/ProxyManager.git", + "reference": "57e9272ec0e8deccf09421596e0e2252df440e11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/57e9272ec0e8deccf09421596e0e2252df440e11", + "reference": "57e9272ec0e8deccf09421596e0e2252df440e11", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "zendframework/zend-code": ">2.2.5,<3.0" + }, + "require-dev": { + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "1.5.*" + }, + "suggest": { + "ocramius/generated-hydrator": "To have very fast object to array to object conversion for ghost objects", + "zendframework/zend-json": "To have the JsonRpc adapter (Remote Object feature)", + "zendframework/zend-soap": "To have the Soap adapter (Remote Object feature)", + "zendframework/zend-stdlib": "To use the hydrator proxy", + "zendframework/zend-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "ProxyManager\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A library providing utilities to generate, instantiate and generally operate with Object Proxies", + "homepage": "https://github.com/Ocramius/ProxyManager", + "keywords": [ + "aop", + "lazy loading", + "proxy", + "proxy pattern", + "service proxies" + ], + "time": "2015-08-09T04:28:19+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf", + "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ], + "time": "2016-04-03T06:00:07+00:00" + }, + { + "name": "phpcollection/phpcollection", + "version": "0.5.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-collection.git", + "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-collection/zipball/f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", + "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", + "shasum": "" + }, + "require": { + "phpoption/phpoption": "1.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4-dev" + } + }, + "autoload": { + "psr-0": { + "PhpCollection": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "General-Purpose Collection Library for PHP", + "keywords": [ + "collection", + "list", + "map", + "sequence", + "set" + ], + "time": "2015-05-17T12:39:23+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27T11:43:31+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2016-09-30T07:12:33+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", + "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2016-06-10T07:14:17+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-0": { + "PhpOption\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "time": "2015-07-25T16:39:46+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.6.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1", + "sebastian/recursion-context": "^1.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2016-06-07T08:13:47+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-10-06T15:47:00+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-06-21T13:08:43+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2016-05-12T18:03:57+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-09-15T10:49:45+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "4.8.27", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "c062dddcb68e44b563f66ee319ddae2b5a322a90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c062dddcb68e44b563f66ee319ddae2b5a322a90", + "reference": "c062dddcb68e44b563f66ee319ddae2b5a322a90", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.3", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.8.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2016-07-21T06:48:14+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-10-02T06:51:40+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "5277094ed527a1c4477177d102fe4c53551953e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/5277094ed527a1c4477177d102fe4c53551953e0", + "reference": "5277094ed527a1c4477177d102fe4c53551953e0", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-09-19T16:02:08+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-07-26T15:48:44+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-12-08T07:14:41+00:00" + }, + { + "name": "sebastian/environment", + "version": "1.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-08-18T05:49:44+00:00" + }, + { + "name": "sebastian/exporter", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-06-17T09:04:28+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-11-11T19:50:13+00:00" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21T13:59:46+00:00" + }, + { + "name": "sensio/distribution-bundle", + "version": "v5.0.12", + "source": { + "type": "git", + "url": "https://github.com/sensiolabs/SensioDistributionBundle.git", + "reference": "b6dcd04595e4db95ead22ddea58c397864e00c32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sensiolabs/SensioDistributionBundle/zipball/b6dcd04595e4db95ead22ddea58c397864e00c32", + "reference": "b6dcd04595e4db95ead22ddea58c397864e00c32", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "sensiolabs/security-checker": "~3.0", + "symfony/class-loader": "~2.3|~3.0", + "symfony/config": "~2.3|~3.0", + "symfony/dependency-injection": "~2.3|~3.0", + "symfony/filesystem": "~2.3|~3.0", + "symfony/http-kernel": "~2.3|~3.0", + "symfony/process": "~2.3|~3.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Sensio\\Bundle\\DistributionBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Base bundle for Symfony Distributions", + "keywords": [ + "configuration", + "distribution" + ], + "time": "2016-09-14T20:25:12+00:00" + }, + { + "name": "sensio/framework-extra-bundle", + "version": "v3.0.16", + "source": { + "type": "git", + "url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git", + "reference": "507a15f56fa7699f6cc8c2c7de4080b19ce22546" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/507a15f56fa7699f6cc8c2c7de4080b19ce22546", + "reference": "507a15f56fa7699f6cc8c2c7de4080b19ce22546", + "shasum": "" + }, + "require": { + "doctrine/common": "~2.2", + "symfony/dependency-injection": "~2.3|~3.0", + "symfony/framework-bundle": "~2.3|~3.0" + }, + "require-dev": { + "symfony/browser-kit": "~2.3|~3.0", + "symfony/dom-crawler": "~2.3|~3.0", + "symfony/expression-language": "~2.4|~3.0", + "symfony/finder": "~2.3|~3.0", + "symfony/phpunit-bridge": "~2.7|~3.0", + "symfony/security-bundle": "~2.4|~3.0", + "symfony/twig-bundle": "~2.3|~3.0", + "twig/twig": "~1.11|~2.0" + }, + "suggest": { + "symfony/expression-language": "", + "symfony/psr-http-message-bridge": "To use the PSR-7 converters", + "symfony/security-bundle": "" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Sensio\\Bundle\\FrameworkExtraBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "This bundle provides a way to configure your controllers with annotations", + "keywords": [ + "annotations", + "controllers" + ], + "time": "2016-03-25T17:08:27+00:00" + }, + { + "name": "sensiolabs/security-checker", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sensiolabs/security-checker.git", + "reference": "21696b0daa731064c23cfb694c60a2584a7b6e93" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/21696b0daa731064c23cfb694c60a2584a7b6e93", + "reference": "21696b0daa731064c23cfb694c60a2584a7b6e93", + "shasum": "" + }, + "require": { + "symfony/console": "~2.0|~3.0" + }, + "bin": [ + "security-checker" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-0": { + "SensioLabs\\Security": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "A security checker for your composer.lock", + "time": "2015-11-07T08:07:40+00:00" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "v5.4.3", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", + "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "mockery/mockery": "~0.9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.4-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", + "keywords": [ + "email", + "mail", + "mailer" + ], + "time": "2016-07-08T11:51:25+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "2.11.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "e7caf4936c7be82bc6d68df87f1d23a0d5bf6e00" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/e7caf4936c7be82bc6d68df87f1d23a0d5bf6e00", + "reference": "e7caf4936c7be82bc6d68df87f1d23a0d5bf6e00", + "shasum": "" + }, + "require": { + "monolog/monolog": "~1.18", + "php": ">=5.3.2", + "symfony/config": "~2.3|~3.0", + "symfony/dependency-injection": "~2.3|~3.0", + "symfony/http-kernel": "~2.3|~3.0", + "symfony/monolog-bridge": "~2.3|~3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8", + "symfony/console": "~2.3|~3.0", + "symfony/yaml": "~2.3|~3.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony MonologBundle", + "homepage": "http://symfony.com", + "keywords": [ + "log", + "logging" + ], + "time": "2016-04-13T16:21:01+00:00" + }, + { + "name": "symfony/phpunit-bridge", + "version": "v3.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/phpunit-bridge.git", + "reference": "1f4e2059cf4ecae1053b9c3027b3fc548fd077b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/1f4e2059cf4ecae1053b9c3027b3fc548fd077b9", + "reference": "1f4e2059cf4ecae1053b9c3027b3fc548fd077b9", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" + }, + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony PHPUnit Bridge", + "homepage": "https://symfony.com", + "time": "2016-08-19T06:48:39+00:00" + }, + { + "name": "symfony/polyfill-apcu", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-apcu.git", + "reference": "6d58bceaeea2c2d3eb62503839b18646e161cd6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/6d58bceaeea2c2d3eb62503839b18646e161cd6b", + "reference": "6d58bceaeea2c2d3eb62503839b18646e161cd6b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "apcu", + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2016-05-18T14:26:46+00:00" + }, + { + "name": "symfony/polyfill-intl-icu", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-icu.git", + "reference": "0f8dc2c45f69f8672379e9210bca4a115cd5146f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/0f8dc2c45f69f8672379e9210bca4a115cd5146f", + "reference": "0f8dc2c45f69f8672379e9210bca4a115cd5146f", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/intl": "~2.3|~3.0" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's ICU-related data and classes", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "icu", + "intl", + "polyfill", + "portable", + "shim" + ], + "time": "2016-05-18T14:26:46+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "dff51f72b0706335131b00a7f49606168c582594" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", + "reference": "dff51f72b0706335131b00a7f49606168c582594", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2016-05-18T14:26:46+00:00" + }, + { + "name": "symfony/polyfill-php56", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php56.git", + "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/3edf57a8fbf9a927533344cef65ad7e1cf31030a", + "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-util": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php56\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2016-05-18T14:26:46+00:00" + }, + { + "name": "symfony/polyfill-php70", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "a42f4b6b05ed458910f8af4c4e1121b0101b2d85" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/a42f4b6b05ed458910f8af4c4e1121b0101b2d85", + "reference": "a42f4b6b05ed458910f8af4c4e1121b0101b2d85", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php70\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2016-05-18T14:26:46+00:00" + }, + { + "name": "symfony/polyfill-util", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-util.git", + "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/ef830ce3d218e622b221d6bfad42c751d974bf99", + "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Util\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony utilities for portability of PHP codes", + "homepage": "https://symfony.com", + "keywords": [ + "compat", + "compatibility", + "polyfill", + "shim" + ], + "time": "2016-05-18T14:26:46+00:00" + }, + { + "name": "symfony/swiftmailer-bundle", + "version": "v2.3.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/swiftmailer-bundle.git", + "reference": "5e1a90f28213231ceee19c953bbebc5b5b95c690" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/swiftmailer-bundle/zipball/5e1a90f28213231ceee19c953bbebc5b5b95c690", + "reference": "5e1a90f28213231ceee19c953bbebc5b5b95c690", + "shasum": "" + }, + "require": { + "php": ">=5.3.2", + "swiftmailer/swiftmailer": ">=4.2.0,~5.0", + "symfony/config": "~2.3|~3.0", + "symfony/dependency-injection": "~2.3|~3.0", + "symfony/http-kernel": "~2.3|~3.0", + "symfony/yaml": "~2.3|~3.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7|~3.0" + }, + "suggest": { + "psr/log": "Allows logging" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\SwiftmailerBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony SwiftmailerBundle", + "homepage": "http://symfony.com", + "time": "2016-01-15T16:41:20+00:00" + }, + { + "name": "symfony/symfony", + "version": "v3.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/symfony.git", + "reference": "e7e1d01fe103de78bca6fbf7f6f4acf64482d63c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/symfony/zipball/e7e1d01fe103de78bca6fbf7f6f4acf64482d63c", + "reference": "e7e1d01fe103de78bca6fbf7f6f4acf64482d63c", + "shasum": "" + }, + "require": { + "doctrine/common": "~2.4", + "php": ">=5.5.9", + "psr/cache": "~1.0", + "psr/log": "~1.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php56": "~1.0", + "symfony/polyfill-php70": "~1.0", + "symfony/polyfill-util": "~1.0", + "twig/twig": "~1.26|~2.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.0", + "phpdocumentor/type-resolver": "<0.2.0" + }, + "provide": { + "psr/cache-implementation": "1.0" + }, + "replace": { + "symfony/asset": "self.version", + "symfony/browser-kit": "self.version", + "symfony/cache": "self.version", + "symfony/class-loader": "self.version", + "symfony/config": "self.version", + "symfony/console": "self.version", + "symfony/css-selector": "self.version", + "symfony/debug": "self.version", + "symfony/debug-bundle": "self.version", + "symfony/dependency-injection": "self.version", + "symfony/doctrine-bridge": "self.version", + "symfony/dom-crawler": "self.version", + "symfony/event-dispatcher": "self.version", + "symfony/expression-language": "self.version", + "symfony/filesystem": "self.version", + "symfony/finder": "self.version", + "symfony/form": "self.version", + "symfony/framework-bundle": "self.version", + "symfony/http-foundation": "self.version", + "symfony/http-kernel": "self.version", + "symfony/inflector": "self.version", + "symfony/intl": "self.version", + "symfony/ldap": "self.version", + "symfony/monolog-bridge": "self.version", + "symfony/options-resolver": "self.version", + "symfony/process": "self.version", + "symfony/property-access": "self.version", + "symfony/property-info": "self.version", + "symfony/proxy-manager-bridge": "self.version", + "symfony/routing": "self.version", + "symfony/security": "self.version", + "symfony/security-bundle": "self.version", + "symfony/security-core": "self.version", + "symfony/security-csrf": "self.version", + "symfony/security-guard": "self.version", + "symfony/security-http": "self.version", + "symfony/serializer": "self.version", + "symfony/stopwatch": "self.version", + "symfony/templating": "self.version", + "symfony/translation": "self.version", + "symfony/twig-bridge": "self.version", + "symfony/twig-bundle": "self.version", + "symfony/validator": "self.version", + "symfony/var-dumper": "self.version", + "symfony/web-profiler-bundle": "self.version", + "symfony/yaml": "self.version" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "~1.6", + "doctrine/data-fixtures": "1.0.*", + "doctrine/dbal": "~2.4", + "doctrine/doctrine-bundle": "~1.4", + "doctrine/orm": "~2.4,>=2.4.5", + "egulias/email-validator": "~1.2,>=1.2.1", + "monolog/monolog": "~1.11", + "ocramius/proxy-manager": "~0.4|~1.0|~2.0", + "phpdocumentor/reflection-docblock": "^3.0", + "predis/predis": "~1.0", + "symfony/phpunit-bridge": "~3.2", + "symfony/polyfill-apcu": "~1.1", + "symfony/security-acl": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Doctrine\\": "src/Symfony/Bridge/Doctrine/", + "Symfony\\Bridge\\Monolog\\": "src/Symfony/Bridge/Monolog/", + "Symfony\\Bridge\\ProxyManager\\": "src/Symfony/Bridge/ProxyManager/", + "Symfony\\Bridge\\Swiftmailer\\": "src/Symfony/Bridge/Swiftmailer/", + "Symfony\\Bridge\\Twig\\": "src/Symfony/Bridge/Twig/", + "Symfony\\Bundle\\": "src/Symfony/Bundle/", + "Symfony\\Component\\": "src/Symfony/Component/" + }, + "classmap": [ + "src/Symfony/Component/Intl/Resources/stubs" + ], + "exclude-from-classmap": [ + "**/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "The Symfony PHP framework", + "homepage": "https://symfony.com", + "keywords": [ + "framework" + ], + "time": "2016-10-03T19:01:14+00:00" + }, + { + "name": "twig/twig", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "81c2b5fd36581370c7731387f05dcdb577050513" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/81c2b5fd36581370c7731387f05dcdb577050513", + "reference": "81c2b5fd36581370c7731387f05dcdb577050513", + "shasum": "" + }, + "require": { + "php": ">=5.2.7" + }, + "require-dev": { + "symfony/debug": "~2.7", + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.26-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + }, + { + "name": "Twig Team", + "homepage": "http://twig.sensiolabs.org/contributors", + "role": "Contributors" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "http://twig.sensiolabs.org", + "keywords": [ + "templating" + ], + "time": "2016-10-02T16:19:13+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "bb2d123231c095735130cc8f6d31385a44c7b308" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308", + "reference": "bb2d123231c095735130cc8f6d31385a44c7b308", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2016-08-09T15:02:57+00:00" + }, + { + "name": "willdurand/hateoas", + "version": "2.10.0", + "source": { + "type": "git", + "url": "https://github.com/willdurand/Hateoas.git", + "reference": "ada89d867e47040f8c4be3be2c8e7930a3d01189" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/willdurand/Hateoas/zipball/ada89d867e47040f8c4be3be2c8e7930a3d01189", + "reference": "ada89d867e47040f8c4be3be2c8e7930a3d01189", + "shasum": "" + }, + "require": { + "doctrine/annotations": "~1.0", + "doctrine/common": "~2.0", + "jms/metadata": "~1.1", + "jms/serializer": "~1.0", + "php": ">=5.4", + "phpoption/phpoption": ">=1.1.0,<2.0-dev", + "symfony/expression-language": "~2.4 || ~3.0" + }, + "require-dev": { + "pagerfanta/pagerfanta": "~1.0", + "phpunit/phpunit": "~4.5", + "symfony/dependency-injection": "~2.4 || ~3.0", + "symfony/routing": "~2.4 || ~3.0", + "symfony/yaml": "~2.4 || ~3.0", + "twig/twig": "~1.12" + }, + "suggest": { + "symfony/routing": "To use the SymfonyRouteFactory.", + "symfony/yaml": "To use yaml based configuration.", + "twig/twig": "To use the Twig extensions." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.10-dev" + } + }, + "autoload": { + "psr-0": { + "Hateoas": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrien Brault", + "email": "adrien.brault@gmail.com" + }, + { + "name": "William DURAND", + "email": "william.durand1@gmail.com" + } + ], + "description": "A PHP library to support implementing representations for HATEOAS REST web services", + "time": "2016-05-19T11:30:35+00:00" + }, + { + "name": "willdurand/hateoas-bundle", + "version": "1.2.0", + "target-dir": "Bazinga/Bundle/HateoasBundle", + "source": { + "type": "git", + "url": "https://github.com/willdurand/BazingaHateoasBundle.git", + "reference": "7c73a949c72dc6bc7363f76c11e70e655b19d94b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/willdurand/BazingaHateoasBundle/zipball/7c73a949c72dc6bc7363f76c11e70e655b19d94b", + "reference": "7c73a949c72dc6bc7363f76c11e70e655b19d94b", + "shasum": "" + }, + "require": { + "jms/serializer-bundle": "~1.0", + "php": ">5.4", + "symfony/framework-bundle": "~2.2 || ~3.0", + "willdurand/hateoas": "^2.10.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.5", + "symfony/expression-language": "~2.4 || ~3.0", + "twig/twig": "~1.12" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-0": { + "Bazinga\\Bundle\\HateoasBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "William Durand", + "email": "william.durand1@gmail.com" + } + ], + "description": "Integration of Hateoas into Symfony2.", + "keywords": [ + "HATEOAS", + "rest" + ], + "time": "2016-05-31T13:55:14+00:00" + }, + { + "name": "zendframework/zend-code", + "version": "2.6.3", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-code.git", + "reference": "95033f061b083e16cdee60530ec260d7d628b887" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-code/zipball/95033f061b083e16cdee60530ec260d7d628b887", + "reference": "95033f061b083e16cdee60530ec260d7d628b887", + "shasum": "" + }, + "require": { + "php": "^5.5 || 7.0.0 - 7.0.4 || ^7.0.6", + "zendframework/zend-eventmanager": "^2.6 || ^3.0" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "^4.8.21", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "suggest": { + "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", + "zendframework/zend-stdlib": "Zend\\Stdlib component" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev", + "dev-develop": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Code\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides facilities to generate arbitrary code using an object oriented interface", + "homepage": "https://github.com/zendframework/zend-code", + "keywords": [ + "code", + "zf2" + ], + "time": "2016-04-20T17:26:42+00:00" + }, + { + "name": "zendframework/zend-eventmanager", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-eventmanager.git", + "reference": "5c80bdee0e952be112dcec0968bad770082c3a6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/5c80bdee0e952be112dcec0968bad770082c3a6e", + "reference": "5c80bdee0e952be112dcec0968bad770082c3a6e", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0" + }, + "require-dev": { + "athletic/athletic": "^0.1", + "container-interop/container-interop": "^1.1.0", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "^2.0", + "zendframework/zend-stdlib": "^2.7.3 || ^3.0" + }, + "suggest": { + "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature", + "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev", + "dev-develop": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\EventManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Trigger and listen to events within a PHP application", + "homepage": "https://github.com/zendframework/zend-eventmanager", + "keywords": [ + "event", + "eventmanager", + "events", + "zf2" + ], + "time": "2016-02-18T20:53:00+00:00" + } + ], + "packages-dev": [ + { + "name": "sensio/generator-bundle", + "version": "v3.0.8", + "source": { + "type": "git", + "url": "https://github.com/sensiolabs/SensioGeneratorBundle.git", + "reference": "3c20d16512f37d2be159eca0411b99a141b90fa4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sensiolabs/SensioGeneratorBundle/zipball/3c20d16512f37d2be159eca0411b99a141b90fa4", + "reference": "3c20d16512f37d2be159eca0411b99a141b90fa4", + "shasum": "" + }, + "require": { + "symfony/console": "~2.7|~3.0", + "symfony/framework-bundle": "~2.7|~3.0", + "symfony/process": "~2.7|~3.0", + "symfony/yaml": "~2.7|~3.0" + }, + "require-dev": { + "doctrine/orm": "~2.4", + "symfony/doctrine-bridge": "~2.7|~3.0", + "twig/twig": "~1.18" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Sensio\\Bundle\\GeneratorBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "This bundle generates code for you", + "time": "2016-09-06T01:30:19+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.5.9" + }, + "platform-dev": [] +} diff --git a/doc.html b/doc.html new file mode 100644 index 0000000..f3399bb --- /dev/null +++ b/doc.html @@ -0,0 +1,1753 @@ + + + + + + + WebHook Documentation + + + + + +
+
+ +
+

+ Documentation auto-generated on Sun, 23 Oct 16 15:02:48 +0200 +

+ + + + diff --git a/doc.md b/doc.md new file mode 100644 index 0000000..74e5610 --- /dev/null +++ b/doc.md @@ -0,0 +1,198 @@ +# Destinations # + +## /destinations ## + +### `GET` /destinations ### + + +#### Response #### + +[]: + + * type: array of objects (Destination) + +[][url]: + + * type: string + +[][id]: + + * type: integer + + +### `POST` /destinations ### + + +#### Parameters #### + +url: + + * type: string + * required: true + + +### `DELETE` /destinations/{id} ### + + +#### Requirements #### + +**id** + + + +### `GET` /destinations/{id} ### + + +#### Requirements #### + +**id** + + +#### Response #### + +url: + + * type: string + +id: + + * type: integer + + +### `PUT|PATCH` /destinations/{id} ### + + +#### Requirements #### + +**id** + + +#### Parameters #### + +url: + + * type: string + * required: true + +#### Response #### + +url: + + * type: string + +id: + + * type: integer + + + +# Messages # + +## /messages ## + +### `GET` /messages ### + + +#### Response #### + +[]: + + * type: array of objects (Message) + +[][id]: + + * type: integer + +[][destination]: + + * type: object (Destination) + +[][destination][id]: + + * type: integer + +[][destination][url]: + + * type: string + +[][contentType]: + + * type: string + +[][msgBody]: + + * type: string + +[][createdAt]: + + * type: DateTime + + +### `POST` /messages ### + + +#### Parameters #### + +destination: + + * type: integer + * required: true + * description: Destination ID. + +contentType: + + * type: string + * required: true + +msgBody: + + * type: string + * required: true + + +### `DELETE` /messages/{id} ### + + +#### Requirements #### + +**id** + + + +### `GET` /messages/{id} ### + + +#### Requirements #### + +**id** + + +#### Response #### + +id: + + * type: integer + +destination: + + * type: object (Destination) + +destination[id]: + + * type: integer + +destination[url]: + + * type: string + +contentType: + + * type: string + +msgBody: + + * type: string + +createdAt: + + * type: DateTime diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..65e9082 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + + + tests + + + + + + src + + src/*Bundle/Resources + src/*/*Bundle/Resources + src/*/Bundle/*Bundle/Resources + + + + diff --git a/src/.htaccess b/src/.htaccess new file mode 100644 index 0000000..fb1de45 --- /dev/null +++ b/src/.htaccess @@ -0,0 +1,7 @@ + + Require all denied + + + Order deny,allow + Deny from all + diff --git a/src/AppBundle/AppBundle.php b/src/AppBundle/AppBundle.php new file mode 100644 index 0000000..05123b6 --- /dev/null +++ b/src/AppBundle/AppBundle.php @@ -0,0 +1,9 @@ +setName('message-processor') + ->setDescription('...') + ->addOption('destination', null, InputOption::VALUE_REQUIRED, 'Destination ID to process') + ->addOption('retry', null, InputOption::VALUE_REQUIRED, 'How many times to retry deliver a message. Default 3.') + ->addOption('retry-delay', null, InputOption::VALUE_REQUIRED, 'How many seconds wait before retry deliver a message. Default 1.') + ->addOption('persistent', null, InputOption::VALUE_NONE, 'If set, msg processor will run until user cancel it') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + //Configuration parameters + $messageFilter = array(); + $persistent = false; + $destinationFilter = null; + $retry = 3; + $retryDelay = 1; + + if ($input->getOption('destination')) { + $destinationFilter = $input->getOption('destination'); + $messageFilter['destination'] = $destinationFilter; + } + if ($input->getOption('retry')) { + $retry = $input->getOption('retry'); + } + if ($input->getOption('retry-delay')) { + $retryDelay = $input->getOption('retry-delay'); + } + if ($input->getOption('persistent')) { + $persistent = true; + } + + $em = $this->getContainer()->get('doctrine.orm.entity_manager'); + $em->getConnection()->getConfiguration()->setSQLLogger(null); + do { + //Check if destination exists + if ($destinationFilter AND !$em->getRepository('AppBundle:Destination') + ->find($input->getOption('destination'))) + { + $output->writeln('Selected destination doesn\'t exist'); + throw new Exception('Selected destination doesn\'t exist'); + } + + //Query for messages + $messages = $em + ->getRepository('AppBundle:Message') + ->findBy( + $messageFilter, + array('id' => 'ASC') + ); + + foreach ($messages as $message) { + //Check if it has more than 24 hours + $diff = date_diff($message->getCreatedAt(), new \DateTime()); + if ($diff->d >= 1){ + $output->writeln("Message id " . $message->getId() . " is in queue for more than 24h"); + $output->writeln("Message will be removed from the queue"); + $em->remove($message); + continue; + } + + + //Check if it's a non private ip + if (!$this->checkDestinationIp($message)) { + $output->writeln("Destination id " . $message->getDestination()->getId() . " is unresolvable or resolves to a private IP." ); + $output->writeln("Message will be removed from the queue"); + $em->remove($message); + continue; + } + + + $deliveredOk = false; + for ($i = 1; $i <= $retry; $i++) { + $status = $this->processMessage($message); + + if ($status == 200) { + $output->writeln("Message id " . $message->getId() . " delivered successful"); + $output->writeln("Message will be removed from the queue"); + $em->remove($message); + $deliveredOk = true; + break; + } + //Wait 1 second before retry deliver message + sleep($retryDelay); + } + if ($deliveredOk) { + continue; + } + + $output->writeln("Error delivering message id " . $message->getId() . "after 3 tries"); + $output->writeln("Status code: " . $status); + $output->writeln("Message will be removed from the queue"); + + $em->remove($message); + } + $em->flush(); + $em->clear(); + + + sleep(0.2); + } while ($persistent); + } + private function processMessage(Message $message) { + $client = new Client(); + $client->setHeader('Content-Type', $message->getContentType()); + $client->request( + 'POST', + $message->getDestination()->getUrl(), + array(), + array(), + array(), + $message->getMsgBody() + ); + + return $client->getResponse()->getStatus(); + } + + private function checkDestinationIp(Message $message) { + $ip = gethostbyname(parse_url($message->getDestination()->getUrl(), PHP_URL_HOST)); + + //Can't resolve IP + if (!$ip) { + return false; + } + + //Returns: + //True: IP isn't in private range + //False: IP is in private range + return filter_var( + $ip, + FILTER_VALIDATE_IP, + FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE + ); + + } +} diff --git a/src/AppBundle/Controller/BaseController.php b/src/AppBundle/Controller/BaseController.php new file mode 100644 index 0000000..43ba839 --- /dev/null +++ b/src/AppBundle/Controller/BaseController.php @@ -0,0 +1,79 @@ +serialize($data); + + return new Response($json, $statusCode, array( + 'Content-Type' => 'application/json' + )); + } + + protected function serialize($data, $format = 'json') + { + $context = new SerializationContext(); + $context->setSerializeNull(true); + + $groups = array('Default'); + $context->setGroups($groups); + + return $this->container->get('jms_serializer') + ->serialize($data, $format, $context); + } + + protected function processForm(Request $request, FormInterface $form) + { + $data = json_decode($request->getContent(), true); + if ($data === null) { + $problem = new Problem(400, Problem::TYPE_INVALID_REQUEST_BODY_FORMAT); + + throw new ProblemException($problem); + } + + $clearMissing = $request->getMethod() != 'PATCH'; + $form->submit($data, $clearMissing); + } + + protected function getErrorsFromForm(FormInterface $form) + { + $errors = array(); + foreach ($form->getErrors() as $error) { + $errors[] = $error->getMessage(); + } + + foreach ($form->all() as $childForm) { + if ($childForm instanceof FormInterface) { + if ($childErrors = $this->getErrorsFromForm($childForm)) { + $errors[$childForm->getName()] = $childErrors; + } + } + } + + return $errors; + } + + protected function throwProblemValidationException(FormInterface $form) + { + $errors = $this->getErrorsFromForm($form); + + $problem = new Problem( + 400, + Problem::TYPE_VALIDATION_ERROR + ); + $problem->set('errors', $errors); + + throw new ProblemException($problem); + } +} diff --git a/src/AppBundle/Controller/DestinationController.php b/src/AppBundle/Controller/DestinationController.php new file mode 100644 index 0000000..08a2867 --- /dev/null +++ b/src/AppBundle/Controller/DestinationController.php @@ -0,0 +1,164 @@ +createForm(DestinationType::class, $destination); + $this->processForm($request, $form); + + if(!$form->isValid()){ + $this->throwProblemValidationException($form); + } + + $em = $this->get('doctrine.orm.entity_manager'); + $em->persist($destination); + $em->flush(); + + $response = $this->createResponse($destination, 201); + $responseUrl = $this->generateUrl( + 'destination_show', + ['id' => $destination->getId()] + ); + $response->headers->set('Location', $responseUrl); + + return $response; + + } + + /** + * @Route("/destinations/{id}", name="destination_show") + * @Method("GET") + * @ApiDoc( + * output="AppBundle\Entity\Destination", + * section="Destinations" + * ) + */ + public function showAction($id) + { + $destination = $this->getDoctrine() + ->getRepository('AppBundle:Destination') + ->find($id); + + if (!$destination) { + throw $this->createNotFoundException(sprintf( + 'No destination found with id "%s"', + $id + )); + } + + $response = $this->createResponse($destination, 200); + + return $response; + } + + /** + * @Route("/destinations/{id}") + * @Method("DELETE") + * @ApiDoc( + * statusCodes={204="Resource deleted"}, + * section="Destinations" + * + * ) + */ + public function deleteAction($id) + { + $destination = $this->getDoctrine() + ->getRepository('AppBundle:Destination') + ->find($id); + + if ($destination) { + // debated point: should we return 404 on an unknown id? + // or should we just return a nice 204 in all cases? + // I choose give 204 in all cases + $em = $this->getDoctrine()->getManager(); + $em->remove($destination); + $em->flush(); + } + + return new Response(null, 204); + } + + /** + * @Route("/destinations", name="destinations_collection") + * @Method("GET") + * @ApiDoc( + * resource=true, + * output="array", + * section="Destinations" + * ) + */ + public function listAction() + { + $qb = $this->getDoctrine() + ->getRepository('AppBundle:Destination') + ->findAll(); + + $response = $this->createResponse($qb, 200); + + return $response; + } + + /** + * @Route("/destinations/{id}") + * @Method({"PUT", "PATCH"}) + * @ApiDoc( + * input={"class"="AppBundle\Form\DestinationType", "name"=""}, + * output="AppBundle\Entity\Destination", + * section="Destinations" + * ) + */ + public function updateAction($id, Request $request) + { + $destination = $this->getDoctrine() + ->getRepository('AppBundle:Destination') + ->find($id); + + if (!$destination) { + throw $this->createNotFoundException(sprintf( + 'No destination found with id "%s"', + $id + )); + } + + $form = $this->createForm(DestinationType::class, $destination); + $this->processForm($request, $form); + + if (!$form->isValid()) { + $this->throwProblemValidationException($form); + } + + $em = $this->getDoctrine()->getManager(); + $em->persist($destination); + $em->flush(); + + $response = $this->createResponse($destination, 200); + + return $response; + } +} diff --git a/src/AppBundle/Controller/MessageController.php b/src/AppBundle/Controller/MessageController.php new file mode 100644 index 0000000..75b7281 --- /dev/null +++ b/src/AppBundle/Controller/MessageController.php @@ -0,0 +1,130 @@ +createForm(MessageType::class, $message); + $this->processForm($request, $form); + + if(!$form->isValid()){ + $this->throwProblemValidationException($form); + } + + $message->setCreatedAt(new \DateTime()); + + $em = $this->get('doctrine.orm.entity_manager'); + $em->persist($message); + $em->flush(); + + $response = $this->createResponse($message, 201); + $responseUrl = $this->generateUrl( + 'message_show', + ['id' => $message->getId()] + ); + $response->headers->set('Location', $responseUrl); + + return $response; + + } + + /** + * @Route("/messages/{id}", name="message_show") + * @Method("GET") + * @ApiDoc( + * output="AppBundle\Entity\Message", + * section="Messages" + * ) + */ + public function showAction($id) + { + $message = $this->getDoctrine() + ->getRepository('AppBundle:Message') + ->find($id); + + if (!$message) { + throw $this->createNotFoundException(sprintf( + 'No message found with id "%s"', + $id + )); + } + + $response = $this->createResponse($message, 200); + + return $response; + } + + /** + * @Route("/messages/{id}") + * @Method("DELETE") + * @ApiDoc( + * statusCodes={204="Resource deleted"}, + * section="Messages" + * ) + */ + public function deleteAction($id) + { + $message = $this->getDoctrine() + ->getRepository('AppBundle:Message') + ->find($id); + + if ($message) { + // debated point: should we return 404 on an unknown id? + // or should we just return a nice 204 in all cases? + // I choose give 204 in all cases + $em = $this->getDoctrine()->getManager(); + $em->remove($message); + $em->flush(); + } + + return new Response(null, 204); + } + + /** + * @Route("/messages", name="messages_collection") + * @Method("GET") + * @ApiDoc( + * resource=true, + * output="array", + * section="Messages" + * ) + */ + public function listAction() + { + $qb = $this->getDoctrine() + ->getRepository('AppBundle:Message') + ->findAll(); + + $response = $this->createResponse($qb, 200); + + return $response; + } +} diff --git a/src/AppBundle/Entity/Destination.php b/src/AppBundle/Entity/Destination.php new file mode 100644 index 0000000..6b4f829 --- /dev/null +++ b/src/AppBundle/Entity/Destination.php @@ -0,0 +1,73 @@ +messages = new ArrayCollection(); + } + + /** + * @ORM\Id + * @ORM\GeneratedValue(strategy="AUTO") + * @ORM\Column(type="integer") + * @Serializer\Expose() + */ + private $id; + + /** + * @ORM\Column(type="string") + * @Assert\NotBlank(message="Please inform a destination URL.") + * @Assert\Url(message="Please inform a valid URL.") + * @Serializer\Expose() + */ + private $url; + + /** + * @ORM\OneToMany(targetEntity="Message", mappedBy="destination") + */ + private $messages; + + + public function getId() + { + return $this->id; + } + + public function getUrl() + { + return $this->url; + } + + public function setUrl($url) + { + $this->url = $url; + } + + +} \ No newline at end of file diff --git a/src/AppBundle/Entity/Message.php b/src/AppBundle/Entity/Message.php new file mode 100644 index 0000000..5e1c0df --- /dev/null +++ b/src/AppBundle/Entity/Message.php @@ -0,0 +1,106 @@ +id; + } + + /** + * @return Destination + */ + public function getDestination() + { + return $this->destination; + } + + public function setDestination($destination) + { + $this->destination = $destination; + } + + public function getContentType() + { + return $this->contentType; + } + + public function setContentType($contentType) + { + $this->contentType = $contentType; + } + + public function getMsgBody() + { + return $this->msgBody; + } + + public function setMsgBody($msgBody) + { + $this->msgBody = $msgBody; + } + + public function getCreatedAt() + { + return $this->createdAt; + } + + public function setCreatedAt($createdAt) + { + $this->createdAt = $createdAt; + } + + +} \ No newline at end of file diff --git a/src/AppBundle/EventListener/ExceptionSubscriber.php b/src/AppBundle/EventListener/ExceptionSubscriber.php new file mode 100644 index 0000000..0ab8192 --- /dev/null +++ b/src/AppBundle/EventListener/ExceptionSubscriber.php @@ -0,0 +1,91 @@ +debug = $debug; + $this->responseFactory = $responseFactory; + $this->logger = $logger; + } + + public function onKernelException(GetResponseForExceptionEvent $event) + { + $e = $event->getException(); + + $statusCode = $e instanceof HttpExceptionInterface ? $e->getStatusCode() : 500; + + // allow 500 errors to be thrown + if ($this->debug && $statusCode >= 500) { + return; + } + + $this->logException($e); + + if ($e instanceof ProblemException) { + $problem = $e->getProblem(); + } else { + + + $problem = new Problem( + $statusCode + ); + + /* + * If it's an HttpException message (e.g. for 404, 403), + * we'll say as a rule that the exception message is safe + * for the client. Otherwise, it could be some sensitive + * low-level exception, which should *not* be exposed + */ + if ($e instanceof HttpExceptionInterface) { + $problem->set('detail', $e->getMessage()); + } + } + + $response = $this->responseFactory->createResponse($problem); + + $event->setResponse($response); + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::EXCEPTION => 'onKernelException' + ); + } + + /** + * Adapted from the core Symfony exception handling in ExceptionListener + * + * @param \Exception $exception + */ + private function logException(\Exception $exception) + { + $message = sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine()); + $isCritical = !$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500; + $context = array('exception' => $exception); + if ($isCritical) { + $this->logger->critical($message, $context); + } else { + $this->logger->error($message, $context); + } + } +} diff --git a/src/AppBundle/Form/DestinationType.php b/src/AppBundle/Form/DestinationType.php new file mode 100644 index 0000000..07c1c8f --- /dev/null +++ b/src/AppBundle/Form/DestinationType.php @@ -0,0 +1,30 @@ +add('url', TextType::class); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + 'data_class' => 'AppBundle\Entity\Destination', + 'csrf_protection' => false, + )); + } + + public function getName() + { + return 'app_bundle_destination_type'; + } +} diff --git a/src/AppBundle/Form/MessageType.php b/src/AppBundle/Form/MessageType.php new file mode 100644 index 0000000..316e06b --- /dev/null +++ b/src/AppBundle/Form/MessageType.php @@ -0,0 +1,38 @@ +add('destination', EntityType::class, [ + 'class' => 'AppBundle\Entity\Destination', + 'property_path' => 'destination', + 'description' => 'Destination ID' + ]) + ->add('contentType', TextType::class) + ->add('msgBody', TextareaType::class); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + 'data_class' => 'AppBundle\Entity\Message', + 'csrf_protection' => false, + )); + } + + public function getName() + { + return 'app_bundle_message_type'; + } +} diff --git a/src/AppBundle/Problem/Problem.php b/src/AppBundle/Problem/Problem.php new file mode 100644 index 0000000..784a614 --- /dev/null +++ b/src/AppBundle/Problem/Problem.php @@ -0,0 +1,76 @@ + 'There was a validation error', + self::TYPE_INVALID_REQUEST_BODY_FORMAT => 'Invalid JSON format sent', + ); + + private $statusCode; + + private $type; + + private $title; + + private $extraData = array(); + + public function __construct($statusCode, $type = null) + { + $this->statusCode = $statusCode; + + if ($type === null) { + // no type? The default is about:blank and the title should + // be the standard status code message + $type = 'about:blank'; + $title = isset(Response::$statusTexts[$statusCode]) + ? Response::$statusTexts[$statusCode] + : 'Unknown status code :('; + } else { + if (!isset(self::$titles[$type])) { + throw new \InvalidArgumentException('No title for type '.$type); + } + + $title = self::$titles[$type]; + } + + $this->type = $type; + $this->title = $title; + } + + public function toArray() + { + return array_merge( + $this->extraData, + array( + 'status' => $this->statusCode, + 'type' => $this->type, + 'title' => $this->title, + ) + ); + } + + public function set($name, $value) + { + $this->extraData[$name] = $value; + } + + public function getStatusCode() + { + return $this->statusCode; + } + + public function getTitle() + { + return $this->title; + } +} diff --git a/src/AppBundle/Problem/ProblemException.php b/src/AppBundle/Problem/ProblemException.php new file mode 100644 index 0000000..c50f56b --- /dev/null +++ b/src/AppBundle/Problem/ProblemException.php @@ -0,0 +1,24 @@ +problem = $problem; + $statusCode = $problem->getStatusCode(); + $message = $problem->getTitle(); + + parent::__construct($statusCode, $message, $previous, $headers, $code); + } + + public function getProblem() + { + return $this->problem; + } +} diff --git a/src/AppBundle/Problem/ResponseFactory.php b/src/AppBundle/Problem/ResponseFactory.php new file mode 100644 index 0000000..76ede31 --- /dev/null +++ b/src/AppBundle/Problem/ResponseFactory.php @@ -0,0 +1,26 @@ +toArray(); + // making type a URL, to a temporarily fake page + if ($data['type'] != 'about:blank') { + //TODO: Create errors documentation + //$data['type'] = 'http://localhost:8000/docs/errors#'.$data['type']; + } + + $response = new JsonResponse( + $data, + $problem->getStatusCode() + ); + $response->headers->set('Content-Type', 'application/problem+json'); + + return $response; + } +} \ No newline at end of file diff --git a/src/AppBundle/Test/HookTestCase.php b/src/AppBundle/Test/HookTestCase.php new file mode 100644 index 0000000..411e2d1 --- /dev/null +++ b/src/AppBundle/Test/HookTestCase.php @@ -0,0 +1,106 @@ +purgeDatabase(); + } + + public static function setUpBeforeClass() + { + self::bootKernel(); + } + + + private function purgeDatabase() + { + $purger = new ORMPurger($this->getService('doctrine')->getManager()); + $purger->purge(); + } + + protected function getService($id) + { + static::bootKernel(); + + return static::$kernel->getContainer() + ->get($id); + + } + + /** + * @return EntityManager + */ + protected function getEntityManager() + { + return $this->getService('doctrine.orm.entity_manager'); + } + + protected function createDestination($url){ + $destination = new Destination(); + + $destination->setUrl($url); + + $em = $this->getEntityManager(); + $em->persist($destination); + $em->flush(); + + return $destination; + } + + protected function createMessage(Destination $destination, $contentType, $msgBody) { + $message = new Message(); + + $em = $this->getEntityManager(); + + $destination = $em + ->getRepository('AppBundle:Destination') + ->find($destination->getId()); + + $message->setDestination($destination); + $message->setContentType($contentType); + $message->setMsgBody($msgBody); + $message->setCreatedAt(new \DateTime()); + + + $em->persist($message); + $em->flush(); + + return $message; + } + + + public function jsonRequest(Client $client, $method, $uri, array $data) { + $client->request( + $method, + $uri, + array(), + array(), + array('CONTENT_TYPE' => 'application/json'), + json_encode($data)); + } + + public function debugResponse(Client $client) { + print_r($client->getResponse()->headers); + print_r($client->getResponse()->getContent()); + } + +} \ No newline at end of file diff --git a/tests/AppBundle/Controller/DestinationControllerTest.php b/tests/AppBundle/Controller/DestinationControllerTest.php new file mode 100644 index 0000000..5b30da9 --- /dev/null +++ b/tests/AppBundle/Controller/DestinationControllerTest.php @@ -0,0 +1,226 @@ + $this->urlTest, + ); + + $client = static::createClient(); + + $this->jsonRequest( + $client, + 'POST', + '/destinations', + $data); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(201, $client->getResponse()->getStatusCode()); + $this->assertTrue( + $client->getResponse()->headers->contains( + 'Content-Type', + 'application/json' + ) + ); + + $this->assertArrayHasKey('id', json_decode((string)$client->getResponse()->getContent(), true)); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['url'], $data['url']); + } + + public function testPOSTDestinationInvalidURL() + { + $data = array( + 'url' => 'abc', + ); + + $client = static::createClient(); + + $this->jsonRequest( + $client, + 'POST', + '/destinations', + $data); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(400, $client->getResponse()->getStatusCode()); + $this->assertTrue( + $client->getResponse()->headers->contains( + 'Content-Type', + 'application/problem+json' + ) + ); + + $this->assertArrayHasKey('errors', json_decode((string)$client->getResponse()->getContent(), true)); + } + + public function testPOSTDestinationInvalidJson() { + + $client = static::createClient(); + + //Request without or with invalid json + $client->request( + 'POST', + '/destinations'); + + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(400, $client->getResponse()->getStatusCode()); + } + + public function testGETDestination() { + $client = static::createClient(); + + $destination = $this->createDestination($this->urlTest); + + + $client->request( + 'GET', + '/destinations/' . $destination->getId() + ); + + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertArrayHasKey('id', json_decode((string)$client->getResponse()->getContent(), true)); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['url'], $this->urlTest); + + } + + public function testDestination404Exception() { + $client = static::createClient(); + + $client->request( + 'GET', + '/destinations/0' + ); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(404, $client->getResponse()->getStatusCode()); + $this->assertArrayHasKey('status', json_decode((string)$client->getResponse()->getContent(), true)); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['type'], 'about:blank'); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['title'], 'Not Found'); + + } + + public function testDELETEDestination() { + $client = static::createClient(); + + $destination = $this->createDestination($this->urlTest); + + $client->request( + 'DELETE', + '/destinations/' . $destination->getId() + ); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(204, $client->getResponse()->getStatusCode()); + } + + public function testGETDestinationsCollection() + { + $client = static::createClient(); + + for ($i = 1; $i <= 5; $i++) { + $this->createDestination($this->urlTest . $i); + } + + $client->request( + 'GET', + '/destinations' + ); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)[0]['url'], $this->urlTest . '1'); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)[4]['url'], $this->urlTest . '5'); + } + + public function testPUTDestination() + { + $client = static::createClient(); + + $destination = $this->createDestination($this->urlTest); + + $data = array( + 'url' => 'http://newurl.com', + ); + + $this->jsonRequest( + $client, + 'PUT', + '/destinations/' . $destination->getId(), + $data + ); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['url'], $data['url']); + // the ID is immutable on edits + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['id'], $destination->getId()); + } + + public function testPATCHDestination() + { + $client = static::createClient(); + + $destination = $this->createDestination($this->urlTest); + + $data = array( + 'url' => 'http://newurl.com', + ); + + $this->jsonRequest( + $client, + 'PATCH', + '/destinations/' . $destination->getId(), + $data + ); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['url'], $data['url']); + // the ID is immutable on edits + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['id'], $destination->getId()); + } + +} diff --git a/tests/AppBundle/Controller/MessageControllerTest.php b/tests/AppBundle/Controller/MessageControllerTest.php new file mode 100644 index 0000000..962ec70 --- /dev/null +++ b/tests/AppBundle/Controller/MessageControllerTest.php @@ -0,0 +1,185 @@ +createDestination($this->urlTest); + + $data = array( + 'destination' => $destination->getId(), + 'contentType' => $this->contentTypeTest, + 'msgBody' => $this->msgBodyTest + ); + + $client = static::createClient(); + + $this->jsonRequest( + $client, + 'POST', + '/messages', + $data); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(201, $client->getResponse()->getStatusCode()); + $this->assertTrue( + $client->getResponse()->headers->contains( + 'Content-Type', + 'application/json' + ) + ); + $this->assertArrayHasKey('id', json_decode((string)$client->getResponse()->getContent(), true)); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['destination']['id'], $destination->getId()); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['destination']['url'], $destination->getUrl()); + } + + public function testPOSTMessageInvalidDestination() + { + + $data = array( + 'destination' => 0, + 'contentType' => $this->contentTypeTest, + 'msgBody' => $this->msgBodyTest + ); + + $client = static::createClient(); + + $this->jsonRequest( + $client, + 'POST', + '/messages', + $data); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(400, $client->getResponse()->getStatusCode()); + $this->assertTrue( + $client->getResponse()->headers->contains( + 'Content-Type', + 'application/problem+json' + ) + ); + + $this->assertArrayHasKey('errors', json_decode((string)$client->getResponse()->getContent(), true)); + } + + public function testPOSTMessageInvalidJson() { + + $client = static::createClient(); + + //Request without or with invalid json + $client->request( + 'POST', + '/messages'); + + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(400, $client->getResponse()->getStatusCode()); + } + + public function testGETMessage() { + $client = static::createClient(); + + $destination = $this->createDestination($this->urlTest); + $message = $this->createMessage($destination, $this->contentTypeTest, $this->msgBodyTest); + + + $client->request( + 'GET', + '/messages/' . $message->getId() + ); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertArrayHasKey('id', json_decode((string)$client->getResponse()->getContent(), true)); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['id'], $message->getId()); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['contentType'], $message->getContentType()); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['msgBody'], $message->getMsgBody()); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['destination']['id'], $destination->getId()); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['destination']['url'], $this->urlTest); + + } + + public function testMessage404Exception() { + $client = static::createClient(); + + $client->request( + 'GET', + '/messages/0' + ); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(404, $client->getResponse()->getStatusCode()); + $this->assertArrayHasKey('status', json_decode((string)$client->getResponse()->getContent(), true)); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['type'], 'about:blank'); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)['title'], 'Not Found'); + + } + + public function testDELETEMessage() { + $client = static::createClient(); + + $destination = $this->createDestination($this->urlTest); + $message = $this->createMessage($destination, $this->contentTypeTest, $this->msgBodyTest); + + $client->request( + 'DELETE', + '/messages/' . $message->getId() + ); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(204, $client->getResponse()->getStatusCode()); + } + + public function testGETMessagesCollection() + { + $client = static::createClient(); + + $destination = $this->createDestination($this->urlTest); + + for ($i = 1; $i <= 5; $i++) { + $this->createMessage($destination, $this->contentTypeTest, $this->msgBodyTest . $i); + } + + $client->request( + 'GET', + '/messages' + ); + + if ($this->debugResponse) { + $this->debugResponse($client); + } + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)[0]['msgBody'], $this->msgBodyTest . '1'); + $this->assertEquals(json_decode((string)$client->getResponse()->getContent(), true)[4]['msgBody'], $this->msgBodyTest . '5'); + } +} diff --git a/var/SymfonyRequirements.php b/var/SymfonyRequirements.php new file mode 100644 index 0000000..7e7723a --- /dev/null +++ b/var/SymfonyRequirements.php @@ -0,0 +1,819 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* + * Users of PHP 5.2 should be able to run the requirements checks. + * This is why the file and all classes must be compatible with PHP 5.2+ + * (e.g. not using namespaces and closures). + * + * ************** CAUTION ************** + * + * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of + * the installation/update process. The original file resides in the + * SensioDistributionBundle. + * + * ************** CAUTION ************** + */ + +/** + * Represents a single PHP requirement, e.g. an installed extension. + * It can be a mandatory requirement or an optional recommendation. + * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration. + * + * @author Tobias Schultze + */ +class Requirement +{ + private $fulfilled; + private $testMessage; + private $helpText; + private $helpHtml; + private $optional; + + /** + * Constructor that initializes the requirement. + * + * @param bool $fulfilled Whether the requirement is fulfilled + * @param string $testMessage The message for testing the requirement + * @param string $helpHtml The help text formatted in HTML for resolving the problem + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement + */ + public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false) + { + $this->fulfilled = (bool) $fulfilled; + $this->testMessage = (string) $testMessage; + $this->helpHtml = (string) $helpHtml; + $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText; + $this->optional = (bool) $optional; + } + + /** + * Returns whether the requirement is fulfilled. + * + * @return bool true if fulfilled, otherwise false + */ + public function isFulfilled() + { + return $this->fulfilled; + } + + /** + * Returns the message for testing the requirement. + * + * @return string The test message + */ + public function getTestMessage() + { + return $this->testMessage; + } + + /** + * Returns the help text for resolving the problem. + * + * @return string The help text + */ + public function getHelpText() + { + return $this->helpText; + } + + /** + * Returns the help text formatted in HTML. + * + * @return string The HTML help + */ + public function getHelpHtml() + { + return $this->helpHtml; + } + + /** + * Returns whether this is only an optional recommendation and not a mandatory requirement. + * + * @return bool true if optional, false if mandatory + */ + public function isOptional() + { + return $this->optional; + } +} + +/** + * Represents a PHP requirement in form of a php.ini configuration. + * + * @author Tobias Schultze + */ +class PhpIniRequirement extends Requirement +{ + /** + * Constructor that initializes the requirement. + * + * @param string $cfgName The configuration name used for ini_get() + * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, + * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement + * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. + * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. + * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. + * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) + * @param string|null $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived) + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement + */ + public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false) + { + $cfgValue = ini_get($cfgName); + + if (is_callable($evaluation)) { + if (null === $testMessage || null === $helpHtml) { + throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.'); + } + + $fulfilled = call_user_func($evaluation, $cfgValue); + } else { + if (null === $testMessage) { + $testMessage = sprintf('%s %s be %s in php.ini', + $cfgName, + $optional ? 'should' : 'must', + $evaluation ? 'enabled' : 'disabled' + ); + } + + if (null === $helpHtml) { + $helpHtml = sprintf('Set %s to %s in php.ini*.', + $cfgName, + $evaluation ? 'on' : 'off' + ); + } + + $fulfilled = $evaluation == $cfgValue; + } + + parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional); + } +} + +/** + * A RequirementCollection represents a set of Requirement instances. + * + * @author Tobias Schultze + */ +class RequirementCollection implements IteratorAggregate +{ + /** + * @var Requirement[] + */ + private $requirements = array(); + + /** + * Gets the current RequirementCollection as an Iterator. + * + * @return Traversable A Traversable interface + */ + public function getIterator() + { + return new ArrayIterator($this->requirements); + } + + /** + * Adds a Requirement. + * + * @param Requirement $requirement A Requirement instance + */ + public function add(Requirement $requirement) + { + $this->requirements[] = $requirement; + } + + /** + * Adds a mandatory requirement. + * + * @param bool $fulfilled Whether the requirement is fulfilled + * @param string $testMessage The message for testing the requirement + * @param string $helpHtml The help text formatted in HTML for resolving the problem + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null) + { + $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false)); + } + + /** + * Adds an optional recommendation. + * + * @param bool $fulfilled Whether the recommendation is fulfilled + * @param string $testMessage The message for testing the recommendation + * @param string $helpHtml The help text formatted in HTML for resolving the problem + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null) + { + $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true)); + } + + /** + * Adds a mandatory requirement in form of a php.ini configuration. + * + * @param string $cfgName The configuration name used for ini_get() + * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, + * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement + * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. + * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. + * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. + * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) + * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived) + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) + { + $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false)); + } + + /** + * Adds an optional recommendation in form of a php.ini configuration. + * + * @param string $cfgName The configuration name used for ini_get() + * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, + * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement + * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. + * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. + * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. + * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) + * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived) + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) + { + $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true)); + } + + /** + * Adds a requirement collection to the current set of requirements. + * + * @param RequirementCollection $collection A RequirementCollection instance + */ + public function addCollection(RequirementCollection $collection) + { + $this->requirements = array_merge($this->requirements, $collection->all()); + } + + /** + * Returns both requirements and recommendations. + * + * @return Requirement[] + */ + public function all() + { + return $this->requirements; + } + + /** + * Returns all mandatory requirements. + * + * @return Requirement[] + */ + public function getRequirements() + { + $array = array(); + foreach ($this->requirements as $req) { + if (!$req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns the mandatory requirements that were not met. + * + * @return Requirement[] + */ + public function getFailedRequirements() + { + $array = array(); + foreach ($this->requirements as $req) { + if (!$req->isFulfilled() && !$req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns all optional recommendations. + * + * @return Requirement[] + */ + public function getRecommendations() + { + $array = array(); + foreach ($this->requirements as $req) { + if ($req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns the recommendations that were not met. + * + * @return Requirement[] + */ + public function getFailedRecommendations() + { + $array = array(); + foreach ($this->requirements as $req) { + if (!$req->isFulfilled() && $req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns whether a php.ini configuration is not correct. + * + * @return bool php.ini configuration problem? + */ + public function hasPhpIniConfigIssue() + { + foreach ($this->requirements as $req) { + if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) { + return true; + } + } + + return false; + } + + /** + * Returns the PHP configuration file (php.ini) path. + * + * @return string|false php.ini file path + */ + public function getPhpIniConfigPath() + { + return get_cfg_var('cfg_file_path'); + } +} + +/** + * This class specifies all requirements and optional recommendations that + * are necessary to run the Symfony Standard Edition. + * + * @author Tobias Schultze + * @author Fabien Potencier + */ +class SymfonyRequirements extends RequirementCollection +{ + const LEGACY_REQUIRED_PHP_VERSION = '5.3.3'; + const REQUIRED_PHP_VERSION = '5.5.9'; + + /** + * Constructor that initializes the requirements. + */ + public function __construct() + { + /* mandatory requirements follow */ + + $installedPhpVersion = phpversion(); + $requiredPhpVersion = $this->getPhpRequiredVersion(); + + $this->addRecommendation( + $requiredPhpVersion, + 'Vendors should be installed in order to check all requirements.', + 'Run the composer install command.', + 'Run the "composer install" command.' + ); + + if (false !== $requiredPhpVersion) { + $this->addRequirement( + version_compare($installedPhpVersion, $requiredPhpVersion, '>='), + sprintf('PHP version must be at least %s (%s installed)', $requiredPhpVersion, $installedPhpVersion), + sprintf('You are running PHP version "%s", but Symfony needs at least PHP "%s" to run. + Before using Symfony, upgrade your PHP installation, preferably to the latest version.', + $installedPhpVersion, $requiredPhpVersion), + sprintf('Install PHP %s or newer (installed version is %s)', $requiredPhpVersion, $installedPhpVersion) + ); + } + + $this->addRequirement( + version_compare($installedPhpVersion, '5.3.16', '!='), + 'PHP version must not be 5.3.16 as Symfony won\'t work properly with it', + 'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)' + ); + + $this->addRequirement( + is_dir(__DIR__.'/../vendor/composer'), + 'Vendor libraries must be installed', + 'Vendor libraries are missing. Install composer following instructions from http://getcomposer.org/. '. + 'Then run "php composer.phar install" to install them.' + ); + + $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache'; + + $this->addRequirement( + is_writable($cacheDir), + 'app/cache/ or var/cache/ directory must be writable', + 'Change the permissions of either "app/cache/" or "var/cache/" directory so that the web server can write into it.' + ); + + $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs'; + + $this->addRequirement( + is_writable($logsDir), + 'app/logs/ or var/logs/ directory must be writable', + 'Change the permissions of either "app/logs/" or "var/logs/" directory so that the web server can write into it.' + ); + + if (version_compare($installedPhpVersion, '7.0.0', '<')) { + $this->addPhpIniRequirement( + 'date.timezone', true, false, + 'date.timezone setting must be set', + 'Set the "date.timezone" setting in php.ini* (like Europe/Paris).' + ); + } + + if (false !== $requiredPhpVersion && version_compare($installedPhpVersion, $requiredPhpVersion, '>=')) { + $timezones = array(); + foreach (DateTimeZone::listAbbreviations() as $abbreviations) { + foreach ($abbreviations as $abbreviation) { + $timezones[$abbreviation['timezone_id']] = true; + } + } + + $this->addRequirement( + isset($timezones[@date_default_timezone_get()]), + sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()), + 'Your default timezone is not supported by PHP. Check for typos in your php.ini file and have a look at the list of deprecated timezones at http://php.net/manual/en/timezones.others.php.' + ); + } + + $this->addRequirement( + function_exists('iconv'), + 'iconv() must be available', + 'Install and enable the iconv extension.' + ); + + $this->addRequirement( + function_exists('json_encode'), + 'json_encode() must be available', + 'Install and enable the JSON extension.' + ); + + $this->addRequirement( + function_exists('session_start'), + 'session_start() must be available', + 'Install and enable the session extension.' + ); + + $this->addRequirement( + function_exists('ctype_alpha'), + 'ctype_alpha() must be available', + 'Install and enable the ctype extension.' + ); + + $this->addRequirement( + function_exists('token_get_all'), + 'token_get_all() must be available', + 'Install and enable the Tokenizer extension.' + ); + + $this->addRequirement( + function_exists('simplexml_import_dom'), + 'simplexml_import_dom() must be available', + 'Install and enable the SimpleXML extension.' + ); + + if (function_exists('apc_store') && ini_get('apc.enabled')) { + if (version_compare($installedPhpVersion, '5.4.0', '>=')) { + $this->addRequirement( + version_compare(phpversion('apc'), '3.1.13', '>='), + 'APC version must be at least 3.1.13 when using PHP 5.4', + 'Upgrade your APC extension (3.1.13+).' + ); + } else { + $this->addRequirement( + version_compare(phpversion('apc'), '3.0.17', '>='), + 'APC version must be at least 3.0.17', + 'Upgrade your APC extension (3.0.17+).' + ); + } + } + + $this->addPhpIniRequirement('detect_unicode', false); + + if (extension_loaded('suhosin')) { + $this->addPhpIniRequirement( + 'suhosin.executor.include.whitelist', + create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'), + false, + 'suhosin.executor.include.whitelist must be configured correctly in php.ini', + 'Add "phar" to suhosin.executor.include.whitelist in php.ini*.' + ); + } + + if (extension_loaded('xdebug')) { + $this->addPhpIniRequirement( + 'xdebug.show_exception_trace', false, true + ); + + $this->addPhpIniRequirement( + 'xdebug.scream', false, true + ); + + $this->addPhpIniRecommendation( + 'xdebug.max_nesting_level', + create_function('$cfgValue', 'return $cfgValue > 100;'), + true, + 'xdebug.max_nesting_level should be above 100 in php.ini', + 'Set "xdebug.max_nesting_level" to e.g. "250" in php.ini* to stop Xdebug\'s infinite recursion protection erroneously throwing a fatal error in your project.' + ); + } + + $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null; + + $this->addRequirement( + null !== $pcreVersion, + 'PCRE extension must be available', + 'Install the PCRE extension (version 8.0+).' + ); + + if (extension_loaded('mbstring')) { + $this->addPhpIniRequirement( + 'mbstring.func_overload', + create_function('$cfgValue', 'return (int) $cfgValue === 0;'), + true, + 'string functions should not be overloaded', + 'Set "mbstring.func_overload" to 0 in php.ini* to disable function overloading by the mbstring extension.' + ); + } + + /* optional recommendations follow */ + + if (file_exists(__DIR__.'/../vendor/composer')) { + require_once __DIR__.'/../vendor/autoload.php'; + + try { + $r = new ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle'); + + $contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php'); + } catch (ReflectionException $e) { + $contents = ''; + } + $this->addRecommendation( + file_get_contents(__FILE__) === $contents, + 'Requirements file should be up-to-date', + 'Your requirements file is outdated. Run composer install and re-check your configuration.' + ); + } + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.3.4', '>='), + 'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions', + 'Your project might malfunction randomly due to PHP bug #52083 ("Notice: Trying to get property of non-object"). Install PHP 5.3.4 or newer.' + ); + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.3.8', '>='), + 'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156', + 'Install PHP 5.3.8 or newer if your project uses annotations.' + ); + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.4.0', '!='), + 'You should not use PHP 5.4.0 due to the PHP bug #61453', + 'Your project might not work properly due to the PHP bug #61453 ("Cannot dump definitions which have method calls"). Install PHP 5.4.1 or newer.' + ); + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.4.11', '>='), + 'When using the logout handler from the Symfony Security Component, you should have at least PHP 5.4.11 due to PHP bug #63379 (as a workaround, you can also set invalidate_session to false in the security logout handler configuration)', + 'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.' + ); + + $this->addRecommendation( + (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<')) + || + version_compare($installedPhpVersion, '5.4.8', '>='), + 'You should use PHP 5.3.18+ or PHP 5.4.8+ to always get nice error messages for fatal errors in the development environment due to PHP bug #61767/#60909', + 'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.' + ); + + if (null !== $pcreVersion) { + $this->addRecommendation( + $pcreVersion >= 8.0, + sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion), + 'PCRE 8.0+ is preconfigured in PHP since 5.3.2 but you are using an outdated version of it. Symfony probably works anyway but it is recommended to upgrade your PCRE extension.' + ); + } + + $this->addRecommendation( + class_exists('DomDocument'), + 'PHP-DOM and PHP-XML modules should be installed', + 'Install and enable the PHP-DOM and the PHP-XML modules.' + ); + + $this->addRecommendation( + function_exists('mb_strlen'), + 'mb_strlen() should be available', + 'Install and enable the mbstring extension.' + ); + + $this->addRecommendation( + function_exists('iconv'), + 'iconv() should be available', + 'Install and enable the iconv extension.' + ); + + $this->addRecommendation( + function_exists('utf8_decode'), + 'utf8_decode() should be available', + 'Install and enable the XML extension.' + ); + + $this->addRecommendation( + function_exists('filter_var'), + 'filter_var() should be available', + 'Install and enable the filter extension.' + ); + + if (!defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->addRecommendation( + function_exists('posix_isatty'), + 'posix_isatty() should be available', + 'Install and enable the php_posix extension (used to colorize the CLI output).' + ); + } + + $this->addRecommendation( + extension_loaded('intl'), + 'intl extension should be available', + 'Install and enable the intl extension (used for validators).' + ); + + if (extension_loaded('intl')) { + // in some WAMP server installations, new Collator() returns null + $this->addRecommendation( + null !== new Collator('fr_FR'), + 'intl extension should be correctly configured', + 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.' + ); + + // check for compatible ICU versions (only done when you have the intl extension) + if (defined('INTL_ICU_VERSION')) { + $version = INTL_ICU_VERSION; + } else { + $reflector = new ReflectionExtension('intl'); + + ob_start(); + $reflector->info(); + $output = strip_tags(ob_get_clean()); + + preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches); + $version = $matches[1]; + } + + $this->addRecommendation( + version_compare($version, '4.0', '>='), + 'intl ICU version should be at least 4+', + 'Upgrade your intl extension with a newer ICU version (4+).' + ); + + if (class_exists('Symfony\Component\Intl\Intl')) { + $this->addRecommendation( + \Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion(), + sprintf('intl ICU version installed on your system is outdated (%s) and does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()), + 'To get the latest internationalization data upgrade the ICU system package and the intl PHP extension.' + ); + if (\Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion()) { + $this->addRecommendation( + \Symfony\Component\Intl\Intl::getIcuDataVersion() === \Symfony\Component\Intl\Intl::getIcuVersion(), + sprintf('intl ICU version installed on your system (%s) does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()), + 'To avoid internationalization data inconsistencies upgrade the symfony/intl component.' + ); + } + } + + $this->addPhpIniRecommendation( + 'intl.error_level', + create_function('$cfgValue', 'return (int) $cfgValue === 0;'), + true, + 'intl.error_level should be 0 in php.ini', + 'Set "intl.error_level" to "0" in php.ini* to inhibit the messages when an error occurs in ICU functions.' + ); + } + + $accelerator = + (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) + || + (extension_loaded('apc') && ini_get('apc.enabled')) + || + (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable')) + || + (extension_loaded('Zend OPcache') && ini_get('opcache.enable')) + || + (extension_loaded('xcache') && ini_get('xcache.cacher')) + || + (extension_loaded('wincache') && ini_get('wincache.ocenabled')) + ; + + $this->addRecommendation( + $accelerator, + 'a PHP accelerator should be installed', + 'Install and/or enable a PHP accelerator (highly recommended).' + ); + + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $this->addRecommendation( + $this->getRealpathCacheSize() >= 5 * 1024 * 1024, + 'realpath_cache_size should be at least 5M in php.ini', + 'Setting "realpath_cache_size" to e.g. "5242880" or "5M" in php.ini* may improve performance on Windows significantly in some cases.' + ); + } + + $this->addPhpIniRecommendation('short_open_tag', false); + + $this->addPhpIniRecommendation('magic_quotes_gpc', false, true); + + $this->addPhpIniRecommendation('register_globals', false, true); + + $this->addPhpIniRecommendation('session.auto_start', false); + + $this->addRecommendation( + class_exists('PDO'), + 'PDO should be installed', + 'Install PDO (mandatory for Doctrine).' + ); + + if (class_exists('PDO')) { + $drivers = PDO::getAvailableDrivers(); + $this->addRecommendation( + count($drivers) > 0, + sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'), + 'Install PDO drivers (mandatory for Doctrine).' + ); + } + } + + /** + * Loads realpath_cache_size from php.ini and converts it to int. + * + * (e.g. 16k is converted to 16384 int) + * + * @return int + */ + protected function getRealpathCacheSize() + { + $size = ini_get('realpath_cache_size'); + $size = trim($size); + $unit = strtolower(substr($size, -1, 1)); + switch ($unit) { + case 'g': + return $size * 1024 * 1024 * 1024; + case 'm': + return $size * 1024 * 1024; + case 'k': + return $size * 1024; + default: + return (int) $size; + } + } + + /** + * Defines PHP required version from Symfony version. + * + * @return string|false The PHP required version or false if it could not be guessed + */ + protected function getPhpRequiredVersion() + { + if (!file_exists($path = __DIR__.'/../composer.lock')) { + return false; + } + + $composerLock = json_decode(file_get_contents($path), true); + foreach ($composerLock['packages'] as $package) { + $name = $package['name']; + if ('symfony/symfony' !== $name && 'symfony/http-kernel' !== $name) { + continue; + } + + return (int) $package['version'][1] > 2 ? self::REQUIRED_PHP_VERSION : self::LEGACY_REQUIRED_PHP_VERSION; + } + + return false; + } +} diff --git a/var/cache/.gitkeep b/var/cache/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/var/logs/.gitkeep b/var/logs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/var/sessions/.gitkeep b/var/sessions/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/web/.htaccess b/web/.htaccess new file mode 100644 index 0000000..4dc7251 --- /dev/null +++ b/web/.htaccess @@ -0,0 +1,68 @@ +# Use the front controller as index file. It serves as a fallback solution when +# every other rewrite/redirect fails (e.g. in an aliased environment without +# mod_rewrite). Additionally, this reduces the matching process for the +# start page (path "/") because otherwise Apache will apply the rewriting rules +# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl). +DirectoryIndex app.php + +# By default, Apache does not evaluate symbolic links if you did not enable this +# feature in your server configuration. Uncomment the following line if you +# install assets as symlinks or if you experience problems related to symlinks +# when compiling LESS/Sass/CoffeScript assets. +# Options FollowSymlinks + +# Disabling MultiViews prevents unwanted negotiation, e.g. "/app" should not resolve +# to the front controller "/app.php" but be rewritten to "/app.php/app". + + Options -MultiViews + + + + RewriteEngine On + + # Determine the RewriteBase automatically and set it as environment variable. + # If you are using Apache aliases to do mass virtual hosting or installed the + # project in a subdirectory, the base path will be prepended to allow proper + # resolution of the app.php file and to redirect to the correct URI. It will + # work in environments without path prefix as well, providing a safe, one-size + # fits all solution. But as you do not need it in this case, you can comment + # the following 2 lines to eliminate the overhead. + RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ + RewriteRule ^(.*) - [E=BASE:%1] + + # Sets the HTTP_AUTHORIZATION header removed by Apache + RewriteCond %{HTTP:Authorization} . + RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Redirect to URI without front controller to prevent duplicate content + # (with and without `/app.php`). Only do this redirect on the initial + # rewrite by Apache and not on subsequent cycles. Otherwise we would get an + # endless redirect loop (request -> rewrite to front controller -> + # redirect -> request -> ...). + # So in case you get a "too many redirects" error or you always get redirected + # to the start page because your Apache does not expose the REDIRECT_STATUS + # environment variable, you have 2 choices: + # - disable this feature by commenting the following 2 lines or + # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the + # following RewriteCond (best solution) + RewriteCond %{ENV:REDIRECT_STATUS} ^$ + RewriteRule ^app\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L] + + # If the requested filename exists, simply serve it. + # We only want to let Apache serve files and not directories. + RewriteCond %{REQUEST_FILENAME} -f + RewriteRule ^ - [L] + + # Rewrite all other queries to the front controller. + RewriteRule ^ %{ENV:BASE}/app.php [L] + + + + + # When mod_rewrite is not available, we instruct a temporary redirect of + # the start page to the front controller explicitly so that the website + # and the generated links can still be used. + RedirectMatch 302 ^/$ /app.php/ + # RedirectTemp cannot be used instead + + diff --git a/web/app.php b/web/app.php new file mode 100644 index 0000000..6bd0ea0 --- /dev/null +++ b/web/app.php @@ -0,0 +1,18 @@ +loadClassCache(); +//$kernel = new AppCache($kernel); + +// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter +//Request::enableHttpMethodParameterOverride(); +$request = Request::createFromGlobals(); +$response = $kernel->handle($request); +$response->send(); +$kernel->terminate($request, $response); diff --git a/web/app_dev.php b/web/app_dev.php new file mode 100644 index 0000000..133f3e5 --- /dev/null +++ b/web/app_dev.php @@ -0,0 +1,30 @@ +loadClassCache(); +$request = Request::createFromGlobals(); +$response = $kernel->handle($request); +$response->send(); +$kernel->terminate($request, $response); diff --git a/web/apple-touch-icon.png b/web/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6e6b6ce170b949de35108974b6b05ecc90cc5f5d GIT binary patch literal 2092 zcmV+{2-Ek8P)&z+r}5D*Y;ZEcQ@j;*b&9UUE8TU$s-NPd2Pm(2P~0000DbW%=J z0FX}%II8UaA!Wnbel$ITMF0Q?Zb?KzRCocr)74>sF$e_UAELfhzZr<_mum zxrzA$6;n1T|3uYd)S!+N(+=;U51ev6SwJoj)K}3R9HCE%Ezo3T0|KV;=S^$}*Zkuq z`UIUlf1nEt^U)m0-9>?iWBPLBUiw$G$*Rc*-51d8O4lv|QC;;5oOER~R>{ zvEl#!@*RYn7%dyKJXW`-X|P745xJpt&b31=OAz4gitPe+mf? zpjHTeZ&@DSCq*6v;92;d5GXXEAWS#apjs2^?9818L4b+nmb}9gZ2*j`l0W~y9EWae zebeUZNM#U`#PPWM2zu`Psm`OFjDnfkf>pR-BC+@>KvK@d$i4B73BT^BfmRBD3Fpnq zt&QNR4@D6Q@z2k%%VAXwLv`?Q?F{rr#IZgfKfY!Qsy2Gtt(IeS;Uf*z20**7ER$bp z#cG~R?m1c^1uQ)1!dG_5U*}t~ofLLqeAo{pj=s9$TFXTk&8F|rllQ$fn+K^sOu!ut zhOzhasWOy{;8U+pZdgCsMN8K^?4BnGuavC?kHk_L$}7SGB6@zr!)#w#8w?LXg{FPJ z!UCEnb)gJJZ!{}tsLgl~1p0kg4A4=+F_l2U4!K4W>hcm-lB1#H1Ud?29niSCt}MNP z5_&PJ73_OadX(2BzCzh(snTX%)kr~6V63Y>JJG$b@vq`cV3VS?KKrM8p)q697_!0u>+i$unT0 z$#4yxV@WMxjn>7!q1CB9F`jJ2#V-g zu@#x}6uRrU^`ewuo}jB|V1rIbhW1SoJwov-Sd&j$+h zoV0Pp_`AHY&Vb4xEP@6v9;or)^}OHJ5`yVo1R-1Z0-KZ+y*M6zcDWV7 z*l2BR!q7H+sZ6;xJDu0z#A^tSdm)0NX$vfvq;p<0@ri!sTbsGb+O6uOSe#Q8XDX z9D;Rtt>{(92v{qx#J|V>VBU(WckYxAA!FiTSgGkpd+{rm#}R+ph85V05ydUSxLTbC zBR_Z{ethB+doU3Nf-RwcnNdCiUMerdgT3OEM(Ar$d;om*ED2&RZPyyH2Cr6 z|2kBQrh8VdS_kFRDET3`(d^GI(tvm8&wZMk6aces06J-Zl+;v6(p6oV3Xj4)6xXl0 zQp+qigkhJqPVb#u^8Z&}L)&+m1T%*|fN73}rHGNyg;pv)#&r{Y z-?nWpwv`?pS8xo$7lS*&7*R5mpmSQ;fYIxnBxnAkYeG{a#1r1ke`%AG z5VMHY-yreZQD86yY=U0575S(<7fl0K65=JAZJqp_3>fK1!qGnlpelMr>J=}_lpRE> z#4BRiFwUV?qX`v+9AAG45|7t)p3Yw-&JwT|0UrhJDm^=SoYp(uY|-duEy3RFFpe)a zLDp=atW&V>I?y`TVs0L80A^jqMOuU`Q8#+5+zU_|#y3eR0Jt_0fbIT??+2)+ zkAwUJdZ+<~&@F#yN)#uPA%&jeFe3BZJ)L6-j$TBC4o0yLC`Z9nwkunc?ME`U2Y^qC z{z8EWz!OR^2g4G@=v4#~&>6{_SQH4ryi(M8wF_wMgDcPg)e)II1d5~3RY?DJCs$yQ z4|xcaBr^|k?U_iRIk9J?!E1>vGZEmJ zHB>Q-JeGDM2>Hf7p1tqGuD6bDaSR>a6~G;|<#9|*`EC7x^t_dxEw3^B#>V~D@#(&KA*0000getFailedRequirements(); +$minorProblems = $symfonyRequirements->getFailedRecommendations(); +$hasMajorProblems = (bool) count($majorProblems); +$hasMinorProblems = (bool) count($minorProblems); + +?> + + + + + + Symfony Configuration Checker + + + + + +
+
+ + + +
+ +
+
+
+

Configuration Checker

+

+ This script analyzes your system to check whether is + ready to run Symfony applications. +

+ + +

Major problems

+

Major problems have been detected and must be fixed before continuing:

+
    + +
  1. getTestMessage() ?> +

    getHelpHtml() ?>

    +
  2. + +
+ + + +

Recommendations

+

+ Additionally, toTo enhance your Symfony experience, + it’s recommended that you fix the following: +

+
    + +
  1. getTestMessage() ?> +

    getHelpHtml() ?>

    +
  2. + +
+ + + hasPhpIniConfigIssue()): ?> +

* + getPhpIniConfigPath()): ?> + Changes to the php.ini file must be done in "getPhpIniConfigPath() ?>". + + To change settings, create a "php.ini". + +

+ + + +

All checks passed successfully. Your system is ready to run Symfony applications.

+ + + +
+
+
+
Symfony Standard Edition
+
+ + diff --git a/web/favicon.ico b/web/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..479f7f50f404ada1e42c536097521d19f2c22f35 GIT binary patch literal 6518 zcmeHLTWD5E5Kuy5M>-BgCK}6B8uRHx|%3>L5P|~O|ntQ zD!!Jkw41=CfUf}7Y>i>k%K=@zd-rz03PXkrQJkKhPTU1316WJ0t;)^K zbyu!jaThLJh>sjO(gCIvVc@`l?8mUf@?VxRKb$qO($xL+ALa-_~@WM&XcK|z6}QYkrb;DB&Ee*AdFuz@nj!@bZS z<->;$=Qy4}f4ng zT`R9&zg9W$g*fMA(V|7V4!nwC1N}icH$iJ+|IndBsoL6Fw{YP?U32~VbvbzOp!Rp| z+QoH3{j>x9l=r2cuRkN**Q-~rq^qk-7B5~b%asw z{R`YNd-iNcpPfE^TKOs}D%6J$A3l`g;$nI7X{UL zSHSyawhQh!&z`LUKzZ$;*}Tik%OlNg-n`jWRaLp_>grTuW24<4-nr1Qk5d>Z|IndB zV}Rb@F=NJ1UdNOvQ{rXImgzjkRbgR-$NZsHK#uLv`8VUnjvZ_3IG5CGYYkHp{Xw7d zUNu1;&*)z`<8uGDG1Qh^W3>M}%s80~_!^L=J#-L5|3XUxZ>I4h7WG4aK41rYe;RNb z{dzzh`=oIWFb~idV2v^;>#wwo1oIc@?}q#)V7o6pV(@W}vHkDBqXE{EGL7~r9QKUK z!ohxnM<=ldqlbHr`L~$+8^Bspw$YMU=aHXyQq|en z*|tyB2O48DW47~gBD^Kg$xGb?+Qc=CMT8&G9|BsT)cQO>~+M55vtF}6w__k_%yb`&ZqF(P}LYkrZe14%vWR1L8kIAS+Ydq zJoUeL@j_))R#q~1xcm3-Q-{(94H^{swD}W2KC|H*`qsi5gZ)L&PrevAT?puFo}m7^ zx;pWCdq3z6r($w*G)-0BO9hyw_IKB<1M-knc#-^QRNgg!KSvzK%(* zN%nO;_$&|q8-2#fZ@3n^^=%`+hBd6wE?v4LckbK~)_qHtF10y#>eMOqKlR_ce~)z5 z8j_Kb@n>hCdZ3T?FjklNeusbaS`$8c^hot?*|J4gyToyn3u|nG?j6v5mbL>r;6L>d>JgQV+Aqk!e%06S-n|p#BF8%R*Y;nP*5$gS zct^3WWsHWbPx(OSO&2kAGmqV6AMdTx*UIwr=~LDJ;K2ix#WQ*K>{;0Fwr$&#{`T$L zKtmm+G`pic*gziI!FxvinnQt=#(iuS;n zw{G218frV4IB_EDeqBp>9(1010jeLk4!|59XvudEx^Q2V-`UxzxaLNU$&<5Z&nk`c zO-)UK&UFOTcYmPyIn!Tn{s*1;RBc3#)p*9Y_U6qS)8TjqT<^cbWb4+gT9;El@`Ag1 z^{QOHd|B;+kCZp@p8l|Z`X3PPpXs-p!tayTwpP_oJLb-vt1@TJnx%O4>eaz7{I=jb zS+{PTFi){I-@kvq@^L?Y-^8@Tax-hDk|Yg%>C>l=*{Xi!{t)W}jr^$Hh3AjD9n;;h zxU{r1=;8NDYiny5`+DIc{gA_YZGqpn#s%spSloq=H3w2&<%;kFa|Q#KYsjJ^~{?$ zPkG2k8hyZ+Wo!8ctWTV{*LL@sKxa+M{8I)*{jtYk?eESm(7`9urcKlF#*G_Qf7|;u zN!o?)64|?VuS}gfRr&lGs1E4d4H?$PV*FnWXan=ZM|x<3|5j2u>Le9aR(|hp! z58sEiK5od38#hSfniT&pfUaLK{sO?JH2}_LBk1OXAOrK-$Gr6I+gHD}jYiCGZ_B&< zrfqL;=eyK39P?b7d~CoO#Jt;(Rfx50)SaxqE@4a?v{nKRcJS`NK8@?%PWH*G`cW@v zpE-lI5@Qp;&-snLY11Z^$r>K~tnsXwZmR`HKqm9D@&i-9%1z)TE#w*Aan@mejjUh4 zUf+fvxBFWDCyZI+vYF2A(TBR6cfoAnUEzJ84Q5Bs0h;!~ub8<%QG<}5Yh#~RsCx{6 z&Fa4H(T887(+?K`rk8dk-=@(6PVn-cbRvev^tb!j=}uC<33gAlnE%;N;oxJW2uoNyrWR#`=%?o~Id@HEm8peo|(F z++&w_Gih%Y#@_;1x1NFgd%%wY{QkZJU>++0u%2X1YmGAOo*V5m{_KIz9{B8m=r_v| BFLeL_ literal 0 HcmV?d00001 diff --git a/web/robots.txt b/web/robots.txt new file mode 100644 index 0000000..4665fca --- /dev/null +++ b/web/robots.txt @@ -0,0 +1,5 @@ +# www.robotstxt.org/ +# www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449 + +User-agent: * +Disallow: