diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6f313c6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.yml] +indent_size = 2 diff --git a/.gitignore b/.gitignore index 81cded9..1cf0c06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /node_modules /vendor -/.phpintel \ No newline at end of file +/.phpintel +/.idea +composer.lock diff --git a/.scrutinizer.yml b/.scrutinizer.yml new file mode 100644 index 0000000..9a78174 --- /dev/null +++ b/.scrutinizer.yml @@ -0,0 +1,28 @@ +filter: + excluded_paths: [tests/*] + +checks: + php: + remove_extra_empty_lines: true + remove_php_closing_tag: true + remove_trailing_whitespace: true + fix_use_statements: + remove_unused: true + preserve_multiple: false + preserve_blanklines: true + order_alphabetically: true + fix_php_opening_tag: true + fix_linefeed: true + fix_line_ending: true + fix_identation_4spaces: true + fix_doc_comments: true + +build: + tests: + override: + - php-scrutinizer-run + - + command: 'vendor/bin/phpunit --coverage-clover=some-file' + coverage: + file: 'some-file' + format: 'clover' diff --git a/.styleci.yml b/.styleci.yml index 334ad18..473c31a 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,7 +1,5 @@ preset: laravel -linting: true - finder: exclude: - "tests" diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b62eb3c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,59 @@ +language: php + +env: + global: + - setup=stable + +matrix: + include: + - php: 7.0 + env: + - testbench=3.4.x + - phpunit=5.7.x + - php: 7.0 + env: + - testbench=3.5.x + - phpunit=6.0.x + - php: 7.1 + env: + - testbench=3.5.x + - phpunit=6.0.x + - php: 7.1 + env: + - testbench=3.6.x + - phpunit=7.0.x + - php: 7.1 + env: + - testbench=3.6.x + - phpunit=7.0.x + - php: 7.1 + env: + - testbench=3.7.x + - phpunit=7.0.x + - php: 7.2 + env: + - testbench=3.5.x + - phpunit=6.0.x + - php: 7.2 + env: + - testbench=3.6.x + - phpunit=7.0.x + - php: 7.2 + env: + - testbench=3.6.x + - phpunit=7.0.x + - php: 7.2 + env: + - testbench=3.7.x + - phpunit=7.0.x + +sudo: false + +install: + - composer require orchestra/testbench:${testbench} --dev --no-update + - composer require phpunit/phpunit:${phpunit} --dev --no-update + - if [[ $setup = 'stable' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-stable; fi + - if [[ $setup = 'lowest' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-lowest --prefer-stable; fi + +script: + - vendor/bin/phpunit diff --git a/README.md b/README.md index 9570d63..2f5277f 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,17 @@ # Laravel Json Exception Handler -[![StyleCI](https://styleci.io/repos/101529653/shield)](https://styleci.io/repos/101529653) -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/sfelix-martins/json-exception-handler/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/sfelix-martins/json-exception-handler/?branch=master) +[![StyleCI](https://styleci.io/repos/101529653/shield?style=plastic&branch=2.0)](https://styleci.io/repos/101529653?style=plastic&branch=2.0) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/sfelix-martins/json-exception-handler/badges/quality-score.png?b=2.0)](https://scrutinizer-ci.com/g/sfelix-martins/json-exception-handler/?branch=2.0) +[![Build Status](https://travis-ci.org/sfelix-martins/json-exception-handler.svg?branch=2.0)](https://travis-ci.org/sfelix-martins/json-exception-handler) Adds methods to your `App\Exceptions\Handler` to treat json responses. It is most useful if you are building APIs! +## Requirements + +* Laravel Framework >= 5.4 +* php >= 7.0 + ## JsonAPI Using [JsonAPI](http://jsonapi.org) standard to responses! @@ -16,17 +22,17 @@ Default error response: ```json { - "errors": [ - { - "status": 404, - "code": 15, - "source": { - "pointer": "" - }, - "title": "Route not found.", - "detail": "NotFoundHttpException line 179 in RouteCollection.php" - } - ] + "errors": [ + { + "status": "404", + "code": "13", + "title": "model_not_found_exception", + "detail": "User not found", + "source": { + "pointer": "data/id" + } + } + ] } ``` @@ -34,35 +40,26 @@ To `Illuminate\Validation\ValidationException`: ```json { - "errors": [ - { - "status": 422, - "code": 1411, - "source": { - "parameter": "name" - }, - "title": "Required validation failed on field name", - "detail": "The name field is required." - }, - { - "status": 422, - "code": 1433, - "source": { - "parameter": "password" - }, - "title": "Min validation failed on field password", - "detail": "The password must be at least 6 characters." - }, - { - "status": 422, - "code": 1432, - "source": { - "parameter": "password" - }, - "title": "Confirmed validation failed on field password", - "detail": "The password confirmation does not match." - } - ] + "errors": [ + { + "status": "422", + "code": "1411", + "title": "Required validation failed on field name", + "detail": "The name field is required.", + "source": { + "pointer": "name" + } + }, + { + "status": "422", + "code": "1421", + "title": "Email validation failed on field email", + "detail": "The email must be a valid email address.", + "source": { + "pointer": "email" + } + } + ] } ``` @@ -76,8 +73,6 @@ To `Illuminate\Validation\ValidationException`: - `League\OAuth2\Server\Exception\OAuthServerException` - `Symfony\Component\HttpKernel\Exception\NotFoundHttpException` - `Symfony\Component\HttpKernel\Exception\BadRequestHttpException` -- `GuzzleHttp\Exception\ClientException` -- `Cielo\API30\Ecommerce\Request\CieloRequestException` ## Installing and configuring @@ -92,7 +87,7 @@ If you are not using **Laravel 5.5** version add the `JsonHandlerServiceProvider ```php 'providers' => [ ... - SMartins\JsonHandler\JsonHandlerServiceProvider::class, + SMartins\Exceptions\JsonHandlerServiceProvider::class, ], ``` @@ -125,13 +120,13 @@ passing the `$exception` if `$request` expects a json response on `render()`meth ```php -use SMartins\JsonHandler\JsonHandler; +use SMartins\Exceptions\JsonHandler; class Handler extends ExceptionHandler { use JsonHandler; - ... + // ... public function render($request, Exception $exception) { @@ -142,21 +137,20 @@ class Handler extends ExceptionHandler return parent::render($request, $exception); } - ... + // ... ``` ### Use sample ```php - class UserController extends Controller { - ... + // ... public function store(Request $request) { // Validation - $request->validate($this->rules); // on Laravel 5.5 + $request->validate($this->rules); // or $this->validate($request, $this->rules); @@ -187,6 +181,119 @@ class UserController extends Controller ``` +## Extending + +You can too create your own handler to any Exception. E.g.: + +- Create a Handler class that extends of `AbstractHandler`: + +```php +namespace App\Exceptions; + +use GuzzleHttp\Exception\ClientException; +use SMartins\Exceptions\Handlers\AbstractHandler; + +class GuzzleClientHandler extends AbstractHandler +{ + /** + * Create instance using the Exception to be handled. + * + * @param \GuzzleHttp\Exception\ClientException $e + */ + public function __construct(ClientException $e) + { + parent::__construct($e); + } +} +``` + +- You must implements the method `handle()` from `AbstractHandler` class. The method must return an instance of `Error` or `ErrorCollection`: + +```php +namespace App\Exceptions; + +use SMartins\Exceptions\JsonAPI\Error; +use SMartins\Exceptions\JsonAPI\Source; +use GuzzleHttp\Exception\ClientException; +use SMartins\Exceptions\Handlers\AbstractHandler; + +class GuzzleClientHandler extends AbstractHandler +{ + // ... + + public function handle() + { + return (new Error)->setStatus($this->getStatusCode()) + ->setCode($this->getCode()) + ->setSource((new Source())->setPointer($this->getDefaultPointer())) + ->setTitle($this->getDefaultTitle()) + ->setDetail($this->exception->getMessage()); + } + + public function getCode() + { + // You can add a new type of code on `config/json-exception-handlers.php` + return config('json-exception-handler.codes.client.default'); + } +} +``` + +```php +namespace App\Exceptions; + +use SMartins\Exceptions\JsonAPI\Error; +use SMartins\Exceptions\JsonAPI\Source; +use SMartins\Exceptions\JsonAPI\ErrorCollection; +use SMartins\Exceptions\Handlers\AbstractHandler; + +class MyCustomizedHandler extends AbstractHandler +{ + public function __construct(MyCustomizedException $e) + { + parent::__construct($e); + } + + public function handle() + { + $errors = (new ErrorCollection)->setStatusCode(400); + + $exceptions = $this->exception->getExceptions(); + + foreach ($exceptions as $exception) { + $error = (new Error)->setStatus(422) + ->setSource((new Source())->setPointer($this->getDefaultPointer())) + ->setTitle($this->getDefaultTitle()) + ->setDetail($exception->getMessage()); + + $errors->push($error); + } + + return $errors; + } +} +``` + +- Now just registry your customized handler on `App\Exception\Handler` file on attribute `exceptionHandlers`. E.g: + +```php +namespace App\Exceptions; + +use Exception; +use GuzzleHttp\Exception\ClientException; +use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; +use SMartins\Exceptions\JsonHandler; + +class Handler extends ExceptionHandler +{ + use JsonHandler; + + protected $exceptionHandlers = [ + // Set on key the exception and on value the handler. + ClientException::class => GuzzleClientHandler::class, + ]; + +``` + ## Response References: - http://jsonapi.org/format/#errors diff --git a/UPGRADE.md b/UPGRADE.md new file mode 100644 index 0000000..3aa9e9e --- /dev/null +++ b/UPGRADE.md @@ -0,0 +1,18 @@ +# Upgrade Guide + +## Upgrading to 2.0 from 1.0 + +### Updating Dependencies + +Update the `sfelix-martins/json-exception-handler` dependency to `^2.0` in your `composer.json` file. + +### Update Configs + +If you are not using Laravel 5.5 version change the `JsonHandlerServiceProvider` from your `config/app.php` providers array: + +```php + 'providers' => [ + ... + SMartins\Exceptions\JsonHandlerServiceProvider::class, + ], +``` diff --git a/composer.json b/composer.json index 6794ccd..17a91b8 100644 --- a/composer.json +++ b/composer.json @@ -11,18 +11,30 @@ } ], "require": { - "php": ">=5.6.4" + "php": ">=7.0.0" }, "autoload": { "psr-4": { - "SMartins\\JsonHandler\\": "src/" + "SMartins\\Exceptions\\": "src/" + } + }, + "autoload-dev": { + "files": [ + "tests/TestCase.php" + ], + "psr-4": { + "SMartins\\Exceptions\\Tests\\": "tests/" } }, "extra": { "laravel": { "providers": [ - "SMartins\\JsonHandler\\JsonHandlerServiceProvider" + "SMartins\\Exceptions\\JsonHandlerServiceProvider" ] } + }, + "require-dev": { + "orchestra/testbench": "~3.0", + "phpunit/phpunit": "^7.1" } } diff --git a/composer.lock b/composer.lock index 714579d..48ba15d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,3487 @@ "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": "43813f6281c6804df66a42cd22b30c55", + "content-hash": "add54d97fbf3a6107d45451014b8591a", "packages": [], - "packages-dev": [], + "packages-dev": [ + { + "name": "doctrine/inflector", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "5527a48b7313d15261292c149e55e26eae771b0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5527a48b7313d15261292c149e55e26eae771b0a", + "reference": "5527a48b7313d15261292c149e55e26eae771b0a", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" + } + }, + "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": "2018-01-09T20:05:19+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.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": "2017-07-22T11:58:36+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": "dragonmantank/cron-expression", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "3f00985deec8df53d4cc1e5c33619bda1ee309a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/3f00985deec8df53d4cc1e5c33619bda1ee309a5", + "reference": "3f00985deec8df53d4cc1e5c33619bda1ee309a5", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "time": "2018-04-06T15:51:55+00:00" + }, + { + "name": "egulias/email-validator", + "version": "2.1.4", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "8790f594151ca6a2010c6218e09d96df67173ad3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/8790f594151ca6a2010c6218e09d96df67173ad3", + "reference": "8790f594151ca6a2010c6218e09d96df67173ad3", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1.0.1", + "php": ">= 5.5" + }, + "require-dev": { + "dominicsayers/isemail": "dev-master", + "phpunit/phpunit": "^4.8.35||^5.7||^6.0", + "satooshi/php-coveralls": "^1.0.1" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "EmailValidator" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "time": "2018-04-10T10:11:19+00:00" + }, + { + "name": "erusev/parsedown", + "version": "1.7.1", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/92e9c27ba0e74b8b028b111d1b6f956a15c01fc1", + "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "time": "2018-03-08T01:11:30+00:00" + }, + { + "name": "fzaninotto/faker", + "version": "v1.7.1", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", + "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "ext-intl": "*", + "phpunit/phpunit": "^4.0 || ^5.0", + "squizlabs/php_codesniffer": "^1.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2017-08-15T16:48:10+00:00" + }, + { + "name": "laravel/framework", + "version": "v5.6.22", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "637fd797a6dde8d24a9f07da77e375ec251c5d24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/637fd797a6dde8d24a9f07da77e375ec251c5d24", + "reference": "637fd797a6dde8d24a9f07da77e375ec251c5d24", + "shasum": "" + }, + "require": { + "doctrine/inflector": "~1.1", + "dragonmantank/cron-expression": "~2.0", + "erusev/parsedown": "~1.7", + "ext-mbstring": "*", + "ext-openssl": "*", + "league/flysystem": "^1.0.8", + "monolog/monolog": "~1.12", + "nesbot/carbon": "1.25.*", + "php": "^7.1.3", + "psr/container": "~1.0", + "psr/simple-cache": "^1.0", + "ramsey/uuid": "^3.7", + "swiftmailer/swiftmailer": "~6.0", + "symfony/console": "~4.0", + "symfony/debug": "~4.0", + "symfony/finder": "~4.0", + "symfony/http-foundation": "~4.0", + "symfony/http-kernel": "~4.0", + "symfony/process": "~4.0", + "symfony/routing": "~4.0", + "symfony/var-dumper": "~4.0", + "tijsverkoyen/css-to-inline-styles": "^2.2.1", + "vlucas/phpdotenv": "~2.2" + }, + "conflict": { + "tightenco/collect": "<5.5.33" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/broadcasting": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/log": "self.version", + "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version" + }, + "require-dev": { + "aws/aws-sdk-php": "~3.0", + "doctrine/dbal": "~2.6", + "filp/whoops": "^2.1.4", + "league/flysystem-cached-adapter": "~1.0", + "mockery/mockery": "~1.0", + "moontoast/math": "^1.1", + "orchestra/testbench-core": "3.6.*", + "pda/pheanstalk": "~3.0", + "phpunit/phpunit": "~7.0", + "predis/predis": "^1.1.1", + "symfony/css-selector": "~4.0", + "symfony/dom-crawler": "~4.0" + }, + "suggest": { + "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.6).", + "ext-pcntl": "Required to use all features of the queue worker.", + "ext-posix": "Required to use all features of the queue worker.", + "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", + "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~6.0).", + "laravel/tinker": "Required to use the tinker console command (~1.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).", + "league/flysystem-cached-adapter": "Required to use the Flysystem cache (~1.0).", + "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", + "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (~1.0).", + "nexmo/client": "Required to use the Nexmo transport (~1.0).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", + "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~3.0).", + "symfony/css-selector": "Required to use some of the crawler integration testing tools (~4.0).", + "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (~4.0).", + "symfony/psr-http-message-bridge": "Required to psr7 bridging features (~1.0)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "files": [ + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "https://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "time": "2018-05-15T13:34:20+00:00" + }, + { + "name": "league/flysystem", + "version": "1.0.45", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "a99f94e63b512d75f851b181afcdf0ee9ebef7e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a99f94e63b512d75f851b181afcdf0ee9ebef7e6", + "reference": "a99f94e63b512d75f851b181afcdf0ee9ebef7e6", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "ext-fileinfo": "*", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "time": "2018-05-07T08:44:23+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.23.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "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 || ^3.0", + "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|^6.0" + }, + "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": "2017-06-19T01:22:40+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-10-19T19:58:43+00:00" + }, + { + "name": "nesbot/carbon", + "version": "1.25.0", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/cbcf13da0b531767e39eb86e9687f5deba9857b4", + "reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/translation": "~2.6 || ~3.0 || ~4.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2", + "phpunit/phpunit": "^4.8.35 || ^5.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.23-dev" + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + } + ], + "description": "A simple API extension for DateTime.", + "homepage": "http://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "time": "2018-03-19T15:50:49+00:00" + }, + { + "name": "orchestra/testbench", + "version": "v3.6.4", + "source": { + "type": "git", + "url": "https://github.com/orchestral/testbench.git", + "reference": "242cc47d2e5d86ababe36d22519e2b948eff8f73" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/orchestral/testbench/zipball/242cc47d2e5d86ababe36d22519e2b948eff8f73", + "reference": "242cc47d2e5d86ababe36d22519e2b948eff8f73", + "shasum": "" + }, + "require": { + "laravel/framework": "~5.6.13", + "orchestra/testbench-core": "~3.6.5", + "php": ">=7.1", + "phpunit/phpunit": "~7.0" + }, + "require-dev": { + "mockery/mockery": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mior Muhammad Zaki", + "email": "crynobone@gmail.com", + "homepage": "https://github.com/crynobone" + } + ], + "description": "Laravel Testing Helper for Packages Development", + "homepage": "http://orchestraplatform.com/docs/latest/components/testbench/", + "keywords": [ + "BDD", + "TDD", + "laravel", + "orchestra-platform", + "orchestral", + "testing" + ], + "time": "2018-03-27T09:27:00+00:00" + }, + { + "name": "orchestra/testbench-core", + "version": "v3.6.5", + "source": { + "type": "git", + "url": "https://github.com/orchestral/testbench-core.git", + "reference": "d089f0fd32a81764fbd98044148a193db828dd52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/d089f0fd32a81764fbd98044148a193db828dd52", + "reference": "d089f0fd32a81764fbd98044148a193db828dd52", + "shasum": "" + }, + "require": { + "fzaninotto/faker": "~1.4", + "php": ">=7.1" + }, + "require-dev": { + "laravel/framework": "~5.6.13", + "mockery/mockery": "~1.0", + "phpunit/phpunit": "~7.0" + }, + "suggest": { + "laravel/framework": "Required for testing (~5.6.13).", + "mockery/mockery": "Allow to use Mockery for testing (~1.0).", + "orchestra/testbench-browser-kit": "Allow to use legacy Laravel BrowserKit for testing (~3.6).", + "orchestra/testbench-dusk": "Allow to use Laravel Dusk for testing (~3.6).", + "phpunit/phpunit": "Allow to use PHPUnit for testing (~7.0)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Orchestra\\Testbench\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mior Muhammad Zaki", + "email": "crynobone@gmail.com", + "homepage": "https://github.com/crynobone" + } + ], + "description": "Testing Helper for Laravel Development", + "homepage": "http://orchestraplatform.com/docs/latest/components/testbench/", + "keywords": [ + "BDD", + "TDD", + "laravel", + "orchestra-platform", + "orchestral", + "testing" + ], + "time": "2018-03-27T08:00:28+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v2.0.12", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "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": "2018-04-04T21:24:14+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^1.0.1", + "php": "^5.6 || ^7.0" + }, + "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": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2017-03-05T18:14:27+00:00" + }, + { + "name": "phar-io/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2017-03-05T17:38:23+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "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": "2017-09-11T18:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "4.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "shasum": "" + }, + "require": { + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0.0", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "doctrine/instantiator": "~1.0.5", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2017-11-30T07:14:17+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "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": "2017-07-14T14:27:02+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "1.7.6", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.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": "2018-04-18T13:57:24+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "6.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "52187754b0eed0b8159f62a6fa30073327e8c2ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/52187754b0eed0b8159f62a6fa30073327e8c2ca", + "reference": "52187754b0eed0b8159f62a6fa30073327e8c2ca", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.1", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.1", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-xdebug": "^2.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-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": "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": "2018-04-29T14:59:09+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "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": "2017-11-27T13:52:08+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": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-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": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2018-02-01T13:07:23+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-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": "2018-02-01T13:16:43+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "7.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "ca64dba53b88aba6af32aebc6b388068db95c435" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ca64dba53b88aba6af32aebc6b388068db95c435", + "reference": "ca64dba53b88aba6af32aebc6b388068db95c435", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.6.1", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.1", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^6.0.1", + "phpunit/php-file-iterator": "^1.4.3", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.0", + "phpunit/phpunit-mock-objects": "^6.1.1", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0", + "sebastian/environment": "^3.1", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0.1" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.1-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": "2018-04-29T15:09:19+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "6.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "70c740bde8fd9ea9ea295be1cd875dd7b267e157" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/70c740bde8fd9ea9ea295be1cd875dd7b267e157", + "reference": "70c740bde8fd9ea9ea295be1cd875dd7b267e157", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.5", + "php": "^7.1", + "phpunit/php-text-template": "^1.2.1", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.1-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": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2018-04-11T04:50:36+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "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-10-10T12:19:37+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "ramsey/uuid", + "version": "3.7.3", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "44abcdad877d9a46685a3a4d221e3b2c4b87cb76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/44abcdad877d9a46685a3a4d221e3b2c4b87cb76", + "reference": "44abcdad877d9a46685a3a4d221e3b2c4b87cb76", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "^1.0|^2.0", + "php": "^5.4 || ^7.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "codeception/aspect-mock": "^1.0 | ~2.0.0", + "doctrine/annotations": "~1.2.0", + "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1", + "ircmaxell/random-lib": "^1.1", + "jakub-onderka/php-parallel-lint": "^0.9.0", + "mockery/mockery": "^0.9.9", + "moontoast/math": "^1.1", + "php-mock/php-mock-phpunit": "^0.3|^1.1", + "phpunit/phpunit": "^4.7|^5.0", + "squizlabs/php_codesniffer": "^2.3" + }, + "suggest": { + "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", + "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + }, + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "homepage": "https://github.com/ramsey/uuid", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "time": "2018-01-20T00:28:24+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "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": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/ed5fd2281113729f1ebcc64d101ad66028aeb3d5", + "reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5", + "shasum": "" + }, + "require": { + "php": "^7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-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": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2018-04-18T13:33:00+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8", + "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0", + "symfony/process": "^2 || ^3.3 || ^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-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", + "udiff", + "unidiff", + "unified diff" + ], + "time": "2018-02-01T13:45:15+00:00" + }, + { + "name": "sebastian/environment", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.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": "2017-07-01T08:51:00+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.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": "2017-04-03T13:19:02+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.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": "2017-04-27T15:39:26+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-08-03T12:35:26+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.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": "2017-03-03T06:23:57+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "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": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.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": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "v6.0.2", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/412333372fb6c8ffb65496a2bbd7321af75733fc", + "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc", + "shasum": "" + }, + "require": { + "egulias/email-validator": "~2.0", + "php": ">=7.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.1", + "symfony/phpunit-bridge": "~3.3@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-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.symfony.com", + "keywords": [ + "email", + "mail", + "mailer" + ], + "time": "2017-09-30T22:39:41+00:00" + }, + { + "name": "symfony/console", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "3e820bc2c520a87ca209ad8fa961c97f42e0b4ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/3e820bc2c520a87ca209ad8fa961c97f42e0b4ae", + "reference": "3e820bc2c520a87ca209ad8fa961c97f42e0b4ae", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/process": "<3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/lock": "~3.4|~4.0", + "symfony/process": "~3.4|~4.0" + }, + "suggest": { + "psr/log-implementation": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "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": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2018-04-30T01:23:47+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "03f965583147957f1ecbad7ea1c9d6fd5e525ec2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/03f965583147957f1ecbad7ea1c9d6fd5e525ec2", + "reference": "03f965583147957f1ecbad7ea1c9d6fd5e525ec2", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2018-03-19T22:35:49+00:00" + }, + { + "name": "symfony/debug", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "e1d57cdb357e5b10f5fdacbb0b86689c0a435e6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/e1d57cdb357e5b10f5fdacbb0b86689c0a435e6e", + "reference": "e1d57cdb357e5b10f5fdacbb0b86689c0a435e6e", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": "<3.4" + }, + "require-dev": { + "symfony/http-kernel": "~3.4|~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "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": "Symfony Debug Component", + "homepage": "https://symfony.com", + "time": "2018-04-30T16:59:37+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "63353a71073faf08f62caab4e6889b06a787f07b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/63353a71073faf08f62caab4e6889b06a787f07b", + "reference": "63353a71073faf08f62caab4e6889b06a787f07b", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/expression-language": "~3.4|~4.0", + "symfony/stopwatch": "~3.4|~4.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "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": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2018-04-06T07:35:43+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/ca27c02b7a3fef4828c998c2ff9ba7aae1641c49", + "reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "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": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2018-04-04T05:10:37+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "014487772c22d893168e5d628a13e882009fea29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/014487772c22d893168e5d628a13e882009fea29", + "reference": "014487772c22d893168e5d628a13e882009fea29", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "symfony/expression-language": "~3.4|~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "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": "Symfony HttpFoundation Component", + "homepage": "https://symfony.com", + "time": "2018-04-30T01:05:59+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "8333264b6de323ea27a08627d5396aa564fb9c25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8333264b6de323ea27a08627d5396aa564fb9c25", + "reference": "8333264b6de323ea27a08627d5396aa564fb9c25", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/log": "~1.0", + "symfony/debug": "~3.4|~4.0", + "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/http-foundation": "~3.4.4|~4.0.4" + }, + "conflict": { + "symfony/config": "<3.4", + "symfony/dependency-injection": "<3.4.5|<4.0.5,>=4", + "symfony/var-dumper": "<3.4", + "twig/twig": "<1.34|<2.4,>=2" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/cache": "~1.0", + "symfony/browser-kit": "~3.4|~4.0", + "symfony/config": "~3.4|~4.0", + "symfony/console": "~3.4|~4.0", + "symfony/css-selector": "~3.4|~4.0", + "symfony/dependency-injection": "^3.4.5|^4.0.5", + "symfony/dom-crawler": "~3.4|~4.0", + "symfony/expression-language": "~3.4|~4.0", + "symfony/finder": "~3.4|~4.0", + "symfony/process": "~3.4|~4.0", + "symfony/routing": "~3.4|~4.0", + "symfony/stopwatch": "~3.4|~4.0", + "symfony/templating": "~3.4|~4.0", + "symfony/translation": "~3.4|~4.0", + "symfony/var-dumper": "~3.4|~4.0" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "", + "symfony/var-dumper": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "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": "Symfony HttpKernel Component", + "homepage": "https://symfony.com", + "time": "2018-04-30T19:45:57+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "3296adf6a6454a050679cde90f95350ad604b171" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", + "reference": "3296adf6a6454a050679cde90f95350ad604b171", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-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": "2018-04-26T10:06:28+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "a4576e282d782ad82397f3e4ec1df8e0f0cafb46" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/a4576e282d782ad82397f3e4ec1df8e0f0cafb46", + "reference": "a4576e282d782ad82397f3e4ec1df8e0f0cafb46", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "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 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2018-04-26T10:06:28+00:00" + }, + { + "name": "symfony/process", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "d7dc1ee5dfe9f732cb1bba7310f5b99f2b7a6d25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/d7dc1ee5dfe9f732cb1bba7310f5b99f2b7a6d25", + "reference": "d7dc1ee5dfe9f732cb1bba7310f5b99f2b7a6d25", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "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": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2018-04-03T05:24:00+00:00" + }, + { + "name": "symfony/routing", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "1dfbfdf060bbc80da8dedc062050052e694cd027" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/1dfbfdf060bbc80da8dedc062050052e694cd027", + "reference": "1dfbfdf060bbc80da8dedc062050052e694cd027", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "conflict": { + "symfony/config": "<3.4", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/common": "~2.2", + "psr/log": "~1.0", + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/expression-language": "~3.4|~4.0", + "symfony/http-foundation": "~3.4|~4.0", + "symfony/yaml": "~3.4|~4.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/dependency-injection": "For loading routes from a service", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "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": "Symfony Routing Component", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "time": "2018-04-20T06:20:23+00:00" + }, + { + "name": "symfony/translation", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "ad3abf08eb3450491d8d76513100ef58194cd13e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/ad3abf08eb3450491d8d76513100ef58194cd13e", + "reference": "ad3abf08eb3450491d8d76513100ef58194cd13e", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/config": "<3.4", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/finder": "~2.8|~3.0|~4.0", + "symfony/intl": "~3.4|~4.0", + "symfony/yaml": "~3.4|~4.0" + }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "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": "Symfony Translation Component", + "homepage": "https://symfony.com", + "time": "2018-04-30T01:23:47+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "3c34cf3f4bbac9e003d9325225e9ef1a49180a18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3c34cf3f4bbac9e003d9325225e9ef1a49180a18", + "reference": "3c34cf3f4bbac9e003d9325225e9ef1a49180a18", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" + }, + "require-dev": { + "ext-iconv": "*", + "twig/twig": "~1.34|~2.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "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 mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2018-04-26T16:12:06+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2017-04-07T12:08:54+00:00" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757", + "reference": "0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "symfony/css-selector": "^2.7 || ^3.0 || ^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "TijsVerkoyen\\CssToInlineStyles\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Tijs Verkoyen", + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" + } + ], + "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", + "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", + "time": "2017-11-27T11:13:29+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause-Attribution" + ], + "authors": [ + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "http://www.vancelucas.com" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "time": "2016-09-01T10:05:43+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "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.3-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": "2018-01-29T19:49:41+00:00" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": [], diff --git a/src/config/json-exception-handler.php b/config/json-exception-handler.php similarity index 70% rename from src/config/json-exception-handler.php rename to config/json-exception-handler.php index 1f67c05..bd624da 100644 --- a/src/config/json-exception-handler.php +++ b/config/json-exception-handler.php @@ -38,11 +38,6 @@ 'authentication' => 16, 'oauth_server' => 17, 'bad_request' => 18, - 'client' => [ - 'default' => 19, - 'pagarme' => 20, - 'mailgun' => 21, - ], ], /* @@ -55,4 +50,21 @@ */ 'http_code' => 500, + /* + |--------------------------------------------------------------------------- + | Response Handler + |--------------------------------------------------------------------------- + | + | Any class the extends of \SMartins\Exceptions\Response\AbstractResponse. + */ + 'response_handler' => \SMartins\Exceptions\JsonApi\Response::class, + + /* + |--------------------------------------------------------------------------- + | Exception Handler + |-------------------------------------------------------------------------- + | + | The class that will handler the exceptions. + */ + 'exception_handler' => \SMartins\Exceptions\Handlers\Handler::class, ]; diff --git a/phpunit.xml b/phpunit.xml index 57e0396..c31b987 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,25 +1,26 @@ - + processIsolation="false" + stopOnFailure="false"> - ./tests/ + ./tests/ - ./src + ./src/ - \ No newline at end of file + + + + + diff --git a/src/resources/lang/pt-br/exceptions.php b/resources/lang/en/exceptions.php similarity index 96% rename from src/resources/lang/pt-br/exceptions.php rename to resources/lang/en/exceptions.php index ed24ee2..90c622f 100644 --- a/src/resources/lang/pt-br/exceptions.php +++ b/resources/lang/en/exceptions.php @@ -35,6 +35,6 @@ | */ 'models' => [ - 'User' => 'Usuário', - ] + 'User' => 'User', + ], ]; diff --git a/src/resources/lang/en/exceptions.php b/resources/lang/pt-br/exceptions.php similarity index 99% rename from src/resources/lang/en/exceptions.php rename to resources/lang/pt-br/exceptions.php index ed24ee2..9fbe0f3 100644 --- a/src/resources/lang/en/exceptions.php +++ b/resources/lang/pt-br/exceptions.php @@ -36,5 +36,5 @@ */ 'models' => [ 'User' => 'Usuário', - ] + ], ]; diff --git a/src/AuthenticationHandler.php b/src/AuthenticationHandler.php deleted file mode 100644 index d409802..0000000 --- a/src/AuthenticationHandler.php +++ /dev/null @@ -1,22 +0,0 @@ - 401, - 'code' => $this->getCode('authentication'), - 'source' => ['pointer' => $exception->getFile().':'.$exception->getLine()], - 'title' => $exception->getMessage(), - 'detail' => __('exception::exceptions.authentication.detail'), - ]]; - - $this->jsonApiResponse->setStatus(401); - $this->jsonApiResponse->setErrors($error); - } -} diff --git a/src/AuthorizationHandler.php b/src/AuthorizationHandler.php deleted file mode 100644 index b323d14..0000000 --- a/src/AuthorizationHandler.php +++ /dev/null @@ -1,51 +0,0 @@ - 403, - 'code' => $this->getCode('authorization'), - 'source' => ['pointer' => $exception->getFile().':'.$exception->getLine()], - 'title' => __('exception::exceptions.authorization.title'), - 'detail' => $exception->getMessage(), - ]]; - - $this->jsonApiResponse->setStatus(403); - $this->jsonApiResponse->setErrors($error); - } - - public function generateDescription($traces) - { - $action = ''; - foreach ($traces as $trace) { - if ($trace['function'] === 'authorize') { - $action = $this->extractAction($trace['args']); - break; - } - } - } - - public function extractAction($args) - { - $action = reset($args); - - $this->getWord($action); - } - - public function getWords($action) - { - $words = explode('.', $action); - if (! (count($words) > 1)) { - $words = explode('-', $action); - if (! (count($words) > 1)) { - $words = preg_split('/(?=[A-Z])/', $action); - } - } - } -} diff --git a/src/BadRequestHttpHandler.php b/src/BadRequestHttpHandler.php deleted file mode 100644 index 122421a..0000000 --- a/src/BadRequestHttpHandler.php +++ /dev/null @@ -1,24 +0,0 @@ -getStatusCode(); - - $error = [[ - 'status' => $statusCode, - 'code' => $this->getCode('bad_request'), - 'source' => ['pointer' => $exception->getFile().':'.$exception->getLine()], - 'title' => 'bad_request', - 'detail' => $exception->getMessage(), - ]]; - - $this->jsonApiResponse->setStatus($statusCode); - $this->jsonApiResponse->setErrors($error); - } -} diff --git a/src/CieloRequestHandler.php b/src/CieloRequestHandler.php deleted file mode 100644 index 1f8d75d..0000000 --- a/src/CieloRequestHandler.php +++ /dev/null @@ -1,31 +0,0 @@ -getCode(); - do { - $cieloError = $e->getCieloError(); - $error = [ - 'status' => $e->getCode(), - 'code' => $this->getCode('cielo').$cieloError->getCode(), - 'source' => ['pointer' => $e->getFile().':'.$e->getLine()], - 'title' => $e->getMessage(), - 'detail' => $cieloError->getMessage(), - ]; - if (! in_array($error, $errors)) { - array_push($errors, $error); - } - $e = $e->getPrevious(); - } while (method_exists($e, 'getPrevious')); - - $this->jsonApiResponse->setStatus($code); - $this->jsonApiResponse->setErrors($errors); - } -} diff --git a/src/ClientHandler.php b/src/ClientHandler.php deleted file mode 100644 index 5bbf5b3..0000000 --- a/src/ClientHandler.php +++ /dev/null @@ -1,81 +0,0 @@ -getMessage(); - $code = $this->getCode(); - - if ($exception instanceof ClientException) { - $requestHost = $exception->getRequest()->getUri()->getHost(); - $clientCausers = $this->clientExceptionCausers(); - - $response = $exception->getResponse(); - - if ($clientCausers->isPagarme($requestHost)) { - $code = config('json-exception-handler.codes.client.pagarme') ?? 'pagarme'; - $errors = json_decode($response->getBody())->errors; - - $firstErrorMessage = ''; - foreach ($errors as $error) { - $firstErrorMessage = $error->message; - break; - } - - $detailedError = $firstErrorMessage.' #'.$code; - } elseif ($clientCausers->isMailgun($requestHost)) { - $code = config('json-exception-handler.codes.client.mailgun') ?? 'mailgun'; - $detailedError = json_decode($response->getBody())->message.' #'.$code; - } else { - // Unknown error - $code = config('json-exception-handler.codes.client.default'); - } - - if (App::environment('production')) { - $detail = __('exception::exceptions.client.unavailable').' #'.$code; - } else { - // Return more details about error - $detail = $detailedError ?? $detail; - $statusCode = $response->getStatusCode(); - } - } - - $error = [[ - 'status' => $statusCode, - 'code' => $code, - 'source' => ['pointer' => $exception->getFile().':'.$exception->getLine()], - 'title' => $title, - 'detail' => $detail, - ]]; - - $this->jsonApiResponse->setStatus($statusCode); - $this->jsonApiResponse->setErrors($error); - } - - public function clientExceptionCausers() - { - return new class() { - const PAGARME_HOST = 'api.pagar.me'; - - const MAILGUN_HOST = 'api.mailgun.net'; - - public function isPagarme($host) - { - return self::PAGARME_HOST == $host; - } - - public function isMailgun($host) - { - return self::MAILGUN_HOST == $host; - } - }; - } -} diff --git a/src/Handlers/AbstractHandler.php b/src/Handlers/AbstractHandler.php new file mode 100644 index 0000000..a820d42 --- /dev/null +++ b/src/Handlers/AbstractHandler.php @@ -0,0 +1,231 @@ + Handler::class, + ModelNotFoundException::class => ModelNotFoundHandler::class, + AuthenticationException::class => AuthenticationHandler::class, + ValidationException::class => ValidationHandler::class, + BadRequestHttpException::class => BadRequestHttpHandler::class, + AuthorizationException::class => AuthorizationHandler::class, + NotFoundHttpException::class => NotFoundHttpHandler::class, + 'Laravel\Passport\Exceptions\MissingScopeException' => MissingScopeHandler::class, + 'League\OAuth2\Server\Exception\OAuthServerException' => OAuthServerHandler::class, + ]; + + /** + * Create instance using the Exception to be handled. + * + * @param Throwable $e + */ + public function __construct(Throwable $e) + { + $this->exception = $e; + } + + /** + * Handle with an exception according to specific definitions. Returns one + * or more errors using the exception from $exceptions attribute. + * + * @return ErrorHandledInterface|ErrorHandledCollectionInterface + */ + abstract public function handle(); + + /** + * Get error code. If code is empty from config file based on type. + * + * @param string $type Code type from config file + * @return int + */ + public function getCode($type = 'default') + { + if (empty($code = $this->exception->getCode())) { + return config('json-exception-handler.codes.'.$type); + } + + return $code; + } + + /** + * Return response with handled exception. + * + * @return \SMartins\Exceptions\Response\AbstractResponse + * @throws \SMartins\Exceptions\Response\InvalidContentException + */ + public function handleException() + { + $handler = $this->getExceptionHandler(); + + $errors = $this->validatedHandledException($handler->handle()); + + $responseHandler = $this->getResponseHandler(); + + return new $responseHandler($errors); + } + + /** + * Validate response from handle method of handler class. + * + * @param ErrorHandledInterface|ErrorHandledCollectionInterface + * @return ErrorHandledCollectionInterface + * + * @throws \SMartins\Exceptions\Response\InvalidContentException + */ + public function validatedHandledException($error) + { + if ($error instanceof ErrorHandledCollectionInterface) { + return $error->validatedContent(ErrorHandledInterface::class); + } elseif ($error instanceof ErrorHandledInterface) { + return $error->toCollection()->setStatusCode($error->getStatus()); + } + + throw new InvalidArgumentException('The errors must be an instance of ['.ErrorHandledInterface::class.'] or ['.ErrorHandledCollectionInterface::class.'].'); + } + + /** + * Get the class the will handle the Exception from exceptionHandlers attributes. + * + * @return mixed + */ + public function getExceptionHandler() + { + $handlers = $this->getConfiguredHandlers(); + + $handler = isset($handlers[get_class($this->exception)]) + ? $handlers[get_class($this->exception)] + : $this->getDefaultHandler(); + + return new $handler($this->exception); + } + + /** + * Get exception handlers from internal and set on App\Exceptions\Handler.php. + * + * @return array + */ + public function getConfiguredHandlers() + { + return array_merge($this->internalExceptionHandlers, $this->exceptionHandlers); + } + + /** + * Get default pointer using file and line of exception. + * + * @return string + */ + public function getDefaultPointer() + { + return ''; + } + + /** + * Get default title from exception. + * + * @return string + */ + public function getDefaultTitle() + { + return Str::snake(class_basename($this->exception)); + } + + /** + * Get default http code. Check if exception has getStatusCode() methods. + * If not get from config file. + * + * @return int + */ + public function getStatusCode() + { + if (method_exists($this->exception, 'getStatusCode')) { + return $this->exception->getStatusCode(); + } + + return config('json-exception-handler.http_code'); + } + + /** + * The default handler to handle not treated exceptions. + * + * @return \SMartins\Exceptions\Handlers\Handler + */ + public function getDefaultHandler() + { + return new Handler($this->exception); + } + + /** + * Get default response handler of the if any response handler was defined + * on config file. + * + * @return string + */ + public function getDefaultResponseHandler() + { + return JsonApiResponse::class; + } + + /** + * Get the response class that will handle the json response. + * + * @todo Check if the response_handler on config is an instance of + * \SMartins\Exceptions\Response\AbstractResponse + * @return string + */ + public function getResponseHandler() + { + $response = config('json-exception-handler.response_handler'); + + return $response ?? $this->getDefaultResponseHandler(); + } + + /** + * Set exception handlers. + * + * @param array $handlers + * @return AbstractHandler + */ + public function setExceptionHandlers(array $handlers) + { + $this->exceptionHandlers = $handlers; + + return $this; + } +} diff --git a/src/Handlers/AuthenticationHandler.php b/src/Handlers/AuthenticationHandler.php new file mode 100644 index 0000000..1d0d1ac --- /dev/null +++ b/src/Handlers/AuthenticationHandler.php @@ -0,0 +1,21 @@ +setStatus(401) + ->setCode($this->getCode('authentication')) + ->setSource((new Source())->setPointer($this->getDefaultPointer())) + ->setTitle($this->getDefaultTitle()) + ->setDetail(__('exception::exceptions.authentication.detail')); + } +} diff --git a/src/Handlers/AuthorizationHandler.php b/src/Handlers/AuthorizationHandler.php new file mode 100644 index 0000000..0ff9b8f --- /dev/null +++ b/src/Handlers/AuthorizationHandler.php @@ -0,0 +1,21 @@ +setStatus(403) + ->setCode($this->getCode('authorization')) + ->setSource((new Source())->setPointer($this->getDefaultPointer())) + ->setTitle(__('exception::exceptions.authorization.title')) + ->setDetail($this->exception->getMessage()); + } +} diff --git a/src/Handlers/BadRequestHttpHandler.php b/src/Handlers/BadRequestHttpHandler.php new file mode 100644 index 0000000..9a3ffb5 --- /dev/null +++ b/src/Handlers/BadRequestHttpHandler.php @@ -0,0 +1,21 @@ +setStatus(400) + ->setCode($this->getCode('bad_request')) + ->setSource((new Source())->setPointer($this->getDefaultPointer())) + ->setTitle($this->getDefaultTitle()) + ->setDetail($this->exception->getMessage()); + } +} diff --git a/src/Handlers/Handler.php b/src/Handlers/Handler.php new file mode 100644 index 0000000..d9ee00b --- /dev/null +++ b/src/Handlers/Handler.php @@ -0,0 +1,21 @@ +setStatus($this->getStatusCode()) + ->setCode($this->getCode()) + ->setSource((new Source())->setPointer($this->getDefaultPointer())) + ->setTitle($this->getDefaultTitle()) + ->setDetail($this->exception->getMessage()); + } +} diff --git a/src/Handlers/MissingScopeHandler.php b/src/Handlers/MissingScopeHandler.php new file mode 100644 index 0000000..8819057 --- /dev/null +++ b/src/Handlers/MissingScopeHandler.php @@ -0,0 +1,21 @@ +setStatus(403) + ->setCode($this->getCode('missing_scope')) + ->setSource((new Source())->setPointer($this->getDefaultPointer())) + ->setTitle($this->getDefaultTitle()) + ->setDetail($this->exception->getMessage()); + } +} diff --git a/src/Handlers/ModelNotFoundHandler.php b/src/Handlers/ModelNotFoundHandler.php new file mode 100644 index 0000000..4a24563 --- /dev/null +++ b/src/Handlers/ModelNotFoundHandler.php @@ -0,0 +1,89 @@ +extractEntityName($this->exception->getModel()); + + $detail = __('exception::exceptions.model_not_found.title', ['model' => $entity]); + + return (new Error)->setStatus(404) + ->setCode($this->getCode('model_not_found')) + ->setSource((new Source())->setPointer('data/id')) + ->setTitle(Str::snake(class_basename($this->exception))) + ->setDetail($detail); + } + + /** + * Get entity name based on model path to mount the message. + * + * @param string $model + * @return string + */ + public function extractEntityName(string $model) + { + $classNames = (array) explode('\\', $model); + + $entityName = end($classNames); + + if ($this->entityHasTranslation($entityName)) { + return __('exception::exceptions.models.'.$entityName); + } + + return $entityName; + } + + /** + * Check if entity returned on ModelNotFoundException has translation on + * exceptions file. + * + * @param string $entityName The model name to check if has translation + * @return bool Has translation or not + */ + public function entityHasTranslation(string $entityName): bool + { + $hasKey = in_array($entityName, $this->translationModelKeys()); + + if ($hasKey) { + return ! empty($hasKey); + } + + return false; + } + + /** + * Get the models keys on exceptions lang file. + * + * @return array An array with keys to translate + */ + private function translationModelKeys(): array + { + return array_keys(__('exception::exceptions.models')); + } +} diff --git a/src/Handlers/NotFoundHttpHandler.php b/src/Handlers/NotFoundHttpHandler.php new file mode 100644 index 0000000..9eae341 --- /dev/null +++ b/src/Handlers/NotFoundHttpHandler.php @@ -0,0 +1,39 @@ +setStatus($this->getStatusCode()) + ->setCode($this->getCode('not_found_http')) + ->setSource((new Source())->setPointer($this->getDefaultPointer())) + ->setTitle($this->getDefaultTitle()) + ->setDetail($this->getNotFoundMessage()); + } + + /** + * Get message based on file. If file is RouteCollection return specific message. + * + * @return string + */ + public function getNotFoundMessage() + { + $message = ! empty($this->exception->getMessage()) + ? $this->exception->getMessage() + : class_basename($this->exception); + + if (basename($this->exception->getFile()) === 'RouteCollection.php') { + $message = __('exception::exceptions.not_found_http.message'); + } + + return $message; + } +} diff --git a/src/Handlers/OAuthServerHandler.php b/src/Handlers/OAuthServerHandler.php new file mode 100644 index 0000000..9b752f0 --- /dev/null +++ b/src/Handlers/OAuthServerHandler.php @@ -0,0 +1,32 @@ +setStatus($this->getHttpStatusCode()) + ->setCode($this->getCode()) + ->setSource((new Source())->setPointer($this->getDefaultPointer())) + ->setTitle($this->exception->getErrorType()) + ->setDetail($this->exception->getMessage()); + } +} diff --git a/src/Handlers/ValidationHandler.php b/src/Handlers/ValidationHandler.php new file mode 100644 index 0000000..b22b3b2 --- /dev/null +++ b/src/Handlers/ValidationHandler.php @@ -0,0 +1,96 @@ +setStatusCode(422); + + $failedFieldsRules = $this->getFailedFieldsRules(); + + foreach ($this->getFailedFieldsMessages() as $field => $messages) { + foreach ($messages as $key => $message) { + $code = $this->getValidationCode($failedFieldsRules, $key, $field); + $title = $this->getValidationTitle($failedFieldsRules, $key, $field); + + $error = (new Error)->setStatus(422) + ->setSource((new Source())->setPointer($field)) + ->setTitle($title ?? $this->getDefaultTitle()) + ->setDetail($message); + + if (! is_null($code)) { + $error->setCode($code); + } + + $errors->push($error); + } + } + + return $errors; + } + + /** + * Get the title of response based on rules and field getting from translations. + * + * @param array $failedFieldsRules + * @param string $key + * @param string $field + * @return string|null + */ + public function getValidationTitle(array $failedFieldsRules, string $key, string $field) + { + $title = __('exception::exceptions.validation.title', [ + 'fails' => strtolower(array_keys($failedFieldsRules[$field])[$key]), + 'field' => $field, + ]); + + return is_array($title) ? $title[0] : $title; + } + + /** + * Get the code of validation error from config. + * + * @param array $failedFieldsRules + * @param string $key + * @param string $field + * @return string|null + */ + public function getValidationCode(array $failedFieldsRules, string $key, string $field) + { + $rule = strtolower(array_keys($failedFieldsRules[$field])[$key]); + + return config('json-exception-handler.codes.validation_fields.'.$field.'.'.$rule); + } + + /** + * Get message based on exception type. If exception is generated by + * $this->validate() from default Controller methods the exception has the + * response object. If exception is generated by Validator::make() the + * messages are get different. + * + * @return array + */ + public function getFailedFieldsMessages(): array + { + return $this->exception->validator->messages()->messages(); + } + + /** + * Get the rules failed on fields. + * + * @return array + */ + public function getFailedFieldsRules(): array + { + return $this->exception->validator->failed(); + } +} diff --git a/src/JsonApi/Error.php b/src/JsonApi/Error.php new file mode 100644 index 0000000..7af2385 --- /dev/null +++ b/src/JsonApi/Error.php @@ -0,0 +1,236 @@ +id; + } + + /** + * Set a unique identifier for this particular occurrence of the problem. + * + * @param string $id + * + * @return self + */ + public function setId(string $id): self + { + $this->id = $id; + + return $this; + } + + /** + * Get the value of links. + * + * @return \SMartins\Exceptions\JsonApi\Links + */ + public function getLinks() + { + return $this->links; + } + + /** + * Set the value of links. + * + * @param \SMartins\Exceptions\JsonApi\Links $links + * + * @return self + */ + public function setLinks(Links $links): self + { + $this->links = $links; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * Set the HTTP status code applicable to this problem, expressed as a string value. + * + * @param string $status + * + * @return self + */ + public function setStatus(string $status): self + { + $this->status = $status; + + return $this; + } + + /** + * Get an application-specific error code, expressed as a string value. + * + * @return string + */ + public function getCode() + { + return $this->code; + } + + /** + * Set an application-specific error code, expressed as a string value. + * + * @param string $code + * + * @return self + */ + public function setCode(string $code): self + { + $this->code = $code; + + return $this; + } + + /** + * Get occurrence to occurrence of the problem, except for purposes of localization. + * + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * Set occurrence to occurrence of the problem, except for purposes of localization. + * + * @param string $title + * + * @return self + */ + public function setTitle(string $title): self + { + $this->title = $title; + + return $this; + } + + /** + * Get like title, this field’s value can be localized. + * + * @return string + */ + public function getDetail() + { + return $this->detail; + } + + /** + * Set like title, this field’s value can be localized. + * + * @param string $detail + * + * @return self + */ + public function setDetail(string $detail): self + { + $this->detail = $detail; + + return $this; + } + + /** + * Get an object containing references to the source of the error. + * + * @return \SMartins\Exceptions\JsonApi\Source + */ + public function getSource() + { + return $this->source; + } + + /** + * Set an object containing references to the source of the error. + * + * @param \SMartins\Exceptions\JsonApi\Source $source + * + * @return self + */ + public function setSource(Source $source): self + { + $this->source = $source; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function toCollection(): ErrorHandledCollectionInterface + { + return new ErrorCollection([$this]); + } +} diff --git a/src/JsonApi/ErrorCollection.php b/src/JsonApi/ErrorCollection.php new file mode 100644 index 0000000..8efb248 --- /dev/null +++ b/src/JsonApi/ErrorCollection.php @@ -0,0 +1,86 @@ +statusCode; + } + + /** + * Returns response headers. + * + * @return array headers + */ + public function getHeaders(): array + { + return $this->headers; + } + + /** + * Set the status code. + * + * @param string $statusCode + * + * @return self + */ + public function setStatusCode(string $statusCode) + { + $this->statusCode = $statusCode; + + return $this; + } + + /** + * Set the headers of response. + * + * @param array $headers + * + * @return self + */ + public function setHeaders(array $headers): self + { + $this->headers = $headers; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function validatedContent(string $type): ErrorHandledCollectionInterface + { + foreach ($this->items as $item) { + if (! $item instanceof $type) { + throw new InvalidContentException('All items on ['.self::class.'] must to be instances of ['.$type.'].'); + } + } + + return $this; + } +} diff --git a/src/JsonApi/Links.php b/src/JsonApi/Links.php new file mode 100644 index 0000000..218c951 --- /dev/null +++ b/src/JsonApi/Links.php @@ -0,0 +1,18 @@ + $this->getErrors()->toArray()], + $this->getStatus(), + $this->getErrors()->getHeaders() + ); + } +} diff --git a/src/JsonApi/Source.php b/src/JsonApi/Source.php new file mode 100644 index 0000000..dc7ea87 --- /dev/null +++ b/src/JsonApi/Source.php @@ -0,0 +1,75 @@ +pointer; + } + + /** + * Set pointer. + * + * @param string $pointer + * + * @return self + */ + public function setPointer(string $pointer) + { + $this->pointer = $pointer; + + return $this; + } + + /** + * Get parameter. + * + * @return string + */ + public function getParameter() + { + return $this->parameter; + } + + /** + * Set parameter. + * + * @param string $parameter + * + * @return self + */ + public function setParameter(string $parameter) + { + $this->parameter = $parameter; + + return $this; + } +} diff --git a/src/JsonHandler.php b/src/JsonHandler.php index 873bc08..af19e7c 100644 --- a/src/JsonHandler.php +++ b/src/JsonHandler.php @@ -1,168 +1,28 @@ $this->getStatusCode(), - 'code' => $this->getCode(), - 'source' => ['pointer' => $this->getDescription()], - 'title' => strtolower(class_basename($this->exception)), - 'detail' => $this->getMessage(), - ]]; - - $this->jsonApiResponse->setStatus($this->getStatusCode()); - $this->jsonApiResponse->setErrors($error); - } - - /** - * Get default message from exception. - * - * @return string Exception message - */ - public function getMessage() - { - return $this->exception->getMessage(); - } - - /** - * Mount the description with exception class, line and file. - * - * @return string - */ - public function getDescription() - { - return class_basename($this->exception). - ' line '.$this->exception->getLine(). - ' in '.$this->exception->getFile(); - } - - /** - * Get default http code. Check if exception has getStatusCode() methods. - * If not get from config file. - * - * @return int - */ - public function getStatusCode() - { - if (method_exists($this->exception, 'getStatusCode')) { - $httpCode = $this->exception->getStatusCode(); - } else { - $httpCode = config($this->configFile.'.http_code'); - } - - return $httpCode; - } - - /** - * Get error code. If code is empty from config file based on type. - * - * @param string $type Code type from config file - * @return int - */ - public function getCode($type = 'default') - { - $code = $this->exception->getCode(); - if (empty($this->exception->getCode())) { - $code = config($this->configFile.'.codes.'.$type); - } - - return $code; - } - /** * Handle the json response. Check if exception is treated. If true call * the specific handler. If false set the default response to be returned. * - * @param Exception $exception - * @return JsonResponse - */ - public function jsonResponse(Exception $exception) - { - $this->exception = $exception; - $this->jsonApiResponse = new JsonApiResponse; - - if ($this->exceptionIsTreated()) { - $this->callExceptionHandler(); - } else { - $this->setDefaultResponse(); - } - - return response()->json( - $this->jsonApiResponse->toArray(), - $this->jsonApiResponse->getStatus() - ); - } - - /** - * Check if method to treat exception exists. + * @param \Throwable $exception * - * @param Exception $exception The exception to be checked - * @return bool If method is callable + * @return \Illuminate\Http\JsonResponse */ - public function exceptionIsTreated() + public function jsonResponse(Throwable $exception) { - return is_callable([$this, $this->methodName()]); - } + $handler = new Handler($exception); - /** - * Call the exception handler after of to check if the method exists. - * - * @param Exception $exception - * @return void Call the method - */ - public function callExceptionHandler() - { - $this->{$this->methodName()}($this->exception); - } + if (property_exists($this, 'exceptionHandlers')) { + $handler->setExceptionHandlers($this->exceptionHandlers); + } - /** - * The method name is the exception name with first letter in lower case. - * - * @param Exception $exception - * @return string The method name - */ - public function methodName() - { - return lcfirst(class_basename($this->exception)); + return $handler->handleException()->json(); } } diff --git a/src/JsonHandlerServiceProvider.php b/src/JsonHandlerServiceProvider.php index 7de8927..15436e3 100644 --- a/src/JsonHandlerServiceProvider.php +++ b/src/JsonHandlerServiceProvider.php @@ -1,6 +1,6 @@ configPath() => config_path('json-exception-handler.php'), ]); - $this->loadTranslationsFrom(__DIR__.'/resources/lang', 'exception'); + $this->loadTranslationsFrom(__DIR__.'/../resources/lang', 'exception'); $this->publishes([ - __DIR__.'/resources/lang' => resource_path('lang/vendor/exception'), + __DIR__.'/../resources/lang' => resource_path('lang/vendor/exception'), ]); } @@ -26,6 +26,6 @@ public function register() public function configPath() { - return __DIR__.'/config/json-exception-handler.php'; + return __DIR__.'/../config/json-exception-handler.php'; } } diff --git a/src/MissingScopeHandler.php b/src/MissingScopeHandler.php deleted file mode 100644 index d1331f9..0000000 --- a/src/MissingScopeHandler.php +++ /dev/null @@ -1,22 +0,0 @@ - 403, - 'code' => $this->getCode('missing_scope'), - 'source' => ['pointer' => $exception->getFile().':'.$exception->getLine()], - 'title' => 'missing_scope', - 'detail' => $exception->getMessage(), - ]]; - - $this->jsonApiResponse->setStatus(403); - $this->jsonApiResponse->setErrors($error); - } -} diff --git a/src/ModelNotFoundHandler.php b/src/ModelNotFoundHandler.php deleted file mode 100644 index 32bcd54..0000000 --- a/src/ModelNotFoundHandler.php +++ /dev/null @@ -1,76 +0,0 @@ -extractEntityName($exception->getModel()); - - $ids = implode($exception->getIds(), ','); - - $error = [[ - 'status' => 404, - 'code' => $this->getCode('model_not_found'), - 'source' => ['pointer' => 'data/id'], - 'title' => $exception->getMessage(), - 'detail' => __('exception::exceptions.model_not_found.title', ['model' => $entity]), - ]]; - - $this->jsonApiResponse->setStatus(404); - $this->jsonApiResponse->setErrors($error); - } - - /** - * Get entitie name based on model path to mount the message. - * - * @param string $model - * @return string - */ - public function extractEntityName($model) - { - $classNames = (array) explode('\\', $model); - - $entityName = end($classNames); - - if ($this->entityHasTranslation($entityName)) { - return __('exception::exceptions.models.'.$entityName); - } - - return $entityName; - } - - /** - * Check if entity returned on ModelNotFoundException has translation on - * exceptions file - * @param string $entityName The model name to check if has translation - * @return bool Has translation or not - */ - public function entityHasTranslation(string $entityName): bool - { - $hasKey = in_array($entityName, $this->translationModelKeys()); - - if ($hasKey) { - return ! empty($hasKey); - } - - return false; - } - - /** - * Get the models keys on exceptions lang file - * @return array An array with keys to translate - */ - private function translationModelKeys(): array - { - return array_keys(__('exception::exceptions.models')); - } -} diff --git a/src/NotFoundHttpHandler.php b/src/NotFoundHttpHandler.php deleted file mode 100644 index f3a9037..0000000 --- a/src/NotFoundHttpHandler.php +++ /dev/null @@ -1,45 +0,0 @@ -getStatusCode(); - $error = [[ - 'status' => $statuCode, - 'code' => $this->getCode('not_found_http'), - 'source' => ['pointer' => $exception->getFile().':'.$exception->getLine()], - 'title' => $this->getDescription($exception), - 'detail' => $this->getNotFoundMessage($exception), - ]]; - - $this->jsonApiResponse->setStatus($statuCode); - $this->jsonApiResponse->setErrors($error); - } - - /** - * Get message based on file. If file is RouteCollection return specific - * message. - * - * @param NotFoundHttpException $exception - * @return string - */ - public function getNotFoundMessage(NotFoundHttpException $exception) - { - $message = ! empty($exception->getMessage()) ? $exception->getMessage() : class_basename($exception); - if (basename($exception->getFile()) === 'RouteCollection.php') { - $message = __('exception::exceptions.not_found_http.message'); - } - - return $message; - } -} diff --git a/src/OAuthServerHandler.php b/src/OAuthServerHandler.php deleted file mode 100644 index 7ea7ad6..0000000 --- a/src/OAuthServerHandler.php +++ /dev/null @@ -1,24 +0,0 @@ -getHttpStatusCode(); - - $error = [[ - 'status' => $statusCode, - 'code' => $this->getCode('not_found_http'), - 'source' => ['pointer' => $exception->getFile().':'.$exception->getLine()], - 'title' => $exception->getErrorType(), - 'detail' => $exception->getMessage(), - ]]; - - $this->jsonApiResponse->setStatus($statusCode); - $this->jsonApiResponse->setErrors($error); - } -} diff --git a/src/Response/AbstractResponse.php b/src/Response/AbstractResponse.php new file mode 100644 index 0000000..abf2657 --- /dev/null +++ b/src/Response/AbstractResponse.php @@ -0,0 +1,75 @@ +errors = $errors; + + $this->setStatus((int) $this->errors->getStatusCode()); + } + + /** + * Get the HTTP status code. + * + * @return int + */ + public function getStatus() + { + return $this->status; + } + + /** + * Set the HTTP status code. + * + * @param int $status The HTTP status code. + * + * @return self + */ + public function setStatus(int $status) + { + $this->status = $status; + + return $this; + } + + /** + * Get the errors on response. + * + * @return \SMartins\Exceptions\Response\ErrorHandledCollectionInterface + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Returns JSON response. + * + * @return \Illuminate\Http\JsonResponse + */ + abstract public function json(): JsonResponse; +} diff --git a/src/Response/ErrorCollectionInterface.php b/src/Response/ErrorCollectionInterface.php new file mode 100644 index 0000000..f30861d --- /dev/null +++ b/src/Response/ErrorCollectionInterface.php @@ -0,0 +1,31 @@ +status; - } - - public function status() - { - return $this->getStatus(); - } - - public function getErrors() - { - return $this->errors; - } - - public function errors() - { - return $this->getErrors(); - } - - public function setStatus($status) - { - $this->status = $status; - } - - public function setErrors($errors) - { - $this->errors = $errors; - } - - public function toArray() - { - return ['errors' => $this->errors()]; - } -} diff --git a/src/Traits/NotNullArrayable.php b/src/Traits/NotNullArrayable.php new file mode 100644 index 0000000..7b41c0d --- /dev/null +++ b/src/Traits/NotNullArrayable.php @@ -0,0 +1,25 @@ + $value) { + if (! is_null($value)) { + $array[$attribute] = $value instanceof Arrayable ? $value->toArray() : $value; + } + } + + return $array; + } +} diff --git a/src/ValidationHandler.php b/src/ValidationHandler.php deleted file mode 100644 index b273f79..0000000 --- a/src/ValidationHandler.php +++ /dev/null @@ -1,106 +0,0 @@ -jsonApiResponse->setStatus(422); - $this->jsonApiResponse->setErrors($this->jsonApiFormatErrorMessages($exception)); - } - - /** - * Get formatted errors on standard code, field, message to each field with - * error. - * - * @param ValidationException $exception - * @return array - */ - public function formattedErrors(ValidationException $exception) - { - return $this->jsonApiFormatErrorMessages($exception); - } - - public function jsonApiFormatErrorMessages(ValidationException $exception) - { - $validationMessages = $this->getTreatedMessages($exception); - $validationFails = $this->getTreatedFails($exception); - - $errors = []; - foreach ($validationMessages as $field => $messages) { - foreach ($messages as $key => $message) { - $attributes = $this->getValidationAttributes($validationFails, $key, $field); - $error = [ - 'status' => 422, - 'code' => $attributes['code'], - 'source' => ['parameter' => $field], - 'title' => $attributes['title'], - 'detail' => $message, - ]; - array_push($errors, $error); - } - } - - return $errors; - } - - public function getValidationAttributes(array $validationFails, $key, $field) - { - return [ - 'code' => $this->getValidationCode($validationFails, $key, $field), - 'title' => $this->getValidationTitle($validationFails, $key, $field), - ]; - } - - public function getValidationTitle(array $validationFails, $key, $field) - { - return __('exception::exceptions.validation.title', [ - 'fails' => array_keys($validationFails[$field])[$key], - 'field' => $field, - ]); - } - - public function getValidationCode(array $validationFails, $key, $field) - { - $rule = strtolower(array_keys($validationFails[$field])[$key]); - - return config($this->configFile.'.codes.validation_fields.'.$field.'.'.$rule); - } - - /** - * Get message based on exception type. If exception is generated by - * $this->validate() from default Controller methods the exception has the - * response object. If exception is generated by Validator::make() the - * messages are getted different. - * - * @param Exception $exception - * @return array - */ - public function getTreatedMessages($exception) - { - return $this->getMessagesFromValidator($exception); - } - - public function getMessagesFromValidator($exception) - { - return $exception->validator->messages()->messages(); - } - - public function getTreatedFails($exception) - { - return $this->getFailsFromValidator($exception); - } - - public function getFailsFromValidator($exception) - { - return $exception->validator->failed(); - } -} diff --git a/tests/Feature/JsonHandlerTest.php b/tests/Feature/JsonHandlerTest.php new file mode 100644 index 0000000..2ded966 --- /dev/null +++ b/tests/Feature/JsonHandlerTest.php @@ -0,0 +1,123 @@ +loadLaravelMigrations(['--database' => 'exceptions']); + + $this->setUpRoutes(); + } + + public function setUpRoutes() + { + Route::get('default_exception', function (Request $request) { + throw new Exception('Test message', 1); + }); + + Route::get('/model_not_found', function (Request $request) { + Model::findOrFail(1); + }); + + Route::middleware('auth')->get('/authentication', function (Request $request) { + // + }); + + Route::get('authorization', function (Request $request) { + throw new AuthorizationException('Forbidden'); + }); + + Route::get('validation', function (Request $request) { + Validator::make($request->all(), [ + 'name' => 'required', + 'email' => 'email', + ])->validate(); + }); + + Route::get('bad_request', function (Request $request) { + throw new BadRequestHttpException('Bad Request'); + }); + } + + public function testThrowsDefaultException() + { + $this->json('GET', 'default_exception') + ->assertStatus(500) + ->assertJsonStructure($this->defaultErrorStructure()); + } + + public function testThrowsModelNotFoundException() + { + $this->json('GET', 'model_not_found') + ->assertStatus(404) + ->assertJsonStructure($this->defaultErrorStructure()); + } + + public function testThrowsAuthenticationException() + { + $this->json('GET', 'authentication') + ->assertStatus(401) + ->assertJsonStructure($this->defaultErrorStructure()); + } + + public function testThrowsAuthorizationException() + { + $this->json('GET', 'authorization') + ->assertStatus(403) + ->assertJsonStructure($this->defaultErrorStructure()); + } + + public function testThrowsValidationExceptions() + { + $params = ['email' => str_repeat('a', 11)]; + + $this->json('GET', 'validation', $params) + ->assertStatus(422) + ->assertJsonStructure($this->defaultErrorStructure()); + } + + public function testThrowsBadRequestHttpException() + { + $this->json('GET', 'bad_request') + ->assertStatus(400) + ->assertJsonStructure($this->defaultErrorStructure()); + } + + public function testThrowsNotFoundHttpException() + { + $this->json('GET', 'not_found_route') + ->assertStatus(404) + ->assertJsonStructure($this->defaultErrorStructure()); + } + + /** + * The default json response error structure. + * + * @return array + */ + public function defaultErrorStructure() + { + return [ + 'errors' => [[ + 'status', + 'code', + 'title', + 'detail', + 'source' => ['pointer'] + ]], + ]; + } +} diff --git a/tests/Fixtures/Exceptions/Handler.php b/tests/Fixtures/Exceptions/Handler.php new file mode 100644 index 0000000..5b5952e --- /dev/null +++ b/tests/Fixtures/Exceptions/Handler.php @@ -0,0 +1,73 @@ + AuthorizationHandler::class, + NotFoundHttpException::class => NotFoundHttpHandler::class, + ]; + + /** + * A list of the exception types that are not reported. + * + * @var array + */ + protected $dontReport = [ + // + ]; + + /** + * A list of the inputs that are never flashed for validation exceptions. + * + * @var array + */ + protected $dontFlash = [ + 'password', + 'password_confirmation', + ]; + + /** + * Report or log an exception. + * + * @param \Exception $exception + * @return void + */ + public function report(Exception $exception) + { + parent::report($exception); + } + + /** + * Render an exception into an HTTP response. + * + * @param \Illuminate\Http\Request $request + * @param \Exception $exception + * @return \Illuminate\Http\Response + */ + public function render($request, Exception $exception) + { + if ($request->expectsJson()) { + return $this->jsonResponse($exception); + } + + return parent::render($request, $exception); + } +} diff --git a/tests/Fixtures/User.php b/tests/Fixtures/User.php new file mode 100644 index 0000000..58f5e55 --- /dev/null +++ b/tests/Fixtures/User.php @@ -0,0 +1,10 @@ +classToTest; + $reflect = new ReflectionClass($class); + $properties = $reflect->getProperties(); + + foreach ($properties as $property) { + $setter = 'set'.ucfirst($property->getName()); + $getter = 'get'.ucfirst($property->getName()); + + $this->assertInstanceOf($this->classToTest, $class->{$setter}('test')); + $this->assertEquals('test', $class->{$getter}()); + } + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..7496354 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,39 @@ +singleton( + ExceptionHandler::class, + Handler::class + ); + + // Setup default database to use sqlite :memory: + $app['config']->set('database.default', 'exceptions'); + $app['config']->set('database.connections.exceptions', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + } + + protected function getPackageProviders($app) + { + return [ + JsonHandlerServiceProvider::class, + ]; + } +} diff --git a/tests/Unit/AbstractHandlerTest.php b/tests/Unit/AbstractHandlerTest.php new file mode 100644 index 0000000..67acc67 --- /dev/null +++ b/tests/Unit/AbstractHandlerTest.php @@ -0,0 +1,34 @@ +assertInstanceOf(Handler::class, $handler->getExceptionHandler()); + } + + public function testGetDefaultHandler() + { + $handler = new Handler(new \Exception); + + $this->assertInstanceOf(Handler::class, $handler->getDefaultHandler()); + } + + public function testValidateHandledExceptionWithInvalidArgument() + { + $this->expectException(InvalidArgumentException::class); + + $handler = new Handler(new \Exception); + $handler->validatedHandledException('invalid'); + } +} diff --git a/tests/Unit/ErrorCollectionTest.php b/tests/Unit/ErrorCollectionTest.php new file mode 100644 index 0000000..0c48620 --- /dev/null +++ b/tests/Unit/ErrorCollectionTest.php @@ -0,0 +1,18 @@ +assertInstanceOf(ErrorCollection::class, $error->setHeaders(['foo' => 'bar'])); + + $this->assertEquals($error->getHeaders(), ['foo' => 'bar']); + } +} diff --git a/tests/Unit/ErrorTest.php b/tests/Unit/ErrorTest.php new file mode 100644 index 0000000..5e5b235 --- /dev/null +++ b/tests/Unit/ErrorTest.php @@ -0,0 +1,61 @@ +assertInstanceOf(Error::class, $error->setId(1)); + $this->assertEquals(1, $error->getId()); + } + + public function testGetAndSetLinks() + { + $error = new Error; + $this->assertInstanceOf(Error::class, $error->setLinks($links = new Links)); + $this->assertEquals($links, $error->getLinks()); + } + + public function testGetAndSetCode() + { + $error = new Error; + $this->assertInstanceOf(Error::class, $error->setCode(1)); + $this->assertEquals(1, $error->getCode()); + } + + public function testGetAndSetTitle() + { + $error = new Error; + $this->assertInstanceOf(Error::class, $error->setTitle('tests')); + $this->assertEquals('tests', $error->getTitle()); + } + + public function testGetAndSetDetail() + { + $error = new Error; + $this->assertInstanceOf(Error::class, $error->setDetail('detail')); + $this->assertEquals('detail', $error->getDetail()); + } + + public function testGetAndSerSource() + { + $error = new Error; + $this->assertInstanceOf(Error::class, $error->setSource($source = new Source)); + $this->assertEquals($source, $error->getSource()); + } + + public function testToCollection() + { + $error = new Error; + $this->assertInstanceOf(ErrorCollection::class, $error->toCollection()); + } +} diff --git a/tests/Unit/HandlerTest.php b/tests/Unit/HandlerTest.php new file mode 100644 index 0000000..afe9d91 --- /dev/null +++ b/tests/Unit/HandlerTest.php @@ -0,0 +1,19 @@ +assertInstanceOf(Error::class, $handler->handle()); + } +} diff --git a/tests/Unit/Handlers/ModelNotFoundHandlerTest.php b/tests/Unit/Handlers/ModelNotFoundHandlerTest.php new file mode 100644 index 0000000..d90358e --- /dev/null +++ b/tests/Unit/Handlers/ModelNotFoundHandlerTest.php @@ -0,0 +1,31 @@ +setModel(NotTranslated::class); + + $handler = new ModelNotFoundHandler($exception); + + $error = $handler->handle(); + + $this->assertEquals(404, $error->getStatus()); + $this->assertEquals( + 'NotTranslated not found', + $error->getDetail() + ); + } +} + +class NotTranslated extends Model {} diff --git a/tests/Unit/SourceTest.php b/tests/Unit/SourceTest.php new file mode 100644 index 0000000..adf89e8 --- /dev/null +++ b/tests/Unit/SourceTest.php @@ -0,0 +1,13 @@ +