From 9b419f20fb74396f4761f9fc7a8b13b826854fca Mon Sep 17 00:00:00 2001 From: Veselov Pavel Date: Mon, 5 Aug 2019 15:10:43 +0300 Subject: [PATCH] Travis Matrix Test + jobs for other platforms (#20) Testing via Matrix Jobs (for merging coverage from different jobs) added jobs for testing PHP 7.2, 7.3, 7.4 added jobs for testing PostgreSQL 9.2, 9.3, 9.4, 9.5, 9.6, 10.0, 11.0 New features in Blueprint: added auto-convert values with USING after ALTER COLUMN CHANGE TYPE added support method: ->using() for converting values between different types added support Expression for default values: ->default(new Expression('')) Resolved issues: #8, #10 --- .travis.yml | 120 +- README.md | 18 +- composer.json | 2 + composer.lock | 1510 +++++++++++++---- ecs.yml | 4 - phpunit.travis.xml | 31 + phpunit.xml.dist | 15 +- src/.meta.php | 9 +- src/Extensions/AbstractComponent.php | 3 - src/PostgresConnection.php | 27 +- src/Schema/Blueprint.php | 42 - src/Schema/Grammars/PostgresGrammar.php | 21 - ...SchemaAlterTableChangeColumnSubscriber.php | 233 +++ tests.sh | 5 + tests/Functional/FunctionalTestCase.php | 31 - tests/Functional/HasIndexTest.php | 42 - tests/Functional/Helpers/ColumnAssertions.php | 72 + tests/Functional/Helpers/IndexAssertions.php | 41 + tests/Functional/Helpers/TableAssertions.php | 36 + tests/Functional/Helpers/ViewAssertions.php | 40 + .../CreateIndexTest.php} | 82 +- .../CreateTableTest.php} | 32 +- .../CreateViewTest.php} | 33 +- .../ChangeColumnSubscriberTest.php | 346 ++++ tests/FunctionalTestCase.php | 49 + tests/TestCase.php | 2 +- .../Unit/Extensions/AbstractExtensionTest.php | 65 + tests/Unit/Helpers/BlueprintAssertions.php | 51 + .../PartitionTest.php} | 37 +- tests/Unit/Schema/Grammars/GrammarTest.php | 46 - tests/Unit/Schema/IndexTest.php | 42 - tests/travis/install-postgres-10.sh | 13 + tests/travis/install-postgres-11.sh | 12 + 33 files changed, 2457 insertions(+), 655 deletions(-) create mode 100644 phpunit.travis.xml create mode 100644 src/Schema/Subscribers/SchemaAlterTableChangeColumnSubscriber.php create mode 100755 tests.sh delete mode 100644 tests/Functional/FunctionalTestCase.php delete mode 100644 tests/Functional/HasIndexTest.php create mode 100644 tests/Functional/Helpers/ColumnAssertions.php create mode 100644 tests/Functional/Helpers/IndexAssertions.php create mode 100644 tests/Functional/Helpers/TableAssertions.php create mode 100644 tests/Functional/Helpers/ViewAssertions.php rename tests/Functional/{UniqueIndexTest.php => Schema/CreateIndexTest.php} (59%) rename tests/Functional/{SchemaTest.php => Schema/CreateTableTest.php} (53%) rename tests/Functional/{ViewTest.php => Schema/CreateViewTest.php} (51%) create mode 100644 tests/Functional/Subscribers/ChangeColumnSubscriberTest.php create mode 100644 tests/FunctionalTestCase.php create mode 100644 tests/Unit/Extensions/AbstractExtensionTest.php create mode 100644 tests/Unit/Helpers/BlueprintAssertions.php rename tests/Unit/Schema/{BlueprintTest.php => Blueprint/PartitionTest.php} (73%) delete mode 100644 tests/Unit/Schema/Grammars/GrammarTest.php delete mode 100644 tests/Unit/Schema/IndexTest.php create mode 100755 tests/travis/install-postgres-10.sh create mode 100755 tests/travis/install-postgres-11.sh diff --git a/.travis.yml b/.travis.yml index 883da78..49767e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,23 +1,117 @@ language: php +sudo: false +dist: trusty -php: - - 7.2 +cache: + directories: + - vendor + - $HOME/.composer/cache -services: - - postgresql - -matrix: - fast_finish: true +before_install: + - phpenv config-rm xdebug.ini || true + - | + if [ "x$COVERAGE" == "xyes" ]; then + pecl install pcov-1.0.0 + fi install: - - composer install - -before_script: - - psql -c 'create database testing;' -U postgres + - rm composer.lock + - travis_retry composer -n update --prefer-dist script: - vendor/bin/ecs check --config=ecs.yml . - - phpdbg -qrr vendor/bin/phpunit --coverage-clover build/logs/clover.xml + - | + if [ "x$DOCKER_POSTGRES" == "xyes" ]; then + sudo docker exec -ti postgres11 psql postgres -U postgres -c "CREATE DATABASE testing" + else + psql -c 'CREATE DATABASE testing;' -U postgres + fi + - | + if [ "x$COVERAGE" == "xyes" ]; then + ./vendor/bin/phpunit --configuration phpunit.travis.xml --coverage-clover build/logs/clover.xml + else + ./vendor/bin/phpunit --configuration phpunit.travis.xml + fi after_success: - - travis_retry vendor/bin/php-coveralls -v + - | + if [ "x$COVERAGE" == "xyes" ]; then + travis_retry vendor/bin/php-coveralls -v + fi + +matrix: + fast_finish: true + allow_failures: + - php: "7.4snapshot" + include: + - stage: Test + php: "7.2" + env: DB=pgsql POSTGRESQL_VERSION=11.0 + sudo: required + services: + - docker + - stage: Test + php: "7.3" + env: DB=pgsql POSTGRESQL_VERSION=9.2 COVERAGE=yes + services: + - postgresql + addons: + postgresql: "9.2" + - stage: Test + php: "7.3" + env: DB=pgsql POSTGRESQL_VERSION=9.3 COVERAGE=yes + services: + - postgresql + addons: + postgresql: "9.3" + - stage: Test + php: "7.3" + env: DB=pgsql POSTGRESQL_VERSION=9.4 COVERAGE=yes + services: + - postgresql + addons: + postgresql: "9.4" + - stage: Test + php: "7.3" + env: DB=pgsql POSTGRESQL_VERSION=9.5 COVERAGE=yes + services: + - postgresql + addons: + postgresql: "9.5" + - stage: Test + php: "7.3" + env: DB=pgsql POSTGRESQL_VERSION=9.6 COVERAGE=yes + services: + - postgresql + addons: + postgresql: "9.6" + - stage: Test + php: "7.3" + env: DB=pgsql POSTGRESQL_VERSION=10.0 COVERAGE=yes + sudo: required + services: + - postgresql + addons: + postgresql: "9.6" + before_script: + - bash ./tests/travis/install-postgres-10.sh + - stage: Test + php: "7.3" + env: DB=pgsql DOCKER_POSTGRES=yes POSTGRESQL_VERSION=11.0 COVERAGE=yes + sudo: required + services: + - docker + - postgresql + addons: + postgresql: "9.6" + before_script: + - bash ./tests/travis/install-postgres-11.sh + - stage: Test + php: "7.4snapshot" + env: DB=pgsql DOCKER_POSTGRES=yes POSTGRESQL_VERSION=11.0 + sudo: required + services: + - docker + - postgresql + before_script: + - bash ./tests/travis/install-postgres-11.sh diff --git a/README.md b/README.md index f974a6e..de52dbf 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ php composer.phar require umbrellio/laravel-pg-extensions ## Features - [Extended `Schema::create()`](#extended-table-creation) - - [Extended `Schema` with GIST/GIN indexes](#create-gist/gin-indexes) + - [Added Support Numeric Type](#numeric-column-type) + - [Extended `Schema` with USING](#extended-schema-using) - [Extended `Schema` for views](#create-views) - [Working with unique indexes](#extended-unique-indexes-creation) - [Working with partitions](#partitions) @@ -31,12 +32,21 @@ Schema::create('table', function (Blueprint $table) { }); ``` -### Create gist/gin indexes +### Extended Schema USING +Example: ```php Schema::create('table', function (Blueprint $table) { - $table->gist(['column1', 'column2']); - $table->gin('column1'); + $table->integer('number'); +}); + +//modifications with data... + +Schema::table('table', function (Blueprint $table) { + $table + ->string('number') + ->using("('[' || number || ']')::character varyiing") + ->change(); }); ``` diff --git a/composer.json b/composer.json index dce9b12..6ab341d 100644 --- a/composer.json +++ b/composer.json @@ -10,10 +10,12 @@ ], "require": { "php": "^7.2", + "doctrine/dbal": "^2.9", "laravel/framework": "^5.8" }, "require-dev": { "umbrellio/code-style-php": "^1.0", + "codeception/codeception": "^3.0", "orchestra/testbench": "^3.5", "php-coveralls/php-coveralls": "^2.1" }, diff --git a/composer.lock b/composer.lock index f8b1d94..57e0594 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "806be43cfecda6994cd0335061c2ad39", + "content-hash": "98cde3c0428143e26c3295002c4d0968", "packages": [ { "name": "doctrine/cache", @@ -83,31 +83,31 @@ }, { "name": "doctrine/dbal", - "version": "v2.9.2", + "version": "v2.10.4", "source": { "type": "git", - "url": "https://github.com/doctrine/dbal.git", - "reference": "22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9" + "url": "https://github.com/pvsaintpe/dbal.git", + "reference": "59aedf521cca50af294bdbbc14337ea3a0293d86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9", - "reference": "22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9", + "url": "https://api.github.com/repos/pvsaintpe/dbal/zipball/59aedf521cca50af294bdbbc14337ea3a0293d86", + "reference": "59aedf521cca50af294bdbbc14337ea3a0293d86", "shasum": "" }, "require": { "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0", "ext-pdo": "*", - "php": "^7.1" + "php": "^7.2" }, "require-dev": { - "doctrine/coding-standard": "^5.0", - "jetbrains/phpstorm-stubs": "^2018.1.2", - "phpstan/phpstan": "^0.10.1", - "phpunit/phpunit": "^7.4", - "symfony/console": "^2.0.5|^3.0|^4.0", - "symfony/phpunit-bridge": "^3.4.5|^4.0.5" + "doctrine/coding-standard": "^6.0", + "jetbrains/phpstorm-stubs": "^2019.1", + "phpstan/phpstan": "^0.11.3", + "phpunit/phpunit": "^8.2.1", + "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", + "symfony/phpunit-bridge": "^3.4.5|^4.0.5|^5.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -118,7 +118,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.9.x-dev", + "dev-master": "2.10.x-dev", "dev-develop": "3.0.x-dev" } }, @@ -127,11 +127,19 @@ "Doctrine\\DBAL\\": "lib/Doctrine/DBAL" } }, - "notification-url": "https://packagist.org/downloads/", + "autoload-dev": { + "psr-4": { + "Doctrine\\Tests\\": "tests/Doctrine/Tests" + } + }, "license": [ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -140,10 +148,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -154,14 +158,28 @@ "keywords": [ "abstraction", "database", + "db2", "dbal", + "mariadb", + "mssql", "mysql", - "persistence", + "oci8", + "oracle", + "pdo", "pgsql", - "php", - "queryobject" - ], - "time": "2018-12-31T03:27:51+00:00" + "postgresql", + "queryobject", + "sasql", + "sql", + "sqlanywhere", + "sqlite", + "sqlserver", + "sqlsrv" + ], + "support": { + "source": "https://github.com/pvsaintpe/dbal/tree/bug/default-expression" + }, + "time": "2019-07-11T16:39:36+00:00" }, { "name": "doctrine/event-manager", @@ -420,16 +438,16 @@ }, { "name": "egulias/email-validator", - "version": "2.1.9", + "version": "2.1.10", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "128cc721d771ec2c46ce59698f4ca42b73f71b25" + "reference": "a6c8d7101b19a451c1707b1b79bbbc56e4bdb7ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/128cc721d771ec2c46ce59698f4ca42b73f71b25", - "reference": "128cc721d771ec2c46ce59698f4ca42b73f71b25", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/a6c8d7101b19a451c1707b1b79bbbc56e4bdb7ec", + "reference": "a6c8d7101b19a451c1707b1b79bbbc56e4bdb7ec", "shasum": "" }, "require": { @@ -439,7 +457,8 @@ "require-dev": { "dominicsayers/isemail": "dev-master", "phpunit/phpunit": "^4.8.35||^5.7||^6.0", - "satooshi/php-coveralls": "^1.0.1" + "satooshi/php-coveralls": "^1.0.1", + "symfony/phpunit-bridge": "^4.4@dev" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" @@ -473,7 +492,7 @@ "validation", "validator" ], - "time": "2019-06-23T10:14:27+00:00" + "time": "2019-07-19T20:52:08+00:00" }, { "name": "erusev/parsedown", @@ -523,16 +542,16 @@ }, { "name": "laravel/framework", - "version": "v5.8.27", + "version": "v5.8.29", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "f1dccffb96f614895393e27e4667105a05407af5" + "reference": "489ae2218c7eb138caac780de584d8df9fe8160b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/f1dccffb96f614895393e27e4667105a05407af5", - "reference": "f1dccffb96f614895393e27e4667105a05407af5", + "url": "https://api.github.com/repos/laravel/framework/zipball/489ae2218c7eb138caac780de584d8df9fe8160b", + "reference": "489ae2218c7eb138caac780de584d8df9fe8160b", "shasum": "" }, "require": { @@ -666,7 +685,7 @@ "framework", "laravel" ], - "time": "2019-07-02T13:43:47+00:00" + "time": "2019-07-16T14:05:28+00:00" }, { "name": "league/flysystem", @@ -832,16 +851,16 @@ }, { "name": "nesbot/carbon", - "version": "2.20.0", + "version": "2.21.3", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "bc671b896c276795fad8426b0aa24e8ade0f2498" + "reference": "58bdbbfab17ccd2ec7347b99e997f18232def4dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bc671b896c276795fad8426b0aa24e8ade0f2498", - "reference": "bc671b896c276795fad8426b0aa24e8ade0f2498", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/58bdbbfab17ccd2ec7347b99e997f18232def4dc", + "reference": "58bdbbfab17ccd2ec7347b99e997f18232def4dc", "shasum": "" }, "require": { @@ -857,6 +876,9 @@ "phpunit/phpunit": "^7.5 || ^8.0", "squizlabs/php_codesniffer": "^3.4" }, + "bin": [ + "bin/carbon" + ], "type": "library", "extra": { "laravel": { @@ -879,6 +901,10 @@ "name": "Brian Nesbitt", "email": "brian@nesbot.com", "homepage": "http://nesbot.com" + }, + { + "name": "kylekatarnls", + "homepage": "http://github.com/kylekatarnls" } ], "description": "A simple API extension for DateTime.", @@ -888,20 +914,20 @@ "datetime", "time" ], - "time": "2019-06-25T10:00:57+00:00" + "time": "2019-07-18T18:47:28+00:00" }, { "name": "opis/closure", - "version": "3.3.0", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/opis/closure.git", - "reference": "f846725591203098246276b2e7b9e8b7814c4965" + "reference": "92927e26d7fc3f271efe1f55bdbb073fbb2f0722" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/f846725591203098246276b2e7b9e8b7814c4965", - "reference": "f846725591203098246276b2e7b9e8b7814c4965", + "url": "https://api.github.com/repos/opis/closure/zipball/92927e26d7fc3f271efe1f55bdbb073fbb2f0722", + "reference": "92927e26d7fc3f271efe1f55bdbb073fbb2f0722", "shasum": "" }, "require": { @@ -949,7 +975,7 @@ "serialization", "serialize" ], - "time": "2019-05-31T20:04:32+00:00" + "time": "2019-07-09T21:58:11+00:00" }, { "name": "paragonie/random_compat", @@ -2745,6 +2771,233 @@ } ], "packages-dev": [ + { + "name": "behat/gherkin", + "version": "v4.6.0", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/ab0a02ea14893860bca00f225f5621d351a3ad07", + "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.5|~5", + "symfony/phpunit-bridge": "~2.7|~3|~4", + "symfony/yaml": "~2.3|~3|~4" + }, + "suggest": { + "symfony/yaml": "If you want to parse features, represented in YAML files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Gherkin": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Gherkin DSL parser for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" + ], + "time": "2019-01-16T14:22:17+00:00" + }, + { + "name": "codeception/codeception", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Codeception.git", + "reference": "feb566a9dc26993611602011ae3834d8e3c1dd7f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/feb566a9dc26993611602011ae3834d8e3c1dd7f", + "reference": "feb566a9dc26993611602011ae3834d8e3c1dd7f", + "shasum": "" + }, + "require": { + "behat/gherkin": "^4.4.0", + "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.0.3", + "codeception/stub": "^2.0", + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "facebook/webdriver": "^1.6.0", + "guzzlehttp/guzzle": "^6.3.0", + "guzzlehttp/psr7": "~1.4", + "hoa/console": "~3.0", + "php": ">=5.6.0 <8.0", + "symfony/browser-kit": ">=2.7 <5.0", + "symfony/console": ">=2.7 <5.0", + "symfony/css-selector": ">=2.7 <5.0", + "symfony/dom-crawler": ">=2.7 <5.0", + "symfony/event-dispatcher": ">=2.7 <5.0", + "symfony/finder": ">=2.7 <5.0", + "symfony/yaml": ">=2.7 <5.0" + }, + "require-dev": { + "codeception/specify": "~0.3", + "doctrine/annotations": "^1", + "doctrine/orm": "^2", + "flow/jsonpath": "~0.2", + "monolog/monolog": "~1.8", + "pda/pheanstalk": "~3.0", + "php-amqplib/php-amqplib": "~2.4", + "predis/predis": "^1.0", + "squizlabs/php_codesniffer": "~2.0", + "symfony/process": ">=2.7 <5.0", + "vlucas/phpdotenv": "^3.0" + }, + "suggest": { + "aws/aws-sdk-php": "For using AWS Auth in REST module and Queue module", + "codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests", + "codeception/specify": "BDD-style code blocks", + "codeception/verify": "BDD-style assertions", + "flow/jsonpath": "For using JSONPath in REST module", + "league/factory-muffin": "For DataFactory module", + "league/factory-muffin-faker": "For Faker support in DataFactory module", + "phpseclib/phpseclib": "for SFTP option in FTP Module", + "stecman/symfony-console-completion": "For BASH autocompletion", + "symfony/phpunit-bridge": "For phpunit-bridge support" + }, + "bin": [ + "codecept" + ], + "type": "library", + "extra": { + "branch-alias": [] + }, + "autoload": { + "psr-4": { + "Codeception\\": "src/Codeception", + "Codeception\\Extension\\": "ext" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" + } + ], + "description": "BDD-style testing framework", + "homepage": "http://codeception.com/", + "keywords": [ + "BDD", + "TDD", + "acceptance testing", + "functional testing", + "unit testing" + ], + "time": "2019-07-18T16:21:08+00:00" + }, + { + "name": "codeception/phpunit-wrapper", + "version": "8.0.4", + "source": { + "type": "git", + "url": "https://github.com/Codeception/phpunit-wrapper.git", + "reference": "7090736f36b4398cae6ef838b9a2bdfe8d8d104b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/7090736f36b4398cae6ef838b9a2bdfe8d8d104b", + "reference": "7090736f36b4398cae6ef838b9a2bdfe8d8d104b", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "phpunit/php-code-coverage": "^7.0", + "phpunit/phpunit": "^8.0", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0" + }, + "require-dev": { + "codeception/specify": "*", + "vlucas/phpdotenv": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\PHPUnit\\": "src\\" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Davert", + "email": "davert.php@resend.cc" + } + ], + "description": "PHPUnit classes used by Codeception", + "time": "2019-02-27T12:58:57+00:00" + }, + { + "name": "codeception/stub", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Stub.git", + "reference": "853657f988942f7afb69becf3fd0059f192c705a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/853657f988942f7afb69becf3fd0059f192c705a", + "reference": "853657f988942f7afb69becf3fd0059f192c705a", + "shasum": "" + }, + "require": { + "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.0.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", + "time": "2019-03-02T15:35:10+00:00" + }, { "name": "composer/semver", "version": "1.5.0", @@ -2975,6 +3228,66 @@ ], "time": "2019-03-17T17:37:11+00:00" }, + { + "name": "facebook/webdriver", + "version": "1.7.1", + "source": { + "type": "git", + "url": "https://github.com/facebook/php-webdriver.git", + "reference": "e43de70f3c7166169d0f14a374505392734160e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/e43de70f3c7166169d0f14a374505392734160e5", + "reference": "e43de70f3c7166169d0f14a374505392734160e5", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-zip": "*", + "php": "^5.6 || ~7.0", + "symfony/process": "^2.8 || ^3.1 || ^4.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "php-coveralls/php-coveralls": "^2.0", + "php-mock/php-mock-phpunit": "^1.1", + "phpunit/phpunit": "^5.7", + "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", + "squizlabs/php_codesniffer": "^2.6", + "symfony/var-dumper": "^3.3 || ^4.0" + }, + "suggest": { + "ext-SimpleXML": "For Firefox profile creation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-community": "1.5-dev" + } + }, + "autoload": { + "psr-4": { + "Facebook\\WebDriver\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "A PHP client for Selenium WebDriver", + "homepage": "https://github.com/facebook/php-webdriver", + "keywords": [ + "facebook", + "php", + "selenium", + "webdriver" + ], + "time": "2019-06-13T08:02:18+00:00" + }, { "name": "friendsofphp/php-cs-fixer", "version": "v2.15.1", @@ -3349,25 +3662,26 @@ "time": "2016-01-20T08:20:44+00:00" }, { - "name": "jean85/pretty-package-versions", - "version": "1.2", + "name": "hoa/consistency", + "version": "1.17.05.02", "source": { "type": "git", - "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48" + "url": "https://github.com/hoaproject/Consistency.git", + "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/75c7effcf3f77501d0e0caa75111aff4daa0dd48", - "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48", + "url": "https://api.github.com/repos/hoaproject/Consistency/zipball/fd7d0adc82410507f332516faf655b6ed22e4c2f", + "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f", "shasum": "" }, "require": { - "ocramius/package-versions": "^1.2.0", - "php": "^7.0" + "hoa/exception": "~1.0", + "php": ">=5.5.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "hoa/stream": "~1.0", + "hoa/test": "~2.0" }, "type": "library", "extra": { @@ -3377,59 +3691,79 @@ }, "autoload": { "psr-4": { - "Jean85\\": "src/" - } + "Hoa\\Consistency\\": "." + }, + "files": [ + "Prelude.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Alessandro Lai", - "email": "alessandro.lai85@gmail.com" + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" } ], - "description": "A wrapper for ocramius/package-versions to get pretty versions strings", + "description": "The Hoa\\Consistency library.", + "homepage": "https://hoa-project.net/", "keywords": [ - "composer", - "package", - "release", - "versions" - ], - "time": "2018-06-13T13:22:40+00:00" + "autoloader", + "callable", + "consistency", + "entity", + "flex", + "keyword", + "library" + ], + "time": "2017-05-02T12:18:12+00:00" }, { - "name": "mockery/mockery", - "version": "1.2.2", + "name": "hoa/console", + "version": "3.17.05.02", "source": { "type": "git", - "url": "https://github.com/mockery/mockery.git", - "reference": "0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2" + "url": "https://github.com/hoaproject/Console.git", + "reference": "e231fd3ea70e6d773576ae78de0bdc1daf331a66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2", - "reference": "0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2", + "url": "https://api.github.com/repos/hoaproject/Console/zipball/e231fd3ea70e6d773576ae78de0bdc1daf331a66", + "reference": "e231fd3ea70e6d773576ae78de0bdc1daf331a66", "shasum": "" }, "require": { - "hamcrest/hamcrest-php": "~2.0", - "lib-pcre": ">=7.0", - "php": ">=5.6.0" + "hoa/consistency": "~1.0", + "hoa/event": "~1.0", + "hoa/exception": "~1.0", + "hoa/file": "~1.0", + "hoa/protocol": "~1.0", + "hoa/stream": "~1.0", + "hoa/ustring": "~4.0" }, "require-dev": { - "phpunit/phpunit": "~5.7.10|~6.5|~7.0|~8.0" + "hoa/test": "~2.0" + }, + "suggest": { + "ext-pcntl": "To enable hoa://Event/Console/Window:resize.", + "hoa/dispatcher": "To use the console kit.", + "hoa/router": "To use the console kit." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { - "psr-0": { - "Mockery": "library/" + "psr-4": { + "Hoa\\Console\\": "." } }, "notification-url": "https://packagist.org/downloads/", @@ -3438,51 +3772,579 @@ ], "authors": [ { - "name": "Pádraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" }, { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" + "name": "Hoa community", + "homepage": "https://hoa-project.net/" } ], - "description": "Mockery is a simple yet flexible PHP mock object framework", - "homepage": "https://github.com/mockery/mockery", + "description": "The Hoa\\Console library.", + "homepage": "https://hoa-project.net/", "keywords": [ - "BDD", - "TDD", + "autocompletion", + "chrome", + "cli", + "console", + "cursor", + "getoption", "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" + "option", + "parser", + "processus", + "readline", + "terminfo", + "tput", + "window" ], - "time": "2019-02-13T09:37:52+00:00" + "time": "2017-05-02T12:26:19+00:00" }, { - "name": "myclabs/deep-copy", - "version": "1.9.1", + "name": "hoa/event", + "version": "1.17.01.13", "source": { "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72" + "url": "https://github.com/hoaproject/Event.git", + "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72", - "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72", + "url": "https://api.github.com/repos/hoaproject/Event/zipball/6c0060dced212ffa3af0e34bb46624f990b29c54", + "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54", "shasum": "" }, "require": { - "php": "^7.1" + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" }, - "replace": { - "myclabs/deep-copy": "self.version" + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Event\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Event library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "event", + "library", + "listener", + "observer" + ], + "time": "2017-01-13T15:30:50+00:00" + }, + { + "name": "hoa/exception", + "version": "1.17.01.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Exception.git", + "reference": "091727d46420a3d7468ef0595651488bfc3a458f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Exception/zipball/091727d46420a3d7468ef0595651488bfc3a458f", + "reference": "091727d46420a3d7468ef0595651488bfc3a458f", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Exception\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Exception library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "exception", + "library" + ], + "time": "2017-01-16T07:53:27+00:00" + }, + { + "name": "hoa/file", + "version": "1.17.07.11", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/File.git", + "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/File/zipball/35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", + "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0", + "hoa/exception": "~1.0", + "hoa/iterator": "~2.0", + "hoa/stream": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\File\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\File library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "Socket", + "directory", + "file", + "finder", + "library", + "link", + "temporary" + ], + "time": "2017-07-11T07:42:15+00:00" + }, + { + "name": "hoa/iterator", + "version": "2.17.01.10", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Iterator.git", + "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Iterator/zipball/d1120ba09cb4ccd049c86d10058ab94af245f0cc", + "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Iterator\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Iterator library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "iterator", + "library" + ], + "time": "2017-01-10T10:34:47+00:00" + }, + { + "name": "hoa/protocol", + "version": "1.17.01.14", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Protocol.git", + "reference": "5c2cf972151c45f373230da170ea015deecf19e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Protocol/zipball/5c2cf972151c45f373230da170ea015deecf19e2", + "reference": "5c2cf972151c45f373230da170ea015deecf19e2", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Protocol\\": "." + }, + "files": [ + "Wrapper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Protocol library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "protocol", + "resource", + "stream", + "wrapper" + ], + "time": "2017-01-14T12:26:10+00:00" + }, + { + "name": "hoa/stream", + "version": "1.17.02.21", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Stream.git", + "reference": "3293cfffca2de10525df51436adf88a559151d82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Stream/zipball/3293cfffca2de10525df51436adf88a559151d82", + "reference": "3293cfffca2de10525df51436adf88a559151d82", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0", + "hoa/exception": "~1.0", + "hoa/protocol": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Stream\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Stream library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "Context", + "bucket", + "composite", + "filter", + "in", + "library", + "out", + "protocol", + "stream", + "wrapper" + ], + "time": "2017-02-21T16:01:06+00:00" + }, + { + "name": "hoa/ustring", + "version": "4.17.01.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Ustring.git", + "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Ustring/zipball/e6326e2739178799b1fe3fdd92029f9517fa17a0", + "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "suggest": { + "ext-iconv": "ext/iconv must be present (or a third implementation) to use Hoa\\Ustring::transcode().", + "ext-intl": "To get a better Hoa\\Ustring::toAscii() and Hoa\\Ustring::compareTo()." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Ustring\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Ustring library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "search", + "string", + "unicode" + ], + "time": "2017-01-16T07:08:25+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "1.2", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/75c7effcf3f77501d0e0caa75111aff4daa0dd48", + "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48", + "shasum": "" + }, + "require": { + "ocramius/package-versions": "^1.2.0", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A wrapper for ocramius/package-versions to get pretty versions strings", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "time": "2018-06-13T13:22:40+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": "myclabs/deep-copy", + "version": "1.9.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72", + "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", @@ -3576,26 +4438,23 @@ }, { "name": "nette/robot-loader", - "version": "v3.1.1", + "version": "v3.2.0", "source": { "type": "git", "url": "https://github.com/nette/robot-loader.git", - "reference": "3e8d75d6d976e191bdf46752ca40a286671219d2" + "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/robot-loader/zipball/3e8d75d6d976e191bdf46752ca40a286671219d2", - "reference": "3e8d75d6d976e191bdf46752ca40a286671219d2", + "url": "https://api.github.com/repos/nette/robot-loader/zipball/0712a0e39ae7956d6a94c0ab6ad41aa842544b5c", + "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c", "shasum": "" }, "require": { "ext-tokenizer": "*", - "nette/finder": "^2.3 || ^3.0", - "nette/utils": "^2.4 || ^3.0", - "php": ">=5.6.0" - }, - "conflict": { - "nette/nette": "<2.2" + "nette/finder": "^2.5", + "nette/utils": "^3.0", + "php": ">=7.1" }, "require-dev": { "nette/tester": "^2.0", @@ -3604,7 +4463,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -3637,27 +4496,24 @@ "nette", "trait" ], - "time": "2019-03-01T20:23:02+00:00" + "time": "2019-03-08T21:57:24+00:00" }, { "name": "nette/utils", - "version": "v2.5.3", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "17b9f76f2abd0c943adfb556e56f2165460b15ce" + "reference": "bd961f49b211997202bda1d0fbc410905be370d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/17b9f76f2abd0c943adfb556e56f2165460b15ce", - "reference": "17b9f76f2abd0c943adfb556e56f2165460b15ce", + "url": "https://api.github.com/repos/nette/utils/zipball/bd961f49b211997202bda1d0fbc410905be370d4", + "reference": "bd961f49b211997202bda1d0fbc410905be370d4", "shasum": "" }, "require": { - "php": ">=5.6.0" - }, - "conflict": { - "nette/nette": "<2.2" + "php": ">=7.1" }, "require-dev": { "nette/tester": "~2.0", @@ -3666,7 +4522,7 @@ "suggest": { "ext-gd": "to use Image", "ext-iconv": "to use Strings::webalize() and toAscii()", - "ext-intl": "for script transliteration in Strings::webalize() and toAscii()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", "ext-json": "to use Nette\\Utils\\Json", "ext-mbstring": "to use Strings::lower() etc...", "ext-xml": "to use Strings::length() etc. when mbstring is not available" @@ -3674,15 +4530,12 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" - ], - "files": [ - "src/loader.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3701,7 +4554,7 @@ "homepage": "https://nette.org/contributors" } ], - "description": "? Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", "homepage": "https://nette.org", "keywords": [ "array", @@ -3719,38 +4572,39 @@ "utility", "validation" ], - "time": "2018-09-18T10:22:16+00:00" + "time": "2019-03-22T01:00:30+00:00" }, { "name": "ocramius/package-versions", - "version": "1.4.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/Ocramius/PackageVersions.git", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb" + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/1d32342b8c1eb27353c8887c366147b4c2da673c", + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c", "shasum": "" }, "require": { "composer-plugin-api": "^1.0.0", - "php": "^7.1.0" + "php": "^7.3.0" }, "require-dev": { - "composer/composer": "^1.6.3", - "doctrine/coding-standard": "^5.0.1", + "composer/composer": "^1.8.6", + "doctrine/coding-standard": "^6.0.0", "ext-zip": "*", - "infection/infection": "^0.7.1", - "phpunit/phpunit": "^7.0.0" + "infection/infection": "^0.13.4", + "phpunit/phpunit": "^8.2.5", + "vimeo/psalm": "^3.4.9" }, "type": "composer-plugin", "extra": { "class": "PackageVersions\\Installer", "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { @@ -3769,7 +4623,7 @@ } ], "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "time": "2019-02-21T12:16:21+00:00" + "time": "2019-07-17T15:49:50+00:00" }, { "name": "orchestra/testbench", @@ -4386,16 +5240,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "7.0.5", + "version": "7.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "aed67b57d459dcab93e84a5c9703d3deb5025dff" + "reference": "7743bbcfff2a907e9ee4a25be13d0f8ec5e73800" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aed67b57d459dcab93e84a5c9703d3deb5025dff", - "reference": "aed67b57d459dcab93e84a5c9703d3deb5025dff", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7743bbcfff2a907e9ee4a25be13d0f8ec5e73800", + "reference": "7743bbcfff2a907e9ee4a25be13d0f8ec5e73800", "shasum": "" }, "require": { @@ -4404,17 +5258,17 @@ "php": "^7.2", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0.1", + "phpunit/php-token-stream": "^3.1.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^4.1", + "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^8.0" + "phpunit/phpunit": "^8.2.2" }, "suggest": { - "ext-xdebug": "^2.6.1" + "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { @@ -4434,8 +5288,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "role": "lead", + "email": "sebastian@phpunit.de" } ], "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", @@ -4445,7 +5299,7 @@ "testing", "xunit" ], - "time": "2019-06-06T12:28:18+00:00" + "time": "2019-07-25T05:31:54+00:00" }, { "name": "phpunit/php-file-iterator", @@ -4589,16 +5443,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "3.0.1", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18" + "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e899757bb3df5ff6e95089132f32cd59aac2220a", + "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a", "shasum": "" }, "require": { @@ -4611,7 +5465,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -4634,20 +5488,20 @@ "keywords": [ "tokenizer" ], - "time": "2018-10-30T05:52:18+00:00" + "time": "2019-07-25T05:29:42+00:00" }, { "name": "phpunit/phpunit", - "version": "8.2.3", + "version": "8.2.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f67ca36860ebca7224d4573f107f79bd8ed0ba03" + "reference": "c1b8534b3730f20f58600124129197bf1183dc92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f67ca36860ebca7224d4573f107f79bd8ed0ba03", - "reference": "f67ca36860ebca7224d4573f107f79bd8ed0ba03", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c1b8534b3730f20f58600124129197bf1183dc92", + "reference": "c1b8534b3730f20f58600124129197bf1183dc92", "shasum": "" }, "require": { @@ -4674,7 +5528,7 @@ "sebastian/global-state": "^3.0.0", "sebastian/object-enumerator": "^3.0.3", "sebastian/resource-operations": "^2.0.1", - "sebastian/type": "^1.1.0", + "sebastian/type": "^1.1.3", "sebastian/version": "^2.0.1" }, "require-dev": { @@ -4717,7 +5571,7 @@ "testing", "xunit" ], - "time": "2019-06-19T12:03:56+00:00" + "time": "2019-07-15T06:26:24+00:00" }, { "name": "psr/cache", @@ -5470,53 +6324,6 @@ "homepage": "https://github.com/sebastianbergmann/version", "time": "2016-10-03T07:35:21+00:00" }, - { - "name": "slam/php-cs-fixer-extensions", - "version": "v1.19.1", - "source": { - "type": "git", - "url": "https://github.com/Slamdunk/php-cs-fixer-extensions.git", - "reference": "ff457bef86539cb4ed7b7eb44eb85f3edddf53e1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Slamdunk/php-cs-fixer-extensions/zipball/ff457bef86539cb4ed7b7eb44eb85f3edddf53e1", - "reference": "ff457bef86539cb4ed7b7eb44eb85f3edddf53e1", - "shasum": "" - }, - "require": { - "friendsofphp/php-cs-fixer": "^2.15", - "php": "^7.2" - }, - "require-dev": { - "phpstan/phpstan": "^0.11", - "phpstan/phpstan-phpunit": "^0.11", - "phpunit/phpunit": "^7.5", - "roave/security-advisories": "dev-master", - "slam/php-debug-r": "^1.4", - "slam/phpstan-extensions": "^3.0", - "thecodingmachine/phpstan-strict-rules": "^0.11" - }, - "type": "library", - "autoload": { - "psr-4": { - "SlamCsFixer\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Filippo Tessarotto", - "email": "zoeslam@gmail.com", - "role": "Developer" - } - ], - "description": "Slam extension of friendsofphp/php-cs-fixer", - "time": "2019-05-28T14:18:12+00:00" - }, { "name": "slevomat/coding-standard", "version": "5.0.4", @@ -5608,6 +6415,65 @@ ], "time": "2019-04-10T23:49:02+00:00" }, + { + "name": "symfony/browser-kit", + "version": "v4.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "a29dd02a1f3f81b9a15c7730cc3226718ddb55ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/a29dd02a1f3f81b9a15c7730cc3226718ddb55ca", + "reference": "a29dd02a1f3f81b9a15c7730cc3226718ddb55ca", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/dom-crawler": "~3.4|~4.0" + }, + "require-dev": { + "symfony/css-selector": "~3.4|~4.0", + "symfony/http-client": "^4.3", + "symfony/mime": "^4.3", + "symfony/process": "~3.4|~4.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "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 BrowserKit Component", + "homepage": "https://symfony.com", + "time": "2019-06-11T15:41:59+00:00" + }, { "name": "symfony/cache", "version": "v4.3.2", @@ -5881,6 +6747,67 @@ "homepage": "https://symfony.com", "time": "2019-06-15T04:08:07+00:00" }, + { + "name": "symfony/dom-crawler", + "version": "v4.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "291397232a2eefb3347eaab9170409981eaad0e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/291397232a2eefb3347eaab9170409981eaad0e2", + "reference": "291397232a2eefb3347eaab9170409981eaad0e2", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "~3.4|~4.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "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 DomCrawler Component", + "homepage": "https://symfony.com", + "time": "2019-06-13T11:03:18+00:00" + }, { "name": "symfony/filesystem", "version": "v4.3.2", @@ -6213,82 +7140,39 @@ "homepage": "https://symfony.com", "time": "2019-04-06T14:04:46+00:00" }, - { - "name": "symplify/better-phpdoc-parser", - "version": "v5.4.16", - "source": { - "type": "git", - "url": "https://github.com/Symplify/BetterPhpDocParser.git", - "reference": "a730f69c4b19c741f13b4d05116da7bb64e3db26" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Symplify/BetterPhpDocParser/zipball/a730f69c4b19c741f13b4d05116da7bb64e3db26", - "reference": "a730f69c4b19c741f13b4d05116da7bb64e3db26", - "shasum": "" - }, - "require": { - "nette/utils": "^2.5", - "php": "^7.1", - "phpstan/phpdoc-parser": "^0.3.1", - "symplify/package-builder": "^5.4.16" - }, - "require-dev": { - "phpunit/phpunit": "^7.5|^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.5-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\BetterPhpDocParser\\": "src", - "Symplify\\BetterPhpDocParser\\Attributes\\": "packages/Attributes/src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Slim wrapper around phpstan/phpdoc-parser with format preserving printer", - "time": "2019-03-05T23:15:04+00:00" - }, { "name": "symplify/coding-standard", - "version": "v5.4.16", + "version": "v6.0.4", "source": { "type": "git", "url": "https://github.com/Symplify/CodingStandard.git", - "reference": "72a3b03f21be6c978a90ad567a29bd9261df0dfa" + "reference": "adf215f9b2061859aa651dc9e6fd07ec3a3ffe9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Symplify/CodingStandard/zipball/72a3b03f21be6c978a90ad567a29bd9261df0dfa", - "reference": "72a3b03f21be6c978a90ad567a29bd9261df0dfa", + "url": "https://api.github.com/repos/Symplify/CodingStandard/zipball/adf215f9b2061859aa651dc9e6fd07ec3a3ffe9b", + "reference": "adf215f9b2061859aa651dc9e6fd07ec3a3ffe9b", "shasum": "" }, "require": { - "friendsofphp/php-cs-fixer": "^2.14", + "friendsofphp/php-cs-fixer": "^2.15", "nette/finder": "^2.4", - "nette/utils": "^2.5", + "nette/utils": "^2.5|^3.0", "php": "^7.1", - "slam/php-cs-fixer-extensions": "^1.17", + "phpstan/phpdoc-parser": "^0.3.4", "squizlabs/php_codesniffer": "^3.4", - "symplify/better-phpdoc-parser": "^5.4.16", - "symplify/package-builder": "^5.4.16" + "symplify/package-builder": "^6.0.4" }, "require-dev": { - "nette/application": "^2.4", + "nette/application": "^2.4|^3.0", "phpunit/phpunit": "^7.5|^8.0", - "symplify/easy-coding-standard-tester": "^5.4.16", - "symplify/package-builder": "^5.4.16" + "symplify/easy-coding-standard-tester": "^6.0.4", + "symplify/package-builder": "^6.0.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -6302,45 +7186,46 @@ "MIT" ], "description": "Set of Symplify rules for PHP_CodeSniffer and PHP CS Fixer.", - "time": "2019-03-05T23:15:04+00:00" + "time": "2019-06-26T20:13:26+00:00" }, { "name": "symplify/easy-coding-standard", - "version": "v5.4.16", + "version": "v6.0.4", "source": { "type": "git", "url": "https://github.com/Symplify/EasyCodingStandard.git", - "reference": "66ed360e0b81881336c7339989dce3b0c14509e9" + "reference": "5fb76e1e4f756ba866e4d94b37c8681bdffadc04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Symplify/EasyCodingStandard/zipball/66ed360e0b81881336c7339989dce3b0c14509e9", - "reference": "66ed360e0b81881336c7339989dce3b0c14509e9", + "url": "https://api.github.com/repos/Symplify/EasyCodingStandard/zipball/5fb76e1e4f756ba866e4d94b37c8681bdffadc04", + "reference": "5fb76e1e4f756ba866e4d94b37c8681bdffadc04", "shasum": "" }, "require": { "composer/xdebug-handler": "^1.3", - "friendsofphp/php-cs-fixer": "^2.14", + "friendsofphp/php-cs-fixer": "^2.15", "jean85/pretty-package-versions": "^1.2", "nette/robot-loader": "^3.1.0", - "nette/utils": "^2.5", + "nette/utils": "^2.5|^3.0", "ocramius/package-versions": "^1.3", "php": "^7.1", + "psr/simple-cache": "^1.0", "slevomat/coding-standard": "^5.0.1", "squizlabs/php_codesniffer": "^3.4", - "symfony/cache": "^3.4|^4.1", - "symfony/config": "^3.4|^4.1", - "symfony/console": "^3.4|^4.1", - "symfony/dependency-injection": "^3.4|^4.1", - "symfony/finder": "^3.4|^4.1", - "symfony/http-kernel": "^3.4|^4.1", - "symfony/yaml": "^3.4|^4.1", - "symplify/coding-standard": "^5.4.16", - "symplify/package-builder": "^5.4.16" + "symfony/cache": "^3.4|^4.2", + "symfony/config": "^3.4|^4.2", + "symfony/console": "^3.4|^4.2", + "symfony/dependency-injection": "^3.4.10|^4.2", + "symfony/finder": "^3.4|^4.2", + "symfony/http-kernel": "^3.4|^4.2", + "symfony/yaml": "^3.4|^4.2", + "symplify/coding-standard": "^6.0.4", + "symplify/package-builder": "^6.0.4" }, "require-dev": { "phpunit/phpunit": "^7.5|^8.0", - "symplify/easy-coding-standard-tester": "^5.4.16" + "symplify/easy-coding-standard-tester": "^6.0.4" }, "bin": [ "bin/ecs" @@ -6348,7 +7233,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -6365,34 +7250,33 @@ "MIT" ], "description": "Use Coding Standard with 0-knowledge of PHP-CS-Fixer and PHP_CodeSniffer.", - "time": "2019-03-05T23:15:04+00:00" + "time": "2019-06-26T20:13:26+00:00" }, { "name": "symplify/package-builder", - "version": "v5.4.16", + "version": "v6.0.4", "source": { "type": "git", "url": "https://github.com/Symplify/PackageBuilder.git", - "reference": "20e04ad9cd15a53527807a62c8b244d8a114f779" + "reference": "14db22e0c9667aeb81873468b4984a490d2183b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Symplify/PackageBuilder/zipball/20e04ad9cd15a53527807a62c8b244d8a114f779", - "reference": "20e04ad9cd15a53527807a62c8b244d8a114f779", + "url": "https://api.github.com/repos/Symplify/PackageBuilder/zipball/14db22e0c9667aeb81873468b4984a490d2183b6", + "reference": "14db22e0c9667aeb81873468b4984a490d2183b6", "shasum": "" }, "require": { - "illuminate/support": "^5.7", "nette/finder": "^2.4", - "nette/utils": "^2.5", + "nette/utils": "^2.5|^3.0", "php": "^7.1", - "symfony/config": "^3.4|^4.1", - "symfony/console": "^3.4|^4.1", - "symfony/debug": "^3.4|^4.1", - "symfony/dependency-injection": "^3.4|^4.1", - "symfony/finder": "^3.4|^4.1", - "symfony/http-kernel": "^3.4|^4.1", - "symfony/yaml": "^3.4|^4.1" + "symfony/config": "^3.4|^4.2", + "symfony/console": "^3.4|^4.2", + "symfony/debug": "^3.4|^4.2", + "symfony/dependency-injection": "^3.4.10|^4.2", + "symfony/finder": "^3.4|^4.2", + "symfony/http-kernel": "^3.4|^4.2", + "symfony/yaml": "^3.4|^4.2" }, "require-dev": { "phpunit/phpunit": "^7.5|^8.0" @@ -6400,7 +7284,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -6413,7 +7297,7 @@ "MIT" ], "description": "Dependency Injection, Console and Kernel toolkit for Symplify packages.", - "time": "2019-03-03T15:32:34+00:00" + "time": "2019-06-26T20:10:56+00:00" }, { "name": "theseer/tokenizer", @@ -6457,21 +7341,21 @@ }, { "name": "umbrellio/code-style-php", - "version": "1.0.1", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/umbrellio/code-style-php.git", - "reference": "be917ff37bde26a32e66cb67a932acd659896106" + "reference": "13ddcdbfa0ec1e6e8527ccb860dec64c2b3cdc81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/umbrellio/code-style-php/zipball/be917ff37bde26a32e66cb67a932acd659896106", - "reference": "be917ff37bde26a32e66cb67a932acd659896106", + "url": "https://api.github.com/repos/umbrellio/code-style-php/zipball/13ddcdbfa0ec1e6e8527ccb860dec64c2b3cdc81", + "reference": "13ddcdbfa0ec1e6e8527ccb860dec64c2b3cdc81", "shasum": "" }, "require": { "php": "^7.2", - "symplify/easy-coding-standard": "^5.0" + "symplify/easy-coding-standard": "^6.0" }, "type": "library", "notification-url": "https://packagist.org/downloads/", @@ -6482,6 +7366,10 @@ { "name": "Vitaliy Lazeev", "email": "vetal@umbrellio.biz" + }, + { + "name": "Umbrellio", + "email": "oss@umbrellio.biz" } ], "description": "Umbrellio php code style.", @@ -6490,7 +7378,7 @@ "code-style", "umbrellio" ], - "time": "2019-05-25T17:13:53+00:00" + "time": "2019-07-22T14:36:34+00:00" }, { "name": "webmozart/assert", @@ -6550,7 +7438,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.1.3" + "php": "^7.2" }, "platform-dev": [] } diff --git a/ecs.yml b/ecs.yml index 768e555..69f949a 100644 --- a/ecs.yml +++ b/ecs.yml @@ -10,7 +10,3 @@ parameters: cache_directory: .ecs_cache exclude_files: - vendor/* - - skip: - Symplify\CodingStandard\Sniffs\CleanCode\CognitiveComplexitySniff: - - src/Schema/Blueprint.php diff --git a/phpunit.travis.xml b/phpunit.travis.xml new file mode 100644 index 0000000..22ab00f --- /dev/null +++ b/phpunit.travis.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + ./tests + + + + + ./src + + ./src/.meta.php + + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1dc3aef..1e2c087 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,19 +1,24 @@ - + stopOnFailure="true"> + + + + + + + + ./src ./src/.meta.php - ./src/Commands diff --git a/src/.meta.php b/src/.meta.php index 30942b0..49db8b7 100644 --- a/src/.meta.php +++ b/src/.meta.php @@ -16,11 +16,16 @@ * @method UniqueDefinition uniquePartial($columns, ?string $index = null, ?string $algorithm = null) * @method ViewDefinition createView(string $view, string $select, bool $materialize = false) * @method Fluent dropView(string $view) - * @method Fluent gin($columns, ?string $name = null) - * @method Fluent gist($columns, ?string $name = null) * @method ColumnDefinition numeric(string $column, ?int $precision = null, ?int $scale = null): */ class Blueprint { } + + /** + * @method ColumnDefinition using($expression) + */ + class ColumnDefinition + { + } } diff --git a/src/Extensions/AbstractComponent.php b/src/Extensions/AbstractComponent.php index 3eb63a7..b03f5a4 100644 --- a/src/Extensions/AbstractComponent.php +++ b/src/Extensions/AbstractComponent.php @@ -4,9 +4,6 @@ namespace Umbrellio\Postgres\Extensions; -/** - * @codeCoverageIgnore - */ abstract class AbstractComponent { final public function __construct() diff --git a/src/PostgresConnection.php b/src/PostgresConnection.php index d1818d1..64a0f49 100644 --- a/src/PostgresConnection.php +++ b/src/PostgresConnection.php @@ -4,12 +4,15 @@ namespace Umbrellio\Postgres; +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Events; use Illuminate\Database\PostgresConnection as BasePostgresConnection; use Illuminate\Support\Traits\Macroable; use Umbrellio\Postgres\Extensions\AbstractExtension; use Umbrellio\Postgres\Extensions\Exceptions\ExtensionInvalidException; use Umbrellio\Postgres\Schema\Builder; use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar; +use Umbrellio\Postgres\Schema\Subscribers\SchemaAlterTableChangeColumnSubscriber; class PostgresConnection extends BasePostgresConnection { @@ -19,6 +22,7 @@ class PostgresConnection extends BasePostgresConnection /** * @param AbstractExtension|string $extension + * @throws ExtensionInvalidException * @codeCoverageIgnore */ final public static function registerExtension(string $extension): void @@ -41,12 +45,19 @@ public function getSchemaBuilder() return new Builder($this); } - public function useDefaultPostProcessor() + public function useDefaultPostProcessor(): void { parent::useDefaultPostProcessor(); $this->registerExtensions(); } + public function getDoctrineConnection(): Connection + { + $doctrineConnection = parent::getDoctrineConnection(); + $this->overrideDoctrineBehavior($doctrineConnection); + return $doctrineConnection; + } + protected function getDefaultSchemaGrammar() { return $this->withTablePrefix(new PostgresGrammar()); @@ -55,9 +66,9 @@ protected function getDefaultSchemaGrammar() /** * @codeCoverageIgnore */ - final private function registerExtensions(): void + private function registerExtensions(): void { - collect(self::$extensions)->each(function ($extension, $key) { + collect(self::$extensions)->each(function ($extension) { /** @var AbstractExtension $extension */ $extension::register(); foreach ($extension::getTypes() as $type => $typeClass) { @@ -65,4 +76,14 @@ final private function registerExtensions(): void } }); } + + private function overrideDoctrineBehavior(Connection $connection): Connection + { + $eventManager = $connection->getEventManager(); + if (!$eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) { + $eventManager->addEventSubscriber(new SchemaAlterTableChangeColumnSubscriber()); + } + $connection->getDatabasePlatform()->setEventManager($eventManager); + return $connection; + } } diff --git a/src/Schema/Blueprint.php b/src/Schema/Blueprint.php index 774a84a..38f7b22 100644 --- a/src/Schema/Blueprint.php +++ b/src/Schema/Blueprint.php @@ -59,26 +59,6 @@ public function uniquePartial($columns, ?string $index = null, ?string $algorith ); } - /** - * Specify an index for the table. - * @param string|array $columns - * @return Fluent - */ - public function gin($columns, ?string $name = null) - { - return $this->indexCommand('gin', $columns, $name); - } - - /** - * Specify a gist index for the table. - * @param string|array $columns - * @return Fluent - */ - public function gist($columns, ?string $name = null) - { - return $this->indexCommand('gist', $columns, $name); - } - public function hasIndex($index, bool $unique = false): bool { if (is_array($index)) { @@ -109,28 +89,6 @@ public function numeric(string $column, ?int $precision = null, ?int $scale = nu return $this->addColumn('numeric', $column, compact('precision', 'scale')); } - protected function addFluentIndexes(): void - { - foreach ($this->columns as $column) { - foreach (['primary', 'unique', 'index', 'gin', 'gist', 'spatialIndex'] as $index) { - // If the index has been specified on the given column, but is simply - // equal to "true" (boolean), no name has been specified for this - // index, so we will simply call the index methods without one. - if ($column->{$index} === true) { - $this->{$index}($column->name); - continue 2; - } - // If the index has been specified on the column and it is something - // other than boolean true, we will assume a name was provided on - // the index specification, and pass in the name to the method. - elseif (isset($column->{$index})) { - $this->{$index}($column->name, $column->{$index}); - continue 2; - } - } - } - } - protected function getSchemaManager() { return Schema::getConnection()->getDoctrineSchemaManager(); diff --git a/src/Schema/Grammars/PostgresGrammar.php b/src/Schema/Grammars/PostgresGrammar.php index 52f4ce4..59a5ff0 100644 --- a/src/Schema/Grammars/PostgresGrammar.php +++ b/src/Schema/Grammars/PostgresGrammar.php @@ -75,27 +75,6 @@ public function compileUniquePartial(Blueprint $blueprint, UniquePartialBuilder return $this->compileUnique($blueprint, $command); } - public function compileGin(Blueprint $blueprint, Fluent $command): string - { - return sprintf( - 'CREATE INDEX %s ON %s USING GIN(%s)', - $command->index, - $this->wrapTable($blueprint), - $this->columnize($command->columns) - ); - } - - - public function compileGist(Blueprint $blueprint, Fluent $command): string - { - return sprintf( - 'CREATE INDEX %s ON %s USING GIST(%s)', - $command->index, - $this->wrapTable($blueprint), - $this->columnize($command->columns) - ); - } - protected function typeNumeric(Fluent $column): string { $type = 'numeric'; diff --git a/src/Schema/Subscribers/SchemaAlterTableChangeColumnSubscriber.php b/src/Schema/Subscribers/SchemaAlterTableChangeColumnSubscriber.php new file mode 100644 index 0000000..d908cee --- /dev/null +++ b/src/Schema/Subscribers/SchemaAlterTableChangeColumnSubscriber.php @@ -0,0 +1,233 @@ +preventDefault(); + + $sql = $this->getAlterTableChangeColumnSQL( + $event->getPlatform(), + $event->getTableDiff(), + $event->getColumnDiff() + ); + + $event->addSql($sql->unique()->toArray()); + } + + public function getSubscribedEvents(): array + { + return [Events::onSchemaAlterTableChangeColumn]; + } + + public function getAlterTableChangeColumnSQL( + AbstractPlatform $platform, + TableDiff $diff, + ColumnDiff $columnDiff + ): Collection { + $sql = new Collection(); + + $quoteName = $this->quoteName($platform, $diff); + + $oldColumnName = $columnDiff->getOldColumnName()->getQuotedName($platform); + $column = $columnDiff->column; + + $this->compileAlterColumnType($platform, $columnDiff, $column, $quoteName, $oldColumnName, $sql); + + $this->compileAlterColumnDefault($platform, $columnDiff, $column, $quoteName, $oldColumnName, $sql); + + $this->compileAlterColumnNull($columnDiff, $column, $quoteName, $oldColumnName, $sql); + + $this->compileAlterColumnSequence($platform, $columnDiff, $diff, $column, $quoteName, $oldColumnName, $sql); + + $this->compileAlterColumnComment($platform, $columnDiff, $column, $quoteName, $sql); + + if (!$columnDiff->hasChanged('length')) { + return $sql; + } + + $sql->add(sprintf( + 'ALTER TABLE %s ALTER %s TYPE %s', + $quoteName, + $oldColumnName, + $column->getType()->getSQLDeclaration($column->toArray(), $platform) + )); + + return $sql; + } + + public function compileAlterColumnComment( + AbstractPlatform $platform, + ColumnDiff $columnDiff, + Column $column, + string $quoteName, + Collection $sql + ): void { + $newComment = $this->getColumnComment($column); + $oldComment = $this->getOldColumnComment($columnDiff); + + if (($columnDiff->fromColumn !== null && $oldComment !== $newComment) + || $columnDiff->hasChanged('comment') + ) { + $sql->add($platform->getCommentOnColumnSQL($quoteName, $column->getQuotedName($platform), $newComment)); + } + } + + public function compileAlterColumnNull( + ColumnDiff $columnDiff, + Column $column, + string $quoteName, + string $oldColumnName, + Collection $sql + ): void { + if ($columnDiff->hasChanged('notnull')) { + $sql->add(sprintf( + 'ALTER TABLE %s ALTER %s %s NOT NULL', + $quoteName, + $oldColumnName, + ($column->getNotnull() ? 'SET' : 'DROP') + )); + } + } + + public function compileAlterColumnDefault( + AbstractPlatform $platform, + ColumnDiff $columnDiff, + Column $column, + string $quoteName, + string $oldColumnName, + Collection $sql + ): void { + if ($columnDiff->hasChanged('default') || $this->typeChangeBreaksDefaultValue($columnDiff)) { + $defaultClause = $column->getDefault() === null + ? ' DROP DEFAULT' + : ' SET' . $this->getDefaultValueDeclarationSQL($platform, $column); + $sql->add(sprintf('ALTER TABLE %s ALTER %s %s', $quoteName, $oldColumnName, trim($defaultClause))); + } + } + + public function compileAlterColumnSequence( + AbstractPlatform $platform, + ColumnDiff $columnDiff, + TableDiff $diff, + Column $column, + string $quoteName, + string $oldColumnName, + Collection $sql + ): void { + if (!$columnDiff->hasChanged('autoincrement')) { + return; + } + + if (!$column->getAutoincrement()) { + $sql->add(sprintf('ALTER TABLE %s ALTER %s DROP DEFAULT', $quoteName, $oldColumnName)); + return; + } + + $seqName = $platform->getIdentitySequenceName($diff->name, $oldColumnName); + + $sql->add(sprintf('CREATE SEQUENCE %s', $seqName)); + $sql->add(sprintf("SELECT setval('%s', (SELECT MAX(%s) FROM %s))", $seqName, $oldColumnName, $quoteName)); + $sql->add(sprintf("ALTER TABLE %s ALTER %s SET DEFAULT nextval('%s')", $quoteName, $oldColumnName, $seqName)); + } + + public function compileAlterColumnType( + AbstractPlatform $platform, + ColumnDiff $columnDiff, + Column $column, + string $quoteName, + string $oldColumnName, + Collection $sql + ): void { + if (!$columnDiff->hasChanged('type') + && !$columnDiff->hasChanged('precision') + && !$columnDiff->hasChanged('scale') + && !$columnDiff->hasChanged('fixed') + ) { + return; + } + + $type = $column->getType(); + + $columnDefinition = $column->toArray(); + $columnDefinition['autoincrement'] = false; + + if ($this->typeChangeBreaksDefaultValue($columnDiff)) { + $sql->add(sprintf('ALTER TABLE %s ALTER %s DROP DEFAULT', $quoteName, $oldColumnName)); + } + + $typeName = $type->getSQLDeclaration($columnDefinition, $platform); + + if ($columnDiff->hasChanged('type')) { + $using = sprintf('USING %s::%s', $oldColumnName, $typeName); + + if ($columnDefinition['using'] ?? false) { + $using = 'USING ' . $columnDefinition['using']; + } + } + + $sql->add(trim(sprintf( + 'ALTER TABLE %s ALTER %s TYPE %s %s', + $quoteName, + $oldColumnName, + $typeName, + $using ?? '' + ))); + } + + public function getDefaultValueDeclarationSQL(AbstractPlatform $platform, Column $column): string + { + if ($column->getDefault() instanceof Expression) { + return ' DEFAULT ' . $column->getDefault(); + } + + return $platform->getDefaultValueDeclarationSQL($column->toArray()); + } + + public function typeChangeBreaksDefaultValue(ColumnDiff $columnDiff): bool + { + $oldTypeIsNumeric = $this->isNumericType($columnDiff->fromColumn->getType()); + $newTypeIsNumeric = $this->isNumericType($columnDiff->column->getType()); + + $isNumeric = !($oldTypeIsNumeric && $newTypeIsNumeric && $columnDiff->column->getAutoincrement()); + + return $columnDiff->hasChanged('type') && $isNumeric; + } + + public function isNumericType(Type $type): bool + { + return $type instanceof IntegerType || $type instanceof BigIntType; + } + + public function quoteName(AbstractPlatform $platform, TableDiff $diff): string + { + return $diff->getName($platform)->getQuotedName($platform); + } + + public function getOldColumnComment(ColumnDiff $columnDiff): ?string + { + return $columnDiff->fromColumn ? $this->getColumnComment($columnDiff->fromColumn) : null; + } + + public function getColumnComment(Column $column): ?string + { + return $column->getComment(); + } +} diff --git a/tests.sh b/tests.sh new file mode 100755 index 0000000..c4ce18c --- /dev/null +++ b/tests.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +psql postgres -U user -tc "SELECT 1 FROM pg_database WHERE datname = 'testing'" | grep -q 1 || psql postgres -U user -c "CREATE DATABASE testing" +composer lint +php -d pcov.directory='.' vendor/bin/phpunit --coverage-html build diff --git a/tests/Functional/FunctionalTestCase.php b/tests/Functional/FunctionalTestCase.php deleted file mode 100644 index af522b6..0000000 --- a/tests/Functional/FunctionalTestCase.php +++ /dev/null @@ -1,31 +0,0 @@ -set('database.default', 'testing'); - $app['config']->set('database.connections.testing', [ - 'driver' => 'pgsql', - 'host' => env('TEST_DB_HOST', 'localhost'), - 'port' => env('TEST_DB_PORT', 5432), - 'database' => env('TEST_DB', 'testing'), - 'username' => env('TEST_DB_USER', 'postgres'), - 'password' => env('TEST_DB_PASSWORD', ''), - 'charset' => 'utf8', - 'prefix' => '', - 'schema' => 'public', - ]); - } -} diff --git a/tests/Functional/HasIndexTest.php b/tests/Functional/HasIndexTest.php deleted file mode 100644 index 811ef37..0000000 --- a/tests/Functional/HasIndexTest.php +++ /dev/null @@ -1,42 +0,0 @@ -increments('id'); - $table->string('name'); - - if (!$table->hasIndex(['name'], true)) { - $table->unique(['name']); - } - }); - - $this->assertTrue(Schema::hasTable('test_table')); - - $indexes = $this->getIndexByName('test_table_name_unique'); - - Schema::table('test_table', function (Blueprint $table) { - if (!$table->hasIndex(['name'], true)) { - $table->unique(['name']); - } - }); - - $this->assertTrue(isset($indexes->indexdef)); - } - - protected function getIndexByName($name) - { - return collect(DB::select("SELECT indexdef FROM pg_indexes WHERE indexname = '{$name}'"))->first(); - } -} diff --git a/tests/Functional/Helpers/ColumnAssertions.php b/tests/Functional/Helpers/ColumnAssertions.php new file mode 100644 index 0000000..dc7e68a --- /dev/null +++ b/tests/Functional/Helpers/ColumnAssertions.php @@ -0,0 +1,72 @@ +getCommentListing($table, $column); + + if ($expected === null) { + $this->assertNull($comment); + } + + $this->assertSame($expected, $comment); + } + + protected function assertDefaultOnColumn(string $table, string $column, ?string $expected = null): void + { + $defaultValue = $this->getDefaultListing($table, $column); + + if ($expected === null) { + $this->assertNull($defaultValue); + } + + $this->assertSame($expected, $defaultValue); + } + + protected function assertTypeColumn(string $table, string $column, string $expected): void + { + $this->assertSame($expected, Schema::getColumnType($table, $column)); + } + private function getCommentListing(string $table, string $column) + { + $definition = DB::selectOne( + ' + SELECT pgd.description + FROM pg_catalog.pg_statio_all_tables AS st + INNER JOIN pg_catalog.pg_description pgd ON (pgd.objoid = st.relid) + INNER JOIN information_schema.columns c ON pgd.objsubid = c.ordinal_position + AND c.table_schema = st.schemaname AND c.table_name = st.relname + WHERE c.table_name = ? AND c.column_name = ? + ', + [$table, $column] + ); + + return $definition ? $definition->description : null; + } + + private function getDefaultListing(string $table, string $column) + { + $definition = DB::selectOne( + ' + SELECT column_default + FROM information_schema.columns c + WHERE c.table_name = ? and c.column_name = ? + ', + [$table, $column] + ); + + return $definition ? $definition->column_default : null; + } +} diff --git a/tests/Functional/Helpers/IndexAssertions.php b/tests/Functional/Helpers/IndexAssertions.php new file mode 100644 index 0000000..07d23d0 --- /dev/null +++ b/tests/Functional/Helpers/IndexAssertions.php @@ -0,0 +1,41 @@ +assertNotNull($this->getIndexListing($index)); + } + + protected function assertSameIndex(string $index, string $expectedDef): void + { + $definition = $this->getIndexListing($index); + + $this->seeIndex($index); + $this->assertSame($expectedDef, $definition); + } + + protected function assertRegExpIndex(string $index, string $expectedDef): void + { + $definition = $this->getIndexListing($index); + + $this->seeIndex($index); + $this->assertRegExp($expectedDef, $definition); + } + private function getIndexListing($index): ?string + { + $definition = DB::selectOne('SELECT indexdef FROM pg_indexes WHERE indexname = ?', [$index]); + + return $definition ? $definition->indexdef : null; + } +} diff --git a/tests/Functional/Helpers/TableAssertions.php b/tests/Functional/Helpers/TableAssertions.php new file mode 100644 index 0000000..c3a2c90 --- /dev/null +++ b/tests/Functional/Helpers/TableAssertions.php @@ -0,0 +1,36 @@ +assertSame($this->getTableDefinition($sourceTable), $this->getTableDefinition($destinationTable)); + } + + protected function assertSameTable(array $expectedDef, string $table): void + { + $definition = $this->getTableDefinition($table); + + $this->assertSame($expectedDef, $definition); + } + + protected function seeTable(string $table): void + { + $this->assertTrue(Schema::hasTable($table)); + } + + private function getTableDefinition(string $table): array + { + return Schema::getColumnListing($table); + } +} diff --git a/tests/Functional/Helpers/ViewAssertions.php b/tests/Functional/Helpers/ViewAssertions.php new file mode 100644 index 0000000..ea0c2d3 --- /dev/null +++ b/tests/Functional/Helpers/ViewAssertions.php @@ -0,0 +1,40 @@ +getViewDefinition($view); + + $this->assertSame($expectedDef, $definition); + } + + protected function seeView(string $view): void + { + $this->assertTrue(Schema::hasView($view)); + } + + protected function notSeeView(string $view): void + { + $this->assertFalse(Schema::hasView($view)); + } + + private function getViewDefinition(string $view): string + { + return preg_replace( + "#\s+#", + ' ', + strtolower(trim(str_replace("\n", ' ', Schema::getViewDefinition($view)))) + ); + } +} diff --git a/tests/Functional/UniqueIndexTest.php b/tests/Functional/Schema/CreateIndexTest.php similarity index 59% rename from tests/Functional/UniqueIndexTest.php rename to tests/Functional/Schema/CreateIndexTest.php index 8de9265..fac3a8f 100644 --- a/tests/Functional/UniqueIndexTest.php +++ b/tests/Functional/Schema/CreateIndexTest.php @@ -2,20 +2,48 @@ declare(strict_types=1); -namespace Umbrellio\Postgres\Tests\Functional; +namespace Umbrellio\Postgres\Tests\Functional\Schema; +use Closure; use Generator; -use Illuminate\Support\Facades\DB; +use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\Schema; use Umbrellio\Postgres\Schema\Blueprint; +use Umbrellio\Postgres\Tests\Functional\Helpers\IndexAssertions; +use Umbrellio\Postgres\Tests\FunctionalTestCase; -class UniqueIndexTest extends FunctionalTestCase +class CreateIndexTest extends FunctionalTestCase { + use DatabaseTransactions, IndexAssertions; + + /** @test */ + public function createIndexIfNotExists(): void + { + Schema::create('test_table', function (Blueprint $table) { + $table->increments('id'); + $table->string('name'); + + if (!$table->hasIndex(['name'], true)) { + $table->unique(['name']); + } + }); + + $this->assertTrue(Schema::hasTable('test_table')); + + Schema::table('test_table', function (Blueprint $table) { + if (!$table->hasIndex(['name'], true)) { + $table->unique(['name']); + } + }); + + $this->seeIndex('test_table_name_unique'); + } + /** * @test * @dataProvider provideIndexes */ - public function createPartialUniqueWithNull($expected, $callback): void + public function createPartialUniqueWithNull(string $expected, Closure $callback): void { Schema::create('test_table', function (Blueprint $table) use ($callback) { $table->increments('id'); @@ -25,15 +53,12 @@ public function createPartialUniqueWithNull($expected, $callback): void $table->boolean('enabled'); $table->integer('icq'); $table->softDeletes(); + $callback($table); }); $this->assertTrue(Schema::hasTable('test_table')); - - $indexes = $this->getIndexByName('test_table_name_unique'); - - $this->assertTrue(isset($indexes->indexdef)); - $this->assertSame($this->getDummyIndex() . $expected, $indexes->indexdef); + $this->assertRegExpIndex('test_table_name_unique', '/' . $this->getDummyIndex() . $expected . '/'); } /** @test */ @@ -45,9 +70,9 @@ public function createSpecifyIndex(): void $this->assertTrue(Schema::hasTable('test_table')); - $this->assertSame( - 'CREATE INDEX specify_index_name ON public.test_table USING btree (name)', - $this->getIndexByName('specify_index_name')->indexdef + $this->assertRegExpIndex( + 'specify_index_name', + '/CREATE INDEX specify_index_name ON (public.)?test_table USING btree \(name\)/' ); } @@ -57,86 +82,81 @@ public function provideIndexes(): Generator $table->uniquePartial('name'); }]; yield [ - ' WHERE (deleted_at IS NULL)', + ' WHERE \(deleted_at IS NULL\)', function (Blueprint $table) { $table->uniquePartial('name')->whereNull('deleted_at'); }, ]; yield [ - ' WHERE (deleted_at IS NOT NULL)', + ' WHERE \(deleted_at IS NOT NULL\)', function (Blueprint $table) { $table->uniquePartial('name')->whereNotNull('deleted_at'); }, ]; yield [ - ' WHERE (phone = 1234)', + ' WHERE \(phone = 1234\)', function (Blueprint $table) { $table->uniquePartial('name')->where('phone', '=', 1234); }, ]; yield [ - " WHERE ((code)::text = 'test'::text)", + " WHERE \(\(code\)::text = 'test'::text\)", function (Blueprint $table) { $table->uniquePartial('name')->where('code', '=', 'test'); }, ]; yield [ - ' WHERE ((phone >= 1) AND (phone <= 2))', + ' WHERE \(\(phone >= 1\) AND \(phone <= 2\)\)', function (Blueprint $table) { $table->uniquePartial('name')->whereBetween('phone', [1, 2]); }, ]; yield [ - ' WHERE ((phone < 1) OR (phone > 2))', + ' WHERE \(\(phone < 1\) OR \(phone > 2\)\)', function (Blueprint $table) { $table->uniquePartial('name')->whereNotBetween('phone', [1, 2]); }, ]; yield [ - ' WHERE (phone <> icq)', + ' WHERE \(phone <> icq\)', function (Blueprint $table) { $table->uniquePartial('name')->whereColumn('phone', '<>', 'icq'); }, ]; yield [ - ' WHERE ((phone = 1) AND (icq < 2))', + ' WHERE \(\(phone = 1\) AND \(icq < 2\)\)', function (Blueprint $table) { $table->uniquePartial('name')->whereRaw('phone = ? and icq < ?', [1, 2]); }, ]; yield [ - ' WHERE (phone = ANY (ARRAY[1, 2, 4]))', + ' WHERE \(phone = ANY \(ARRAY\[1, 2, 4\]\)\)', function (Blueprint $table) { $table->uniquePartial('name')->whereIn('phone', [1, 2, 4]); }, ]; yield [ - ' WHERE (0 = 1)', + ' WHERE \(0 = 1\)', function (Blueprint $table) { $table->uniquePartial('name')->whereIn('phone', []); }, ]; yield [ - ' WHERE (phone <> ALL (ARRAY[1, 2, 4]))', + ' WHERE \(phone <> ALL \(ARRAY\[1, 2, 4\]\)\)', function (Blueprint $table) { $table->uniquePartial('name')->whereNotIn('phone', [1, 2, 4]); }, ]; yield [ - ' WHERE (1 = 1)', + ' WHERE \(1 = 1\)', function (Blueprint $table) { $table->uniquePartial('name')->whereNotIn('phone', []); }, ]; } - protected function getDummyIndex() - { - return 'CREATE UNIQUE INDEX test_table_name_unique ON public.test_table USING btree (name)'; - } - - protected function getIndexByName($name) + protected function getDummyIndex(): string { - return collect(DB::select("SELECT indexdef FROM pg_indexes WHERE indexname = '{$name}'"))->first(); + return 'CREATE UNIQUE INDEX test_table_name_unique ON (public.)?test_table USING btree \(name\)'; } } diff --git a/tests/Functional/SchemaTest.php b/tests/Functional/Schema/CreateTableTest.php similarity index 53% rename from tests/Functional/SchemaTest.php rename to tests/Functional/Schema/CreateTableTest.php index 3e9f825..ce234a0 100644 --- a/tests/Functional/SchemaTest.php +++ b/tests/Functional/Schema/CreateTableTest.php @@ -2,27 +2,32 @@ declare(strict_types=1); -namespace Umbrellio\Postgres\Tests\Functional; +namespace Umbrellio\Postgres\Tests\Functional\Schema; +use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\Schema; use Umbrellio\Postgres\Schema\Blueprint; +use Umbrellio\Postgres\Tests\Functional\Helpers\TableAssertions; +use Umbrellio\Postgres\Tests\FunctionalTestCase; -class SchemaTest extends FunctionalTestCase +class CreateTableTest extends FunctionalTestCase { + use DatabaseTransactions, TableAssertions; + /** @test */ - public function create(): void + public function createSimple(): void { Schema::create('test_table', function (Blueprint $table) { $table->increments('id'); $table->string('name'); }); - $this->assertTrue(Schema::hasTable('test_table')); - $this->assertSame(['id', 'name'], Schema::getColumnListing('test_table')); + $this->seeTable('test_table'); + $this->assertSameTable(['id', 'name'], 'test_table'); } /** @test */ - public function createLikeSimple(): void + public function createViaLike(): void { Schema::create('test_table', function (Blueprint $table) { $table->increments('id'); @@ -33,14 +38,13 @@ public function createLikeSimple(): void $table->like('test_table'); }); - $this->assertTrue(Schema::hasTable('test_table')); - $this->assertTrue(Schema::hasTable('test_table2')); - - $this->assertSame(Schema::getColumnListing('test_table'), Schema::getColumnListing('test_table2')); + $this->seeTable('test_table'); + $this->seeTable('test_table2'); + $this->assertCompareTables('test_table', 'test_table2'); } /** @test */ - public function createLikeFull(): void + public function createViaLikeIncludingAll(): void { Schema::create('test_table', function (Blueprint $table) { $table->increments('id'); @@ -52,8 +56,8 @@ public function createLikeFull(): void $table->ifNotExists(); }); - $this->assertTrue(Schema::hasTable('test_table')); - $this->assertTrue(Schema::hasTable('test_table2')); - $this->assertSame(Schema::getColumnListing('test_table'), Schema::getColumnListing('test_table2')); + $this->seeTable('test_table'); + $this->seeTable('test_table2'); + $this->assertCompareTables('test_table', 'test_table2'); } } diff --git a/tests/Functional/ViewTest.php b/tests/Functional/Schema/CreateViewTest.php similarity index 51% rename from tests/Functional/ViewTest.php rename to tests/Functional/Schema/CreateViewTest.php index 755255e..a683af8 100644 --- a/tests/Functional/ViewTest.php +++ b/tests/Functional/Schema/CreateViewTest.php @@ -4,11 +4,16 @@ namespace Umbrellio\Postgres\Tests\Functional; +use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\Schema; use Umbrellio\Postgres\Schema\Blueprint; +use Umbrellio\Postgres\Tests\Functional\Helpers\ViewAssertions; +use Umbrellio\Postgres\Tests\FunctionalTestCase; -class ViewTest extends FunctionalTestCase +class CreateViewTest extends FunctionalTestCase { + use DatabaseTransactions, ViewAssertions; + protected function setUp(): void { parent::setUp(); @@ -29,35 +34,33 @@ public function createFacadeView(): void { Schema::createView('test_view', 'select * from test_table where name is not null'); - $this->assertSame( - strtolower( - 'select test_table.id, test_table.name from test_table where (test_table.name is not null);' - ), - trim(strtolower(str_replace("\n", ' ', Schema::getViewDefinition('test_view')))) + $this->seeView('test_view'); + $this->assertSameView( + 'select test_table.id, test_table.name from test_table where (test_table.name is not null);', + 'test_view' ); Schema::dropView('test_view'); - $this->assertFalse(Schema::hasView('test_view')); + $this->notSeeView('test_view'); } /** @test */ public function createBlueprintView(): void { - Schema::create('users', function (Blueprint $table) { - $table->increments('id'); - $table->string('name'); - $table->createView('test_view', 'select * from users where name is not null'); + Schema::table('test_table', function (Blueprint $table) { + $table->createView('test_view', 'select * from test_table where name is not null'); }); - $this->assertSame( - strtolower('select users.id, users.name from users where (users.name is not null);'), - trim(strtolower(str_replace("\n", ' ', Schema::getViewDefinition('test_view')))) + $this->seeView('test_view'); + $this->assertSameView( + 'select test_table.id, test_table.name from test_table where (test_table.name is not null);', + 'test_view' ); Schema::table('users', function (Blueprint $table) { $table->dropView('test_view'); }); - $this->assertFalse(Schema::hasView('test_view')); + $this->notSeeView('test_view'); } } diff --git a/tests/Functional/Subscribers/ChangeColumnSubscriberTest.php b/tests/Functional/Subscribers/ChangeColumnSubscriberTest.php new file mode 100644 index 0000000..6a10072 --- /dev/null +++ b/tests/Functional/Subscribers/ChangeColumnSubscriberTest.php @@ -0,0 +1,346 @@ +blueprint = new Blueprint('some_table'); + $this->postgresGrammar = new PostgresGrammar(); + $this->subscriber = new SchemaAlterTableChangeColumnSubscriber(); + $this->platform = new PostgreSqlPlatform(); + } + + /** @test */ + public function getSubscriberEvents(): void + { + $this->assertSame([Events::onSchemaAlterTableChangeColumn], $this->subscriber->getSubscribedEvents()); + } + + /** + * @test + * @dataProvider provideSchemas + */ + public function changeSchema(string $column, Closure $callback, array $expectedSQL): void + { + $callback($this->blueprint, $column); + $eventArgs = $this->getEventArgsForColumn($column); + $this->subscriber->onSchemaAlterTableChangeColumn($eventArgs); + + $this->assertSame($expectedSQL, $eventArgs->getSql()); + } + + public function provideSchemas(): Generator + { + yield $this->dropCommentCase(); + yield $this->changeCommentCase(); + yield $this->dropNotNullCase(); + yield $this->createSequenceCase(); + yield $this->dropDefaultCase(); + yield $this->setSimpleDefaultCase(); + yield $this->setExpressionDefaultCase(); + yield $this->changeTypeWithUsingCase(); + yield $this->changeLengthCase(); + } + + private function getEventArgsForColumn(string $columnName): SchemaAlterTableChangeColumnEventArgs + { + /** @var PostgresConnection $connection */ + $connection = DB::connection(); + $schemaManager = $connection->getDoctrineSchemaManager(); + + $this->columns = []; + foreach ($this->getListColumns() as $listColumn) { + $this->columns[] = ReflectionHelper::invokePrivateMethod( + $schemaManager, + '_getPortableTableColumnDefinition', + ['tableName' => $listColumn] + ); + } + + $this->table = new Table('some_table', $this->columns); + + $this->tableDiff = (new Comparator())->diffTable( + $this->table, + $this + ->getStaticMethod(ChangeColumn::class, 'getTableWithColumnChanges') + ->invoke(null, $this->blueprint, $this->table) + ); + + foreach ($this->tableDiff->changedColumns as $columnDiff) { + if ($columnDiff->oldColumnName !== $columnName) { + continue; + } + $this->columnDiff = $columnDiff; + } + + return new SchemaAlterTableChangeColumnEventArgs($this->columnDiff, $this->tableDiff, $this->platform); + } + + private function dropCommentCase(): array + { + return [ + 'some_comment', + function (Blueprint $table, string $column) { + $table->string($column)->nullable(false)->change(); + }, + ['ALTER TABLE some_table ALTER some_comment SET NOT NULL'], + ]; + } + + private function changeCommentCase(): array + { + return [ + 'some_comment', + function (Blueprint $table, string $column) { + $table->string($column) + ->comment('new_comment') + ->change(); + }, + ["COMMENT ON COLUMN some_table.some_comment IS 'new_comment'"], + ]; + } + + private function dropNotNullCase(): array + { + return [ + 'some_integer_default', + function (Blueprint $table, string $column) { + $table->integer($column)->nullable()->change(); + }, + ['ALTER TABLE some_table ALTER some_integer_default DROP NOT NULL'], + ]; + } + + private function createSequenceCase(): array + { + return [ + 'some_integer_default', + function (Blueprint $table, string $column) { + $table->increments($column)->change(); + }, + [ + 'CREATE SEQUENCE some_table_some_integer_default_seq', + "SELECT setval('some_table_some_integer_default_seq', (SELECT MAX(some_integer_default) FROM some_table))", + "ALTER TABLE some_table ALTER some_integer_default SET DEFAULT nextval('some_table_some_integer_default_seq')", + ], + ]; + } + + private function dropDefaultCase(): array + { + return [ + 'some_key', + function (Blueprint $table, string $column) { + $table->integer($column)->change(); + }, + [ + 'ALTER TABLE some_table ALTER some_key DROP DEFAULT', + 'ALTER TABLE some_table ALTER some_key TYPE INT USING some_key::INT', + ], + ]; + } + + private function setSimpleDefaultCase(): array + { + return [ + 'some_comment', + function (Blueprint $table, string $column) { + $table->string($column)->default('some_default')->change(); + }, + ["ALTER TABLE some_table ALTER some_comment SET DEFAULT 'some_default'"], + ]; + } + + private function setExpressionDefaultCase(): array + { + return [ + 'some_comment', + function (Blueprint $table, string $column) { + $table->string($column)->default( + new Expression("('some_string:' || some_comment)::character varying") + )->change(); + }, + [ + "ALTER TABLE some_table ALTER some_comment SET DEFAULT ('some_string:' || some_comment)::character varying", + ], + ]; + } + + private function changeTypeWithUsingCase(): array + { + return [ + 'some_integer_default', + function (Blueprint $table, string $column) { + $table + ->text($column) + ->default(null) + ->using(sprintf("('[some_exp:' || %s || ']')::character varying", $column)) + ->change(); + }, + [ + 'ALTER TABLE some_table ALTER some_integer_default DROP DEFAULT', + "ALTER TABLE some_table ALTER some_integer_default TYPE TEXT USING ('[some_exp:' || some_integer_default || ']')::character varying", + ], + ]; + } + + private function changeLengthCase(): array + { + return [ + 'some_comment', + function (Blueprint $table, string $column) { + $table->string($column, 75)->change(); + }, + ['ALTER TABLE some_table ALTER some_comment TYPE VARCHAR(75)'], + ]; + } + + private function getListColumns(): array + { + return [ + $this->getDefinitionSomeKeySequence(), + $this->getDefinitionSomeString(), + $this->getDefinitionSomeStringDefault(), + $this->getDefinitionSomeIntegerDefault(), + $this->getDefinitionSomeComment(), + ]; + } + + private function getStaticMethod($class, $method): ReflectionMethod + { + $method = new ReflectionMethod($class, $method); + $method->setAccessible(true); + + return $method; + } + + private function getDefinitionSomeKeySequence(): array + { + return [ + 'attnum' => 1, + 'field' => 'some_key', + 'type' => 'int8', + 'complete_type' => 'bigint', + 'domain_type' => null, + 'domain_complete_type' => null, + 'isnotnull' => true, + 'pri' => 't', + 'default' => "nextval('some_table_some_key_seq'::regclass)", + 'comment' => null, + ]; + } + + private function getDefinitionSomeString(): array + { + return [ + 'attnum' => 2, + 'field' => 'some_string', + 'type' => 'varchar', + 'complete_type' => 'character varying', + 'domain_type' => null, + 'domain_complete_type' => null, + 'isnotnull' => false, + 'pri' => null, + 'default' => null, + 'comment' => null, + ]; + } + + private function getDefinitionSomeStringDefault(): array + { + return [ + 'attnum' => 3, + 'field' => 'some_string_default', + 'type' => 'varchar', + 'complete_type' => 'character varying', + 'domain_type' => null, + 'domain_complete_type' => null, + 'isnotnull' => true, + 'pri' => null, + 'default' => "'some_default_value'::character varying", + 'comment' => null, + ]; + } + + private function getDefinitionSomeIntegerDefault(): array + { + return [ + 'attnum' => 4, + 'field' => 'some_integer_default', + 'type' => 'int4', + 'complete_type' => 'integer', + 'domain_type' => null, + 'domain_complete_type' => null, + 'isnotnull' => true, + 'pri' => null, + 'default' => 1, + 'comment' => null, + ]; + } + + private function getDefinitionSomeComment(): array + { + return [ + 'attnum' => 5, + 'field' => 'some_comment', + 'type' => 'varchar', + 'complete_type' => 'character varying', + 'domain_type' => null, + 'domain_complete_type' => null, + 'isnotnull' => false, + 'pri' => null, + 'default' => null, + 'comment' => 'some_comment_value', + ]; + } +} diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php new file mode 100644 index 0000000..ecf2691 --- /dev/null +++ b/tests/FunctionalTestCase.php @@ -0,0 +1,49 @@ +getConnectionParams(); + + $app['config']->set('database.default', 'main'); + $app['config']->set('database.connections.main', [ + 'driver' => 'pgsql', + 'host' => $params['host'], + 'port' => (int) $params['port'], + 'database' => $params['database'], + 'username' => $params['user'], + 'password' => $params['password'], + 'charset' => 'utf8', + 'prefix' => '', + 'schema' => 'public', + ]); + } + + private function getConnectionParams(): array + { + return [ + 'driver' => $GLOBALS['db_type'] ?? 'pdo_pgsql', + 'user' => $GLOBALS['db_username'], + 'password' => $GLOBALS['db_password'], + 'host' => $GLOBALS['db_host'], + 'database' => $GLOBALS['db_database'], + 'port' => $GLOBALS['db_port'], + ]; + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 2467719..67c8ab0 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -9,7 +9,7 @@ abstract class TestCase extends BaseTestCase { - protected function getPackageProviders($app) + protected function getPackageProviders($app): array { return [UmbrellioPostgresProvider::class]; } diff --git a/tests/Unit/Extensions/AbstractExtensionTest.php b/tests/Unit/Extensions/AbstractExtensionTest.php new file mode 100644 index 0000000..24c1ee9 --- /dev/null +++ b/tests/Unit/Extensions/AbstractExtensionTest.php @@ -0,0 +1,65 @@ + new class() extends Model { + }, + ]; + } + }; + + $this->expectException(MixinInvalidException::class); + + /** @var AbstractExtension $abstractExtension */ + $abstractExtension::register(); + } + + /** @test */ + public function registerWithInvalidMixin(): void + { + $abstractExtension = new class() extends AbstractExtension { + public static function getName(): string + { + return 'extension'; + } + + public static function getMixins(): array + { + return [ + ServiceProvider::class => new class() extends AbstractComponent { + }, + ]; + } + }; + + $this->expectException(MacroableMissedException::class); + + /** @var AbstractExtension $abstractExtension */ + $abstractExtension::register(); + } +} diff --git a/tests/Unit/Helpers/BlueprintAssertions.php b/tests/Unit/Helpers/BlueprintAssertions.php new file mode 100644 index 0000000..be7de4b --- /dev/null +++ b/tests/Unit/Helpers/BlueprintAssertions.php @@ -0,0 +1,51 @@ +blueprint = new Blueprint($table); + $this->postgresConnection = $this->createMock(PostgresConnection::class); + $this->postgresGrammar = new PostgresGrammar(); + } + + /** + * @param string|array $sql + */ + protected function assertSameSql($sql): void + { + $this->assertSame((array) $sql, $this->runToSql()); + } + + protected function assertRegExpSql(string $regexpExpected): void + { + foreach ($this->runToSql() as $sql) { + $this->assertRegExp($regexpExpected, $sql); + } + } + + private function runToSql(): array + { + return $this->blueprint->toSql($this->postgresConnection, $this->postgresGrammar); + } +} diff --git a/tests/Unit/Schema/BlueprintTest.php b/tests/Unit/Schema/Blueprint/PartitionTest.php similarity index 73% rename from tests/Unit/Schema/BlueprintTest.php rename to tests/Unit/Schema/Blueprint/PartitionTest.php index 8c76c0f..8556790 100644 --- a/tests/Unit/Schema/BlueprintTest.php +++ b/tests/Unit/Schema/Blueprint/PartitionTest.php @@ -2,32 +2,29 @@ declare(strict_types=1); -namespace Umbrellio\Postgres\Unit\Schema; +namespace Umbrellio\Postgres\Unit\Schema\Blueprint; use Illuminate\Support\Carbon; use InvalidArgumentException; -use Umbrellio\Postgres\PostgresConnection; -use Umbrellio\Postgres\Schema\Blueprint; -use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar; use Umbrellio\Postgres\Tests\TestCase; +use Umbrellio\Postgres\Tests\Unit\Helpers\BlueprintAssertions; -class BlueprintTest extends TestCase +class PartitionTest extends TestCase { - /** @var Blueprint */ - private $blueprint; + use BlueprintAssertions; + + private const TABLE = 'test_table'; protected function setUp(): void { parent::setUp(); - - $this->blueprint = new Blueprint('test_table'); + $this->initializeMock(static::TABLE); } /** @test */ public function detachPartition(): void { $this->blueprint->detachPartition('some_partition'); - $this->assertSameSql('alter table "test_table" detach partition some_partition'); } @@ -38,7 +35,6 @@ public function attachPartitionRangeInt(): void 'from' => 10, 'to' => 100, ]); - $this->assertSameSql('alter table "test_table" attach partition some_partition for values from (10) to (100)'); } @@ -46,7 +42,6 @@ public function attachPartitionRangeInt(): void public function attachPartitionFailedWithoutForValuesPart(): void { $this->blueprint->attachPartition('some_partition'); - $this->expectException(InvalidArgumentException::class); $this->runToSql(); } @@ -61,9 +56,11 @@ public function attachPartitionRangeDates(): void 'to' => $tomorrow, ]); - $this->assertSameSql( - 'alter table "test_table" attach partition some_partition ' - . "for values from ('{$today->toDateTimeString()}') to ('{$tomorrow->toDateTimeString()}')"); + $this->assertSameSql(sprintf( + 'alter table "test_table" attach partition some_partition for values from (\'%s\') to (\'%s\')', + $today->toDateTimeString(), + $tomorrow->toDateTimeString() + )); } /** @test */ @@ -86,14 +83,4 @@ public function addingNumericColumnWithDefinedPrecicionAndScope() $this->blueprint->numeric('foo', 8, 2); $this->assertSameSql('alter table "test_table" add column "foo" numeric(8, 2) not null'); } - - private function assertSameSql(string $sql): void - { - $this->assertSame([$sql], $this->runToSql()); - } - - private function runToSql(): array - { - return $this->blueprint->toSql($this->createMock(PostgresConnection::class), new PostgresGrammar()); - } } diff --git a/tests/Unit/Schema/Grammars/GrammarTest.php b/tests/Unit/Schema/Grammars/GrammarTest.php deleted file mode 100644 index 808628b..0000000 --- a/tests/Unit/Schema/Grammars/GrammarTest.php +++ /dev/null @@ -1,46 +0,0 @@ -gin('foo'); - $statements = $blueprint->toSql($this->getConnectionMock(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertStringContainsString('CREATE INDEX', $statements[0]); - $this->assertStringContainsString('GIN("foo")', $statements[0]); - } - - /** @test */ - public function addingGistIndex() - { - $blueprint = new Blueprint('test'); - $blueprint->gist('foo'); - $statements = $blueprint->toSql($this->getConnectionMock(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertStringContainsString('CREATE INDEX', $statements[0]); - $this->assertStringContainsString('GIST("foo")', $statements[0]); - } - - protected function getConnectionMock() - { - return Mockery::mock(PostgresConnection::class); - } - - protected function getGrammar() - { - return new PostgresGrammar(); - } -} diff --git a/tests/Unit/Schema/IndexTest.php b/tests/Unit/Schema/IndexTest.php deleted file mode 100644 index 1b05de6..0000000 --- a/tests/Unit/Schema/IndexTest.php +++ /dev/null @@ -1,42 +0,0 @@ -blueprint = Mockery::mock(Blueprint::class) - ->makePartial() - ->shouldAllowMockingProtectedMethods(); - } - - /** @test */ - public function ginIndex() - { - $this->blueprint - ->shouldReceive('indexCommand') - ->with('gin', 'col', 'myName'); - $this->blueprint->gin('col', 'myName'); - } - - /** @test */ - public function gistIndex() - { - $this->blueprint - ->shouldReceive('indexCommand') - ->with('gist', 'col', 'myName'); - $this->blueprint->gist('col', 'myName'); - } -} diff --git a/tests/travis/install-postgres-10.sh b/tests/travis/install-postgres-10.sh new file mode 100755 index 0000000..8804124 --- /dev/null +++ b/tests/travis/install-postgres-10.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -ex + +echo "Installing Postgres 10" +sudo service postgresql stop +sudo apt-get remove -q 'postgresql-*' +sudo apt-get update -q +sudo apt-get install -q postgresql-10 postgresql-client-10 +sudo cp /etc/postgresql/{9.6,10}/main/pg_hba.conf + +echo "Restarting Postgres 10" +sudo service postgresql restart diff --git a/tests/travis/install-postgres-11.sh b/tests/travis/install-postgres-11.sh new file mode 100755 index 0000000..2ef1aab --- /dev/null +++ b/tests/travis/install-postgres-11.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -ex + +echo "Preparing Postgres 11" + +sudo service postgresql stop || true + +sudo docker run -d --name postgres11 -p 5432:5432 postgres:11.1 +sudo docker exec -i postgres11 bash <<< 'until pg_isready -U postgres > /dev/null 2>&1 ; do sleep 1; done' + +echo "Postgres 11 ready"