diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bf0c3fa --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +/.gitattributes export-ignore +/.gitignore export-ignore +/.travis.yml export-ignore +/phpunit.xml export-ignore +/tests export-ignore +/.editorconfig export-ignore diff --git a/.gitignore b/.gitignore index 49ce3c1..a7dfead 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -/vendor \ No newline at end of file +composer.lock +.phpunit.result.cache +vendor diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c62c9c6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,28 @@ +# Changelog + +All notable changes to `ajcastro/searchable` will be documented in this file + +## 2.0.1 (2021-07-28) + +### Added +- Added scope method `\AjCastro\Searchable\Searchable::scopeParseUsing()` to override the default fuzzy search. + +## 2.0.0 (2021-07-25) + +### Added +- Added `\AjCastro\Searchable\Columns`. +- Added `\AjCastro\Searchable\TableColumns`. +- Added `\AjCastro\Searchable\SearchParsers\*` classes. +- Added `\AjCastro\Searchable\BaseSearch`, simplified base search query decorator. +- Added `\AjCastro\Searchable\BaseSearch::parseUsing(callable $callback)` method using custom search string parsing. + +### Changed +- Moved $searchable property methods to separate trait `\AjCastro\Searchable\WithSearchableColumns`. +- Improved implementation of `searchByRelevance()` scope query, it is not called by default and should be called explicitly. +- Change method `\AjCastro\Searchable\Searchable::isColumnValid($column)` to non-static/instance method. + +### Removed +- Remove method `\AjCastro\Searchable\Searchable::getTableColumns()`. +- Remove `AjCastro\Searchable\Search\SublimeSearch`. +- Remove `AjCastro\Searchable\BaseGridQuery`. +- Remove `AjCastro\Searchable\BaseSearchQuery`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d4da4d3..7877330 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,3 @@ # Contribution Guidelines -Please submit all issues and pull requests to [sedp-mis/base-grid-query](http://github.com/sedp-mis/base-grid-query) repository! :) \ No newline at end of file +Please submit all issues and pull requests to [ajcastro/searchable](https://github.com/ajcastro/searchable) repository! :) diff --git a/README.md b/README.md index 74e46fb..f759087 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ # Searchable -Full-text search and reusable queries in laravel. +Pattern-matching search for Laravel eloquent models. - Currently supports MySQL only. - Helpful for complex table queries with multiple joins and derived columns. -- Reusable queries and column definitions. +- Fluent columns definitions. -## Overview +## Demo Project + +See [demo project](https://github.com/ajcastro/searchable-demo). -### Full-text search on eloquent models +## Overview Simple setup for searchable model and can search on derived columns. @@ -43,7 +45,7 @@ Post::search("Some title or body content or even the author's full name") ->paginate(); ``` -Imagine we have an api for a table or list that has full-text searching and column sorting and pagination. +Imagine we have an api for a table or list that has searching and column sorting and pagination. This is a usual setup for a table or list. The internal explanations will be available on the documentation below. Our api call may look like this: @@ -56,16 +58,31 @@ Your code can look like this: ```php class PostsController { - public function index() + public function index(Request $request) { - return Post::sortByRelevance(!request()->bool('sort_by')) - ->search(request('search')) - ->when(Post::isColumnValid($sortColumn = request('sort_by')), function ($query) use ($sortColumn) { - $query->orderBy( - \DB::raw(Post::searchQuery()->getColumn($sortColumn) ?? $sortColumn), - request()->bool('descending') ? 'desc' : 'asc' - ); + $query = Post::query(); + + return $query + ->with('author') + // advance usage with custom search string parsing + ->when($request->parse_using === 'exact', function ($query) { + $query->parseUsing(function ($searchStr) { + return "%{$searchStr}%"; + }); }) + ->search($request->search) + ->when( + $request->has('sort_by') && $query->getModel()->isColumnValid($request->sort_by), + function ($query) use ($request) { + $query->orderBy( + DB::raw($query->getModel()->getColumn($request->sort_by)), + $request->descending ? 'desc' : 'asc' + ); + }, + function ($query) { + $query->sortByRelevance(); + }, + ) ->paginate(); } @@ -102,7 +119,8 @@ class Post extends Model ], // This is needed if there is a need to join other tables for derived columns. 'joins' => [ - 'authors' => ['authors.id', 'posts.author_id'] + 'authors' => ['authors.id', 'posts.author_id'], // defaults to leftJoin method of eloquent builder + 'another_table' => ['another_table.id', 'authors.another_table_id', 'join'], // can pass leftJoin, rightJoin, join of eloquent builder. ] ]; @@ -135,13 +153,14 @@ Post::where('likes', '>', 100)->search('Some post')->paginate(); ``` -This will addSelect field `sort_index` which will used to order or sort by relevance. -If you want to disable sort by relevance, call method `sortByRelevance(false)` before `search()` method. +If you want to sort by relevance, call method `sortByRelevance()` after `search()` method. +This will addSelect field `sort_index` which will be used to order or sort by relevance. + Example: ``` -Post::sortByRelevance(false)->search('Some post')->paginate(); -Post::sortByRelevance(false)->where('likes', '>', 100)->search('Some post')->paginate(); +Post::search('Some post')->sortByRelevance()->paginate(); +Post::where('likes', '>', 100)->search('Some post')->sortByRelevance()->paginate(); ``` ### Set searchable configurations on runtime. @@ -167,204 +186,157 @@ $post->setSearchableJoins([ // addSearchableJoins() method is also available ]); ``` -### Searchable Model Custom Search Query +### Easy Sortable Columns -Sometimes our queries have lots of things and constraints to do and we can contain it in a search query class like this `PostSearch`. +You can define columns to be only sortable but not be part of search query constraint. +Just put it under `sortable_columns` as shown below . +This column can be easily access to put in `orderBy` of query builder. All searchable columns are also sortable columns. ```php -use AjCastro\Searchable\BaseSearchQuery; - -class PostSearch extends BaseSearchQuery -{ - public function query() - { - // The query conditions here is always applied to our search. - return $this->query - ->leftJoin('authors', 'authors.id', '=', 'posts.author_id') - ->where('posts.likes', '>', 100) - ->where('is_active', 1) - ->orderBy('some_column') - // We can even access our column definition here that will result to the equivalent actual column - // CAUTION: - // MySQL functions need to be wrapped with DB::raw() to be parsed properly. - // Also we can use orderByRaw() for this example. - // Also consider wrapping it in the columns() method so it will be ready - // everytime we use it in orderBy() or where() methods. - ->orderBy($this->author_full_name); - } - - public function columns() - { - return [ - 'posts.title', - 'posts.body', - // We wrap CONCAT() column so it will always be ready to be used in orderBy() and where() methods - 'author_full_name' => DB::raw('CONCAT(authors.first_name, " ", authors.last_name)') - ]; - } +class Post { + protected $searchable = [ + 'columns' => [ + 'title' => 'posts.title', + ], + 'sortable_columns' => [ + 'status_name' => 'statuses.name', + ], + 'joins' => [ + 'statuses' => ['statuses.id', 'posts.status_id'] + ] + ]; } +// Usage + +Post::search('A post title')->orderBy(Post::make()->getSortableColumn('status_name')); +// This will only perform search on `posts`.`title` column and it will append "order by `statuses`.`name`" in the query. +// This is beneficial if your column is mapped to a different column name coming from front-end request. ``` -Then, we can use it as the default search query for the model like: + +### Custom Search String Parser - Exact Search Example + +Override the `deafultSearchQuery` in the model like so: ```php -class Post +use AjCastro\Searchable\BaseSearch; + +class User extends Model { public function defaultSearchQuery() { - return new PostSearch; + return BaseSearch::make($this->buildSearchableColumns()) + ->parseUsing(function ($searchStr) { + return $searchStr; // produces "where `column` like '{$searchStr}'" + return "%{$searchStr}%"; // produces "where `column` like '%{$searchStr}%'" + }); } } - -// Usage -Post::search($searchStr)->paginate(); ``` -We can also use custom search query temporarily by passing it as second parameter in `search()` method. +You may also check the build query by dd-ing it: ```php -Post::search('William Shakespeare', new PostSearch)->paginate(); +$query = User::search('John Doe'); +dd($query->toSql()); +``` +which may output to +``` +select * from users where `column` like 'John Doe' +// or +select * from users where `column` like '%John Doe%' ``` ### Using derived columns for order by and where conditions -Usually we have queries that has a derived columns like our example for `PostSearch`'s `author_full_name`. +Usually we have queries that has a derived columns like our example for `Post`'s `author_full_name`. Sometimes we need to sort our query results by this column. ```php -// CAUTION: -// Remember to wrap column with MySQL functions with DB::raw() in column definition -Post::search('Some search')->orderBy(Post::searchQuery()->author_full_name, 'desc')->paginate(); -Post::search('Some search')->where(Post::searchQuery()->author_full_name, 'William%')->paginate(); +$query = Post::query(); +$post = $query->getModel(); +// (A) +$query->search('Some search')->orderBy($post->getColumn('author_full_name'), 'desc')->paginate(); +// (B) +$query->search('Some search')->where($post->getColumn('author_full_name'), 'William%')->paginate(); +``` +which may output to +```sql +-- (A) +select * from posts where ... order by CONCAT(authors.first_name, " ", authors.last_name) desc limit 0, 15; +-- (B) +select * from posts where ... and CONCAT(authors.first_name, " ", authors.last_name) like 'William%' limit 0, 15; ``` -### Running gridQuery and searchQuery on its own - -You can run gridQuery and searchQuery on its own but you need to make sure you initiliaze your query. - -```php -use AjCastro\Searchable\BaseSearchQuery; - -class PostSearch extends BaseSearchQuery -{ - public function query() - { - // Initialize query when $this->query is not available. - $query = $this->query ?? Post::query(); - return $this->query; - // ->leftJoin('authors', 'authors.id', '=', 'posts.author_id') - // -> ... and so on - } -} +## Helper methods available -// Then you can run it... -(new PostSearch)->search('something')->paginate(); -``` +### TableColumns::get() [static] -### Grid Query Declarative Definition +- Get the table columns. ```php -use AjCastro\Searchable\BaseGridQuery; +TableColumns::get('posts'); +``` -class PostGridQuery extends BaseGridQuery -{ - public function initQuery() - { - return Post::leftJoin('authors', 'authors.id', '=', 'posts.author_id'); - } +### isColumnValid - public function columns() - { - return [ - 'posts.title', // same with 'title' => 'posts.title' - 'text' => 'posts.body', // will result to "posts.body as text" - 'author_full_name' => 'CONCAT(authors.first_name, " ", authors.last_name)' - ]; - } -} -``` +- Identifies if the column is a valid column, either a regular table column or derived column. +- Useful for checking valid columns to avoid sql injection especially in `orderBy` query, [see post](https://freek.dev/1317-an-important-security-release-for-laravel-query-builder). ```php -$gridQuery = new PostGridQuery; -$actualColumn = $gridQuery->getColumn('author_full_name'); -$actualColumn = $gridQuery->author_full_name; // or using magic getters -$gridQuery - ->selectColumns() // puts columns() to $query->select() and return the laravel query builder - ->orderBy($actualColumn, 'desc') - ->get(); +$query->getModel()->isColumnValid(request('sort_by')); ``` -### Search Query Declarative Definition +### enableSearchable + +- Enable the searchable behavior. ```php -use AjCastro\Searchable\BaseSearchQuery; +$query->getModel()->enableSearchable(); +$query->search('foo'); +``` -class PostSearch extends BaseSearchQuery -{ - public function query() - { - // $this->query is available since this is set on Searchable trait scopeSearch() method - // If you're going to run this searchQuery on its own and not via scopeSearch() - // you should consider to initialize $this->query first or use initQuery() method instead of query() - // just like the above example - return $this->query->leftJoin('authors', 'authors.id', '=', 'posts.author_id'); - } +### disableSearchable - public function columns() - { - return [ - 'posts.title', // same with 'title' => 'posts.title' - 'text' => 'posts.body', // will result to "posts.body as text" - 'author_full_name' => 'CONCAT(authors.first_name, " ", authors.last_name)' - ]; - } -} -``` +- Disable the searchable behavior. +- Calling `search()` method will not perform a search. ```php -// All defined columns are searchable in the query -$searchQuery = new PostSearch; -$searchQuery->search('This is a post title.'); -$searchQuery->search('This is a post body.'); -$searchQuery->search('William Shakespeare'); -// You can chain laravel query builder's paginate() or get() afterwards -$searchQuery->search('William Shakespeare')->get(); -// If you want to select the columns from the columns() we call selectColumns(), use initQuery for this -$results = tap($searchQuery)->search('William Shakespeare')->selectColumns()->get(); -$results = [ - [ - 'title' => 'This is a post title', - 'text' => 'This is a post body.', - 'author_full_name' => 'William Shakespeare' - ], - // ... and so on -]; +$query->getModel()->disableSearchable(); +$query->search('foo'); ``` -## Helper methods available on model - -### isColumnValid +### setSearchable -- Identifies if the column is a valid column, either a regular table column or derived column. -- Useful for checking valid columns to avoid sql injection especially in `orderBy` query. +- Set or override the model's `$searchable` property. +- Useful for building searchable config on runtime. ```php -Post::isColumnValid(request('sort_by')); +$query->getModel()->setSearchable([ + 'columns' => ['title', 'status'], + 'joins' => [...], +]); +$query->search('foo'); ``` -### getTableColumns +### addSearchable -- Get the table columns. +- Add columns or joins in the model's `$searchable` property. +- Useful for building searchable config on runtime. ```php -Post::getTableColumns(); +$query->getModel()->addSearchable([ + 'columns' => ['title', 'status'], + 'joins' => [...], +]); +$query->search('foo'); ``` ## Warning Calling `select()` after `search()` will overwrite `sort_index` field, so it is recommended to call `select()` -before `search()` which is also the normal case. +before `search()`. Or you can use `addSelect()` instead. ## Credits diff --git a/composer.json b/composer.json index a7b97a3..6e209ff 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "ajcastro/searchable", - "description": "Full-text search and reusable queries in laravel.", - "keywords": ["laravel", "laravel-package", "query", "query-builder", "full-text-search", "eloquent-search", "grid"], + "description": "Pattern-matching search for Laravel eloquent models.", + "keywords": ["laravel", "laravel-package", "query", "query-builder", "pattern-matching-search", "eloquent-search"], "license": "MIT", "authors": [ { @@ -17,8 +17,14 @@ "AjCastro\\Searchable\\": "src" } }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, "minimum-stability": "dev", "require-dev": { - "orchestra/testbench": "~3.0" + "orchestra/testbench": "^6.0", + "phpunit/phpunit": "9.5.x-dev" } } diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 1913f87..0000000 --- a/composer.lock +++ /dev/null @@ -1,4095 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "766fc2da2c0f4056cdfa7a2b5c34294b", - "packages": [], - "packages-dev": [ - { - "name": "doctrine/inflector", - "version": "1.3.x-dev", - "source": { - "type": "git", - "url": "https://github.com/doctrine/inflector.git", - "reference": "45d9b132b262c1d03835cdeefd42938d881556fa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/45d9b132b262c1d03835cdeefd42938d881556fa", - "reference": "45d9b132b262c1d03835cdeefd42938d881556fa", - "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-06-15T19:03:38+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "16ca33ecc67a625de250f476531dfe5de4c32ff2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/16ca33ecc67a625de250f476531dfe5de4c32ff2", - "reference": "16ca33ecc67a625de250f476531dfe5de4c32ff2", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "doctrine/coding-standard": "^5.0", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.13", - "phpstan/phpstan-shim": "^0.9.2", - "phpunit/phpunit": "^7.0" - }, - "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://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2019-02-20T06:21:04+00:00" - }, - { - "name": "doctrine/lexer", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "4ab6ea7c838ccb340883fd78915af079949cc64d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/4ab6ea7c838ccb340883fd78915af079949cc64d", - "reference": "4ab6ea7c838ccb340883fd78915af079949cc64d", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "^4.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" - } - }, - "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": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", - "keywords": [ - "annotations", - "docblock", - "lexer", - "parser", - "php" - ], - "time": "2018-10-21T19:22:05+00:00" - }, - { - "name": "dragonmantank/cron-expression", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "714f6a8ab14b1951dcc2141b8e5d21ee96e06474" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/714f6a8ab14b1951dcc2141b8e5d21ee96e06474", - "reference": "714f6a8ab14b1951dcc2141b8e5d21ee96e06474", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.4|^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "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": "2019-02-14T15:33:25+00:00" - }, - { - "name": "egulias/email-validator", - "version": "2.1.7", - "source": { - "type": "git", - "url": "https://github.com/egulias/EmailValidator.git", - "reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/709f21f92707308cdf8f9bcfa1af4cb26586521e", - "reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e", - "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-12-04T22:38:24+00:00" - }, - { - "name": "erusev/parsedown", - "version": "1.8.0-beta-5", - "source": { - "type": "git", - "url": "https://github.com/erusev/parsedown.git", - "reference": "c26a2ee4bf8ba0270daab7da0353f2525ca6564a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/c26a2ee4bf8ba0270daab7da0353f2525ca6564a", - "reference": "c26a2ee4bf8ba0270daab7da0353f2525ca6564a", - "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-06-11T18:15:32+00:00" - }, - { - "name": "fzaninotto/faker", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/fzaninotto/Faker.git", - "reference": "76b1c25e614c5e09adeb62f1b953536697a41a4b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/76b1c25e614c5e09adeb62f1b953536697a41a4b", - "reference": "76b1c25e614c5e09adeb62f1b953536697a41a4b", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "ext-intl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7", - "squizlabs/php_codesniffer": "^1.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.9-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": "2019-01-09T06:29:58+00:00" - }, - { - "name": "hamcrest/hamcrest-php", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "a8c1c7b982c989ad16c8f17f1834fa5df744b689" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/a8c1c7b982c989ad16c8f17f1834fa5df744b689", - "reference": "a8c1c7b982c989ad16c8f17f1834fa5df744b689", - "shasum": "" - }, - "require": { - "php": "^5.3|^7.0" - }, - "replace": { - "cordoval/hamcrest-php": "*", - "davedevelopment/hamcrest-php": "*", - "kodova/hamcrest-php": "*" - }, - "require-dev": { - "phpunit/php-file-iterator": "^1.4", - "phpunit/phpunit": ">=4.8.35 <5|>=5.4.3 <6", - "satooshi/php-coveralls": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "hamcrest" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "This is the PHP port of Hamcrest Matchers", - "keywords": [ - "test" - ], - "time": "2018-11-01T08:19:18+00:00" - }, - { - "name": "laravel/framework", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/laravel/framework.git", - "reference": "9f722df5769f8a73edbd96e14cd609c8ff661442" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/9f722df5769f8a73edbd96e14cd609c8ff661442", - "reference": "9f722df5769f8a73edbd96e14cd609c8ff661442", - "shasum": "" - }, - "require": { - "doctrine/inflector": "^1.1", - "dragonmantank/cron-expression": "^2.0", - "egulias/email-validator": "^2.0", - "erusev/parsedown": "^1.7", - "ext-json": "*", - "ext-mbstring": "*", - "ext-openssl": "*", - "league/flysystem": "^1.0.8", - "monolog/monolog": "^1.12", - "nesbot/carbon": "^1.26.3 || ^2.0", - "opis/closure": "^3.1", - "php": "^7.2", - "psr/container": "^1.0", - "psr/simple-cache": "^1.0", - "ramsey/uuid": "^3.7", - "swiftmailer/swiftmailer": "^6.0", - "symfony/console": "^4.2", - "symfony/debug": "^4.2", - "symfony/finder": "^4.2", - "symfony/http-foundation": "^4.2", - "symfony/http-kernel": "^4.2", - "symfony/process": "^4.2", - "symfony/routing": "^4.2", - "symfony/var-dumper": "^4.2", - "tijsverkoyen/css-to-inline-styles": "^2.2.1", - "vlucas/phpdotenv": "^3.3" - }, - "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", - "guzzlehttp/guzzle": "^6.3", - "league/flysystem-cached-adapter": "^1.0", - "mockery/mockery": "^1.0", - "moontoast/math": "^1.1", - "orchestra/testbench-core": "3.9.*", - "pda/pheanstalk": "^4.0", - "phpunit/phpunit": "^7.5|^8.0", - "predis/predis": "^1.1.1", - "symfony/css-selector": "^4.2", - "symfony/dom-crawler": "^4.2", - "true/punycode": "^2.1" - }, - "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.", - "filp/whoops": "Required for friendly error pages in development (^2.1.4).", - "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).", - "moontoast/math": "Required to use ordered UUIDs (^1.1).", - "nexmo/client": "Required to use the Nexmo transport (^1.0).", - "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.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.2).", - "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (^4.2).", - "symfony/psr-http-message-bridge": "Required to psr7 bridging features (^1.1)." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.9-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": "2019-02-21T11:07:09+00:00" - }, - { - "name": "league/flysystem", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/flysystem.git", - "reference": "0a342db3a10cb31862e83d550f67c2d087825467" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/0a342db3a10cb31862e83d550f67c2d087825467", - "reference": "0a342db3a10cb31862e83d550f67c2d087825467", - "shasum": "" - }, - "require": { - "ext-fileinfo": "*", - "php": ">=5.5.9" - }, - "conflict": { - "league/flysystem-sftp": "<1.0.6" - }, - "require-dev": { - "phpspec/phpspec": "^3.4", - "phpunit/phpunit": "^5.7.10" - }, - "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": "2019-02-14T07:18:57+00:00" - }, - { - "name": "mockery/mockery", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/mockery/mockery.git", - "reference": "0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2", - "reference": "0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2", - "shasum": "" - }, - "require": { - "hamcrest/hamcrest-php": "~2.0", - "lib-pcre": ">=7.0", - "php": ">=5.6.0" - }, - "require-dev": { - "phpunit/phpunit": "~5.7.10|~6.5|~7.0|~8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "Mockery": "library/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Pádraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" - }, - { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" - } - ], - "description": "Mockery is a simple yet flexible PHP mock object framework", - "homepage": "https://github.com/mockery/mockery", - "keywords": [ - "BDD", - "TDD", - "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" - ], - "time": "2019-02-13T09:37:52+00:00" - }, - { - "name": "monolog/monolog", - "version": "1.x-dev", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "4d5b7e6ba1127789c7ff59d6f762298eaa29787f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/4d5b7e6ba1127789c7ff59d6f762298eaa29787f", - "reference": "4d5b7e6ba1127789c7ff59d6f762298eaa29787f", - "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": "2018-12-26T14:24:03+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.x-dev", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "replace": { - "myclabs/deep-copy": "self.version" - }, - "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.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": "2018-06-11T23:09:50+00:00" - }, - { - "name": "nesbot/carbon", - "version": "2.12.0", - "source": { - "type": "git", - "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "35dc8834ae9ad79b77c22d1e276fd838ca8c503d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/35dc8834ae9ad79b77c22d1e276fd838ca8c503d", - "reference": "35dc8834ae9ad79b77c22d1e276fd838ca8c503d", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": "^7.1.8", - "symfony/translation": "^3.4 || ^4.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", - "phpmd/phpmd": "^2.6", - "phpstan/phpstan": "^0.10.8", - "phpunit/phpunit": "^7.1.5", - "squizlabs/php_codesniffer": "^3.4" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Carbon\\Laravel\\ServiceProvider" - ] - } - }, - "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": "2019-02-06T21:23:55+00:00" - }, - { - "name": "opis/closure", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/opis/closure.git", - "reference": "41f5da65d75cf473e5ee582df8fc7f2c733ce9d6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/41f5da65d75cf473e5ee582df8fc7f2c733ce9d6", - "reference": "41f5da65d75cf473e5ee582df8fc7f2c733ce9d6", - "shasum": "" - }, - "require": { - "php": "^5.4 || ^7.0" - }, - "require-dev": { - "jeremeamia/superclosure": "^2.0", - "phpunit/phpunit": "^4.0|^5.0|^6.0|^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Opis\\Closure\\": "src/" - }, - "files": [ - "functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marius Sarca", - "email": "marius.sarca@gmail.com" - }, - { - "name": "Sorin Sarca", - "email": "sarca_sorin@hotmail.com" - } - ], - "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", - "homepage": "https://opis.io/closure", - "keywords": [ - "anonymous functions", - "closure", - "function", - "serializable", - "serialization", - "serialize" - ], - "time": "2019-01-14T14:45:33+00:00" - }, - { - "name": "orchestra/testbench", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/orchestral/testbench.git", - "reference": "d4ca70d6405c33b11a5430c6389e7e082265767d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench/zipball/d4ca70d6405c33b11a5430c6389e7e082265767d", - "reference": "d4ca70d6405c33b11a5430c6389e7e082265767d", - "shasum": "" - }, - "require": { - "laravel/framework": "~5.9.0", - "mockery/mockery": "^1.0", - "orchestra/testbench-core": "~3.9.0", - "php": ">=7.2", - "phpunit/phpunit": "^7.5 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.9-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": "2019-02-13T00:32:22+00:00" - }, - { - "name": "orchestra/testbench-core", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/orchestral/testbench-core.git", - "reference": "2c67e779baf60af96da0cfaaecfe2ed7e5b317f1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/2c67e779baf60af96da0cfaaecfe2ed7e5b317f1", - "reference": "2c67e779baf60af96da0cfaaecfe2ed7e5b317f1", - "shasum": "" - }, - "require": { - "fzaninotto/faker": "^1.4", - "php": ">=7.2" - }, - "require-dev": { - "laravel/framework": "~5.9.0", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^7.5 || ^8.0" - }, - "suggest": { - "laravel/framework": "Required for testing (~5.9.0).", - "mockery/mockery": "Allow to use Mockery for testing (^1.0).", - "orchestra/testbench-browser-kit": "Allow to use legacy Laravel BrowserKit for testing (^3.9).", - "orchestra/testbench-dusk": "Allow to use Laravel Dusk for testing (^3.9).", - "phpunit/phpunit": "Allow to use PHPUnit for testing (^7.5 || ^8.0)." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.9-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": "2019-02-22T00:59:34+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v9.99.99", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "shasum": "" - }, - "require": { - "php": "^7" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "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", - "polyfill", - "pseudorandom", - "random" - ], - "time": "2018-07-02T15:55:56+00:00" - }, - { - "name": "phar-io/manifest", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-phar": "*", - "phar-io/version": "^2.0", - "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": "2018-07-08T19:23:20+00:00" - }, - { - "name": "phar-io/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "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": "2018-07-08T19:19:57+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": "phpoption/phpoption", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-option.git", - "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", - "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "4.7.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-0": { - "PhpOption\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Option Type for PHP", - "keywords": [ - "language", - "option", - "php", - "type" - ], - "time": "2015-07-25T16:39:46+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "7e272180527c34a97680de85eb5aba0847a664e0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/7e272180527c34a97680de85eb5aba0847a664e0", - "reference": "7e272180527c34a97680de85eb5aba0847a664e0", - "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 || ^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.8.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "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-12-18T15:40:51+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "cfca9c5f7f2694ca0c7749ffb142927d9f05250f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cfca9c5f7f2694ca0c7749ffb142927d9f05250f", - "reference": "cfca9c5f7f2694ca0c7749ffb142927d9f05250f", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-xmlwriter": "*", - "php": "^7.2", - "phpunit/php-file-iterator": "^2.0.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0.1", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^4.1", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^8.0" - }, - "suggest": { - "ext-xdebug": "^2.6.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "7.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": "2019-02-15T13:40:27+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "5e99c0ea25f1eb9bd4d7380499788302984dd77b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/5e99c0ea25f1eb9bd4d7380499788302984dd77b", - "reference": "5e99c0ea25f1eb9bd4d7380499788302984dd77b", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.1" - }, - "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": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2019-02-11T12:49:18+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": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "eb9e39fb4c2034c31897cdb5f59498fc9126ddcc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/eb9e39fb4c2034c31897cdb5f59498fc9126ddcc", - "reference": "eb9e39fb4c2034c31897cdb5f59498fc9126ddcc", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.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": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2019-02-20T14:16:29+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "cca9f57a2c7bb3d1e294f2aae84083ffe83dfa92" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/cca9f57a2c7bb3d1e294f2aae84083ffe83dfa92", - "reference": "cca9f57a2c7bb3d1e294f2aae84083ffe83dfa92", - "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": "2019-02-11T12:50:48+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "efb5af42b4ad74b93f6bb0647695da903173ebc0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/efb5af42b4ad74b93f6bb0647695da903173ebc0", - "reference": "efb5af42b4ad74b93f6bb0647695da903173ebc0", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.1", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.7", - "phar-io/manifest": "^1.0.2", - "phar-io/version": "^2.0", - "php": "^7.2", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^7.0", - "phpunit/php-file-iterator": "^2.0.1", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.1", - "sebastian/comparator": "^3.0", - "sebastian/diff": "^3.0", - "sebastian/environment": "^4.1", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^3.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0", - "sebastian/version": "^2.0.1" - }, - "require-dev": { - "ext-pdo": "*" - }, - "suggest": { - "ext-soap": "*", - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "8.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": "2019-02-21T08:29:35+00:00" - }, - { - "name": "psr/container", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "014d250daebff39eba15ba990eeb2a140798e77c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/014d250daebff39eba15ba990eeb2a140798e77c", - "reference": "014d250daebff39eba15ba990eeb2a140798e77c", - "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": "2018-12-29T15:36:03+00:00" - }, - { - "name": "psr/log", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "c4421fcac1edd5a324fda73e589a5cf96e52ffd0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/c4421fcac1edd5a324fda73e589a5cf96e52ffd0", - "reference": "c4421fcac1edd5a324fda73e589a5cf96e52ffd0", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.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": "2018-11-21T13:42:00+00:00" - }, - { - "name": "psr/simple-cache", - "version": "dev-master", - "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.x-dev", - "source": { - "type": "git", - "url": "https://github.com/ramsey/uuid.git", - "reference": "4c467ce4d5a72c3cf0832c813d4d84d222c3d4bb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/4c467ce4d5a72c3cf0832c813d4d84d222c3d4bb", - "reference": "4c467ce4d5a72c3cf0832c813d4d84d222c3d4bb", - "shasum": "" - }, - "require": { - "ext-json": "*", - "paragonie/random_compat": "^1.0|^2.0|9.99.99", - "php": "^5.4 || ^7.0", - "symfony/polyfill-ctype": "^1.8" - }, - "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.0", - "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|^6.5", - "squizlabs/php_codesniffer": "^2.3" - }, - "suggest": { - "ext-ctype": "Provides support for PHP Ctype functions", - "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-08-12T15:49:01+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "383c44e104c1fd46ecc915f55145bd2831318747" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/383c44e104c1fd46ecc915f55145bd2831318747", - "reference": "383c44e104c1fd46ecc915f55145bd2831318747", - "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": "2019-02-11T12:48:46+00:00" - }, - { - "name": "sebastian/comparator", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "17ef3ffcdab9194ad7a2715a9fb1235f1361a366" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/17ef3ffcdab9194ad7a2715a9fb1235f1361a366", - "reference": "17ef3ffcdab9194ad7a2715a9fb1235f1361a366", - "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": "2019-02-11T12:51:04+00:00" - }, - { - "name": "sebastian/diff", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "d4193340fc9bebb17533e00bc82f61da28fe7125" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/d4193340fc9bebb17533e00bc82f61da28fe7125", - "reference": "d4193340fc9bebb17533e00bc82f61da28fe7125", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.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": "2019-02-11T12:50:35+00:00" - }, - { - "name": "sebastian/environment", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "dbf7b0d103084622e8a5015452a2650dcb248758" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dbf7b0d103084622e8a5015452a2650dcb248758", - "reference": "dbf7b0d103084622e8a5015452a2650dcb248758", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.5" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.1-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": "2019-02-11T12:51:52+00:00" - }, - { - "name": "sebastian/exporter", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "8be786b3b65fbe706733d44a4b4a53d5391a4772" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/8be786b3b65fbe706733d44a4b4a53d5391a4772", - "reference": "8be786b3b65fbe706733d44a4b4a53d5391a4772", - "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": "2019-02-11T12:49:46+00:00" - }, - { - "name": "sebastian/global-state", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "4b60cdb437ccff1871814451541cbe41f4b8ac58" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/4b60cdb437ccff1871814451541cbe41f4b8ac58", - "reference": "4b60cdb437ccff1871814451541cbe41f4b8ac58", - "shasum": "" - }, - "require": { - "php": "^7.2", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^8.0" - }, - "suggest": { - "ext-uopz": "*" - }, - "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": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2019-02-11T12:52:08+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "41af86e2a7b06e7e364c81a705b1f7caf6110218" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/41af86e2a7b06e7e364c81a705b1f7caf6110218", - "reference": "41af86e2a7b06e7e364c81a705b1f7caf6110218", - "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": "2019-02-11T12:50:05+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "fae17b5d19ab523c9e821e5559d27e4c8a5bdee1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/fae17b5d19ab523c9e821e5559d27e4c8a5bdee1", - "reference": "fae17b5d19ab523c9e821e5559d27e4c8a5bdee1", - "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": "2019-02-11T12:48:12+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "87b0893f697db6d75943e26d50bf91c82796a371" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/87b0893f697db6d75943e26d50bf91c82796a371", - "reference": "87b0893f697db6d75943e26d50bf91c82796a371", - "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": "2019-02-11T12:48:28+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "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": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2018-10-04T04:07:39+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": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "c2100aa5bf9acd57e712f208030f1e5e32e420c5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/c2100aa5bf9acd57e712f208030f1e5e32e420c5", - "reference": "c2100aa5bf9acd57e712f208030f1e5e32e420c5", - "shasum": "" - }, - "require": { - "egulias/email-validator": "~2.0", - "php": ">=7.0.0", - "symfony/polyfill-iconv": "^1.0", - "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" - }, - "require-dev": { - "mockery/mockery": "~0.9.1", - "symfony/phpunit-bridge": "^3.4.19|^4.1.8" - }, - "suggest": { - "ext-intl": "Needed to support internationalized email addresses", - "true/punycode": "Needed to support internationalized email addresses, if ext-intl is not installed" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.2-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": "https://swiftmailer.symfony.com", - "keywords": [ - "email", - "mail", - "mailer" - ], - "time": "2019-01-30T06:37:50+00:00" - }, - { - "name": "symfony/console", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "b32588547642e984501c5dfbd4a1e8c204786c20" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/b32588547642e984501c5dfbd4a1e8c204786c20", - "reference": "b32588547642e984501c5dfbd4a1e8c204786c20", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/contracts": "^1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.4", - "symfony/process": "<3.3" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "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": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-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": "2019-02-19T18:29:52+00:00" - }, - { - "name": "symfony/contracts", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/contracts.git", - "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/contracts/zipball/1aa7ab2429c3d594dd70689604b5cf7421254cdf", - "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf", - "shasum": "" - }, - "require": { - "php": "^7.1.3" - }, - "require-dev": { - "psr/cache": "^1.0", - "psr/container": "^1.0" - }, - "suggest": { - "psr/cache": "When using the Cache contracts", - "psr/container": "When using the Service contracts", - "symfony/cache-contracts-implementation": "", - "symfony/service-contracts-implementation": "", - "symfony/translation-contracts-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\": "" - }, - "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": "A set of abstractions extracted out of the Symfony components", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "time": "2018-12-05T08:06:11+00:00" - }, - { - "name": "symfony/css-selector", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "105c98bb0c5d8635bea056135304bd8edcc42b4d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/105c98bb0c5d8635bea056135304bd8edcc42b4d", - "reference": "105c98bb0c5d8635bea056135304bd8edcc42b4d", - "shasum": "" - }, - "require": { - "php": "^7.1.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-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": "2019-01-16T21:53:39+00:00" - }, - { - "name": "symfony/debug", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "4792c7baab24f95e8f0ec2da1145ff025c93cc73" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/4792c7baab24f95e8f0ec2da1145ff025c93cc73", - "reference": "4792c7baab24f95e8f0ec2da1145ff025c93cc73", - "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.3-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": "2019-02-20T23:39:50+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "63dd1cfa74bff0c8ae596fb90a3a4511bd5cb84b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/63dd1cfa74bff0c8ae596fb90a3a4511bd5cb84b", - "reference": "63dd1cfa74bff0c8ae596fb90a3a4511bd5cb84b", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/contracts": "^1.0" - }, - "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.3-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": "2019-01-16T21:53:45+00:00" - }, - { - "name": "symfony/finder", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "7f64183e3ee0cda0644f31ed8f37f01e800af5e8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/7f64183e3ee0cda0644f31ed8f37f01e800af5e8", - "reference": "7f64183e3ee0cda0644f31ed8f37f01e800af5e8", - "shasum": "" - }, - "require": { - "php": "^7.1.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-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": "2019-01-16T21:53:39+00:00" - }, - { - "name": "symfony/http-foundation", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "046265438c0282cc9ac4a7f858b26470ca0f2984" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/046265438c0282cc9ac4a7f858b26470ca0f2984", - "reference": "046265438c0282cc9ac4a7f858b26470ca0f2984", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/mime": "^4.3", - "symfony/polyfill-mbstring": "~1.1" - }, - "require-dev": { - "predis/predis": "~1.0", - "symfony/expression-language": "~3.4|~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-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": "2019-01-29T09:50:57+00:00" - }, - { - "name": "symfony/http-kernel", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "e2a7971b4be1c9b3dfaa24628466ccc90e9231bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e2a7971b4be1c9b3dfaa24628466ccc90e9231bf", - "reference": "e2a7971b4be1c9b3dfaa24628466ccc90e9231bf", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "psr/log": "~1.0", - "symfony/contracts": "^1.0.2", - "symfony/debug": "~3.4|~4.0", - "symfony/event-dispatcher": "~4.1", - "symfony/http-foundation": "^4.1.1", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/config": "<3.4", - "symfony/dependency-injection": "<4.2", - "symfony/translation": "<4.2", - "symfony/var-dumper": "<4.1.1", - "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": "^4.2", - "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": "~4.2", - "symfony/var-dumper": "^4.1.1" - }, - "suggest": { - "symfony/browser-kit": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/var-dumper": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-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": "2019-02-21T09:57:57+00:00" - }, - { - "name": "symfony/mime", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/mime.git", - "reference": "7b7393521d94e7bc4ccd7ea2980320e2ec8b46cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/7b7393521d94e7bc4ccd7ea2980320e2ec8b46cb", - "reference": "7b7393521d94e7bc4ccd7ea2980320e2ec8b46cb", - "shasum": "" - }, - "require": { - "php": "^7.1.3" - }, - "require-dev": { - "symfony/dependency-injection": "~3.4|^4.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Mime\\": "" - }, - "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": "A ", - "homepage": "https://symfony.com", - "keywords": [ - "mime", - "mime-type" - ], - "time": "2019-01-30T07:03:13+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "82ebae02209c21113908c229e9883c419720738a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", - "reference": "82ebae02209c21113908c229e9883c419720738a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "time": "2019-02-06T07:57:58+00:00" - }, - { - "name": "symfony/polyfill-iconv", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "f037ea22acfaee983e271dd9c3b8bb4150bd8ad7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/f037ea22acfaee983e271dd9c3b8bb4150bd8ad7", - "reference": "f037ea22acfaee983e271dd9c3b8bb4150bd8ad7", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-iconv": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Iconv\\": "" - }, - "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 Iconv extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "iconv", - "polyfill", - "portable", - "shim" - ], - "time": "2019-02-06T07:57:58+00:00" - }, - { - "name": "symfony/polyfill-intl-idn", - "version": "v1.10.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "89de1d44f2c059b266f22c9cc9124ddc4cd0987a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/89de1d44f2c059b266f22c9cc9124ddc4cd0987a", - "reference": "89de1d44f2c059b266f22c9cc9124ddc4cd0987a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php72": "^1.9" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, - { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" - } - ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "idn", - "intl", - "polyfill", - "portable", - "shim" - ], - "time": "2018-09-30T16:36:12+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fe5e94c604826c35a32fa832f35bd036b6799609" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609", - "reference": "fe5e94c604826c35a32fa832f35bd036b6799609", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-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": "2019-02-06T07:57:58+00:00" - }, - { - "name": "symfony/polyfill-php72", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/ab50dcf166d5f577978419edd37aa2bb8eabce0c", - "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-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": "2019-02-06T07:57:58+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "d1fb4abcc0c47be136208ad9d68bf59f1ee17abd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/d1fb4abcc0c47be136208ad9d68bf59f1ee17abd", - "reference": "d1fb4abcc0c47be136208ad9d68bf59f1ee17abd", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "time": "2019-02-06T07:57:58+00:00" - }, - { - "name": "symfony/process", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "9a8319d32b6c338826f9181aadfa8865b31ed9f8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/9a8319d32b6c338826f9181aadfa8865b31ed9f8", - "reference": "9a8319d32b6c338826f9181aadfa8865b31ed9f8", - "shasum": "" - }, - "require": { - "php": "^7.1.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-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": "2019-01-24T22:35:38+00:00" - }, - { - "name": "symfony/routing", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/routing.git", - "reference": "1d314e30c738d65bbb64c5cd08c426e8a5a10fb7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/1d314e30c738d65bbb64c5cd08c426e8a5a10fb7", - "reference": "1d314e30c738d65bbb64c5cd08c426e8a5a10fb7", - "shasum": "" - }, - "require": { - "php": "^7.1.3" - }, - "conflict": { - "symfony/config": "<4.2", - "symfony/dependency-injection": "<3.4", - "symfony/yaml": "<3.4" - }, - "require-dev": { - "doctrine/annotations": "~1.0", - "psr/log": "~1.0", - "symfony/config": "~4.2", - "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.3-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": "2019-02-15T14:28:25+00:00" - }, - { - "name": "symfony/translation", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "65d772fd969419e264d1721e7a10f7ccde35c17b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/65d772fd969419e264d1721e7a10f7ccde35c17b", - "reference": "65d772fd969419e264d1721e7a10f7ccde35c17b", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/contracts": "^1.0.2", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/config": "<3.4", - "symfony/dependency-injection": "<3.4", - "symfony/yaml": "<3.4" - }, - "provide": { - "symfony/translation-contracts-implementation": "1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/console": "~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.3-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": "2019-02-19T18:29:52+00:00" - }, - { - "name": "symfony/var-dumper", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "1c4cb1b574ffe75c33c6c2f2cc71840155dd36f8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1c4cb1b574ffe75c33c6c2f2cc71840155dd36f8", - "reference": "1c4cb1b574ffe75c33c6c2f2cc71840155dd36f8", - "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", - "symfony/console": "<3.4" - }, - "require-dev": { - "ext-iconv": "*", - "symfony/console": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0", - "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", - "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" - }, - "bin": [ - "Resources/bin/var-dump-server" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-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": "2019-02-19T21:52:41+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": "dev-master", - "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": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "1ee9369cfbf26cfcf1f2515d98f15fab54e9647a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1ee9369cfbf26cfcf1f2515d98f15fab54e9647a", - "reference": "1ee9369cfbf26cfcf1f2515d98f15fab54e9647a", - "shasum": "" - }, - "require": { - "php": "^5.4 || ^7.0", - "phpoption/phpoption": "^1.5", - "symfony/polyfill-ctype": "^1.9" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.3-dev" - } - }, - "autoload": { - "psr-4": { - "Dotenv\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "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": "2019-01-30T10:43:17+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0", - "symfony/polyfill-ctype": "^1.8" - }, - "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-12-25T11:19:39+00:00" - } - ], - "aliases": [], - "minimum-stability": "dev", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.4.0" - }, - "platform-dev": [] -} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..bdd211d --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,30 @@ + + + + + src/ + + + + + ./tests + + + + + + + diff --git a/src/BaseGridQuery.php b/src/BaseGridQuery.php deleted file mode 100644 index 513900b..0000000 --- a/src/BaseGridQuery.php +++ /dev/null @@ -1,200 +0,0 @@ -query ?? $this->query = $this->initQuery(); - } - - /** - * Return the final query of this gridQuery. - * By default context, we can call selectColumns() to return the query with its selected columns - * to treat them as the final query. - * - * @return \Illuminate\Database\Eloquent\Builder - */ - public function makeQuery() - { - return $this->selectColumns(); - } - - /** - * Return the query from the query() method with its select statement from the columns() method. - * - * @return \Illuminate\Database\Eloquent\Builder - */ - public function selectColumns() - { - return $this->query()->select($this->makeSelect($this->columns())); - } - - /** - * Create an array of select parameters that can be passed in $query->select(). - * String indexed columns will be transformed to have an alias like "column_key as as actual_column". - * - * @param array|null $columns - * @return array - */ - public function makeSelect(array $columns = null) - { - $columns = $columns ?: $this->columns(); - $selects = []; - - foreach ($columns as $key => $select) { - if (is_int($key)) { - $selects[] = $select; - } else { - $selects[] = DB::raw($select.' as '.$key); - } - } - - return $selects; - } - - /** - * Set the query. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return $this - */ - public function setQuery($query) - { - $this->query = $query; - - return $this; - } - - /** - * Set the columns of this gridQuery instance of the grid to the given query's select clause. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder - */ - public function setSelectQuery($query) - { - return $query->select($this->makeSelect($this->columns())); - } - - /** - * Get the actual column of the given column key. - * - * @param string $columnKey - * @return string|mixed - */ - public function getColumn($columnKey) - { - return $this->findColumn($this->columns(), $columnKey); - - } - - /** - * Find the column from columns. - * - * @param string $columns - * @param string $columnKey - * @return string - */ - public function findColumn($columns, $columnKey) - { - if (array_key_exists($columnKey, $columns)) { - return $columns[$columnKey]; - } - - foreach ($columns as $column) { - if ($column === $columnKey || ends_with($column, ".{$columnKey}")) { - return $column; - } - } - } - - /** - * Get the actual columns of the given column keys. - * - * @param array $columnKeys - * @return array - */ - public function getColumns(array $columnKeys) - { - $columns = []; - - foreach ($columnKeys as $columnKey) { - $columns[] = $this->getColumn($columnKey); - } - - return $columns; - } - - /** - * Getter for column. - * - * @param string $columnKey - * @return string|mixed - */ - public function __get($columnKey) - { - return $this->getColumn($columnKey); - } - - /** - * Handle dynamic calls on query. - * - * @param string $method - * @param array $parameters - * @return $this - */ - public function __call($method, $parameters) - { - if (!$this->query) { - throw new \Exception("Property \$query is not set. Cannot call method {$method} on object of ".static::class.'.'); - } - - call_user_func_array([$this->query, $method], $parameters); - - return $this; - } - - /** - * Initialize query. - * - * @return \Illuminate\Database\Eloquent\Builder - */ - public function initQuery() - { - throw new \Exception('Please create self initQuery() method on '.get_class($this).'.'); - } - - /** - * Columns declaration of the report grid. - * - * @return array - */ - abstract public function columns(); - - /** - * Return new instance. - * - * @return static - */ - public static function make() - { - return new static; - } -} diff --git a/src/BaseSearch.php b/src/BaseSearch.php new file mode 100644 index 0000000..def07fb --- /dev/null +++ b/src/BaseSearch.php @@ -0,0 +1,163 @@ +columns = $columns; + } + + public static function make(Columns $columns) + { + return new static($columns); + } + + /** + * Apply a search query. + * + * @param string $searchStr + * @return \Illuminate\Database\Eloquent\Builder + */ + public function search($searchStr) + { + $this->searchStr = $searchStr; + $columnsToCompare = $this->columnsToCompare(); + $conditions = []; + $query = $this->query; + + if (count($columnsToCompare) === 0) { + return $query; + } + + $parsedStr = $this->parseSearchStr($searchStr); + + foreach ($columnsToCompare as $column) { + $conditions[] = $column . ' like "' . $parsedStr . '"'; + } + + $method = $this->searchOperator . 'Raw'; + $query->{$method}('(' . join(' OR ', $conditions) . ')'); + + return $query; + } + + /** + * Parse string to search. + * + * @param string|mixed $searchStr + * @return string + */ + protected function parseSearchStr($searchStr) + { + return $this->getDefaultParser()->parse($searchStr); + } + + /** + * Get default search string parser. + * + * @return \AjCastro\Searchable\Search\ParserInterface + */ + public function getDefaultParser(): ParserInterface + { + if (isset($this->defaultParser)) { + return $this->defaultParser; + } + + return new FuzzySearch; + } + + /** + * Set a custom search string parser via callback + * + * @param callable $callback + * @return $this + */ + public function parseUsing(callable $callback) + { + $this->defaultParser = new CustomSearch($callback); + + return $this; + } + + /** + * Set query. + * + * @param Builder $query + * @return $this + */ + public function setQuery(Builder $query) + { + $this->query = $query; + + return $this; + } + + /** + * Set search operator. + * + * @param string $searchOperator + * @return $this + */ + public function setSearchOperator($searchOperator) + { + $this->searchOperator = $searchOperator; + + return $this; + } + + /** + * Return the searchable columns to compare, actual columns for `where` operator and alias column names for `having` operator. + * + * @return array + */ + public function columnsToCompare() + { + return $this->searchOperator === 'having' ? $this->columns->keys() : $this->columns->actual(); + } + + /** + * Return the search string. + * + * @return string + */ + public function getSearchStr() + { + return $this->searchStr; + } +} diff --git a/src/BaseSearchQuery.php b/src/BaseSearchQuery.php deleted file mode 100644 index e00867a..0000000 --- a/src/BaseSearchQuery.php +++ /dev/null @@ -1,133 +0,0 @@ -searcher()->search($this->searchStr = $searchStr); - } - - /** - * Return a searcher, the search query logic and algorithm. - * - * @return mixed - */ - public function searcher() - { - return new SublimeSearch( - $this->query(), - $this->columns(), - $this->sort, - $this->searchOperator - ); - } - - /** - * Return the columns for sorting query. - * - * @return array - */ - protected function sortColumns() - { - return $this->columns(); - } - - /** - * Set search operator. - * - * @param string $searchOperator - * @return $this - */ - public function setSearchOperator($searchOperator) - { - $this->searchOperator = $searchOperator; - - return $this; - } - - /** - * Alias of sortByRelevance. - * - * @param bool $bool - * @return $this - */ - public function sort($sort = true) - { - return $this->sortByRelevance($sort); - } - - /** - * Set sort boolean. - * - * @param bool $bool - * @return $this - */ - public function sortByRelevance($sort = true) - { - $this->sort = $sort; - - return $this; - } - - /** - * Whether this search query should sort by relevance with key of `sort_index`. - * - * @return boolean - */ - public function shouldSortByRelevance() - { - return $this->sort; - } - - /** - * Apply sorting query by relevance to the search. - * By default using mysql locate function. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param string $searchStr - * @return \Illuminate\Database\Eloquent\Builder - */ - public function applySortByRelevance() - { - if (!method_exists($this, 'sortColumns')) { - throw new \Exception("Sort by relevance requires sortColumns() method."); - } - - SortByRelevance::sort($this->query, $this->sortColumns(), $this->searchStr); - } -} diff --git a/src/Columns.php b/src/Columns.php new file mode 100644 index 0000000..59d3f5a --- /dev/null +++ b/src/Columns.php @@ -0,0 +1,150 @@ + 'authors.name', + * 'authors.age as author_age', + * ] + * + * @var array + */ + protected array $columns; + + protected array $selects = []; + protected array $actual = []; + protected array $keys = []; + protected array $cache; + + public function __construct(array $columns) + { + $this->columns = $columns; + } + + public static function make(array $columns) + { + return new static($columns); + } + + /** + * Find the real actual column representing the column in the database table. + * + * @param string $key + * @return mixed + */ + public function find($key) + { + if (array_key_exists($key, $this->columns)) { + return $this->columns[$key]; + } + + if ($this->cache[$key] ?? null) { + return $this->cache[$key]; + } + + foreach ($this->columns as $column) { + if ($column === $key || Str::endsWith($column, ".{$key}")) { + return $this->cache[$key] = $column; + } + + if (Str::endsWith($column, " as {$key}")) { + return $this->cache[$key] = str_replace(" as {$key}", '', $column); + } + } + } + + /** + * Return the columns as a valid select array for query builder's select() method. + */ + public function selects(): array + { + if (!empty($this->selects)) return $this->selects; + + foreach ($this->columns as $key => $select) { + if (is_string($key)) { + $select = $select . ' as ' . $key; + } + if (Str::contains($select, ' as ')) { + $select = DB::raw($select); + } + $this->selects[] = $select; + } + + return $this->selects; + } + + /** + * Get the actual columns that are in the database table. + * + * @return array + */ + public function actual(): array + { + if (! empty($this->actual)) return $this->actual; + + foreach ($this->selects() as $select) { + $this->actual[] = static::extractActualFromSelect($select); + } + + return $this->actual; + } + + /** + * Return the valid column keys which can be used as reference name for query sort. + * + * @return array + */ + public function keys(): array + { + if (! empty($this->keys)) return $this->keys; + + foreach ($this->selects() as $select) { + $this->keys[] = static::extractKeyFromSelect($select); + } + + return $this->keys; + } + + public static function extractKeyFromSelect(string $select): string + { + if (Str::contains($select, ' as ')) { + [$rawSelect, $alias] = explode(' as ', $select); + return $alias; + } + + if (Str::contains($select, '.')) { + [$table, $column] = explode('.', $select); + return $column; + } + + return $select; + } + + public static function extractActualFromSelect(string $select): string + { + if (Str::contains($select, ' as ')) { + [$rawSelect, $alias] = explode(' as ', $select); + return $rawSelect; + } + + return $select; + } + + public function __get($key) + { + return $this->find($key); + } +} + + diff --git a/src/GridQueryInterface.php b/src/GridQueryInterface.php deleted file mode 100644 index 93d6704..0000000 --- a/src/GridQueryInterface.php +++ /dev/null @@ -1,20 +0,0 @@ -query = $query; - $this->columns = $columns; - $this->sort = $sort; - $this->searchOperator = $searchOperator; - } - - /** - * Get the actual searchable column of the given column key. - * - * @param string $columnKey - * @return string|mixed - */ - public function getColumn($columnKey) - { - return $this->findColumn($this->columnsToCompare(), $columnKey); - } - - /** - * Return the searchable columns to compare, actual columns for `where` operator and alias column names for `having` operator. - * - * @return array - */ - public function columnsToCompare() - { - return $this->searchOperator === 'having' ? $this->columnKeys() : $this->columns(); - } - - /** - * Get the keys of columns to be used in the query result. - * - * @return array - */ - public function columnKeys() - { - $columnKeys = []; - - foreach ($this->columns() as $key => $column) { - if (is_string($key)) { - $columnKeys[] = $key; - } elseif (str_contains($column, '.')) { - list($table, $columnKey) = explode('.', $column); - $columnKeys[] = $columnKey; - } else { - $columnKeys[] = $column; - } - } - - return $columnKeys; - } - - /** - * Apply search query. - * - * @param string|mixed $searchStr - * @return \Illuminate\Database\Eloquent\Builder - */ - public function search($searchStr) - { - $conditions = []; - - $parsedStr = $this->parseSearchStr($this->searchStr = $searchStr); - - foreach ($this->columnsToCompare() as $column) { - $conditions[] = $column.' like "'.$parsedStr.'"'; - } - - $method = $this->searchOperator.'Raw'; - $query = $this->query()->{$method}('('.join(' OR ', $conditions).')'); - - if ($this->shouldSortByRelevance()) { - $this->applySortByRelevance(); - } - - return $query; - } - - /** - * Parse string to search. - * - * @param string|mixed $searchStr - * @return string - */ - protected function parseSearchStr($searchStr) - { - $searchStr = preg_replace('/[^A-Za-z0-9]/', '', $searchStr); - - return '%'.join('%', str_split($searchStr)).'%'; - } - - /** - * Return the columns for sorting query. - * - * @return array - */ - public function columns() - { - return $this->columns; - } -} diff --git a/src/SearchParsers/CustomSearch.php b/src/SearchParsers/CustomSearch.php new file mode 100644 index 0000000..ba34e07 --- /dev/null +++ b/src/SearchParsers/CustomSearch.php @@ -0,0 +1,18 @@ +callback = $callback; + } + + public function parse($searchStr) + { + return ($this->callback)($searchStr); + } +} diff --git a/src/SearchParsers/FuzzySearch.php b/src/SearchParsers/FuzzySearch.php new file mode 100644 index 0000000..7814ac5 --- /dev/null +++ b/src/SearchParsers/FuzzySearch.php @@ -0,0 +1,13 @@ +searchableColumns; - } - - if (property_exists($this, 'searchable') && array_key_exists('columns', $this->searchable)) { - return $this->searchable['columns']; - } - - return static::getTableColumns($this->getTable()); - } - - /** - * Get table columns. - * - * @param string $table - * @return array - */ - public static function getTableColumns($table = null) - { - $table = $table ?? (new static)->getTable(); - - if (!Arr::has(static::$allSearchableColumns, $table)) { - static::$allSearchableColumns[$table] = Schema::getColumnListing($table); - } - - return static::$allSearchableColumns[$table]; - } - - /** - * Identifies if the column is a valid column, either a regular table column or derived column. - * Useful for checking valid columns to avoid sql injection especially in orderBy query. - * - * @param string $column - * @return boolean - */ - public static function isColumnValid($column) - { - $model = new static; - $searchableColumns = $model->searchableColumns(); - - // Derived columns are a key in searchableColumns. - if (array_key_exists($column, $searchableColumns)) { - return true; - } - - // Regular table column can be included in the searchableColumns. - if (in_array($column, $searchableColumns)) { - return true; - } - - // Regular table column from the table - return in_array($column, static::getTableColumns($model->getTable())); - } - - /** - * Return the searchable joins for the search query. - * - * @return array - */ - public function searchableJoins() - { - if (property_exists($this, 'searchableJoins')) { - return $this->searchableJoins; - } - - if (property_exists($this, 'searchable') && array_key_exists('joins', $this->searchable)) { - return $this->searchable['joins']; - } - - return []; - } - /** * Apply searchable joins for the search query. * - * @param $query + * @param \Illuminate\Database\Eloquent\Builder $query * @return void */ protected function applySearchableJoins($query) { foreach ($this->searchableJoins() as $table => $join) { - $query->leftJoin($table, $join[0], '=', $join[1]); + $joinMethod = $join[2] ?? 'leftJoin'; + $query->{$joinMethod}($table, $join[0], '=', $join[1]); } } /** * Return the search query. * - * @return mixed|\AjCastro\Searchable\Search\SublimeSearch + * @return \AjCastro\Searchable\BaseSearch */ - public function searchQuery() + public function searchQuery(): BaseSearch { if ($this->searchQuery) { return $this->searchQuery; @@ -121,15 +43,15 @@ public function searchQuery() return $this->searchQuery = $this->defaultSearchQuery(); } - return $this->searchQuery = new SublimeSearch($this, $this->searchableColumns(), $this->sortByRelevance, 'where'); + return $this->searchQuery = new BaseSearch($this->buildSearchableColumns()); } /** * Set the model's search query. * - * @param \AjCastro\Searchable\BaseSearchQuery $searchQuery + * @param \AjCastro\Searchable\BaseSearch $searchQuery */ - public function setSearchQuery($searchQuery) + public function setSearchQuery(BaseSearch $searchQuery) { $this->searchQuery = $searchQuery; @@ -137,169 +59,76 @@ public function setSearchQuery($searchQuery) } /** - * Apply search in the query. - * - * @param query $query - * @param string $search - * - * @return void - */ - public function scopeSearch($query, $search) - { - $this->applySearchableJoins($query); - - $query->select($this->getTable().'.*'); - - $this->searchQuery()->setQuery($query)->search($search); - } - - /** - * Scope query to set $sortByRelevance. - * @param \Illuminate\Database\Eloquent\Builder $query - * @param boolean $sortByRelevance - * @return void - */ - public function scopeSortByRelevance($query, $sortByRelevance = true) - { - $query->getModel()->searchableSortByRelevance($sortByRelevance); - } - - /** - * Set model's $sortByRelevance for searchable query. + * Disable searchable in the model. * - * @param boolean $sortByRelevance * @return $this */ - public function searchableSortByRelevance($sortByRelevance = true) + public function disableSearchable() { - $this->sortByRelevance = $sortByRelevance; - - $this->searchQuery()->sortByRelevance($sortByRelevance); + $this->searchableEnabled = false; return $this; } /** - * If model should sort by relevance. + * Enable searchable in the model. * - * @return bool - */ - public function shouldSortByRelevance() - { - return $this->sortByRelevance; - } - - /** - * Set $searchable. - * - * @param array $config - * @return $this + * @return $this */ - public function setSearchable($config) + public function enableSearchable() { - if ($columns = array_get($config, 'columns')) { - $this->setSearchableColumns($columns); - } - - if ($joins = array_get($config, 'joins')) { - $this->setSearchableJoins($joins); - } + $this->searchableEnabled = true; return $this; } /** - * Set searchable columns. + * Apply search in the query. * - * @param array $columns - * @return $this - */ - public function setSearchableColumns($columns) - { - if (property_exists($this, 'searchableColumns')) { - $this->searchableColumns = $columns; - } - - if (property_exists($this, 'searchable')) { - $this->searchable['columns'] = $columns; - } - - return $this; - } - - /** - * Set searchable joins. + * @param \Illuminate\Database\Eloquent\Builder $query + * @param string $search * - * @param array $joins - * @return $this + * @return void */ - public function setSearchableJoins($joins) + public function scopeSearch($query, $search) { - if (property_exists($this, 'searchableJoins')) { - $this->searchableJoins = $joins; - } - - if (property_exists($this, 'searchable')) { - $this->searchable['joins'] = $joins; + if (!$this->searchableEnabled) { + return; } - return $this; - } - - /** - * Add searchable. - * - * @param array $config - * @return $this - */ - public function addSearchable($config) - { - if ($columns = array_get($config, 'columns')) { - $this->addSearchableColumns($columns); - } + $this->applySearchableJoins($query); - if ($joins = array_get($config, 'joins')) { - $this->addSearchableJoins($joins); + if (empty($query->getQuery()->columns)) { + $query->select([$query->getQuery()->from.'.*']); } - return $this; + $query->getModel()->searchQuery()->setQuery($query)->search($search); } /** - * Add searchable columns. - * - * @param array $config - * @return $this + * Scope query to set $sortByRelevance. + * @param \Illuminate\Database\Eloquent\Builder $query + * @param boolean $sortByRelevance + * @return void */ - public function addSearchableColumns($columns) + public function scopeSortByRelevance($query, $sortByRelevance = true) { - if (property_exists($this, 'searchableColumns')) { - $this->searchableColumns = $columns + $this->searchableColumns; - } - - if (property_exists($this, 'searchable')) { - $this->searchable['columns'] = $columns + $this->searchable['columns']; - } - - return $this; + $sortByRelevance && SortByRelevance::sort( + $query, + $this->buildSearchableColumns()->actual(), + $query->getModel()->searchQuery()->getSearchStr() + ); } /** - * Add searchable joins. + * Override search string parser * - * @param array $config - * @return $this + * @param \Illuminate\Database\Eloquent\Builder $query + * @param callable $parser + * @return void */ - public function addSearchableJoins($joins) + public function scopeParseUsing($query, callable $parser) { - if (property_exists($this, 'searchableJoins')) { - $this->searchableJoins = $joins + $this->searchableJoins; - } - - if (property_exists($this, 'searchable')) { - $this->searchable['joins'] = $joins + $this->searchable['joins']; - } - - return $this; + $query->getModel()->searchQuery()->parseUsing($parser); } } diff --git a/src/TableColumns.php b/src/TableColumns.php new file mode 100644 index 0000000..9ded4fd --- /dev/null +++ b/src/TableColumns.php @@ -0,0 +1,26 @@ +searchableColumns; + } + + if (property_exists($this, 'searchable') && array_key_exists('columns', $this->searchable)) { + return $this->searchable['columns']; + } + + return TableColumns::get($this->getTable()); + } + + /** + * Return the sortable columns for this model's table. + * + * @return array + */ + public function sortableColumns() + { + if (property_exists($this, 'sortableColumns')) { + return $this->sortableColumns; + } + + if (property_exists($this, 'searchable') && array_key_exists('sortable_columns', $this->searchable)) { + return $this->searchable['sortable_columns']; + } + + return TableColumns::get($this->getTable()); + } + + /** + * Identifies if the column is a valid column, either a regular table column or derived column. + * Useful for checking valid columns to avoid sql injection especially in orderBy query. + * + * @param string $column + * @return boolean + */ + public function isColumnValid($column) + { + return (bool) $this->buildAllColumns()->find($column); + } + + + /** + * Build columns from both searchable and sortable columns + */ + public function buildAllColumns(): Columns + { + return Columns::make(array_merge($this->searchableColumns(), $this->sortableColumns())); + } + + /** + * Build columns from searchable + */ + public function buildSearchableColumns(): Columns + { + return Columns::make($this->searchableColumns()); + } + + /** + * Build columns from sortable + */ + public function buildSortableColumns(): Columns + { + return Columns::make($this->sortableColumns()); + } + + /** + * Get the actual column from both searchable and sortable columns + * + * @param string $column + * @return void + */ + public function getColumn($column) + { + return $this->buildAllColumns()->find($column); + } + + /** + * Get the actual sortable column. + * + * @param string $column + * @return string|mixed + */ + public function getSearchableColumn($column) + { + return $this->buildSearchableColumns()->find($column); + } + + /** + * Get the actual sortable column. + * + * @param string $column + * @return string|mixed + */ + public function getSortableColumn($column) + { + return $this->buildSortableColumns()->find($column); + } + + /** + * Return the searchable joins for the search query. + * + * @return array + */ + public function searchableJoins() + { + if (property_exists($this, 'searchableJoins')) { + return $this->searchableJoins; + } + + if (property_exists($this, 'searchable') && array_key_exists('joins', $this->searchable)) { + return $this->searchable['joins']; + } + + return []; + } + + /** + * Set $searchable. + * + * @param array $config + * @return $this + */ + public function setSearchable($config) + { + $this->setSearchableColumns(Arr::get($config, 'columns')); + $this->setSearchableJoins(Arr::get($config, 'joins')); + $this->setSortableColumns(Arr::get($config, 'sortable_columns')); + + return $this; + } + + /** + * Set searchable columns. + * + * @param array $columns + * @return $this + */ + public function setSearchableColumns($columns) + { + if (property_exists($this, 'searchableColumns')) { + $this->searchableColumns = $columns ?? []; + } + + if (property_exists($this, 'searchable')) { + $this->searchable['columns'] = $columns ?? []; + } + + return $this; + } + + /** + * Set searchable joins. + * + * @param array $joins + * @return $this + */ + public function setSearchableJoins($joins) + { + if (property_exists($this, 'searchableJoins')) { + $this->searchableJoins = $joins ?? []; + } + + if (property_exists($this, 'searchable')) { + $this->searchable['joins'] = $joins ?? []; + } + + return $this; + } + + /** + * Set sortable columns. + * + * @param array $columns + * @return $this + */ + public function setSortableColumns($columns) + { + if (property_exists($this, 'sortableColumns')) { + $this->sortableColumns = $columns ?? []; + } + + if (property_exists($this, 'searchable')) { + $this->searchable['sortable_columns'] = $columns ?? []; + } + + return $this; + } + + /** + * Add searchable. + * + * @param array $config + * @return $this + */ + public function addSearchable($config) + { + if ($columns = Arr::get($config, 'columns')) { + $this->addSearchableColumns($columns); + } + + if ($columns = Arr::get($config, 'sortable_columns')) { + $this->addSortableColumns($columns); + } + + if ($joins = Arr::get($config, 'joins')) { + $this->addSearchableJoins($joins); + } + + return $this; + } + + /** + * Add searchable columns. + * + * @param array $columns + * @return $this + */ + public function addSearchableColumns($columns) + { + if (property_exists($this, 'searchableColumns')) { + $this->searchableColumns = array_merge($this->searchableColumns, $columns); + } + + if (property_exists($this, 'searchable')) { + $this->searchable['columns'] = array_merge($this->searchable['columns'], $columns); + } + + return $this; + } + + /** + * Add searchable joins. + * + * @param array $joins + * @return $this + */ + public function addSearchableJoins($joins) + { + if (property_exists($this, 'searchableJoins')) { + $this->searchableJoins = array_merge($this->searchableJoins, $joins); + } + + if (property_exists($this, 'searchable')) { + $this->searchable['joins'] = array_merge($this->searchable['joins'], $joins); + } + + return $this; + } + + /** + * Add sortable columns. + * + * @param array $columns + * @return $this + */ + public function addSortableColumns($columns) + { + if (property_exists($this, 'sortableColumns')) { + $this->sortableColumns = array_merge($this->sortableColumns, $columns); + } + + if (property_exists($this, 'searchable')) { + $this->searchable['sortable_columns'] = array_merge($this->searchable['sortable_columns'], $columns); + } + + return $this; + } +} diff --git a/tests/BaseSearchTest.php b/tests/BaseSearchTest.php new file mode 100644 index 0000000..85dcac1 --- /dev/null +++ b/tests/BaseSearchTest.php @@ -0,0 +1,57 @@ +search = BaseSearch::make( + Columns::make([ + 'posts.title', + 'description', + 'author_name' => 'authors.name', + 'authors.age as author_age', + ]), + ) + ->setQuery(Post::query()); + } + + public function test_can_initialize_base_search_and_perform_a_search() + { + $this->assertInstanceOf(BaseSearch::class, $this->search); + $sql = $this->search->search('My Daily Posts')->toSql(); + $this->assertTrue(is_string($sql)); // we just check if it parse successfully + } + + public function test_columns_to_compare_using_where() + { + $this->assertEquals([ + 'posts.title', + 'description', + 'authors.name', + 'authors.age', + ], $this->search->columnsToCompare()); + } + + public function test_columns_to_compare_using_having() + { + $this->search->setSearchOperator('having'); + + $this->assertEquals([ + 'title', + 'description', + 'author_name', + 'author_age', + ], $this->search->columnsToCompare()); + } +} diff --git a/tests/ColumnsTest.php b/tests/ColumnsTest.php new file mode 100644 index 0000000..b5c313e --- /dev/null +++ b/tests/ColumnsTest.php @@ -0,0 +1,78 @@ +columns = Columns::make([ + 'posts.title', + 'description', + 'author_name' => 'authors.name', + 'authors.age as author_age', + ]); + } + + public function test_find_can_return_the_actual_column() + { + $this->assertEquals('posts.title', $this->columns->title); + $this->assertEquals('description', $this->columns->description); + $this->assertEquals('authors.name', $this->columns->author_name); + $this->assertEquals('authors.age', $this->columns->author_age); + } + + public function test_selects_can_return_correct_select() + { + $asserts = [ + 'posts.title', + 'description', + 'authors.name as author_name', + 'authors.age as author_age', + ]; + + $selects = $this->columns->selects(); + + foreach ($asserts as $index => $assert) { + $this->assertEquals($assert, $selects[$index]); + } + } + + public function test_keys_should_return_correct_keys() + { + $asserts = [ + 'title', + 'description', + 'author_name', + 'author_age', + ]; + + $keys = $this->columns->keys(); + + foreach ($asserts as $index => $assert) { + $this->assertEquals($assert, $keys[$index]); + } + } + + public function test_actual_should_return_correct_actual_columns() + { + $asserts = [ + 'posts.title', + 'description', + 'authors.name', + 'authors.age', + ]; + + $keys = $this->columns->actual(); + + foreach ($asserts as $index => $assert) { + $this->assertEquals($assert, $keys[$index]); + } + } +} diff --git a/tests/Stubs/Post.php b/tests/Stubs/Post.php new file mode 100644 index 0000000..d7a8acf --- /dev/null +++ b/tests/Stubs/Post.php @@ -0,0 +1,12 @@ +setSearchable([ + 'columns' => [ + 'posts.title', + 'description', + 'author_name' => 'authors.name', + 'authors.age as author_age', + ], + ]); + } + + private function postWithSortableColumns() + { + return Post::make()->setSearchable([ + 'sortable_columns' => [ + 'posts.title', + 'description', + 'author_name' => 'authors.name', + 'authors.age as author_age', + ], + ]); + } + + private function assertGetColumn(Post $post) + { + $this->assertEquals('posts.title', $post->getColumn('title')); + $this->assertEquals('description', $post->getColumn('description')); + $this->assertEquals('authors.name', $post->getColumn('author_name')); + $this->assertEquals('authors.age', $post->getColumn('author_age')); + } + + private function assertIsColumnValid(Post $post) + { + $this->assertTrue($post->isColumnValid('title')); + $this->assertTrue($post->isColumnValid('description')); + $this->assertTrue($post->isColumnValid('author_name')); + $this->assertTrue($post->isColumnValid('author_age')); + + $this->assertFalse($post->isColumnValid('title_x')); + $this->assertFalse($post->isColumnValid('description_x')); + $this->assertFalse($post->isColumnValid('author_name_x')); + $this->assertFalse($post->isColumnValid('author_age_x')); + } + + public function test_Searchable_getColumn_from_searchable_columns() + { + $post = $this->postWithSearchableColumns(); + $this->assertGetColumn($post); + } + + public function test_Searchable_isColumnValid_from_searchable_columns() + { + $post = $this->postWithSearchableColumns(); + $this->assertIsColumnValid($post); + } + public function test_Searchable_getColumn_from_sortable_columns() + { + $post = $this->postWithSortableColumns(); + $this->assertGetColumn($post); + } + + public function test_Searchable_isColumnValid_from_sortable_columns() + { + $post = $this->postWithSortableColumns(); + $this->assertIsColumnValid($post); + } +}