From 62c27a0e17ad5845e350bd24c7c1c2552bda0e08 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Thu, 29 Sep 2022 16:07:31 -0400 Subject: [PATCH 01/13] [changelog] update changelog [skip ci] --- CHANGELOG.md | 299 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..ba4947750 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,299 @@ +# CHANGELOG + +## [v1.22.1](https://github.com/zenstruck/foundry/releases/tag/v1.22.1) + +September 28th, 2022 - [v1.22.0...v1.22.1](https://github.com/zenstruck/foundry/compare/v1.22.0...v1.22.1) + +* 8d41ca8 [bug] discover relations with inheritance (#300) by @NorthBlue333 +* ae6bda2 [bug] multiple relationships with same entity (#302) by @NorthBlue333 + +## [v1.22.0](https://github.com/zenstruck/foundry/releases/tag/v1.22.0) + +September 21st, 2022 - [v1.21.1...v1.22.0](https://github.com/zenstruck/foundry/compare/v1.21.1...v1.22.0) + +* 4fb5fb8 [feature] Introduce Sequences (#298) by @nikophil + +## [v1.21.1](https://github.com/zenstruck/foundry/releases/tag/v1.21.1) + +September 12th, 2022 - [v1.21.0...v1.21.1](https://github.com/zenstruck/foundry/compare/v1.21.0...v1.21.1) + +* 3b105a7 [bug] Fix usage of faker dateTime in factory maker (#297) by @jmsche +* 0663f29 [doc] Fix code block docs about faker seed (#296) by @jmsche +* b57d067 [doc] fix typo (#295) by @Chris53897 +* 4577ef4 [minor] Improve deprecation message for `createMany()` (#291) by @gazzatav, @kbond + +## [v1.21.0](https://github.com/zenstruck/foundry/releases/tag/v1.21.0) + +June 27th, 2022 - [v1.20.0...v1.21.0](https://github.com/zenstruck/foundry/compare/v1.20.0...v1.21.0) + +* e02fbe1 [doc] update config for 5.4+ (#285) by @kbond +* 39258de [feature] add configuration option for faker generator seed (#285) by @kbond +* 1bd05ce [feature] re-save created object after "afterPersist" events called (#279) by @kbond +* 195c815 [bug] Use DateTimeImmutable with immutable ORM types (#283) by @HypeMC + +## [v1.20.0](https://github.com/zenstruck/foundry/releases/tag/v1.20.0) + +June 20th, 2022 - [v1.19.0...v1.20.0](https://github.com/zenstruck/foundry/compare/v1.19.0...v1.20.0) + +* 6009499 [feature] add `Story::getPool()` (#282) by @kbond + +## [v1.19.0](https://github.com/zenstruck/foundry/releases/tag/v1.19.0) + +May 24th, 2022 - [v1.18.2...v1.19.0](https://github.com/zenstruck/foundry/compare/v1.18.2...v1.19.0) + +* 46de01a [feature] Handle variadic constructor arguments (#277) by @ndench +* f5d9177 [minor] use symfony/phpunit-bridge 6+ by @kbond +* 09b0ae2 [minor] fix sca by @kbond + +## [v1.18.2](https://github.com/zenstruck/foundry/releases/tag/v1.18.2) + +April 29th, 2022 - [v1.18.1...v1.18.2](https://github.com/zenstruck/foundry/compare/v1.18.1...v1.18.2) + +* 2b2d2e7 [minor] allow `doctrine/persistence` 3 (#275) by @kbond +* 429466e [doc] add note about phpstan docblocks (#274) by @kbond, Jacob Dreesen + +## [v1.18.1](https://github.com/zenstruck/foundry/releases/tag/v1.18.1) + +April 22nd, 2022 - [v1.18.0...v1.18.1](https://github.com/zenstruck/foundry/compare/v1.18.0...v1.18.1) + +* ff9e4ef [bug] fix embeddable support when used with file (ie xml) mapping (#271) by @kbond +* 40a5a1e [minor] support Symfony 6.1 (#267) by @kbond + +## [v1.18.0](https://github.com/zenstruck/foundry/releases/tag/v1.18.0) + +April 11th, 2022 - [v1.17.0...v1.18.0](https://github.com/zenstruck/foundry/compare/v1.17.0...v1.18.0) + +* b9d2ed3 [feature] add `Factory::delayFlush()` (#84) by @kbond +* 91609b4 [minor] remove scrutinizer (#266) by @kbond +* 8117f40 [minor] allow `dama/doctrine-test-bundle` 7.0 (#266) by @kbond +* 6052e81 [minor] Revert "[bug] fix global state with symfony/framework-bundle >= 5.4.6/6.0.6" (#260) by @kbond + +## [v1.17.0](https://github.com/zenstruck/foundry/releases/tag/v1.17.0) + +March 24th, 2022 - [v1.16.0...v1.17.0](https://github.com/zenstruck/foundry/compare/v1.16.0...v1.17.0) + +* c131715 [bug] fix global state with symfony/framework-bundle >= 5.4.6/6.0.6 (#259) by @kbond +* 0edbea8 [minor] remove Symfony 5.3 from test matrix (#259) by @kbond +* 5768345 [feature] add Story "pools" (#252) by @kbond +* be6b6c8 Revert "[feature] Allow any type for Story States (#231)" (#252) by @kbond +* 02cd0c8 [minor] deprecate `Story:add()` and add `Story::addState()` (#254) by @kbond +* 02609a9 [minor] add return type for stub command (deprecated in symfony 6) (#257) by @Chris53897, Christopher Georg +* 6977f3a [doc] Use `UserPasswordHasherInterface` instead of `UserPasswordEncoderInterface` (#255) by @zairigimad +* 01ebfab [feature] add an 'All' option to make:factory to create all missing factories (#247) by @abeal-hottomali +* 39fa8e2 [bug] ignore abstract classes in the maker (#249) by @abeal-hottomali +* 62eeb75 [minor] run php-cs-fixer on php 7.2 (#243) by @kbond + +## [v1.16.0](https://github.com/zenstruck/foundry/releases/tag/v1.16.0) + +January 6th, 2022 - [v1.15.0...v1.16.0](https://github.com/zenstruck/foundry/compare/v1.15.0...v1.16.0) + +* 79261d6 [feature] MongoDB ODM Support (#153) by @kbond, @nikophil +* d97d895 [minor] fix psalm (#232) by @kbond +* fc74f26 [minor] add allow-plugins for composer 2.2+ (#232) by @kbond + +## [v1.15.0](https://github.com/zenstruck/foundry/releases/tag/v1.15.0) + +December 30th, 2021 - [v1.14.1...v1.15.0](https://github.com/zenstruck/foundry/compare/v1.14.1...v1.15.0) + +* fb79022 [feature] Allow any type for Story States (#231) by @wouterj +* d6d7d52 [doc] update url (#230) by @bfoks +* 4915b61 [doc] Fix event hook argument name (#229) by @Aeet, @kbond +* 7e13ed0 [doc] add note about how attributes are built (#228) by @gnito-org +* 552dc6f [doc] Correct spelling in index.rst (#226) by @gnito-org +* 50a91b9 [bug] Fix smallint generated Faker (#223) by @jmsche +* 68552a7 [doc] Document the MakeFactory all-fields option (#220) by @gnito-org +* 93a2f9c [feature] Add all-fields option to MakeFactory (#218) by @gnito-org + +## [v1.14.1](https://github.com/zenstruck/foundry/releases/tag/v1.14.1) + +December 2nd, 2021 - [v1.14.0...v1.14.1](https://github.com/zenstruck/foundry/compare/v1.14.0...v1.14.1) + +* bf1cbc9 [minor] Bump symfony/http-kernel from 5.3.7 to 5.4.0 in /bin/tools/psalm (#217) by @dependabot[bot], dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +* 433f9b2 [minor] allow symfony/deprecation-contracts 3+ by @kbond +* 2b10729 [minor] fix failing test by @kbond +* b3ce03f [minor] add void return type (#176) by @seb-jean + +## [v1.14.0](https://github.com/zenstruck/foundry/releases/tag/v1.14.0) + +November 13th, 2021 - [v1.13.4...v1.14.0](https://github.com/zenstruck/foundry/compare/v1.13.4...v1.14.0) + +* 46e968e [minor] add Symfony 6.0/PHP 8.1 support (#198) by @kbond + +## [v1.13.4](https://github.com/zenstruck/foundry/releases/tag/v1.13.4) + +October 21st, 2021 - [v1.13.3...v1.13.4](https://github.com/zenstruck/foundry/compare/v1.13.3...v1.13.4) + +* 676f00a [bug] disable migration transactions (#207) by @kbond +* c6df43d [ci] re-enable migration tests on php >= 8 (#207) by @kbond +* 2ef6c6a [ci] disable migration tests on php >= 8 (#206) by @kbond +* e29a008 [bug] fix maker auto-defaults with yaml driver (#205) by @domagoj-orioly +* c483b2e [ci] use reusable workflows where possible (#203) by @kbond +* 886204f [minor] adjust CI output by @kbond +* 63a956e [minor] use zenstruck/assert for assertions instead of phpunit (#182) by @kbond + +## [v1.13.3](https://github.com/zenstruck/foundry/releases/tag/v1.13.3) + +September 24th, 2021 - [v1.13.2...v1.13.3](https://github.com/zenstruck/foundry/compare/v1.13.2...v1.13.3) + +* 477db0a [minor] install psalm as composer-bin tool (#199) by @kbond +* 6ced887 [minor] add Symfony 5.4 to test matrix (#197) by @kbond +* 6610c5d [bug] rename "rank" as it's a reserved keyword in mysql 8 (#197) by @kbond + +## [v1.13.2](https://github.com/zenstruck/foundry/releases/tag/v1.13.2) + +September 3rd, 2021 - [v1.13.1...v1.13.2](https://github.com/zenstruck/foundry/compare/v1.13.1...v1.13.2) + +* 06b24d4 [bug] when creating collections, check for is persisting first (#195) by @jordisala1991, @kbond + +## [v1.13.1](https://github.com/zenstruck/foundry/releases/tag/v1.13.1) + +August 31st, 2021 - [v1.13.0...v1.13.1](https://github.com/zenstruck/foundry/compare/v1.13.0...v1.13.1) + +* 1dccda1 [bug] fix/improve embeddable support (#193) by @kbond +* 5f39d8a [minor] update symfony-tools/docs-builder by @kbond + +## [v1.13.0](https://github.com/zenstruck/foundry/releases/tag/v1.13.0) + +August 30th, 2021 - [v1.12.0...v1.13.0](https://github.com/zenstruck/foundry/compare/v1.12.0...v1.13.0) + +* 39f69f9 [doc] update symfony.com links (#191) by @kbond +* 31b7569 [doc] switch documentation to symfony.com bundle doc format (#190) by @kbond, @wouterj +* d4943d7 [minor] exclude maker templates from phpunit code coverage (#189) by @kbond +* 60f78b3 [doc] add note about simplified factory annotations in PhpStorm 2021.2+ (#189) by @kbond +* 8769d7a [minor] update factory maker template annotations (#189) by @kbond +* 1faf97d [feature] persisting factories respect cascade persist (#181) by @mpiot +* 0416dc4 [minor] Be able to remove most of method annotations on user factories (#185) by @Nyholm +* 468e80b [minor] add missing ->expectDeprecation() to legacy tests (#188) by @kbond +* 1647e1b [bug] ensure legacy test works as expected (#187) by @kbond +* a6f6413 [minor] Added .editorconfig to sync up styles (#186) by @Nyholm +* 2517f54 [minor] change Instantiator::$forceProperties type-hint (#183) by @kbond +* b145059 [minor] psalm fix (#180) by @kbond + +## [v1.12.0](https://github.com/zenstruck/foundry/releases/tag/v1.12.0) + +July 6th, 2021 - [v1.11.1...v1.12.0](https://github.com/zenstruck/foundry/compare/v1.11.1...v1.12.0) + +* 6b97f0f [minor] refactor make:factory auto-default feature (#174) by @kbond +* 2a0bbce [feature] Auto populate ModelFactory::getDefaults() from doctrine mapping (#173) by @benblub + +## [v1.11.1](https://github.com/zenstruck/foundry/releases/tag/v1.11.1) + +June 25th, 2021 - [v1.11.0...v1.11.1](https://github.com/zenstruck/foundry/compare/v1.11.0...v1.11.1) + +* ccac05c [minor] disable codecov pr annotations (#172) by @kbond +* 5c3abe2 [bug] allow passing full namespace with make:factory (#171) by @kbond + +## [v1.11.0](https://github.com/zenstruck/foundry/releases/tag/v1.11.0) + +June 4th, 2021 - [v1.10.0...v1.11.0](https://github.com/zenstruck/foundry/compare/v1.10.0...v1.11.0) + +* d2cd4c7 [feature] customize namespace for factories generated with make:factory (#164) by @kbond +* b9c161b [minor] suppress psalm error (#165) by @kbond +* 112d57d [feature] make:factory only lists entities w/o factories (#162) by @jschaedl +* 6001e7e [minor] Detect missing maker bundle and suggest installation via StubCommands (#161) by @jschaedl +* cdab96e [minor] upgrade to php-cs-fixer 3 (#159) by @kbond +* d357215 [minor] update php-cs-fixer config (#159) by @kbond +* 3ce7da0 [minor] Update .gitattributes file (#158) by @ker0x +* be1d899 [doc] Fix example $posts for Attributes section (#155) by @babeuloula + +## [v1.10.0](https://github.com/zenstruck/foundry/releases/tag/v1.10.0) + +April 19th, 2021 - [v1.9.1...v1.10.0](https://github.com/zenstruck/foundry/compare/v1.9.1...v1.10.0) + +* 7dc49f0 [minor] unlock php-cs-fixer in gh action by @kbond +* e800c83 [feature] add option to use doctrine migrations to reset database (#145) by @kbond +* 8466067 [doc] fix small typo in docs (#147) by @nikophil +* 69fe2a6 [doc] fix typo (#146) by @AntoineRoue +* 463d32a [minor] fix faker deprecations by @kbond +* aa6b32a [minor] lock php-cs-fixer version in ci (bug in latest release) by @kbond +* 4dc13e6 [minor] adjust codecov threshold by @kbond +* cd5cefe [minor] use SHELL_VERBOSITY to hide logs during tests by @kbond + +## [v1.9.1](https://github.com/zenstruck/foundry/releases/tag/v1.9.1) + +March 19th, 2021 - [v1.9.0...v1.9.1](https://github.com/zenstruck/foundry/compare/v1.9.0...v1.9.1) + +* 0ebf0dd [bug] fix false positive for auto-refresh deprecation (fixes #141) (#143) by @kbond +* 7e693ed [doc] remove unnecessary notes about rebooting kernel (ref: #140) (#142) by @kbond +* ba7947c [minor] improve make:factory error message when no entities exist (#139) by @kbond +* 3812def [minor] use project var dir for test cache/logs (#139) by @kbond + +## [v1.9.0](https://github.com/zenstruck/foundry/releases/tag/v1.9.0) + +March 12th, 2021 - [v1.8.0...v1.9.0](https://github.com/zenstruck/foundry/compare/v1.8.0...v1.9.0) + +* 0872be0 [doc] Add --test option as tip (#138) by @OskarStark +* f55afe2 [doc] Fix typos in the docs (#136) by @jdreesen +* 88c081e [minor] "require" explicitly configuring global auto_refresh_proxies (#131) by @kbond +* 632de3d [feature] throw exception during autorefresh if unsaved changes detected (#131) by @kbond +* 5318c7f [minor] deprecate instantiating Factory directly: (#134) by @kbond +* b7a7880 [feature] add AnonymousFactory (#134) by @kbond +* 228895f [minor] add dev stability to ci matrix (#133) by @kbond +* b759712 [minor] explicitly add sqlite extension for gh actions (#130) by @kbond +* 1f332ed [bug] Fix exception message (#129) by @jdreesen +* 4bc80fb [minor] increase codecov threshold by @kbond + +## [v1.8.0](https://github.com/zenstruck/foundry/releases/tag/v1.8.0) + +February 27th, 2021 - [v1.7.1...v1.8.0](https://github.com/zenstruck/foundry/compare/v1.7.1...v1.8.0) + +* 83d6b26 [feature] add ModelFactory::assert()/RepositoryProxy::assert() (#123) by @kbond +* a657d14 [feature] add ModelFactory::all()/find()/findBy() (#123) by @kbond +* ac775b9 [feature] add ModelFactory::count()/truncate() (#123) by @kbond +* 34373da [feature] add ModelFactory::first()/last() (#123) by @kbond +* 5978574 [minor] psalm fixes (#122) by @kbond +* 88cb7c9 [minor] add getCommandDescription() to Maker's (#121) by @kbond +* 31971e0 [minor] fail ci if direct deprecations (#121) by @kbond +* ecc0e10 [bug] bump min php version (fixes #118) (#119) by @kbond + +## [v1.7.1](https://github.com/zenstruck/foundry/releases/tag/v1.7.1) + +February 6th, 2021 - [v1.7.0...v1.7.1](https://github.com/zenstruck/foundry/compare/v1.7.0...v1.7.1) + +* 6bab709 [bug] fix unmanaged many-to-one entity problem (fixes #114) (#117) by @kbond +* b92a69a [minor] adjust cs-check gh action and fix cs (#116) by @kbond + +## [v1.7.0](https://github.com/zenstruck/foundry/releases/tag/v1.7.0) + +January 17th, 2021 - [v1.6.0...v1.7.0](https://github.com/zenstruck/foundry/compare/v1.6.0...v1.7.0) + +* 9d42401 [feature] add attributes to ModelFactory/RepositoryProxy random methods (#112) by @kbond +* 149ea48 [feature] Remove "visual duplication" of ModelFactory::new()->create() (#111) by @wouterj +* 0c69967 [feature] Added ModelFactory::randomOrCreate() (#108) by @wouterj +* 574c246 [minor] use zenstruck/callback for Proxy::executeCallback() (#107) by @kbond +* 07f1ffe [minor] apply suggested psalm fix (#102) by @kbond +* e53b834 [minor] enable code coverage action to work with xdebug 3 (#99) by @kbond +* 6ea273b [minor] psalm-suppress InternalMethod (#99) by @kbond +* 1dbbab8 [minor] add codecov badge (#98) by @kbond +* 77f7ce0 [minor] switch to codecov by @kbond +* f269dc4 [minor] use ramsey/composer-install in static-analysis job (#97) by @kbond +* 0ca5479 [minor] Streamline GitHub CI by using ramsey/composer-install (#96) by @wouterj +* 8511d7a [minor] Re-enable Psalm and fixed annotations (#95) by @wouterj, @kbond + +## [v1.6.0](https://github.com/zenstruck/foundry/releases/tag/v1.6.0) + +December 7th, 2020 - [v1.5.0...v1.6.0](https://github.com/zenstruck/foundry/compare/v1.5.0...v1.6.0) + +* c3f38d2 [minor] use local kernel instance in Factories and ResetDatabase traits (#92) by @kbond +* 88db502 [doc] document the need to create test client before factories (#92) by @kbond +* bf4d47a [bug] ensure foundry isn't rebooted in DatabaseReset (#92) by @kbond +* 1b6231a [bug] ensure kernel shutdown after ResetDatabase::_resetSchema() (#92) by @kbond +* 63c8eb7 [minor] disable psalm static analysis pending fix (#71) by @kbond +* e4d0a06 [doc] Added another relation example to Many-To-One (#93) by @weaverryan +* 596af47 [minor] support php8 (#71) by @kbond +* 2d574a5 [doc] Added docs for ModelFactory::new() (#91) by @Nyholm +* 6bd3195 [doc] Update link to faker (#90) by @Nyholm +* 338f6c8 [minor] Do not turn Psalm PHPdocs into comments (#85) by @wouterj +* dfc4388 [minor] Fixed issues found by Psalm level 4 (#85) by @wouterj +* 99aa22a [minor] Suppress nullable Psalm level 5 error (#85) by @wouterj +* e4ea180 [minor] Fixed issues found by Psalm level 6 (#85) by @wouterj +* 72c2e77 [minor] Added Psalm templated annotations (#85) by @wouterj +* 48572ce [minor] Installed Psalm and configured GitHub Workflow (#85) by @wouterj +* 0476572 [minor] Update docs with PHP file config (#87) by @TavoNiievez +* 66d0025 [minor] Use PHP CS Fixer udiff to only show snippets (#86) by @wouterj +* 8ecb162 [minor] Use consistent spacing in GitHub Actions config (#86) by @wouterj +* 7e90a05 [minor] Only run one build with prefer-lowest (#86) by @wouterj + +## [v1.5.0](https://github.com/zenstruck/foundry/releases/tag/v1.5.0) + +November 10th, 2020 - _[Initial Release](https://github.com/zenstruck/foundry/commits/v1.5.0)_ From f7d9399b8d77147ae79f3943705c6f14b290620e Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Thu, 29 Sep 2022 17:09:17 -0400 Subject: [PATCH 02/13] [changelog] update changelog [skip ci] --- CHANGELOG.md | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba4947750..5eefc0077 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -296,4 +296,111 @@ December 7th, 2020 - [v1.5.0...v1.6.0](https://github.com/zenstruck/foundry/comp ## [v1.5.0](https://github.com/zenstruck/foundry/releases/tag/v1.5.0) -November 10th, 2020 - _[Initial Release](https://github.com/zenstruck/foundry/commits/v1.5.0)_ +November 10th, 2020 - [v1.4.0...v1.5.0](https://github.com/zenstruck/foundry/compare/v1.4.0...v1.5.0) + +* 3b36c9f [minor] deprecate using snake/kebab-cased attributes (#81) by @kbond +* 3ecd4f6 [minor] set min version of symfony/maker-bundle to 1.13.0 (#81) by @kbond +* 3c0e149 [minor] swap phpunit for phpunit-bridge mark deprecated tests (#81) by @kbond +* 4292d02 [bug] fix typo (#81) by @kbond +* de1fb41 [minor] trigger deprecations for other deprecated code (#81) by @kbond +* 5134347 [minor] deprecate "optional:" & "force:" attribute prefixes (#81) by @kbond +* def8ebc [feature] define extra attributes/forced properties on Instantiator (#81) by @kbond +* da504e0 [bug] boolean nodes should default to false instead of null (#83) by @kbond +* c376fef [minor] sort available entities (#80) by @wouterj +* d3a32cf [minor] add static return annotations (#79) by @micheh +* 77a3583 [minor] run test suite on PostgreSQL (#51) by @kbond +* 8db03c8 [minor] change faker lib used (#70) by @kbond +* 188eb63 [minor] disable dependabot by @kbond +* ea8fefe [minor] bump actions/cache from v1 to v2.1.2 (#69) by @dependabot[bot], dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +* bd5249d [minor] update shivammathur/setup-php requirement to 2.7.0 (#68) by @dependabot[bot], dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +* 800fae7 [minor] update actions/checkout requirement to v2.3.3 (#67) by @dependabot[bot], dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +* 0252e90 [minor] add dependabot for github actions by @kbond +* 537b2fd [bug] RepositoryProxy::findOneBy() with $orderBy checks inner repo (#66) by @kbond +* 9302855 [minor] RepositoryProxy::truncate() compatible with any ObjectManager (#66) by @kbond +* 9fe12e5 [minor] have RepositoryProxy implement \Countable & \IteratorAggregate (#66) by @kbond +* 1c43645 [feature] improve RespositoryProxy::first() and add last() (#64) by @mpiot +* f9418ac [bug] add $orderBy param to RepositoryProxy::findOneBy() (#63) by @mpiot + +## [v1.4.0](https://github.com/zenstruck/foundry/releases/tag/v1.4.0) + +October 20th, 2020 - [v1.3.0...v1.4.0](https://github.com/zenstruck/foundry/compare/v1.3.0...v1.4.0) + +* d5cab62 [doc] fixes (#59) by @kbond +* 4eb546c [doc] document non-Kernel testing (#59) by @kbond +* c8040f7 [doc] document using in PHPUnit data providers (#59) by @kbond +* fce3610 [minor] throw helpful exception if creating service factories w/o boot (#59) by @kbond +* a904e41 [minor] throw helpful exception if using service factories w/o bundle (#59) by @kbond +* 1efc502 [minor] throw helpful exception if using service stories without bundle (#59) by @kbond +* a5d4154 [feature] remove ->withoutPersisting() requirement in pure unit tests (#59) by @kbond +* aef9123 [feature] allow Factories trait to be used in pure units tests (#59) by @kbond +* 732e616 [minor] deprecate TestState::withoutBundle() (#59) by @kbond +* d2c8b47 [bug] ensure Foundry is "shutdown" after each test (#59) by @kbond +* f3cc0c3 [bug] allow model factories to be created in dataProviders (#59) by @kbond +* b80d778 [doc] adding a link to SymfonyCasts (#60) by @weaverryan +* e37f492 [minor] add script to run all test configurations locally by @kbond + +## [v1.3.0](https://github.com/zenstruck/foundry/releases/tag/v1.3.0) + +October 14th, 2020 - [v1.2.1...v1.3.0](https://github.com/zenstruck/foundry/compare/v1.2.1...v1.3.0) + +* fd433b1 [feature] allow factories to be defined as services (#53) by @kbond +* e686a08 [minor] remove dead debug code (#57) by @kbond +* aaf6ab4 [bug] fix typo in Factory stub (fixes #52) (#57) by @kbond + +## [v1.2.1](https://github.com/zenstruck/foundry/releases/tag/v1.2.1) + +October 12th, 2020 - [v1.2.0...v1.2.1](https://github.com/zenstruck/foundry/compare/v1.2.0...v1.2.1) + +* ecf674a [doc] note that the ResetDatabase trait is required for global state by @kbond +* b748615 [minor] ensure coverage jobs use dama bundle (#48) by @kbond +* d4e3a2e [bug] sqlite does not support --if-exists (fixes #46) (#48) by @kbond +* 1138cf0 [minor] add sqlite tests (#48) by @kbond +* 91a6032 [minor] adjust github actions to use DATABASE_URL env var (#48) by @kbond + +## [v1.2.0](https://github.com/zenstruck/foundry/releases/tag/v1.2.0) + +October 8th, 2020 - [v1.1.4...v1.2.0](https://github.com/zenstruck/foundry/compare/v1.1.4...v1.2.0) + +* e7b8481 [feature] add FactoryCollection object to help with relationships (#38) by @kbond + +## [v1.1.4](https://github.com/zenstruck/foundry/releases/tag/v1.1.4) + +October 7th, 2020 - [v1.1.3...v1.1.4](https://github.com/zenstruck/foundry/compare/v1.1.3...v1.1.4) + +* 60e6881 [bug] allow RepositoryProxy::proxyResult() to handle doctrine proxies (#43) by @kbond + +## [v1.1.3](https://github.com/zenstruck/foundry/releases/tag/v1.1.3) + +September 28th, 2020 - [v1.1.2...v1.1.3](https://github.com/zenstruck/foundry/compare/v1.1.2...v1.1.3) + +* 118186d [bug] ensure all attributes passed to afterPersist events (fixes #31) (#40) by @kbond +* f054e3c [bug] allow array callables in Proxy::executeCallback() (#39) by @kbond + +## [v1.1.2](https://github.com/zenstruck/foundry/releases/tag/v1.1.2) + +September 8th, 2020 - [v1.1.1...v1.1.2](https://github.com/zenstruck/foundry/compare/v1.1.1...v1.1.2) + +* fb5b4ff [minor] run php-cs-fixer self-update (#33) by @kbond +* d734536 [minor] allow doctrine/persistence v2 (#33) by @kbond + +## [v1.1.1](https://github.com/zenstruck/foundry/releases/tag/v1.1.1) + +July 24th, 2020 - [v1.1.0...v1.1.1](https://github.com/zenstruck/foundry/compare/v1.1.0...v1.1.1) + +* 91af450 [doc] better document without persisting usage (closes #22) (#27) by @kbond +* 03bce0d [minor] improve "foundry not booted" exception message (closes #24) (#28) by @kbond +* 2d7bc47 [doc] fix test example (closes #25) (#26) by @kbond +* 0a4fa3a Update README.md (#23) by @kbond +* 576858a [doc] fix typo (#20) by @jdreesen +* 331716a [doc] add packagist version badge by @kbond + +## [v1.1.0](https://github.com/zenstruck/foundry/releases/tag/v1.1.0) + +July 11th, 2020 - [v1.0.0...v1.1.0](https://github.com/zenstruck/foundry/compare/v1.0.0...v1.1.0) + +* 7d91e42 [minor] change composer "type" by @kbond +* c01374a [BC BREAK] moved bundle to src root so it can be auto-configured by flex by @kbond + +## [v1.0.0](https://github.com/zenstruck/foundry/releases/tag/v1.0.0) + +July 10th, 2020 - _[Initial Release](https://github.com/zenstruck/foundry/commits/v1.0.0)_ From cb9a4ece911c9a1bb9684cb83de53e39aa681ef0 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Sat, 1 Oct 2022 13:08:17 +0200 Subject: [PATCH 03/13] [feature] add a docker stack (#306) --- .gitattributes | 3 + .github/workflows/ci.yml | 50 +- .gitignore | 1 + Makefile | 102 ++ README.md | 67 + bin/tools/cs-fixer/composer.json | 5 + bin/tools/cs-fixer/composer.lock | 2115 ++++++++++++++++++++++++++++++ bin/tools/psalm/composer.json | 2 +- bin/tools/psalm/composer.lock | 851 ++++++------ docker-compose.yaml | 69 + docker/Dockerfile | 50 + docker/mongo-init.js | 13 + docker/xdebug.ini | 10 + docs/phpstorm-xdebug-config.png | Bin 0 -> 72874 bytes phpunit-dama-doctrine.xml.dist | 2 +- phpunit.xml.dist | 2 +- 16 files changed, 2955 insertions(+), 387 deletions(-) create mode 100644 Makefile create mode 100644 bin/tools/cs-fixer/composer.json create mode 100644 bin/tools/cs-fixer/composer.lock create mode 100644 docker-compose.yaml create mode 100644 docker/Dockerfile create mode 100644 docker/mongo-init.js create mode 100644 docker/xdebug.ini create mode 100644 docs/phpstorm-xdebug-config.png diff --git a/.gitattributes b/.gitattributes index a9163c7d6..a02d25904 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,6 +9,9 @@ /.php-cs-fixer.dist.php export-ignore /.scrutinizer.yml export-ignore /.symfony.bundle.yaml export-ignore +/docker export-ignore +/docker-compose.yaml export-ignore +/Makefile export-ignore /phpunit.xml.dist export-ignore /phpunit-dama-doctrine.xml.dist export-ignore /psalm.xml export-ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cead70c9..9078158c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -349,10 +349,28 @@ jobs: run: bin/build-docs cs-check: - uses: zenstruck/.github/.github/workflows/php-cs-fixer.yml@main - with: - php: 7.2 - version: 3.4 + name: PHP CS-Fixer check + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2.3.3 + + - name: Setup PHP + uses: shivammathur/setup-php@2.7.0 + with: + php-version: 7.2 + coverage: none + + - name: Install dependencies + uses: ramsey/composer-install@v1 + with: + composer-options: --prefer-dist + + - name: Install PHP CS-Fixer + run: composer bin cs-fixer install + + - name: Run PHP CS-Fixer check + run: bin/tools/cs-fixer/vendor/friendsofphp/php-cs-fixer/php-cs-fixer fix --dry-run --diff static-analysis: name: Psalm Static Analysis @@ -364,7 +382,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@2.7.0 with: - php-version: 7.4 + php-version: 7.2 coverage: none - name: Install dependencies @@ -376,4 +394,24 @@ jobs: run: composer bin psalm install - name: Run static analysis - run: bin/tools/psalm/vendor/vimeo/psalm/psalm --output-format=github --php-version=7.4 + run: bin/tools/psalm/vendor/vimeo/psalm/psalm --output-format=github --php-version=7.2 + + docker-stack: + name: CI with docker stack + strategy: + matrix: + os: + - ubuntu-latest + # - macos-latest + # - windows-latest + runs-on: ${{ matrix.os }} + steps: + - uses: docker-practice/actions-setup-docker@master + if: ${{ matrix.os == 'macos-latest' }} + + - name: Checkout code + uses: actions/checkout@v2.3.3 + + - name: Run test suite with docker + run: | + make validate diff --git a/.gitignore b/.gitignore index 6f6dd37ff..cdc5006a5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ /tests/Fixtures/tmp /var/ /docs/output/ +/.env diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..3c7f1f38c --- /dev/null +++ b/Makefile @@ -0,0 +1,102 @@ +.PHONY: $(filter-out vendor bin/tools/psalm/vendor bin/tools/cs-fixer/vendor,$(MAKECMDGOALS)) + +MYSQL_URL="mysql://root:root@mysql:3306/zenstruck_foundry?charset=utf8" +POSTGRESQL_URL="postgresql://root:root@postgres:5432/zenstruck_foundry?charset=utf8&serverVersion=13" +MONGO_URL="mongodb://mongo:mongo@mongo:27017/mongo?compressors=disabled&gssapiServiceName=mongodb&authSource=mongo" +SQLITE_URL="sqlite://./var/app.db" + +ifeq ($(shell docker --help | grep "compose"),) + DOCKER_COMPOSE=docker-compose +else + DOCKER_COMPOSE=docker compose +endif + +INTERACTIVE:=$(shell [ -t 0 ] && echo 1) +ifdef INTERACTIVE + DC_EXEC=$(DOCKER_COMPOSE) exec +else + DC_EXEC=$(DOCKER_COMPOSE) exec -T +endif + +DOCKER_PHP=${DC_EXEC} php + +.DEFAULT_GOAL := help + +UID = $(shell id -u) + +DOCKER_IS_UP = $(shell $(DOCKER_COMPOSE) ps | grep "Up (healthy)") + +ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)) +$(eval $(RUN_ARGS):;@:) + +# From inside the containers, docker host ip is different in linux and macos +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + XDEBUG_HOST=172.17.0.1 +endif +ifeq ($(UNAME_S),Darwin) + XDEBUG_HOST=host.docker.internal +endif + +help: + @fgrep -h "###" $(MAKEFILE_LIST) | fgrep -v fgrep | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +validate: fixcs sca test-full ### Run fixcs, sca and full test suite + +test-full: docker-start vendor ### Run full PHPunit (MySQL + Mongo) + @$(eval filter ?= '.') + @${DC_EXEC} -e USE_FOUNDRY_BUNDLE=1 -e DATABASE_URL=${MYSQL_URL} -e MONGO_URL=${MONGO_URL} php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) + +test-fast: docker-start vendor ### Run PHPunit with SQLite + @$(eval filter ?= '.') +ifeq ($(shell which docker),) + @DATABASE_URL=${SQLITE_URL} php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) +else + @${DC_EXEC} -e DATABASE_URL=${SQLITE_URL} php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) +endif + +test-mysql: docker-start vendor ### Run PHPunit with mysql + @$(eval filter ?= '.') + @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) + +test-postgresql: docker-start vendor ### Run PHPunit with postgreSQL + @$(eval filter ?= '.') + @${DC_EXEC} -e DATABASE_URL=${POSTGRESQL_URL} php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) + +test-mongo: docker-start vendor ### Run PHPunit with Mongo + @$(eval filter ?= '.') + @${DC_EXEC} -e MONGO_URL=${MONGO_URL} php vendor/bin/simple-phpunit --configuration phpunit.xml.dist --filter=$(filter) + +fixcs: docker-start bin/tools/cs-fixer/vendor ### Run PHP CS-Fixer + @${DOCKER_PHP} bin/tools/cs-fixer/vendor/friendsofphp/php-cs-fixer/php-cs-fixer --no-interaction --diff -v fix + +bin/tools/cs-fixer/vendor: vendor bin/tools/cs-fixer/composer.json bin/tools/cs-fixer/composer.lock + @${DOCKER_PHP} composer bin cs-fixer update + +sca: docker-start bin/tools/psalm/vendor ### Run Psalm + @${DOCKER_PHP} bin/tools/psalm/vendor/vimeo/psalm/psalm --config=./psalm.xml + +bin/tools/psalm/vendor: vendor bin/tools/psalm/composer.json bin/tools/psalm/composer.lock + @${DOCKER_PHP} composer bin psalm update + +vendor: composer.json $(wildcard composer.lock) + @${DOCKER_PHP} composer update + +docker-start: ### Build and run containers +ifeq ($(DOCKER_IS_UP),) + @$(DOCKER_COMPOSE) build --build-arg UID="${UID}" --build-arg XDEBUG_HOST="${XDEBUG_HOST}" + @$(DOCKER_COMPOSE) up --detach --remove-orphans + @$(DOCKER_COMPOSE) ps +endif + +docker-stop: ### Stop containers + @$(DOCKER_COMPOSE) stop + +docker-purge: docker-stop ### Purge containers + @$(DOCKER_COMPOSE) down --volumes + +composer: ### Run composer command + @${DC_EXEC} php composer $(ARGS) + +clear: ### Start from a fresh install (needed if vendors have already been installed with another php version) + rm -rf composer.lock bin/tools/psalm/vendor/ bin/tools/cs-fixer/vendor/ vendor/ diff --git a/README.md b/README.md index ccc404f55..580bc693b 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,73 @@ Want to watch a screencast 🎥 about it? Check out https://symfonycasts.com/fou **[Read the Documentation](https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html)** +## How to contribute + +The test suite of this library needs one or more database, and static analysis needs to be ran on the smaller PHP version +supported (currently PHP 7.2), then it comes with a full docker stack. + +### Install docker + +You must [install docker](https://docs.docker.com/engine/install/) and [install docker-compose](https://docs.docker.com/compose/install/) +at first before running the tests. + +### Run tests + +The library is shipped with a `Makefile` to run tests. +Each target will build and start the docker stack and install composer only if needed. + +```shell +$ make help +validate Run fixcs, sca and full test suite +test-full Run full PHPunit (MySQL + Mongo) +test-fast Run PHPunit with SQLite +test-mysql Run PHPunit with mysql +test-postgresql Run PHPunit with postgreSQL +test-mongo Run PHPunit with Mongo +fixcs Run PHP CS-Fixer +sca Run Psalm +docker-start Build and run containers +docker-stop Stop containers +docker-purge Purge containers +composer Run composer command +clear Start from a fresh install (needed if vendors have already been installed with another php version) +``` + +You can run each `test-*` target with a special argument `filter`: +```shell +$ make test-mysql filter=FactoryTest +``` + +which will use PHPUnit's `--filter` option. + +### Change docker's ports + +You can create a `.env` file to change the ports used by docker: +```dotenv +MYSQL_PORT=3307 +POSTGRES_PORT=5434 +MONGO_PORT=27018 +``` + +### Execute commands in php container + +You can execute any command into the php container using docker compose: +```shell +$ docker-compose exec php [you commmand] # or "docker compose" depending on your docker compose version +``` + +### Using xdebug with PhpStorm + +The php container is shipped with xdebug activated. You can use step by step debugging session with PhpStorm: you should +create a server called `FOUNDRY` in your PHP Remote Debug, with the IDE key `xdebug_foundry` + +![PhpStorm with xdebug](docs/phpstorm-xdebug-config.png) + +### Run tests without docker + +If for any reason docker is not available on your computer, the target `make test-fast` will run tests with your local +php version, and sqlite will be used as database. Results may differ from the CI! + ## Credit The [AAA](https://www.thephilocoder.com/unit-testing-aaa-pattern/) style of testing was first introduced to me by diff --git a/bin/tools/cs-fixer/composer.json b/bin/tools/cs-fixer/composer.json new file mode 100644 index 000000000..f0b7eda0f --- /dev/null +++ b/bin/tools/cs-fixer/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "friendsofphp/php-cs-fixer": "^3.4" + } +} diff --git a/bin/tools/cs-fixer/composer.lock b/bin/tools/cs-fixer/composer.lock new file mode 100644 index 000000000..95eb712ce --- /dev/null +++ b/bin/tools/cs-fixer/composer.lock @@ -0,0 +1,2115 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "1d19845c6e2a8ee77726417ced70f3e3", + "packages": [ + { + "name": "composer/pcre", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/1.0.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-01-21T20:24:37+00:00" + }, + { + "name": "composer/semver", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-04-01T19:23:25+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/9e36aeed4616366d2b690bdce11f71e9178c579a", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a", + "shasum": "" + }, + "require": { + "composer/pcre": "^1", + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/2.0.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-02-24T20:20:32+00:00" + }, + { + "name": "doctrine/annotations", + "version": "1.13.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "648b0343343565c4a056bfc8392201385e8d89f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0", + "reference": "648b0343343565c4a056bfc8392201385e8d89f0", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^6.0 || ^8.1", + "phpstan/phpstan": "^1.4.10 || ^1.8.0", + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", + "symfony/cache": "^4.4 || ^5.2", + "vimeo/psalm": "^4.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.13.3" + }, + "time": "2022-07-02T10:48:51+00:00" + }, + { + "name": "doctrine/lexer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2022-02-28T11:07:21+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "shasum": "" + }, + "require": { + "composer/semver": "^3.2", + "composer/xdebug-handler": "^2.0", + "doctrine/annotations": "^1.12", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.2.5 || ^8.0", + "php-cs-fixer/diff": "^2.0", + "symfony/console": "^4.4.20 || ^5.1.3 || ^6.0", + "symfony/event-dispatcher": "^4.4.20 || ^5.0 || ^6.0", + "symfony/filesystem": "^4.4.20 || ^5.0 || ^6.0", + "symfony/finder": "^4.4.20 || ^5.0 || ^6.0", + "symfony/options-resolver": "^4.4.20 || ^5.0 || ^6.0", + "symfony/polyfill-mbstring": "^1.23", + "symfony/polyfill-php80": "^1.23", + "symfony/polyfill-php81": "^1.23", + "symfony/process": "^4.4.20 || ^5.0 || ^6.0", + "symfony/stopwatch": "^4.4.20 || ^5.0 || ^6.0" + }, + "require-dev": { + "justinrainbow/json-schema": "^5.2", + "keradus/cli-executor": "^1.5", + "mikey179/vfsstream": "^1.6.8", + "php-coveralls/php-coveralls": "^2.5.2", + "php-cs-fixer/accessible-object": "^1.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", + "phpspec/prophecy": "^1.15", + "phpspec/prophecy-phpunit": "^1.1 || ^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5", + "phpunitgoodpractices/polyfill": "^1.5", + "phpunitgoodpractices/traits": "^1.9.1", + "symfony/phpunit-bridge": "^5.2.4 || ^6.0", + "symfony/yaml": "^4.4.20 || ^5.0 || ^6.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "support": { + "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", + "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2021-12-11T16:25:08+00:00" + }, + { + "name": "php-cs-fixer/diff", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/diff.git", + "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", + "symfony/process": "^3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "sebastian/diff v3 backport support for PHP 5.6+", + "homepage": "https://github.com/PHP-CS-Fixer", + "keywords": [ + "diff" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/diff/issues", + "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" + }, + "abandoned": true, + "time": "2020-10-14T08:32:19+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" + }, + "time": "2021-03-05T17:36:06+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "symfony/console", + "version": "v5.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "3f97f6c7b7e26848a90c0c0cfb91eeb2bb8618be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/3f97f6c7b7e26848a90c0c0cfb91eeb2bb8618be", + "reference": "3f97f6c7b7e26848a90c0c0cfb91eeb2bb8618be", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.1|^6.0" + }, + "conflict": { + "psr/log": ">=3", + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-26T13:50:20+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v5.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-05T16:45:39+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "ac09569844a9109a5966b9438fc29113ce77cf51" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/ac09569844a9109a5966b9438fc29113ce77cf51", + "reference": "ac09569844a9109a5966b9438fc29113ce77cf51", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "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": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-21T19:53:16+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.4.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/7872a66f57caffa2916a584db1aa7f12adc76f8c", + "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.4.11" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-29T07:37:50+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v5.4.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "54f14e36aa73cb8f7261d7686691fd4d75ea2690" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/54f14e36aa73cb8f7261d7686691fd4d75ea2690", + "reference": "54f14e36aa73cb8f7261d7686691fd4d75ea2690", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "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": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.4.11" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T13:00:38+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "433d05519ce6990bf3530fba6957499d327395c2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", + "reference": "433d05519ce6990bf3530fba6957499d327395c2", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T07:21:04+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/process", + "version": "v5.4.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/6e75fe6874cbc7e4773d049616ab450eff537bf1", + "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.4.11" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T16:58:25+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-30T19:17:29+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v5.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "6df7a3effde34d81717bbef4591e5ffe32226d69" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/6df7a3effde34d81717bbef4591e5ffe32226d69", + "reference": "6df7a3effde34d81717bbef4591e5ffe32226d69", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/service-contracts": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "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": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-28T13:19:49+00:00" + }, + { + "name": "symfony/string", + "version": "v5.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "2900c668a32138a34118740de3e4d5a701801f53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/2900c668a32138a34118740de3e4d5a701801f53", + "reference": "2900c668a32138a34118740de3e4d5a701801f53", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "conflict": { + "symfony/translation-contracts": ">=3.0" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-01T01:52:16+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/bin/tools/psalm/composer.json b/bin/tools/psalm/composer.json index 4171cb19b..dd4082477 100644 --- a/bin/tools/psalm/composer.json +++ b/bin/tools/psalm/composer.json @@ -1,6 +1,6 @@ { "require": { - "vimeo/psalm": "^4.10", + "vimeo/psalm": "4.10", "psalm/plugin-symfony": "^3.0" }, "config": { diff --git a/bin/tools/psalm/composer.lock b/bin/tools/psalm/composer.lock index 2faa79476..c313447c1 100644 --- a/bin/tools/psalm/composer.lock +++ b/bin/tools/psalm/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8dc4f81a811a55e98879c6df35f62696", + "content-hash": "a3345774672cb79c0302924a7106fdbf", "packages": [ { "name": "amphp/amp", - "version": "v2.6.0", + "version": "v2.6.2", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "caa95edeb1ca1bf7532e9118ede4a3c3126408cc" + "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/caa95edeb1ca1bf7532e9118ede4a3c3126408cc", - "reference": "caa95edeb1ca1bf7532e9118ede4a3c3126408cc", + "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", "shasum": "" }, "require": { @@ -39,13 +39,13 @@ } }, "autoload": { - "psr-4": { - "Amp\\": "lib" - }, "files": [ "lib/functions.php", "lib/Internal/functions.php" - ] + ], + "psr-4": { + "Amp\\": "lib" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -70,7 +70,7 @@ } ], "description": "A non-blocking concurrency framework for PHP applications.", - "homepage": "http://amphp.org/amp", + "homepage": "https://amphp.org/amp", "keywords": [ "async", "asynchronous", @@ -85,7 +85,7 @@ "support": { "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.6.0" + "source": "https://github.com/amphp/amp/tree/v2.6.2" }, "funding": [ { @@ -93,7 +93,7 @@ "type": "github" } ], - "time": "2021-07-16T20:06:06+00:00" + "time": "2022-02-20T17:52:18+00:00" }, { "name": "amphp/byte-stream", @@ -128,12 +128,12 @@ } }, "autoload": { - "psr-4": { - "Amp\\ByteStream\\": "lib" - }, "files": [ "lib/functions.php" - ] + ], + "psr-4": { + "Amp\\ByteStream\\": "lib" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -174,16 +174,16 @@ }, { "name": "composer/package-versions-deprecated", - "version": "1.11.99.4", + "version": "1.11.99.5", "source": { "type": "git", "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "b174585d1fe49ceed21928a945138948cb394600" + "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b174585d1fe49ceed21928a945138948cb394600", - "reference": "b174585d1fe49ceed21928a945138948cb394600", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d", + "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d", "shasum": "" }, "require": { @@ -227,7 +227,78 @@ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "support": { "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.4" + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-01-17T14:14:24+00:00" + }, + { + "name": "composer/pcre", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/1.0.1" }, "funding": [ { @@ -243,27 +314,27 @@ "type": "tidelift" } ], - "time": "2021-09-13T08:41:34+00:00" + "time": "2022-01-21T20:24:37+00:00" }, { "name": "composer/semver", - "version": "3.2.5", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9" + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/31f3ea725711245195f62e54ffa402d8ef2fdba9", - "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9", + "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.54", + "phpstan/phpstan": "^1.4", "symfony/phpunit-bridge": "^4.2 || ^5" }, "type": "library", @@ -308,7 +379,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.5" + "source": "https://github.com/composer/semver/tree/3.3.2" }, "funding": [ { @@ -324,29 +395,31 @@ "type": "tidelift" } ], - "time": "2021-05-24T12:41:47+00:00" + "time": "2022-04-01T19:23:25+00:00" }, { "name": "composer/xdebug-handler", - "version": "2.0.2", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339" + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/84674dd3a7575ba617f5a76d7e9e29a7d3891339", - "reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/9e36aeed4616366d2b690bdce11f71e9178c579a", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a", "shasum": "" }, "require": { + "composer/pcre": "^1", "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1 || ^2 || ^3" }, "require-dev": { - "phpstan/phpstan": "^0.12.55", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" }, "type": "library", "autoload": { @@ -372,7 +445,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/2.0.2" + "source": "https://github.com/composer/xdebug-handler/tree/2.0.5" }, "funding": [ { @@ -388,7 +461,7 @@ "type": "tidelift" } ], - "time": "2021-07-31T17:03:58+00:00" + "time": "2022-02-24T20:20:32+00:00" }, { "name": "dnoegel/php-xdg-base-dir", @@ -474,16 +547,16 @@ }, { "name": "felixfbecker/language-server-protocol", - "version": "1.5.1", + "version": "v1.5.2", "source": { "type": "git", "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730" + "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/9d846d1f5cf101deee7a61c8ba7caa0a975cd730", - "reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", + "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", "shasum": "" }, "require": { @@ -524,9 +597,9 @@ ], "support": { "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/1.5.1" + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" }, - "time": "2021-02-22T14:02:09+00:00" + "time": "2022-03-02T22:36:06+00:00" }, { "name": "netresearch/jsonmapper", @@ -581,16 +654,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.12.0", + "version": "v4.15.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143" + "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ef6c55a3f47f89d7a374e6f835197a0b5fcf900", + "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900", "shasum": "" }, "require": { @@ -631,9 +704,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.1" }, - "time": "2021-07-21T10:44:31+00:00" + "time": "2022-09-04T07:30:47+00:00" }, { "name": "openlss/lib-array2xml", @@ -743,16 +816,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.2.2", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", "shasum": "" }, "require": { @@ -763,7 +836,8 @@ "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2" + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -793,22 +867,22 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" }, - "time": "2020-09-03T19:13:55+00:00" + "time": "2021-10-19T17:43:47+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.4.0", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + "reference": "77a32518733312af16a44300404e945338981de3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", + "reference": "77a32518733312af16a44300404e945338981de3", "shasum": "" }, "require": { @@ -816,7 +890,8 @@ "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "*" + "ext-tokenizer": "*", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -842,22 +917,22 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1" }, - "time": "2020-09-17T18:55:26+00:00" + "time": "2022-03-15T21:29:03+00:00" }, { "name": "psalm/plugin-symfony", - "version": "v3.0.3", + "version": "v3.0.4", "source": { "type": "git", "url": "https://github.com/psalm/psalm-plugin-symfony.git", - "reference": "7b19393d11204e63a1c4b3cdee8585aa72a0ea70" + "reference": "65586604237c9062c15adc92faee5f84d1698af6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/psalm/psalm-plugin-symfony/zipball/7b19393d11204e63a1c4b3cdee8585aa72a0ea70", - "reference": "7b19393d11204e63a1c4b3cdee8585aa72a0ea70", + "url": "https://api.github.com/repos/psalm/psalm-plugin-symfony/zipball/65586604237c9062c15adc92faee5f84d1698af6", + "reference": "65586604237c9062c15adc92faee5f84d1698af6", "shasum": "" }, "require": { @@ -906,9 +981,9 @@ "description": "Psalm Plugin for Symfony", "support": { "issues": "https://github.com/psalm/psalm-plugin-symfony/issues", - "source": "https://github.com/psalm/psalm-plugin-symfony/tree/v3.0.3" + "source": "https://github.com/psalm/psalm-plugin-symfony/tree/v3.0.4" }, - "time": "2021-09-06T15:39:00+00:00" + "time": "2021-10-14T04:48:39+00:00" }, { "name": "psr/cache", @@ -1109,29 +1184,29 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211", + "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1163,7 +1238,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/3.0.3" }, "funding": [ { @@ -1171,20 +1246,20 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2020-11-30T07:59:04+00:00" }, { "name": "symfony/cache", - "version": "v5.3.7", + "version": "v5.4.13", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "864867b13bd67347497ce956f4b253f8fe18b80c" + "reference": "89bb6a0fe27205636d80e568ffaf9bbb52f691e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/864867b13bd67347497ce956f4b253f8fe18b80c", - "reference": "864867b13bd67347497ce956f4b253f8fe18b80c", + "url": "https://api.github.com/repos/symfony/cache/zipball/89bb6a0fe27205636d80e568ffaf9bbb52f691e3", + "reference": "89bb6a0fe27205636d80e568ffaf9bbb52f691e3", "shasum": "" }, "require": { @@ -1192,35 +1267,35 @@ "psr/cache": "^1.0|^2.0", "psr/log": "^1.1|^2|^3", "symfony/cache-contracts": "^1.1.7|^2", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-php73": "^1.9", "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0" + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/var-exporter": "^4.4|^5.0|^6.0" }, "conflict": { - "doctrine/dbal": "<2.10", + "doctrine/dbal": "<2.13.1", "symfony/dependency-injection": "<4.4", "symfony/http-kernel": "<4.4", "symfony/var-dumper": "<4.4" }, "provide": { "psr/cache-implementation": "1.0|2.0", - "psr/simple-cache-implementation": "1.0", + "psr/simple-cache-implementation": "1.0|2.0", "symfony/cache-implementation": "1.0|2.0" }, "require-dev": { "cache/integration-tests": "dev-master", "doctrine/cache": "^1.6|^2.0", - "doctrine/dbal": "^2.10|^3.0", + "doctrine/dbal": "^2.13.1|^3.0", "predis/predis": "^1.1", - "psr/simple-cache": "^1.0", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/filesystem": "^4.4|^5.0", - "symfony/http-kernel": "^4.4|^5.0", - "symfony/messenger": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/messenger": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" }, "type": "library", "autoload": { @@ -1245,14 +1320,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Provides an extended PSR-6, PSR-16 (and tags) implementation", + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", "homepage": "https://symfony.com", "keywords": [ "caching", "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v5.3.7" + "source": "https://github.com/symfony/cache/tree/v5.4.13" }, "funding": [ { @@ -1268,20 +1343,20 @@ "type": "tidelift" } ], - "time": "2021-08-29T15:08:21+00:00" + "time": "2022-09-06T13:23:31+00:00" }, { "name": "symfony/cache-contracts", - "version": "v2.4.0", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "c0446463729b89dd4fa62e9aeecc80287323615d" + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/c0446463729b89dd4fa62e9aeecc80287323615d", - "reference": "c0446463729b89dd4fa62e9aeecc80287323615d", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", "shasum": "" }, "require": { @@ -1294,7 +1369,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -1331,7 +1406,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v2.4.0" + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" }, "funding": [ { @@ -1347,26 +1422,26 @@ "type": "tidelift" } ], - "time": "2021-03-23T23:28:01+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/config", - "version": "v5.3.4", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "4268f3059c904c61636275182707f81645517a37" + "reference": "ec79e03125c1d2477e43dde8528535d90cc78379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/4268f3059c904c61636275182707f81645517a37", - "reference": "4268f3059c904c61636275182707f81645517a37", + "url": "https://api.github.com/repos/symfony/config/zipball/ec79e03125c1d2477e43dde8528535d90cc78379", + "reference": "ec79e03125c1d2477e43dde8528535d90cc78379", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/filesystem": "^4.4|^5.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/filesystem": "^4.4|^5.0|^6.0", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-php80": "^1.16", "symfony/polyfill-php81": "^1.22" @@ -1375,11 +1450,11 @@ "symfony/finder": "<4.4" }, "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/messenger": "^4.4|^5.0", - "symfony/service-contracts": "^1.1|^2", - "symfony/yaml": "^4.4|^5.0" + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/messenger": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/yaml": "^4.4|^5.0|^6.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -1410,7 +1485,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.3.4" + "source": "https://github.com/symfony/config/tree/v5.4.11" }, "funding": [ { @@ -1426,30 +1501,30 @@ "type": "tidelift" } ], - "time": "2021-07-21T12:40:44+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/console", - "version": "v5.3.7", + "version": "v5.4.13", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a" + "reference": "3f97f6c7b7e26848a90c0c0cfb91eeb2bb8618be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a", - "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a", + "url": "https://api.github.com/repos/symfony/console/zipball/3f97f6c7b7e26848a90c0c0cfb91eeb2bb8618be", + "reference": "3f97f6c7b7e26848a90c0c0cfb91eeb2bb8618be", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php73": "^1.9", "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2", - "symfony/string": "^5.1" + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.1|^6.0" }, "conflict": { "psr/log": ">=3", @@ -1464,12 +1539,12 @@ }, "require-dev": { "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" }, "suggest": { "psr/log": "For using the console logger", @@ -1509,7 +1584,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.3.7" + "source": "https://github.com/symfony/console/tree/v5.4.13" }, "funding": [ { @@ -1525,27 +1600,28 @@ "type": "tidelift" } ], - "time": "2021-08-25T20:02:16+00:00" + "time": "2022-08-26T13:50:20+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.3.7", + "version": "v5.4.13", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "a665946279f566d94ed5eb98999cfa65c6fa5a78" + "reference": "24cf522668845391c0542bc1de496366072a6d0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a665946279f566d94ed5eb98999cfa65c6fa5a78", - "reference": "a665946279f566d94ed5eb98999cfa65c6fa5a78", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/24cf522668845391c0542bc1de496366072a6d0e", + "reference": "24cf522668845391c0542bc1de496366072a6d0e", "shasum": "" }, "require": { "php": ">=7.2.5", "psr/container": "^1.1.1", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22", "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { @@ -1553,16 +1629,16 @@ "symfony/config": "<5.3", "symfony/finder": "<4.4", "symfony/proxy-manager-bridge": "<4.4", - "symfony/yaml": "<4.4" + "symfony/yaml": "<4.4.26" }, "provide": { "psr/container-implementation": "1.0", "symfony/service-implementation": "1.0|2.0" }, "require-dev": { - "symfony/config": "^5.3", - "symfony/expression-language": "^4.4|^5.0", - "symfony/yaml": "^4.4|^5.0" + "symfony/config": "^5.3|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/yaml": "^4.4.26|^5.0|^6.0" }, "suggest": { "symfony/config": "", @@ -1597,7 +1673,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.3.7" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.13" }, "funding": [ { @@ -1613,20 +1689,20 @@ "type": "tidelift" } ], - "time": "2021-08-02T16:16:27+00:00" + "time": "2022-08-30T19:10:13+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.0", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", - "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", "shasum": "" }, "require": { @@ -1664,7 +1740,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -1680,20 +1756,20 @@ "type": "tidelift" } ], - "time": "2021-07-12T14:48:14+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/error-handler", - "version": "v5.4.0", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "8433fa3145ac78df88b87a4a539118e950828126" + "reference": "f75d17cb4769eb38cd5fccbda95cd80a054d35c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/8433fa3145ac78df88b87a4a539118e950828126", - "reference": "8433fa3145ac78df88b87a4a539118e950828126", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/f75d17cb4769eb38cd5fccbda95cd80a054d35c8", + "reference": "f75d17cb4769eb38cd5fccbda95cd80a054d35c8", "shasum": "" }, "require": { @@ -1735,7 +1811,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.0" + "source": "https://github.com/symfony/error-handler/tree/v5.4.11" }, "funding": [ { @@ -1751,20 +1827,20 @@ "type": "tidelift" } ], - "time": "2021-11-29T15:30:56+00:00" + "time": "2022-07-29T07:37:50+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.4.0", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "27d39ae126352b9fa3be5e196ccf4617897be3eb" + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/27d39ae126352b9fa3be5e196ccf4617897be3eb", - "reference": "27d39ae126352b9fa3be5e196ccf4617897be3eb", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", "shasum": "" }, "require": { @@ -1820,7 +1896,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9" }, "funding": [ { @@ -1836,20 +1912,20 @@ "type": "tidelift" } ], - "time": "2021-11-23T10:19:22+00:00" + "time": "2022-05-05T16:45:39+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v2.5.0", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "66bea3b09be61613cd3b4043a65a8ec48cfa6d2a" + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/66bea3b09be61613cd3b4043a65a8ec48cfa6d2a", - "reference": "66bea3b09be61613cd3b4043a65a8ec48cfa6d2a", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", "shasum": "" }, "require": { @@ -1899,7 +1975,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" }, "funding": [ { @@ -1915,25 +1991,26 @@ "type": "tidelift" } ], - "time": "2021-07-12T14:48:14+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/filesystem", - "version": "v5.3.4", + "version": "v5.4.13", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "343f4fe324383ca46792cae728a3b6e2f708fb32" + "reference": "ac09569844a9109a5966b9438fc29113ce77cf51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/343f4fe324383ca46792cae728a3b6e2f708fb32", - "reference": "343f4fe324383ca46792cae728a3b6e2f708fb32", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/ac09569844a9109a5966b9438fc29113ce77cf51", + "reference": "ac09569844a9109a5966b9438fc29113ce77cf51", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", "symfony/polyfill-php80": "^1.16" }, "type": "library", @@ -1962,7 +2039,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.3.4" + "source": "https://github.com/symfony/filesystem/tree/v5.4.13" }, "funding": [ { @@ -1978,24 +2055,25 @@ "type": "tidelift" } ], - "time": "2021-07-21T12:40:44+00:00" + "time": "2022-09-21T19:53:16+00:00" }, { "name": "symfony/finder", - "version": "v5.3.7", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93" + "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/a10000ada1e600d109a6c7632e9ac42e8bf2fb93", - "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93", + "url": "https://api.github.com/repos/symfony/finder/zipball/7872a66f57caffa2916a584db1aa7f12adc76f8c", + "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c", "shasum": "" }, "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-php80": "^1.16" }, "type": "library", @@ -2024,7 +2102,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.3.7" + "source": "https://github.com/symfony/finder/tree/v5.4.11" }, "funding": [ { @@ -2040,46 +2118,48 @@ "type": "tidelift" } ], - "time": "2021-08-04T21:20:46+00:00" + "time": "2022-07-29T07:37:50+00:00" }, { "name": "symfony/framework-bundle", - "version": "v5.3.7", + "version": "v5.4.13", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "5d4fcef02a42ea86280afcbacedf8de7a039032c" + "reference": "394866c2cb8bb189b9bd5ebd043b66f89c800363" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/5d4fcef02a42ea86280afcbacedf8de7a039032c", - "reference": "5d4fcef02a42ea86280afcbacedf8de7a039032c", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/394866c2cb8bb189b9bd5ebd043b66f89c800363", + "reference": "394866c2cb8bb189b9bd5ebd043b66f89c800363", "shasum": "" }, "require": { "ext-xml": "*", "php": ">=7.2.5", - "symfony/cache": "^5.2", - "symfony/config": "^5.3", - "symfony/dependency-injection": "^5.3", - "symfony/deprecation-contracts": "^2.1", - "symfony/error-handler": "^4.4.1|^5.0.1", - "symfony/event-dispatcher": "^5.1", - "symfony/filesystem": "^4.4|^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/http-foundation": "^5.3", - "symfony/http-kernel": "^5.3", + "symfony/cache": "^5.2|^6.0", + "symfony/config": "^5.3|^6.0", + "symfony/dependency-injection": "^5.4.5|^6.0.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/error-handler": "^4.4.1|^5.0.1|^6.0", + "symfony/event-dispatcher": "^5.1|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^5.3|^6.0", + "symfony/http-kernel": "^5.4|^6.0", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php80": "^1.16", - "symfony/routing": "^5.3" + "symfony/polyfill-php81": "^1.22", + "symfony/routing": "^5.3|^6.0" }, "conflict": { + "doctrine/annotations": "<1.13.1", + "doctrine/cache": "<1.11", "doctrine/persistence": "<1.3", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "phpunit/phpunit": "<5.4.3", "symfony/asset": "<5.3", - "symfony/browser-kit": "<4.4", "symfony/console": "<5.2.5", "symfony/dom-crawler": "<4.4", "symfony/dotenv": "<5.1", @@ -2087,13 +2167,13 @@ "symfony/http-client": "<4.4", "symfony/lock": "<4.4", "symfony/mailer": "<5.2", - "symfony/messenger": "<4.4", + "symfony/messenger": "<5.4", "symfony/mime": "<4.4", "symfony/property-access": "<5.3", "symfony/property-info": "<4.4", - "symfony/security-core": "<5.3", "symfony/security-csrf": "<5.3", "symfony/serializer": "<5.2", + "symfony/service-contracts": ">=3.0", "symfony/stopwatch": "<4.4", "symfony/translation": "<5.3", "symfony/twig-bridge": "<4.4", @@ -2103,40 +2183,38 @@ "symfony/workflow": "<5.2" }, "require-dev": { - "doctrine/annotations": "^1.10.4", - "doctrine/cache": "^1.0|^2.0", - "doctrine/persistence": "^1.3|^2.0", - "paragonie/sodium_compat": "^1.8", + "doctrine/annotations": "^1.13.1", + "doctrine/cache": "^1.11|^2.0", + "doctrine/persistence": "^1.3|^2|^3", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/asset": "^5.3", - "symfony/browser-kit": "^4.4|^5.0", - "symfony/console": "^5.2", - "symfony/css-selector": "^4.4|^5.0", - "symfony/dom-crawler": "^4.4.30|^5.3.7", - "symfony/dotenv": "^5.1", - "symfony/expression-language": "^4.4|^5.0", - "symfony/form": "^5.2", - "symfony/http-client": "^4.4|^5.0", - "symfony/lock": "^4.4|^5.0", - "symfony/mailer": "^5.2", - "symfony/messenger": "^5.2", - "symfony/mime": "^4.4|^5.0", - "symfony/notifier": "^5.3", - "symfony/phpunit-bridge": "^5.3", + "symfony/asset": "^5.3|^6.0", + "symfony/browser-kit": "^5.4|^6.0", + "symfony/console": "^5.4.9|^6.0.9", + "symfony/css-selector": "^4.4|^5.0|^6.0", + "symfony/dom-crawler": "^4.4.30|^5.3.7|^6.0", + "symfony/dotenv": "^5.1|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/form": "^5.2|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/mailer": "^5.2|^6.0", + "symfony/messenger": "^5.4|^6.0", + "symfony/mime": "^4.4|^5.0|^6.0", + "symfony/notifier": "^5.4|^6.0", "symfony/polyfill-intl-icu": "~1.0", - "symfony/process": "^4.4|^5.0", - "symfony/property-info": "^4.4|^5.0", - "symfony/rate-limiter": "^5.2", - "symfony/security-bundle": "^5.3", - "symfony/serializer": "^5.2", - "symfony/stopwatch": "^4.4|^5.0", - "symfony/string": "^5.0", - "symfony/translation": "^5.3", - "symfony/twig-bundle": "^4.4|^5.0", - "symfony/validator": "^5.2", - "symfony/web-link": "^4.4|^5.0", - "symfony/workflow": "^5.2", - "symfony/yaml": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/property-info": "^4.4|^5.0|^6.0", + "symfony/rate-limiter": "^5.2|^6.0", + "symfony/security-bundle": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0", + "symfony/stopwatch": "^4.4|^5.0|^6.0", + "symfony/string": "^5.0|^6.0", + "symfony/translation": "^5.3|^6.0", + "symfony/twig-bundle": "^4.4|^5.0|^6.0", + "symfony/validator": "^5.2|^6.0", + "symfony/web-link": "^4.4|^5.0|^6.0", + "symfony/workflow": "^5.2|^6.0", + "symfony/yaml": "^4.4|^5.0|^6.0", "twig/twig": "^2.10|^3.0" }, "suggest": { @@ -2175,7 +2253,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v5.3.7" + "source": "https://github.com/symfony/framework-bundle/tree/v5.4.13" }, "funding": [ { @@ -2191,20 +2269,20 @@ "type": "tidelift" } ], - "time": "2021-08-26T08:37:07+00:00" + "time": "2022-09-29T08:12:55+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.0", + "version": "v5.4.13", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "5ef86ac7927d2de08dc1e26eb91325f9ccbe6309" + "reference": "54be067587a4f2b7fffb7a699f9481ec3daf9379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5ef86ac7927d2de08dc1e26eb91325f9ccbe6309", - "reference": "5ef86ac7927d2de08dc1e26eb91325f9ccbe6309", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/54be067587a4f2b7fffb7a699f9481ec3daf9379", + "reference": "54be067587a4f2b7fffb7a699f9481ec3daf9379", "shasum": "" }, "require": { @@ -2216,8 +2294,11 @@ "require-dev": { "predis/predis": "~1.0", "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/mime": "^4.4|^5.0|^6.0" + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", + "symfony/mime": "^4.4|^5.0|^6.0", + "symfony/rate-limiter": "^5.2|^6.0" }, "suggest": { "symfony/mime": "To use the file extension guesser" @@ -2248,7 +2329,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.0" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.13" }, "funding": [ { @@ -2264,20 +2345,20 @@ "type": "tidelift" } ], - "time": "2021-11-28T15:25:38+00:00" + "time": "2022-09-17T07:31:22+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.0", + "version": "v5.4.13", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "e012f16688bcb151e965473a70d8ebaa8b1d15ea" + "reference": "4f25330c216b7bb178603b2e25fb7a9325015507" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e012f16688bcb151e965473a70d8ebaa8b1d15ea", - "reference": "e012f16688bcb151e965473a70d8ebaa8b1d15ea", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4f25330c216b7bb178603b2e25fb7a9325015507", + "reference": "4f25330c216b7bb178603b2e25fb7a9325015507", "shasum": "" }, "require": { @@ -2360,7 +2441,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.4.0" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.13" }, "funding": [ { @@ -2376,32 +2457,35 @@ "type": "tidelift" } ], - "time": "2021-11-29T16:56:53+00:00" + "time": "2022-09-30T07:40:28+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.23.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "suggest": { "ext-ctype": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2409,12 +2493,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2439,7 +2523,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" }, "funding": [ { @@ -2455,20 +2539,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.23.1", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "16880ba9c5ebe3642d1995ab866db29270b36535" + "reference": "433d05519ce6990bf3530fba6957499d327395c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/16880ba9c5ebe3642d1995ab866db29270b36535", - "reference": "16880ba9c5ebe3642d1995ab866db29270b36535", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", + "reference": "433d05519ce6990bf3530fba6957499d327395c2", "shasum": "" }, "require": { @@ -2480,7 +2564,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2488,12 +2572,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2520,7 +2604,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" }, "funding": [ { @@ -2536,20 +2620,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T12:26:48+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.23.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -2561,7 +2645,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2569,12 +2653,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -2604,7 +2688,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" }, "funding": [ { @@ -2620,32 +2704,35 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.23.1", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", - "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-mbstring": "*" + }, "suggest": { "ext-mbstring": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2653,12 +2740,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2684,7 +2771,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" }, "funding": [ { @@ -2700,20 +2787,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T12:26:48+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.23.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", "shasum": "" }, "require": { @@ -2722,7 +2809,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2730,12 +2817,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -2763,7 +2850,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" }, "funding": [ { @@ -2779,20 +2866,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.23.1", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", - "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", "shasum": "" }, "require": { @@ -2801,7 +2888,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2809,12 +2896,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -2846,7 +2933,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" }, "funding": [ { @@ -2862,20 +2949,20 @@ "type": "tidelift" } ], - "time": "2021-07-28T13:41:28+00:00" + "time": "2022-05-10T07:21:04+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.23.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "e66119f3de95efc359483f810c4c3e6436279436" + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", - "reference": "e66119f3de95efc359483f810c4c3e6436279436", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1", "shasum": "" }, "require": { @@ -2884,7 +2971,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2892,12 +2979,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -2925,7 +3012,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0" }, "funding": [ { @@ -2941,25 +3028,25 @@ "type": "tidelift" } ], - "time": "2021-05-21T13:25:03+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/routing", - "version": "v5.3.7", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "be865017746fe869007d94220ad3f5297951811b" + "reference": "3e01ccd9b2a3a4167ba2b3c53612762300300226" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/be865017746fe869007d94220ad3f5297951811b", - "reference": "be865017746fe869007d94220ad3f5297951811b", + "url": "https://api.github.com/repos/symfony/routing/zipball/3e01ccd9b2a3a4167ba2b3c53612762300300226", + "reference": "3e01ccd9b2a3a4167ba2b3c53612762300300226", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-php80": "^1.16" }, "conflict": { @@ -2971,11 +3058,11 @@ "require-dev": { "doctrine/annotations": "^1.12", "psr/log": "^1|^2|^3", - "symfony/config": "^5.3", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/http-foundation": "^4.4|^5.0", - "symfony/yaml": "^4.4|^5.0" + "symfony/config": "^5.3|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/yaml": "^4.4|^5.0|^6.0" }, "suggest": { "symfony/config": "For using the all-in-one router or any loader", @@ -3015,7 +3102,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.3.7" + "source": "https://github.com/symfony/routing/tree/v5.4.11" }, "funding": [ { @@ -3031,25 +3118,29 @@ "type": "tidelift" } ], - "time": "2021-08-04T21:42:42+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.4.0", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb" + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", - "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/container": "^1.1" + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" }, "suggest": { "symfony/service-implementation": "" @@ -3057,7 +3148,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3094,7 +3185,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.4.0" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" }, "funding": [ { @@ -3110,20 +3201,20 @@ "type": "tidelift" } ], - "time": "2021-04-01T10:43:52+00:00" + "time": "2022-05-30T19:17:29+00:00" }, { "name": "symfony/string", - "version": "v5.3.7", + "version": "v5.4.13", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5" + "reference": "2900c668a32138a34118740de3e4d5a701801f53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5", - "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5", + "url": "https://api.github.com/repos/symfony/string/zipball/2900c668a32138a34118740de3e4d5a701801f53", + "reference": "2900c668a32138a34118740de3e4d5a701801f53", "shasum": "" }, "require": { @@ -3134,20 +3225,23 @@ "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php80": "~1.15" }, + "conflict": { + "symfony/translation-contracts": ">=3.0" + }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0", - "symfony/http-client": "^4.4|^5.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0" + "symfony/var-exporter": "^4.4|^5.0|^6.0" }, "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\String\\": "" - }, "files": [ "Resources/functions.php" ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, "exclude-from-classmap": [ "/Tests/" ] @@ -3177,7 +3271,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.3.7" + "source": "https://github.com/symfony/string/tree/v5.4.13" }, "funding": [ { @@ -3193,20 +3287,20 @@ "type": "tidelift" } ], - "time": "2021-08-26T08:00:08+00:00" + "time": "2022-09-01T01:52:16+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.0", + "version": "v5.4.13", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "89ab66eaef230c9cd1992de2e9a1b26652b127b9" + "reference": "2bf2ccab581bec363191672f0df40e0c85569e1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/89ab66eaef230c9cd1992de2e9a1b26652b127b9", - "reference": "89ab66eaef230c9cd1992de2e9a1b26652b127b9", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2bf2ccab581bec363191672f0df40e0c85569e1c", + "reference": "2bf2ccab581bec363191672f0df40e0c85569e1c", "shasum": "" }, "require": { @@ -3266,7 +3360,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.0" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.13" }, "funding": [ { @@ -3282,20 +3376,20 @@ "type": "tidelift" } ], - "time": "2021-11-29T15:30:56+00:00" + "time": "2022-09-06T13:23:31+00:00" }, { "name": "symfony/var-exporter", - "version": "v5.3.7", + "version": "v5.4.10", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "2ded877ab0574d8b646f4eb3f716f8ed7ee7f392" + "reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/2ded877ab0574d8b646f4eb3f716f8ed7ee7f392", - "reference": "2ded877ab0574d8b646f4eb3f716f8ed7ee7f392", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/8fc03ee75eeece3d9be1ef47d26d79bea1afb340", + "reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340", "shasum": "" }, "require": { @@ -3303,7 +3397,7 @@ "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "symfony/var-dumper": "^4.4.9|^5.0.9" + "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" }, "type": "library", "autoload": { @@ -3339,7 +3433,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v5.3.7" + "source": "https://github.com/symfony/var-exporter/tree/v5.4.10" }, "funding": [ { @@ -3355,7 +3449,7 @@ "type": "tidelift" } ], - "time": "2021-08-04T22:42:42+00:00" + "time": "2022-05-27T12:56:18+00:00" }, { "name": "vimeo/psalm", @@ -3433,13 +3527,13 @@ } }, "autoload": { - "psr-4": { - "Psalm\\": "src/Psalm/" - }, "files": [ "src/functions.php", "src/spl_object_id.php" - ] + ], + "psr-4": { + "Psalm\\": "src/Psalm/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3464,21 +3558,21 @@ }, { "name": "webmozart/assert", - "version": "1.10.0", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" + "ext-ctype": "*", + "php": "^7.2 || ^8.0" }, "conflict": { "phpstan/phpstan": "<0.12.20", @@ -3516,9 +3610,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" + "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, - "time": "2021-03-09T10:59:23+00:00" + "time": "2022-06-03T18:03:27+00:00" }, { "name": "webmozart/path-util", @@ -3568,6 +3662,7 @@ "issues": "https://github.com/webmozart/path-util/issues", "source": "https://github.com/webmozart/path-util/tree/2.3.0" }, + "abandoned": "symfony/filesystem", "time": "2015-12-17T08:42:14+00:00" } ], @@ -3579,5 +3674,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.3.0" } diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 000000000..d2457b835 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,69 @@ +version: '3.9' + +services: + php: + container_name: foundry_php + build: + context: . + dockerfile: ./docker/Dockerfile + depends_on: + mysql: + condition: service_healthy + postgres: + condition: service_healthy + mongo: + condition: service_healthy + volumes: + - .:/app + working_dir: /app + environment: + PHP_IDE_CONFIG: "serverName=FOUNDRY" + + mysql: + container_name: foundry_mysql + image: mysql + command: --default-authentication-plugin=mysql_native_password + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: zenstruck_foundry + ports: + - ${MYSQL_PORT:-3306}:3306 + healthcheck: + test: 'mysql -u root -proot -D zenstruck_foundry -e "SELECT 1"' + timeout: 120s + retries: 60 + interval: 2s + + postgres: + container_name: foundry_postgres + image: postgres:13 + environment: + POSTGRES_DB: zenstruck_foundry + POSTGRES_PASSWORD: root + POSTGRES_USER: root + ports: + - ${POSTGRES_PORT:-5432}:5432 + healthcheck: + test: /usr/bin/pg_isready + timeout: 10s + retries: 10 + + mongo: + container_name: foundry_mongo + image: mongo:4.4 + tmpfs: + - /data + environment: + - MONGO_INITDB_ROOT_USERNAME=admin + - MONGO_INITDB_ROOT_PASSWORD=admin + - MONGO_INITDB_DATABASE=mongo + - MONGO_NON_ROOT_USERNAME=mongo + - MONGO_NON_ROOT_PASSWORD=mongo + ports: + - ${MONGO_PORT:-27017}:27017 + volumes: + - ./docker/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro + healthcheck: + test: echo 'db.runCommand("ping").ok' | mongo mongo:27017/test --quiet + timeout: 10s + retries: 10 diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 000000000..8d95ebd1b --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,50 @@ +FROM php:7.2-cli + +COPY --from=composer:2.3 /usr/bin/composer /usr/bin/composer + +COPY docker/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini +ARG XDEBUG_HOST + +RUN apt-get update && apt-get install -y \ +RUN set -eux ; \ + apt-get update ; \ + apt-get install --no-install-recommends -y \ + $PHPIZE_DEPS \ + git \ + curl \ + zip \ + unzip \ + libicu-dev \ + git \ + curl \ + unzip \ + procps \ + dialog \ + apt-utils \ + libpq-dev \ + libcurl4-openssl-dev \ + pkg-config \ + libssl-dev \ + ; \ + sed -i "s/%xdebug_host%/${XDEBUG_HOST}/g" /usr/local/etc/php/conf.d/xdebug.ini; \ + docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql; \ + docker-php-ext-install pdo pdo_mysql pdo_pgsql pgsql; \ + pecl install -f mongodb-1.10.0; \ + pecl install xdebug ; \ + docker-php-ext-enable mongodb xdebug ; \ + pecl clear-cache ; \ + apt-get remove -y $PHPIZE_DEPS zlib1g-dev libcurl4-openssl-dev pkg-config libssl-dev ; \ + rm -rf /var/lib/apt/lists/* ; \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false + +# Set user rights +ARG USER=docker +# this may be overridden to match host's machine user +ARG UID=1001 +RUN addgroup --system --gid ${UID} ${USER} \ + && adduser --system --disabled-password --uid ${UID} --ingroup ${USER} ${USER} \ + && mkdir -p /app/var \ + && chown -R ${USER}:${USER} /app +USER ${USER} + +CMD tail -f /dev/null diff --git a/docker/mongo-init.js b/docker/mongo-init.js new file mode 100644 index 000000000..d2c2ecbe0 --- /dev/null +++ b/docker/mongo-init.js @@ -0,0 +1,13 @@ +db.createUser( + { + user: "mongo", + pwd: "mongo", + roles: [ + { + role: "readWrite", + db: "mongo" + } + ] + } +); + diff --git a/docker/xdebug.ini b/docker/xdebug.ini new file mode 100644 index 000000000..736355870 --- /dev/null +++ b/docker/xdebug.ini @@ -0,0 +1,10 @@ +[xdebug] +xdebug.mode=debug +xdebug.start_with_request=yes +xdebug.client_host=%xdebug_host% +xdebug.client_port=9003 +xdebug.idekey=xdebug_foundry + +# prevents a warning to be displayed in CLI +# when phpstorm does not listen incoming connexions +xdebug.log_level=0 diff --git a/docs/phpstorm-xdebug-config.png b/docs/phpstorm-xdebug-config.png new file mode 100644 index 0000000000000000000000000000000000000000..d28c1f434da238eeaace6449633336bb9746bf2b GIT binary patch literal 72874 zcmZ^~V_+sr^9LH+b~eezwylkA+qP|QY}>YNZLE!L`)1#B&i?QHaQnmaOwV-H{JN^T zs!*1aPdT0YJK{g zo=~n-?j(p6x?CuFjJATIVcKQ0whLFt7?8e@@)o=3Y~4zKZGTL6N7h-h3-jo0@r?qU zkB|bN=MSa%)vjEA&UyPTh`N9ZA@=+5-5s)_ozY|}75Ds%>o&t7A+9-U5pc$-%-ih6 zC3`w#>0DsR2?Z2IxG-8;#h4BQ0t6^3OGU8|*_&i_>&KBwNp9BhJUFqM>HbHq zb9$K=!Gv``l5v&0SgA(-g9~Va`ze;6u|FzD8(dqJ!ZumIE*%0UYS@DLpdnL}&*^`B zAnYvUz9GQ;zIM0e$Y`O^6dDxGRX*e+3zyHt$n}M5%TocRzB}<1j_3`)VW`kk);G{E ztE1w=<7$hpayhSn`h(>kKs3T~vM8YWvp)nhxr|Wv6HpTnGclsd7C|Yi;M5iOO)*Mg zxqca`{o+#EE`d@O5*3zHQzPg9KL&x4)zYq4&z?{3-g$(10A#cjq#Oik?%aYirBhWU zA5xXsa&k&3aVgq@KcplEjiE_NIIxn(iF^N#gC?WalATgpC`^pdf|4hmjn!pz8EBaT z`CS>f`DFZpML=Ev-nZKc$Vd@jn&fiE)xX$7HDZT%d(o`>m9~pMVo~@ypFm2SwD`+D zt1qZ_U`E%~fOJudsI=Iimfap!`d?!UP2cc}v&M_I*H=!P$`55UrwX;DpT0PlwCBub z>s#%JN~5PbsiVpv8SPVL95G(-_q{0m-i)9{-{2#JYg%3?uCE8R4=5zA6WsKCnR+mmesU2l7)#+xMqW<9D8In6Ih{~GsH;Ta6syru8 z{vX5KHrhT^`_;kIb^g@^?rhm$2P%iu4eT|1!-73fr(Z25Ur zyeaP_o zJdv*XI%g zR?Urc{(TDJB{IKFn|nJ%djnsnI(_HYkN)3*0~BAwWqsn;1=Z8}rJKH{%T9hDJ*Bti zKB!?9&&Z;ZO})J+$r9Qlyq^`7L-BB)d64Cn{74_K*O<#NF_MwoEHnN^xPILUNZ9Tqcig5if0~s+Iwlx%O_RjCcN7v(ft-Ypk%Ohp$*IxYR^BX3Z zHgM5eWG=Yy1p=zfIpB8Y)MMm1*X`fr91b^5#QHqlI*%Gf*fO`>@H|u4$tPe03do{# zda_K;{iY-^a3=fD_RsFbUmY&0WvfGSc;^HT7jNFG9BAD&$iUv}G*^4=u+h!#3hmgU z0`5G~G?jBi6K!)Vt<(}MQ*weReOXfVQI+oeK>E_)fYhi+bC;J`7-OCV7XPG>t0aXW zNil=rj^)tX2fg>rENa6dv^nEzi<@Ma{OnD0?J-&8haJ$YGU}v8*nF{Wl%#Rb@&ybA zW3tDkcbG|*ccQ^m`ffq_kknyz_9t${i|VNntI&*958K7n<>CF3bK`VyWIzf#5oo^l z(2x%G0jma14%t!Q?c%Kk{l9iZ?VRA)jv8u z$fcm8pYXVkZwq!99v@=_+)C@OsDHAMi3#k@^$d^*^-k!BQVU-;Cb7>D9QE zyh1dM?szK?o{b>cls^-mKU=}Ob9o~^@69f-lSJetQJl-884p3$ww@_{G`xb#^9Bmi73;W1+H|^MT8>7lUlDn~$F~+ly|H}WRK9cFHSazFz(7WN z9g$~gas~NagJq}jFmSb4_D}PPiu{CK-?bK8opD$9k;@2-uNS73Zw%> zib*~V#e1G^lEX;Dfy=N5u_yn~d8O+1x>Qv1I#I|=eV(Xp>5f6&a0_1Wd55NS&djIN zC2IY&g8BVTg^4f9D z0P0Jxu5Lr-X4;l`a$tXu=8l0PNt$GN@hP94>MU2> z`R31w>5B_ddrLME8}iiQrmMxRER&6AcXo~;g14gpuQ!M*{14=aEKU9_I}nL1_rT{S z%jM?8ZXD=_>8@VBX7a7=Lz&I~BOdw`E~7o2^#L892XyD8(dIv6e2MnU?@ld0HAzbu z3%@D&fbc!Ong^gV14h2=L}G;veS7v>B)y%n*hO}CO3Awj=F=J;E1#p>D*J$ZB$o^r_mmoYuE*I zmeJ>2w(6GPo4JAAMyeVl5jl0zoIJd^rwj?zr^|;v*><`Qn{W9nT6&HU{c-l^RQ82L zF9H?mYo8m?b>}g=ElikODMmVkDw!Q)tB*TO*~NZ2`e*8=cBVpRuDtZ%hb9963TM90 z4UUgT4ZJZ>ONKU~d$hqdZ7@CENxSFe0^^gwMmAK=tKHtA>ELu_P1n@ zg5RcR9S=k~&#{R=ti7+>ZRiKla=1=`)U-J_kS1Iy_C3-O1VSGW4NQ5!8}(-Lj#jc+ zPYC68GWem%b>%pd&7^YjUU;>tc_l`ay8na|R!(5A?rW1xjc58(7N0SnO~jZocDA=; zW16N$-q5UmQC_VcEf=bN8SsrGbHe!|_(8>XUxB+{ZjsO`5Zar4Lw8AF#aH$>TZWptl>mHvQRIiuZY>BEx8@%a(F9vF6t)5r;oUH~QnN+XU z8;VC@?h`r#fe7tkWuv!lp5E}0?lcxYt%1Vu+(Xqo9qan&n1bf`bCOUXw6&Lf+VSIM zVJ_DLJDVx@o-7~Z?-N;0;P7vDtZ*Acu_1VR;_okwZM=Zo+0)*g8N?DvHD|BY_GSEc z+v=;cgxu-y-uA36lbO90mt7J?Xuq$rFH9b^BwY8}xAtc*-x7hX>54X{N?vS!Tyfca z8e&Q$QRzK*SLN4)K{YIO$sx-h>nY7}gS&0N##~(mJlYTE@!HcBj6{CLR=fC;WWib2 z5*e|YKQ#&2nxVqkViyWXXXNmt$-{213=?JTVPUHp-(Aw%S=q42n4*U)Kcw-7R)bn{ zej3Y_zE)*0RawQxmjl1(ssOv+bYL1NDC4%?4LcHWILpH(-D!bZa&*q8y$kgzV31D% zzS--zoNSl?#1*7o?IHHyz>)9Zv(pthiRVWB7j-kz&+Z%Ylao_=IBW_0#-Np!tQJiN zh&>VqZLl~GrzH>kFsBPb?`dnR8b3^|8g&)@P zT5Ft4Yn@wB&SXbej%hT%+{f_0C`Z*ZYLa}LS(*PlkKL`SFT_A(Bhh>3MuL}F2FUKj zN3Ta8!Xswfqq3nVpk$H%VcrLGuwg9>X;|Yn{w1Ek21fTChzcmvpybhtU;NC9_x@ML zHEx5+nx!hf+TIDCQAO7DIVqAUD11whVD|`XidwOFFReP`lZ2!t@s?+!N3&ub&OFU_ zGly8+KbRVM1?Sy4tM0kMYGgdZeO?dP2s4MDf49Q3DYM5C^L~QmQ!xiES*jGK*0P=| z6-cF5Etqb(Mqiz|bPorG;2S-2$79ledPJtMXC`+)g3xALGu?!KDSy`34G?$`uyK|R z?LGkYez>CK7;nxNCt@eZ&p);;py90S5)7%~kCl`|8dn~~RO1vOC0avgAA}(;mZ5hP zCbTfgdeB*_dScTiohpc>(I>~DL1e6qBpJV^ld0;zFuu2c4pyUo&pF|ls?-=B1puMR z*cRXur61ItS{u-y?dpN1?daj%)R+{_J}ZS%Wulmxnh}P^Fb0{7n>x0nE?@zr$=a9a z6OBq8>02RRrkedexRN%R0WbsQQv2S5u2swMGWxk=0xc4UW-)9XLu_rG99TrsIrZ*tD`o`I^QIMlzYO)}!^P z^0lbom7?VCILA5P=F%30j~Od{^YFaUCNgf|$VBz_jQ4tmJLYC53_x6!w@603GkRC$ z%Qcnc1ADA5mS-y}_7!i*%+~XEQ_yX%KhX$Je`H*VLG!h~NH(k)wH9FtoP5ITT4EH% z;t_n=m^C$4Dn9Rc$YWO@k(Wo^QOM)%Z2YC&pijm*XGF{4rVz>74loPXwop{K#dTk& zm^lOEA>6Q}?{0dN(qxhyDsVveCmd&&MUN$m@#Ncv^n7VwOFdPBv1 zN3#L@Cw)7%%iA!;1%w&8as7!5E!}x*HXVsO+4#q~QPP4>t1GNg#OH)Xc@pD^U)IEH zjFRL>5PCf~4l>?U$0wQ&8=!-Ri#4 zKkBdC=JZQW!I<8q1oDk^xr4f0TLqGqxYaG8l^G=;vz|V*{Cj+SyYlVh7S~V!ug>U7 zn%UGngY(DIqw7m+BhC~Rsc979+*$tbb@H3HgEHtdUA$ozFJTdBcE1|c9V@`_DeqB_ zZjYbETiiORPY{Jt>IB$6uiPKUtxA?#J}K1?mU^exNKB57J~=DS9*mp&$D-K>D@yI` z@fy*jIfz%vvbGJMmTu78aeU$H1$FhiH( zE`8v6!1GMge!gLf)&mc~;Pki9cS1O5Zr}A*xBMh;!~rGTvlbAg2F#2 zs?%{Y`BFnbZU!YfZVJ*1U5*ZtcrPSN$CboKO)2;A)t6(qc2dD%x-xbPnC(c1P-c2u zJvG`!0k5Kdl(DfDQ3!^^&pmCE?#Is_j@rQ6iQWC^>SGpM z%4O?F9_4JK&46sGXdOOfUiBlH)zw%NBU#%g13a4(*S@C6VT0oQ>wN@mMWhCq>sIh) zb9d?%6qX%|SnfEzYR3a;*ui;ZO1x$AkL`I(%&47lB?;OInp_J-;gDaG2OUmxeB;UE z5V=Qt+xZ8Q;)XN(1l5CgW8!X%{oIxUB*LAr=JXz?1eqn1buRShW^vB1a1ly#a!KrL z4-AGEX20kJZx$@0;#x_SF}*s2`WkWM~K5z~%ShE|i%MJNQ ztHl!MKg8KKJK{B|&ZU}Lge1GbVv(CiFppBH9-=|2w%is()gOA zo=OA$jO5pcRcbaB_osLU?01UF--CZT-r5)t4*8M^MqV(z-GSu`>9DR+fRq!YTp8G- zyrDnUe+&c^rRL+%>0;4M%>$1uc9#@IVsQC;lZaaAelmHYb#m#{oGk1rQpib3tySiO zG8-=beYLawen3NLVEo-9Qc40*hgd(P+!XH8WuN^MmW2^^3K-c_*!OD~Agt_d{pE=Gy zPlbjp*n)%d$jHn$E`N&rNAacQ;=yg^PHh{}1;M|3@{}V0BML6aah2c+0*`E~!tE^) zlXj3hKD=6Djp zL4QHD;f&UlJk*e@}p-5EqRd$(|6)*ef1DUn1G!g?`xNiu0&4# zqG#XPMH%%!KA|G3%(`;%g|>_)gzHCbtP^`=l(f6|OFE<&zpRg(Pv@O7=j_4#azqq` z*lK6vkp2o~w(v)=FfvD-#}7wErhL&Dz0Z&Lb9rsD31eh>IXT4`Bmc57S(5)c*@gzG z>IkS%EU9;rKrYqgOvJ!rsZ1FTwBiOTwAvpQ9d7w(^;d*TfmebU;1HwuuT z!e*z)_64KIkm)A^dO-c$0?pdr9mQ3NUEiRUXep<>Q+HCu;#2vnOPQO(D>y4>Tl*po@B5>IprV`?L>AD=hTTuOlU8inP zS=qqwAi^&uii|`InBb|hqW`RAwm<|Et*sh~Rg6r0Egy|R)$mk(O_aI1c^CtY88AG! zTZ7tof&>|0R1DHLQtv-I%Cj(ACl)F%AZy0>wOGvDsk9;Pm;B-vjz!Zf3WV}kw+$pF zkh5GyroFnNOTxb#C_$wH5t@tm-(Q`bQNONy@9GaZ+o8Uix0R3pqka7gkcHkq@^reFMffbmqG&8YMuE;+x=)6m?M2)bJlOp$*lkFFiRsO;&NIp7hczC$`;4Y}n zGoepF%-)I%gtqO7PZ!&8*GcBPd3AlCxap*2({5Ay{%dZYHzDhCE>cG zGk{jUT^|}ZZ8R$VF6AB?5@LM)QNGraw}R1n1Zk`echf8CG1_&)ebm1pL-TECd`Z== z0SJXM;KDQT8Q2N~1(f<|@SKd~ag06M%PI1qhnUMP0i6w5fC`=5RYiWOws{g)(MTi3@@m~4Vm#YPJa%b-E!pDPO7jb`!(okSBtO0`Ouzl zgxKmM(wE?uwtO`b5BlZg1?+-~H(lZ^Q0918XS{AY*H`L8E3>=C_r>YJ!>`S@&sAdF zzl@)!8$Y1ecfq{UYty_@{`dg_2FxP)*z}Lf3w6%b70a5K^B8kI&o@YDI#k;uDKxs= z@26!fjTk?574Q7o60Bh|rqUis8DWsdUl|YfBu%5v+7z@g*sSX+@csZiWyr8v&+}(D z<9ghbn`+O_%&S;=EQTyh$^4xiY-(&4}rv0c7HguIS|^+lN8tjZ!-p;`UeoLK%p_ zjDjQ*RcJF4M(adn;DKYLpj=Z=N&IzsWrg6v>q`1Q7E|Z&4j0a)8*$3-vJoK)WSlz> z&3?6=j&oFUP9AqB8IkvPXL2?^QgjjDw{USE+7N<_iyF3c*l);`SLW2OsZMSD6M6R< z97uJ-cx()pEhF)~<$h7D=WCd*iqTyn5tllsaTSKLIv+57`CJ56cf|4HdqR?lA2Ui5 zg+yzr?YmrXxUz(pT#wd8_cGr}2w{+U#2I7iE+u^%wgr#kQT%2#`dZ(ypDd?Q&23Jw z^Nx7kSmuL^;|x_wC&qP`hNN)D?)|L*9z87p$uY}ajdq0vx@{c1m|V!&S5}z1TyzPY zc5p;QQELqLDIU-l1DR-S4-COtAE`_(DoQiDZ`e(^tk#TcenS;<8`s%-LQ+2LHKx>+ zx{05hB)i4k#gmR?bZ2lLP7zYNz!q!Xug1k|G_EI(YdWevJ$MOXt{T9vB+Jz8&e-B% zaR+Ua@*I=^M~)h#u1`;gErg6DTObk$!79)WZQ}J8;$Av9U)dW+;`Su36x%iL=gHO1 zo6K1nZ)|2;J7

+~TY@rD`Q-9AO-Deu8tQ*axa;uZU%VVZ7K*$0Q@X4?=f1)d1mw zu8kDFIc8~CVvR;26yyyq}gZ28zhvl?XB6TUrLqYLi@2nK|a=e6Ns5JCz zM-pVd7=d$N{+lrnU+h_B^;HZvSP@HwsG!x8hn!MSCkRD77bJ7?gvzxV$V(-sSnakoz2I4HEYe+3}x0?eH4*rQ*J0f;?lr-6WcRQZe=eS z>oBq3QoAz-3SQ_AZ(3^}oq_f8(lg_Ne^^{#nyK%$`DQzf3rKGRlhuaAWpZM7=E2Id zV?)%nn|z(wfMCAvV=7n@mM)Iv7BC5p++?XJM)j~}&SeaDz15LrpSEfjhoY=3$N8>9 z7OJF7of9{)%HoJaSJG&?2ZCar)uE+^zxzjJB=V~?!-HQO%&7tKuHqU?X(HZX{l-3( z4qG-mDCN^z2jv}Y5OCW; z!mP4u3V#sj4KNvV*TBqc*wj&z@;&TR0rj`fb4wCb%Zo-y-w0u#g zw^DsJqI@cVx_ZgIU4vsd(~4fOvz248v2OCj!LHYtM>}1#2dCdxj4`#@6>acKc$%WZ zA8UTf+5)94;XHz`NST@ZYVpNQ-`qTS4e#Z^IXLh{V`Zb84<2nOFVzCxm*%ed`&2JF z>+w-Jm#$u(p%SiCE8t9!ho#7dZEx?bIxArt7e$b{i>P;d?Ydvrd;ZG>peXKEoo>QG z4~D?bnoDENDfQY^UD=jVt?dTDy;4caL*5$W+-&lyHsg>sA(o3nY@9|-OxU(pahhxl z3PQxk)_T-tr{rW(1=OO_B@m(>6tFa>AcvG|q4gYGnM)^6qVDQqqL{YY$=}%8i+gsl zXa6*aW;$8O*`;pjNlgoJ!$S)3jF2O@D>-H+_u<(5NkwCLkQWz3`$ z2>j2xs?}ljQSVJ}2lVF$RsBhhAU9B^d(>~LDWd$poskUkWz$BcO;dwUcbpf`bjEJj z>s#fYFiBTqTT7DBVlNeraM7ducHFDU$V3<)Qt%>ExDresL7fj2x0bFBYfRR}Ubc7> zIWNm{Jnm4Nyq(dKJuM*#%*o^;TRK^*kS}dVi;=l}0(Ylu=-dqnL!8k9e|>GqJ($cL zu|YX^_N4_39`y`PAWcBZ(7Ac~I9GE-vECA{Oca=ehgDBK)f5*Z?cef=V{O2gwC0h{ zP%a2;*N!VPy+qDkqiF4%1(mfo9n$XQ^Ik*jlHM6@oxpSuWOg%g1);Nh9G`G@S5_|x zv}g5(4ejj#eR_jN)vM>X#$G6Z*_FbLQfH!cSQ|RR5smwOt*|W8`*pP<2 zU9RU%%7AIxf*Bv#uz5ay);GGXb7W0uS+Xyr3-|A|H0)bRD{JaNe=Qc!nC;l|e@3v? zu~eS`ai>hi83;$>vim1!r9-AFGomGg79^R%2hEnAK&Xv#0YW zhjqr&8}7}Qy8y9!JpN9nOWCZ2QtQpS3#ZyYYfYm0Sq2Kl=F|F9j5|I|iE(6M)%~N) zuJTl=xqZPwb9iQ4f^5FOCdg?9Y)#5H&*0Sc`7XHt24~1BpX8<|USZ@zANBIGO~8Sh zR*+*ejXhM|XZpm4*6jHSLYsY}Dgrq5G3qkb^M(!_9*>xN8gWi}#7-!{w@9 zRpX5^Wn85C9fHG)upT3YZ}8T6LBqF*NQ2iE53c4D>tv+yz2WZuj0*~4kFCAuN#;1M zM7;X0{$`TF+(WCw%g<#gM1rIhA+6x8&Ol7B{ID7|x-u+p8DgWLl?+ZdU+$24TjvK~ z&m;n>*W*qYhJ?D)sO07KbyDe)1Tt%#JB0dI5d>p-z$oA1pLIK$G)6dwJ-PKL&W$;t z2(02YDZmy@Gml~HR5n>nm*4o@%WRn!sC$xj=({cTcdlJ{9xiCS|N} zVG?cZ`p!Oe?IvfcBXsXxy0v8g(Ux_80+o~Kps83wtR+0(YHr)Rc$5|lMuv+@U}n;` z)tiXi-fF)C@Jd2`czx_bcYRiFNoj5!b!uvg-Id(n?g;|D{Q0rPzU0AXFdVbHNlHTJ z{R*|YnTS32E6@GM26|O)Wo09MZaiFq^2tI%2?VEd1SmlLN+31WSs4w1aXlnJ`JjMe zU}t|lRT{i18TBXNbQX8|$jA?#C*6G|e&}@S$U=$aZCf_gMsuZfig`un!Jb^A(8zG( z;UT9dPiiL&MkG8`u@*6Y_^0cqUKBJj`Rd&7_c$Xt1&`0e2jf;amNWwl*zdR)VUm*H zSo(acPEFIoN3q28)xU?80%K&{5ztoiZZ+{It!AowUC(R71PTl5GL|3lDhG4hQ7f; zrY*j{^yreCh$4%DBiM`)G`BlgS+wNL@rf#J$cD+}ibE8$Z(CEMJ&YiTA~+0BH00r@ zh0b;KL{4+9D|spgf6Gp@;91N%Fw4oD!6znH&scX9jcmET86s*NLpr-`k3DHk%oc{== zI6GJO1R^*JzSv}6*g2WwDvMTkDkm;-_9r=SeN>06G>SNr895?II274z)%zRjiTh+z zd!s|f>fHR@RCDJ5 z8Um)y>1xptA6nRwGXD)c?*)hJ+S#XfrRh}3qH^u}wf@qQvt>J~G)Prd*@PsbPHYy> zsky>&)iy^ptC>6!Rk>UD67|!axQw4edn+zAR`10Gi7M__+*w;0QO03LN4Vo^OoVAq za{0%fgZpi>v1=uR4C%Oo+Qp7r>0I6H;C(w7Tpo~*G2z7S%MdTt>^e&5gCeWTm=hS> zz6qwt-l9B*aF>R+n-YqqzG*$@F4KCB;#{?HEL7$QCbPoPxYNWHTXbL#p@T?{u^z^} z*etk&?Z)1OgCZwKW)m2UvA-~&d&51aaMuPGwGPQDefG*~CB5I0CBg3M-a8)pjH^Hd zOH?FYPkO@3yo_K-&3=O%Y_VtkI^v(`=8TwVhLg=}F7$-Sd2+f#Ri)cEzA$} zzx7aSC)YaQLuZZL9S~uG|3G_$D|sz}MMM8u&Wp%k2HzSIB&KDWp5BAPJ1t>8;HC}; zB43)sHAN7q!2uQhKYnP#PbOP9yTjl}s;z~Kw&Yb|rq*C=ui3d{afWdXefGl6 zzEIS_AulBdQDoen9lgV4$>6U|#L?(ZoKKWWEZrSnoje3rP~-7N%b)fc@k4@CgCI~h zK4whtTf}k3X%*5A(DvU{Xq8Ok$na}&jBZ(P;ewjw2A^kb3Unxh#Y@i6d+ZJ4VtD33 zdvdnzkR`Aia3mo`sdMRnUY&OC{GJ)_rjW`^{&R=hMn1>S`v3-X-h@Gp+IZ=p!SA0~g4i|yfkwW38ID1`TndLp!v`%H#ll5h)UK)hNmu8ox0xrf+$dS@jrzPO~%(A`(Gf_gIt>D;OOZO81e+r0m0FuAX8 zE-J4bag1jX6>@Po(Ldf257%XaRL-V|%h(mww0e2NGR`n@dh=~t2<)hr_oxM!BTO)K`nlc;KM8zx~{7otEmhP z9i0^~>r_wiV&< zqP@b-m79Zp6N_Cb%C`2e*1-i6IW#u1{ihEIlGx)r#0IkgJnPX&_Ek8#3vC7&v{uL3 z8oukmYwQfVkjTZbgkJZhvF+(!Nx#7;*ubK9!wK~PktFWo$(ig@4-=S?7&yJN0sA;x ztucVNUpt0Yn3~H!=YQL=sI6@sdVN|NOSi?uZU3I&9Itw8zA|#|oTly!L>^{Hjl-EL zoqtwxaUP$trEme;STMkuw4s?P`@Ph6#OMY%PZ-rAL1SmTK+>dD)fVPfd04Hy^tFt4 zkvL?t$-mdYA3jzr?=a5&9fxA zVke&()$I>I$DshXbud2#n?sw@9r_7avME1xIkIi2EN42b5wHHCE&pj>(YV{ME2DcA zXg3j6s|V9YKFK*A%lq0X zH2N!SVISIukbHQnKYN(vL4?#J#VmzPUk-m|v!f$NEyy!Rl@6cgw=_iR(uJ-V_8ne6 zd44xKszGdvj;>mIO9_)Ym;P8$aFjV+Fb8B-L$#}|MM+N3RH(_j>>E(mz`)bO9th=fdjY*U&H#HbfVU;$gM`(D*C+lF zJ`rj0lLk+RC0w=BH?z89tm%dzst(z_+y*{ZJL)DY4I3LIA#l|5aBW^pc>~Aov)VI_ zH4pau!S<~G(`W$`zv*kqH2~a0c6l!t$N}((J*`+x(W#+~Il>jd?jkh7j>(NzT zZkL!F0QNI8J7x`gRjZ0FA_z}REJKoa{-sYV@#jc`4e!v^t<81cqUQ0%Vpvzwu#QK| z>~IZ1kedvT&}Dx0&0KO&^PQ?v+=FdiJ|Q3(rAtl;g&g8Tc@lZGt^9>)wg!s|jaH9t zNgIm_O5sECf!!_)bUkkRiO`au2evr_wefV?WKyNZDo%we&uue6Y#2TyJK@+1KnXWmU!nXla9`PkMF`OSHX?NS|uWk z;=PTFmgJ$pzSThRa4d$6|J-781qn&KX~in~ungx6rzMrywbPAF_p{Q-_{Zzz$0xSx zp99?`N=nw`ggtAFsN5(idMpc$Nc9Gj8bXw)4i>iT> zNgu!-eK-T#Y_U6W%-*l+b{D(MQkVBuMlm+^QbU4^)O|T*J>}e-Ypl z#VFcY*QD4}^7?J}|E)ha^r&3*$%*nMzu$}ZHc?`$AjtkI^HXlnpE{E$uJK;o+_AAa ztfOLmD#d?3)G|1ZY2jpRHm%;I1JlqoB{hW)@!LgvW9kJkJQ_xs4;c`8LnSP|z&VRQ z&*^c}Ee%SAT<6RuMw^^SK)s5+@O87TOhUk;rHVo8aHZk;yI0cJPKy(ROEgD6XUNzL z)a?j7TyZi1PWd5@$D`ry9ABdlvL0FfIy}>sL!p|wHw(KT;vHily}c{dafo>B1KyM` z8E6Ai-3`|fAnk=OT(B(?QlD&HrY>C$NI>oaB?y=Wj9Gt?{b9oe2I`e2*Vrh-OoN44 zb6iVY{xLpSoAM9oEPVe&#TLN!OgwUW32Xy)`Yv3-(@qzrlZ0gMbL#R+hVc!f0xj}LF=J&= zGu<|CeqaUo*XF^KuIJxyUrtvbaH{yJioLc~DolL%L5Tg9{P0s{`$ zRN?D@qO{G4*86o zJ}CiF4yNUn^X+D;&0YLc^1n0WwzNob(=3JtU5^9OKoSPRxND-zQZLUhi??VGYG_!O z;-@`4dJsebb3%DVDB8q}$n#+9zP8%j^bCX!N(712Tb|&k`iUd1`Q;RD;##dhZEVs6uE=iCME6OnJs8B zF?m{pKPSu7yX=ZM1M3!DhjZ-t?06lFEY0NT+)Bi5Wd=n8vpqJq|!kCO|C%5 z8~>VT{>$+zWg$buJ}DM|Y7EkC<*>=Q+wW`n|8E|`Kw~V-|2uJ~*)SM1Fo}ION%Egg z{SR!028-_O%$?u<*+i(oQo0)7Y${!)Kd~4ry6g{L(?fi8MMpk*vq+5JM)Kyqc+R*1 zIt0x#1DlS};NmEb0Kx_jIHdDqmT%d>BL4T{5}3-p3Z0Q1Ei{qPZBv0}aA;{%9Uc8+ z#6F#%O1$u!rz9t?AhcNuGpLzyyBSn6^K^MRX0pffqZ6#PpB1SJsNz(GVRZN%tf5iW-NYDxo#=x@S(`Z3^x^3CI-<|_DMe@0*EB2g*Mnfr zj1TXm0=}HVAHGwHW7FQDQqgPUVHV%4TQd$)SKt^g$VF6ic&_vD1&xG$3vhRHbF7Ma ze?9Ze&}uxVE00#U+}<}J@hp=T67szc;NnUxx!yseES6DcU)$)P_~4Juq*DY{M2XrC z==`4ewc5`6bN>A=>?&g*G&GdKrCMe)@JgraA7S?l9zQToqX${qBM+2XH4O*Wj!-kZ z`qw2Ju~pltGtP~er_cGlP!Qe6&=&h1s=r^3Ab*wcq8=)94vt-@uf2O}m zoL5Yk2_^*>*&hXlk>7eo%FMEPYMa^D`pWc1M6Uqk#K!9xxuiw75dmkc7Be^(z*{I| zU_+;A>-=lrfk!{2K&YsMh6Cet9B(&_x7G#dc7&W=^XaM5psZ8eTb^SIFII=s`unz6 zR7c_Ff6!6vC1OA@$$8gI@JY)SdlUoZrKrW z_}$w9@e9mT;@k04Y{7wF{ewO<<=!~~`O6a_oRt|ROG|@Vy8H3t(s-A+-*;m(1!+dB z{&NGf%uGbP+jOYGCEqq+p$1W*+Ti@YVZd-uXfjKLu7H@1DNQd} zt@l*DD}znk*A#RI-5{)03W12xlcR8=nBV9FfhvD^4}?x*7#@JI0t123B(NTt=TRE& zVO%}@5}UR-)y@6um7?a4Sh_CC2c$s4?Hx9)bXtB-OJ>}m93NYJWs<7{B7;|#2o<@d zVl4b-Rx+4Cz`y1p3b9voRD`1F!9mYyF8#3Q2O}{D!2t_T3xhkNLB_|Y|4Fwz{#%wL zQ;B&9=Jw|qYaMMl%~8&)lKnW$9!l!7Z8oT=fBHUf0EU3Y-|t&zOR;p2EdI zEz;s@E799Yn&JGqpQAB_m{4JeETxic@(=pp23$E2Nxm_>gx)%96fyBBKI@ zf4PX*-p=>PaM|T%+Q@!9(6o{0YczE=H2I(V=zmh1>EL#=yyQ0Jf% zCY+x`u z^s}?Fq8JUyy$=QkC@ZLhNfbP#j5ROj4;MERr&wTGb%h^Ts{E~61xWQ7|3 zXj-t0$=cIoNM!=~-w{Oj-(p$kefPE{EUmq+{uI3~O--Om_+3pP5J3k&SWrek!jz3H z>Yo9SN2J;62pEuSULY(iXYON;x5a>ohUECahfh9VpUc}Sn)qM7Umhz{ntUff_=)h% zo(@w83>Xi`7NZ#Q;cR)+Qw9KYSg#knIZ(+y5b z-hqKV0BFp-&{~YTw0+^Y!v{i079{Z3a<`0t%SWYzz{)SDC3MHIFdhcPB&x~u#LJ0fCkaStIwmZ}7Hkr|wz!~byqfet|h6QR`4 z|8Lz;)d`wPQil@{iRt)13BaUZ2nq!SL{#2F24h6CapbA>&8h>q7?PVxJva2h#*(GroziTLtizHpq2DA{C zr>)4k$+(sTXO;91^B9yr@(CCSl{C1?145I+9v|6LB?LNWJKNXfXiE+tuH<@Jl~5L; zT^T`cjXHb2kx6J4H0<%CMF|-{9+*8bQbjLlGOXKsM#pe_vl7SlZ1%>#2@-w%gK;k| zuSY=05CLPBz2fCqf=bG2`{X#^Q(+;JmoTe=zI9*~%q%oB?uWHB617U#fvX;Kv$&JP z&io@AJzFCTPd!1$+W#=>iG8Va1UTZG$un3|!D9X8yA)1IXQfMTA!GB$TBwO;FP8H3 zC@JG+L1R;(f`^M;OGRbtT`74SFxDX67Z^cT?0j)zb%~ zI^BIEyEeBW22v@$aa`FtZwrJcEbrJF;|8NTU0Fs7^&>x`2?%GV7S4V4>Tk~rro6IL zl46L7N&Iux_*YgsJ?pzcmMX9D4S7G7-gb8Z0IMuNOn6!|#%`?7J!UNaXL?&MP*g%f zcnQ=o!$qX?-frNcHt>`e>tPj%)mLL&@ev-~x-R+rFBAI}-p|CAm)*mgX#faP?$&U2 z_peWH>FPjnb~} ztTS_y3{cxqupBewM)OZd+8FL!f9sVH66!1l6NfZ@2u^Ct1mkjqJz*z@PhmiX^k8B! z9TARv@Ttv+$z;AKxRAA<(%xAZCNga{kba~H55@hywO>r~;famv3Q4BcRbXklMW7z* zty;h2%M`treVJR{%poHn+sd2o@NsB~1`8S*bXF}_#6+fr7_KzINL~8SY1~y{Pc5IWqZ$!FR(uJX!_V^f@sjWhYMDUvpia(wb0yK$W#tLLi z1RPfIR@#DIHp6D`=x`@bV>BK2VO4U$(DE&Q^hp7xbHePp?o&G^u;oN%I9R1Ci3n#m ze&WQ2UnZ9ZNJv<-@J1i}>Zv#A{lhXXS9O*Wy5^3rpSZX~z3Wy$eS2-Vk_JNwU1?e0 zBa&+zy*JScZerBL3_>V7zw`$}V!y9u|Evw_-K%e2d-d=tAS`U3B?@QYulX5He+BH) zE}xBHMBJRLsdrRoTCZ7{W?NzU_6w@?j=7DW~_fOqXueXP^IxlaJX>-UCa)Wzk6Cd zESiDGd)c~~A3hA0=vO-;7qB5_9XMQoUIqocQXawNLa*utF~I&x>7e=Q z-u|(E%pB4vB8@9~#y+(L>N}$1U|GSHY5uG4~g|nR` zBmzTlV zWpr$6XOM%O?b;BWY2gR|`W#@mP+oRUah%|QvTHo0uAVMNJ>d_rU#Fe9xB`GvEtP1! zOUhou3LD2ORN`ms&jaZrch;P#9BR!zu7LirKWax?XY;I<+TwKiU{9Q5??}t<&IQFM z8t-I>>OuR$>&YE19j&tpw4%3B#X*Yb{kbi8aa!DAk98!4LnfostJjA2kvo6o0=boc z9p_pnlPXcaB9Y6Ez8B@VeR|2gx5fxWHasHwVX%~?REOf5ATZi4n=j6#i;sv(@q_Wv zMm9OsMIOIb(BcN}m`!_-w|iCXVU5+OOp`1_?%sA+-igh+E~`pM`ur(uD-3|0yLAe< zhWy>6&eXHSr3r?8RD)gih7(ifD*}sW)fzhj(w+$HKQ?wS7rjVufG%|MdAmm@7Rjwk zidF;r&g@8op(&`aJ~3MCy4-r+GzAIimaD0A(HaTXL7F++YHU!)5T z!58gOH!h{yJPk`tsc_PHcecr(Jz7zqYCztLie|jCf6aeB4{qGf2@p427^p5vh?FwT z4$n<;{V@*xo%`2G79j*}SD1FUSu{((WW~BeoQ>rw{k4`EDXh-$)_?E$2l~oWz%5$<@t9vXd)a#0_b!IKxktJqX2^uxrX=LEn^D;yYaqf9rqGm$nQHd5&HvJi9LTZYWm{;iP?D+p|qP z=j2wcb^&)I@O>)RQcvgQk}JLUOm3o z$@f?1CqGd{71;_spU^88ug{OukjteagnE(%I$PvB|R(a{rm z^eL}@N%B~-b8b-mzPYDnpzfGnl6ElU1g@%g1b6VJqy_|tJHKF&^MC zd=A^q6=XIv#9r&lS0|KVu9s_Z9^wQEzCB!;ppy|OTj%wddZhrkjnxr$S z*^91VGh;B|z`2))BqhiNT|gw)eqApY*5_I{agSil#A&@YOiNyA2YaaB*0hr|xlu}q ztrDtSDx-W09Nu5M8@J+^(Mo06ygItY6*&Lq|o%yf5KZyI~`Nw zy3l4;%ObdP=VY!@iJ1XqXT!Aq?q=<>#&KegZCj<*2lSeoRedWNhyY4ncK^CN5BDb- zy6=6MlvqW2%Ls)w50*6DEuJ+_mv+2dcc$7_Hx>Q|XFqqwEff{BZ~Ej6CEk25sNbZ- z&s=$fQ*L0Gw_eKS)0|$GDb{W@a>C!=!5+^9vVDy$w=74Zqawz*GryyP%G2+kJZkUv z)}w{0_R59+hE(4k3tMh={|4QpQeIQF{mM)kA|Nb~#IOr?Kq?5LOgVItA3EH&OPyID09M;{Ta8s62dL5;4%&czQA`}oLO-MPIu~$oW zodJn`KXBm`Po4uxWtS2{$|pMeR5$ut@?53W;KOZpr9r$DIak8j&D|3&8}sU(zMgpu zq5p+T3n1)q3>5&p+;yIub~E)7>=+8~C@?xfUHPxB6-KApk;W)-1WJ2(Qy^S$R)CGv zrMd9mV#d$I$;&3vB-(f}r9MO|1<~BEXibcbUghsMd#Jdz#N#+E$G3BY2Q@d}sOkCMTPYOg&zWQXKNKQ@0 zY;60{-onblf`pBJEo~nF&T#C_Fj#&$voe6yuOcNQOJs9l25421(ZZlpXp|0DZD=Va~U%Ihbe{8w+y zB!-EH_t#AgPwZfqlzEL<-cA<_Z-$aj+xkA0#Qn=<-#u}2J_wKxsi?10TUny>DG%u* zzv!tcxqxGp*BT!ffJ@9)E&06M8JI*Tn>380r|(*Faeeft86Lp5!2TKKfaiD#T;jG# zzx@Tw#U}ku?y&yCnWdt?eA+hC9ztqy#am~dZ)I84_Fz?@PsnbxayaU8E}F;8Z0(e& zM!|XU2kYZ9q@*iKHN|Fu?X5$>z{{@(<)|3`ES&o8|O+6k{O@`UpZge`LE0(mQ5&WC9?E2c}2w^;3!1od@M- zCufeG@#46}lgPb{T|Kz=yj(`=WAv{s`Vz)Xl4l+zGYC4_VS4s4ftBS2G)+w0YWanQ zcx|na7*1Pn4^1XjZ?g^}nW1R*T8I-g9kS(HbDBV`mM5Zx)DKRXy$sIRjc=>GzBqWT8$1gsD$SCn~Y5PNpI z#^u$6S)hEDs;cqG!^Mx7s!=!zID`PtE_&`H%e7BcOo%vgX=&5a>ofOgo}IcfXB=ja z5!LU~N~ddMmruZuw=B#qHXkbWqNa$|y7>g=?b60K*AFG7Nj>>|d{>IKUblMub_Ua^ zI7LWQ3@)#9W%L6v<&z(a`_r0I&^q?T28f94swcVX`DXKXij;>8YnE+~<9%~seV`fk z2nOQHJdv^Dh|0d%vBg{C0xkOruLWr9oFt`h+%7IuC+@HU0VE-o$( z=C;A*r!p1*FVn1H>2$yIg3~v^W4a?s z^{{j3{Q)LGGR6MWPAG)56^Xyx$5YpKgogz0lwZaqIGlcHk+p<*GB=<0nF3@7bsy$n zAJC{nQX6Bs`yKEfe%0AE?)@w)OMCl<#-(9opxzaQ9E57N^lM{tE2pW-ob15Ezi$0o z%mZ~u)u+8>3rB35OLGitZ$5{7nlCGS10b3!&aC2S)(wMww9LY*|gZf?idy13Fihkjfq#`6$iz6b3 zG2{9~-|%p^RW(|AlE_ohytJIz&Sl(@hIv-uWB{6*e(Pcw5;&=RQQb9#hHTC~l7U}t z?JB)w4czUx!mAkE+UlmmH&?%;sP?5R$N?|^0}YUX07cBo>wOuS$nkE!!81M~MOw*` z{@%&FxmOK<3msB7e+Ton+wy|3(IQDE#^(CO(mmPi-zL#%a9F1V;u%$1I+DyfDciY> zI@+db^$!rqbxn*5_dmU(|H}HM;hv1GUb#|lhD%F>5RQO;pW$R{00I)>RH4}mgUDH_ z-1T^)sfrd_s?B>)wSBrLnd0`YpjS%Bg~9>@`(nM2Nkxz_=@-I0c$`nxo{j-6^LQ8A zJW#cFAV-dcu1B(MQqs|W%K$I}?u3x_Vh{rRvgw<5 zKae)(!|gmjX`&0-*YWzC!#iJr-XsVR9mk3Ok_taRi<`vcIyNt5b%WyvgQK`Tv5UB^ z7tynq!G+;vTWu;UYG-8dK`Vw{nqD`*Jx8}>TaX#BM^bdO+9hQP=V#xlDQYm}uDjaI zdIt9Q57DUf`?64-Iyj%y69T@nwVre`-{eOorr{B6`8@+r5~ema6%D&p9S|!#AFESW z50DXmcWiWNval(kI6J+zhcid!C9R05N+xEzw_okQR6&GAR{X7YB}HWK-m0?l?kTP- z<{p*F&%x?3Ax7xAp9*^c#-U@Fgk5|mijy)Kw{k~8L0;6s@Qp>u$Zt|Uro^H{e9@hd zt&T*DDW$K-T8jYqC5#%VI8Z50-JnJ4+;v@ks8>fpn4AsskJRK24Cp&8s93~h`4Alt z@V!{@1xz-Ce-+wv#A2o#r5LoHnA+|Rkpz8de?5^rT3#%x+ueyRFwtk987eM1sy;}& zD#2Ixkni`_+l#*XYb*!eem{U6aqYIz@K)>X3mS`K?~+WfPi~=CAs}U6`e*hL!#Y1z zv@y$$mmb(cl<4S6G7<{~EtxXK-?1eADA)taC$-IrdVp2=?)On+zpq&?p?sqVRh4`4 z*&>rk8XP^_$`dQ&|HU~j#D%Rb1~W^q{d-{x0YxhT*r9L^*vL1x2Y0R*MTG#!;&v#H zgAQ!rfRE)dy&8e)ko8Yg{Qm-K|3BgK|M_CH&SeMy&ATwNsRLOiMyMDB-nxiRX2AO0 z)Mb`Ab>^Kr*ar%S@gD0l5!3Oe*3IG2#-$9Z-#yyg<08&m0Xco+OcQb#V4H#3k0S!r7CzHAt?Mj;)cBzRw@TjY4=175oI^EOe_AI_?!9QNkg>Gsqf;ckZv7|`8aER}>7N1l+W>||2X&aQyeq3BY+cAq#q z{JENRQHHLtKE0~>@5*xOwnRVP!hnsfaGy$66P#05M#@NyXwAIt^s#_a5zgntd50E0 z>l3*Ac6@RzY>`V0e7}Qfif?XzTA{LKfT(q^J?-n&ZG?d<=xcldbMSOuor3ATeqJA+LG^27Z{X0Da-cwZe=%jz#J#%aX_K{7Ezn{`Lox&h_Ihfez%0eE>n*To}8@%$?)=% zlllJ((pJkyQAACMld|j}+1G@K+}sW&Rjl@gPY+FDy-_pbro^Jf62f(=WBG&ZyS@U* z{^Kik`pR622}c_ms{P|2%pWo-yv|`FrK20=flL~_URGcIQb1sLFP75QQ(8RJ)vdvf z>+d(#uxxgo&k|TI^&y`^r3@i;DrXDFSGkl?xcG)UFgm%-)Jf2 zw7l~gex986rfc+xDE8C80ooip&+iKsK!MolFS$lmdHGPpfAJ~Y>~0%)Pox9hauNLW zanYdVgc@_oO||?bZ9n$ArvaZr^QZViA$Q+REfHyVzt+clP=hBjE8*IW)k$YsL{ETt zbVCxCt6BlCid7z)4uzdCx@fuwxhr~RvolpX0T{Q`!uiK}!zkw>+i8{zh~OI88_tAU z#kk2L_&XY!NJoIVQE7_Auf_o0uk0(4PalvEIYu|*l`n=W=_?cl=AP!iF0f*~cxY1v zlX(F6H(aW-S+3D+^-NXBlS2|J?C=Moypd%XKhGYNo-PJRdZd#^4tudK&b8@s?tUBb z@o5C||8Gz-tU{$N9aY4N1vN1Zojx|%Jb@!D!4CUuN7}$$n8K~JT6YPQcy0{)Hzp;8 zVHp$M2n9WSUtYZTfPu>AJb&wEs|{M7w9CKC-r^hF!(=ic^SVh6P32D@S@<<_ekJBs zx4_z;8(3>kw5o+ON>e#e_jKfCGjjFmD-iSMQOq^5-RvXD%*w*$b+w;8F*7v#Ijp$y%D%f|dBXP<#!Dh{nvc&~Cj-r(S;U`S|G)2)u#WDZ5Udvm|PP+&9WZpQ6| z!w`}}e>h#X$2pYw*8O{Pb`mh(V2s$0KLFAxy)$z3Z3-ZVfrhJ$vRqIUE?Q>) zc!&h10KbX_8?E)?2NGx?yA>6FVxuker#FW7kFfXDrH#Zw>^ zP9)cB|H<|i4>vep*VO7e7@@2%5#f%sbiWCB4N>NTerOU9FH*Y-vjSogKJvRpEm;i$ z58kxIy5Lc}>Ga_cT$Ti;alvu0;DQX{PidEI@F1sCPVDWTR6?@ntP{?Rff1cYh@utR zPB2e`5nd=VLk-hLAKJtz)<0T+zy^<2`=0Pns=2vumGPrrjRrYe=2d0)qbN2Pp~vXW z;476zNV2kgCY3ccGrZ@=1vNE!tH18t-UUZjZIx`#i{LIb8yCJyOO1B$XQ&ZEq zW;d$uZOzEt51wC8fceL$Kdja_SxH*(p>}eLuq^;r;OWPFHnstxfSXk8iM`@_FpS?&_t=)A(gfl%2hv4c{gGUXL_tD6M>Kb}CS7N&rtPpB_%& zAZpVf#VX%kKX#`4vUR$$hMgf?mm_j4GupzBL0xxC!Yy3$mH{Zk);A>Hn>+S$1k*;$Nex%qJ9$88S?hmW zmmu(Ht`i(U%tsGh+j!#&lgu{{d=1aK=>Z-NE3>zazFqZD(Tiv&#pFltLA#dn>H%MM zb#(|nXH;FC%D)_HE3>?k668)jfdjtX? znxTNb`LEXbB3AjU`K10O&CO7VXGVO;;*^*;%k_=QDD6$rf|cXo30d8#DML(&?5fK|s)%EK5zT`Z36lJJyW z`ltd6Rfd?G-9F%}05Z@BI@V@4lDQL^Us0lzN=iD;_71D!@!8!=;HmUQtMNcA5}g*` zo8J}Se;t9#)bI^Nm@eqLDfH_n{|xQS!%4 z0=gT|N1&s#+0`fjuWbp(X2|1emS^ob>G@(u>NW%?m-hk-FRvR-7suzd)=~)&StzyH z?lOTVc;XIoGflZFdF`!u;^MzbWTS&T&q>a#57t-@ZZXtOblTl-*6jOBo&?n5*n-LD zt?{p9(Kgyj!HB^(!B0ClZ`P-Ws%{?q~C3%^5Ec8{YOQSAkt*@9fD^#y8;uDr@ z;+>w|lX{4CWJtaG-^Gpg=^8ZoUM~nDpUm}ByG6i_J|xA9rEMNLANLVo#HS#)FzGfy;?+k|r7+y??wxgfcCsgKqvlF=4muku|M%umC^>p4_ zR!={0DNZgHd9Q&5Dax|}KU3x^%a?dYSzJw#vd|dZX=ssp#E70)aV-(IlNTL@8jM6# z(x4Z1G}rDl?R15?SMU&^m|Ltd7=&A&EqZ7CtAGl}0=3Qo+eU*X+Y?MnX?UEI$rXUc z9SQOTW9q}RUyOuJ2pr*}a<9Q@twxN*j`A64SECda3_YLG3|TD>H?C@A5fGF5_Dd;! zW~4}-66YVj_G?@~RKdV))!_`z3nAfM`O#RCaB_XLW3Jg7YNkg*X$4m*Jw(hh9#mTp zCFOr(mtR-U@~OAvD9!Ykmc@jP-^GIvDcNguWB?U)Frj`>h0hE>5svM& z(ZsZ9>*1+5<<~(LN-&y$&oHseG0j7(-K!sSD4uOFR4ECf`1(7gI`c(5%z82l`-2=# z#{9iBi`Q`IvyDlA zSi;{tBudSfo@?}|KHau6y|a42lT^P{&`Osdrh2Z9m!x0-c7#8+K=nV8Wvdurx&-Yh zpmcqKQ*t6pzDZoA|DIK3`yllJR(hC%eGT=BzAb=)hWoA8G|8a=9!BK^)6uHD8%wEp z`e+Xo<(TVlnkSWsAhdYNssmB+F_5M@we0@mT+3i{a_Ij@McTb2M#%e~Qjf%)TqkSK zRjd{ZMv0-c{)urXzK7)D=_%*9C{`}ytc5o!Wh#iYD7s42PW`VOu^)Y?h_uDW)5Crz zwj^~+7#`lfG+UozxllG-+hv+cxya%!#jU}+V665{+^(&Z? zI;MY*^y-Qd&VRd}_jcQyn{yj=8QU^vn98wwl6{X6_P!pNDe-5MGRH4>uGf+m{aQ?v ze`G4?<)Ddj>1nRLwK5zqlBaVFyN}Y^sZ7PabMd~|8a?p|S_*61&fp>zuNm*ZjNZI-RiWUb=E)db(bSl`+S=Sf(BkSp}$sCj{l4Huys~^ier0J zw$o)@sO7075>=;*k}19)l2`sm8WujX*sMFLs3ISNQO=n2gGUSRq7R&+BD=oSJvG8k z*hUvSr15NMg~y1gB#kMYyo87uX+3|Upq5|k7qRErQUzFT{Wlb`)wK)Qb+U%WtQ&Uv zoNnWxCc_3p;?YUo*Nc93fDwKuyFynH*2TG*NK^q3tw@kkMa1@E=45v8>p-C&(k2@6Ot#ShGu>rOc9ji&Y{N6Lg1 z$6@4HB#82$p+UcDeV%E07YpLh;0ko$cL|n{AF)2)i8tRFEuvY@{yjPRn9-oF!P&V&z=t6N?^}6tdI)!P&I{Q3B zzt>}rU3sEI-8#n@nq8sk?oixpmP|nriiT!^sZ@LI+C)K-YOjtNc(A(eRn++Mn|sBs zo6!CCG6zF7dMeW_uDUMga+1ZM$|L zgZ~R|*(RiP*xN*Kyc_+8oQ&?5C5m6?JyB!Mv3l5_zI|#V?=Wh-V#F)jX$*h%UT?x3 z(gt22XGN>G)*|C>Jtv#r+VJC8EBxw4-txw(;KV9Yf(3K`p{KRA(`rcQTTUwhS=l@> zDo$I3PrHtAWMr(Yfjm(voFvt;dfZK3veQWm zoxr{-N0|$URruXTy}I_gS_hRB^WBh`L)J6*id>_sp5G52My^#9$a>Fatj(NFN!-F& z83VyXR#RKs04GfOU*Xz72Wh(E-2A0r-_4+X4M?uNyOTPKV(t2N->+Rx->bgq>RPq- z8|7b;lz-6kd^pt4UQt0~{ZA}xCzLdg2&n#W*l^}jd2>(WC*a@C+^QFZ`XLU)4p*M$t&5fzwo_lQ#mU*(!86`P6u#y2aJL7CANhW# zH;^lL6(B{%&W_zWE$VKH1+Fw=;Vn*`RIjls z4=q845 z1QlvPnFktleYCk2WF?^dkHqK_tc?3yAs&-aIBBPA-~cfWHFyXQ!NH;UmJTjNCK$RD zFC5N@-vJ!u#$Quvdt&5TYO}eir=@;QD+j)|%V;Oo--eINX16wX>xV2I(RD@ObkF=g zi=g$p7k^Vx1fji;DI}ojV$q4r>pu3A&!}R+;@4c@q`?ny@D1_VI@F zgT$+FIfkuC1p1*c^cL=e-_vj8$^mYm(2_z2PiDZvf{nL3rK##0_6~plcFM{$RyX!fQaA+SX!(tFWX<&+KaANvg+xSsV>Y@x)H$^BWtxCroGz~UhQ$&nt z(UuYcsFZGfUW8vS^n_zJNjmC+GE(>Z`8|(QWtI=dPLi|B8uZM4nDso|o&thO%=Yii z6};K{bVsD@u%{C3^w-lVjZ;IT+a(m71MPbRvPduh?yQ%oZR;pgDaX09qb5b?`#A#UKqx5|A_xyEZwGKJ@L21+@B|ffO2hQ1= zlcsLLnZ=J$JdqZU1_=^!p_N z8!?Fc$Wd@tV~k;?QiYBD$C+=~%64x>Mv^VA*?3#?LC>&7E9Bn2 zJWa^_tY@IO0I|c)=x06<9cOi3UD5Fipm$=-l}R^AN=VoajYpGm9T7Jz(bBUYnOn0= z59kxxumogCBqnvqXU4%eoei~~(gPXKo6!ihGFZms%s11uDtq$-R<#e7`0im=IF}fWS99e?h~!)xhKXab2t%gcG+kGk#5{v}ujgBP58OpVjHXA^Nx*Y% z=Jn;0VF0e?7#w~#Je?W!uRxEE+Fya5V?J{7DcP*$b|F<%Ex_7${JW6PvA!9U1leRD z8!0ZY6EVt6v8bKxB^*k9||v8pUSL`#0Z6g5y) z&G0#bFf(T#ebw`dz#)8&8rU@veF25HWz+u_MDz3MyXn5M5f{gn`q)o~9&l)*4=WcO zt(5+n7zmYQFgF3@GtfFj`lRf~N9*s^?Dw^38NriryjreMs8*OI-&@QaX$HDZ&1C2N=xR z6QQHO@PiP+ajb9u`rgR3as3Zy=WH18(Ebf{|9tur!@uHHeb#^a=+A%tQ^e`d+5awW z?my?-0hj-G7gOog;Q^ZeRWDIRpk!02{$7_n`P}O|diQQGb2HE$9s@J@&S+)jYna#V zJF$OB+8M2$R+74ttc}xOMiV9Gh1jt+_&2f`awr0&c2Gd3Uj(3qWn9dR>(rf5ibAw1 zBB^Zg<}bF=-&^_jeS_3~j~qW4m^D3EmKI78O)=Wq24r(7Ec|Y~x{qMs`I8fO4mr(R z7Jx4xdkrgDs)6sf4J>3TgmD`tm0u_qYia22aqrg^Dign!1*M0}ZDg%l<#m}|YfE!5 z0*N*fnOg(1_zXpqbJgv`fpV)GU5sqSaz;YVwQ|5j+jJ}0A;fA2()ij?Uxw<~sDS{` zcyByIe691V@=!Se_if2Sa9}8GvcP`kEO?mo8}YQ;%G!-sF|FGL_RxEm^wr~Xr)xdN z^*+_QAXYmnX0CC+J+r)m48KY4TI(jhWGb&mc(U-;VWKcr-PfY$?w)7L!TF1qR_1i! zM_aB{(Ofq!TB>|;F$u6gEMW{mH|N7o=o+;>UJ;MC+85#BkWh6M;B@e&?T5j}>Jx#| zKPv-K5l~+3X3PijDFy~C`EO<$Xt`XyUDwlhTUt4GtlZ0z`B?jLRT)gu8vf0s+o&4i zKMAFo$|EcH4Yg7hI@VIt%ctKC-{u^+tar0k0TN{q0;hOWGBdDLQ$t%vtoP!a`bJL@ zYH%&}T)o8>O%wCz=K2c5+_G^5pB-nRwkO=;{YiN(C4_KvTC$MFBOl*$ZrmpWcnk!k z@?+m=4$s=yb-XOvq*3?w+>?E#S6*%ylqS4Y8-|`WeWGjaN9MmQJH^vF7LX?UBtQOa zX)T;wy!uu%z;d`?o1(-(zDc(!Mw4b_apZLho=zqaj9Ac5uh>dKz`!V_nG*tgThldY zy1gvqJsFhmzIe*P>+ooi_v1?wL))Y57ZXwp=(xBpy=>{Dy}wk?JYay=SI3fxK_1+sl%g~7$;~# z=x?}fRu9iWPO!bktjF&CNn)4)On~5PC>01)auwo8y;sy_Qi|9GqMYTls!WR+_EJ_lNOaHKdCbwCWUb`LgBW=6a<%Z^jYiVOSs$8Q&<3xOhPj3sm8L zBYq{(I;vKQ1p_iVS*7=Hdm82g*{axx!5715Z#R=&9~{sARI#O2OOZZkj|czuAwbG6 zvD1-siHjYy<*YhF=Z!SBUp&aqHxbN3-INwCx%%VQN8e3ND-fE#5=KHea5#2FlV4pKfFArzWX)!JZ~y(qi$U|ty8=oUIFttpe)pfNqYkJ6)lqh%7v`GA zdoFHeF}2TgBZ^tU6ARY@?D10+dC@Cwhx>wB4qwz~`;$`ab9d>-8HK~t53I*ZM07)g znu;4X?Q`F0#(bT}T{Ub@>uUOHt`aG?9fK1hz(5j>d^ND^`DSIPMO;D>=PT`>q5{#r z!%Q`)oskhfKv|R}sOoBm!?`oKnSb@@ zBT`epm8{)K2`aj=&^7nQ_@xaJk5Mq|yV8D-qg+tzIhys|FWdNx9i52lKQYJ0!Ib5? zYfD2;PNmx>OWa|LR4^$%J$7}t00WX+!D{;ygLAu(k* z!@YXIfuH^PX1}^t-gf=aIE%=`e9*ADJc{jhQ1DNtu&MV{pb^%wVkCDDPXAF3@Lg(n zSt1~97!&D>`Zn$oIanOeX|MN2uGl@{{_&mzq#&+YmlR9Q7Iv6#z;i-U;6iV=zW#x* z^@8O1+G~V@n|ynOLI!3UA}O_^LP-g`cpH7K2}4is(tR7@Qbc`e1xCi4zKe^NN$;P%J4!sFgS z)0%4UzKGMAN;zDEW|h`bXO10`5N%Oo!Q&y4)=i1w(Yg#zOOJ5hr0Cx9y8$&#jrn^@ zE9jZZnq6Hi5g}zePMFn)m{B~^w+$}aS_m0i;8@42t?tMEO; zowAPghJV4l517EXbevfEEEVnMGbo-EUUn3X!}iv~;NT03ZuIQSz>AMSCl81J zXaSfccEyLarTy01=C_1c@)+}ssi}`B%&j5~{!|g_QVu1j1xhbSBL^kk4!H+y=b#c< zKzU&oSA(4Iy+;dBWbLj0e9^j6^vePZ=oh&7(sF+jbCS0E3HTf^)eRUM7%KmIikBxA*;eQpWxlPFRe>anI3nlU}TMxx(cCh zH_@r&b%lX2wJo!bH_9VyaA(SPbP!oATfM;wS(G-+#D0mv@#Q)T24V6q+rs>qYT##X z)A!E7LTG{krIZQ_N9LY-kh$K^?PgSs9SrYcjj{N_ylijyHuIhxUOk5@mPmoN;>5(c z@6e}f@IIIb55$y4yUuzWgPx!lyBk*6KI~4UQ#o{Uy%y8%(pqt!+<(seJn{VFGV~^c z$n^N{G1bYlCNx<07vnbn(5iWu{wjm^R+-&{ez`QA!Q%qOCWu_073$Q!O5W=Uf`}+T z^FV3D0w@)v4eO18MZ$1|Y`LEIvN=OwN`1J9ds}H_g4|CTx)0QAp`2J)>9WyfDhO^7 zlkR*L0EwYWBLt{BGDvo|PHK_#!$S2Ht}nt{3P# zGi$=_0sR%!jT-Myu_GUKvKnyT#y_TI)jBN@C_irfu@;>%J36gsLoa&aLSK`MCcQ2` zv3k+v@iRt78c|eA+K+YxxoEQoGWjC#(#J*R~k@BUCyv-uttfQ z20r!a=WP!W@+~L_nn|~kK0u8;w$|l7#nin`K0A7VUCwMJ?y<-09bfjj8<+y=&^@r( zRBmUnJ7QEQXC%fPMDI2z(juf$Sk4HB$a5+7>T2|AcUat9HbWRLOlBKw=>)O;bV%#= z*rwpxPjWp_5nkU;*QvXFZGoLM20^h+lFM@m`(3V8!p#mf21?p4oy2p*R(c!@mIJOv zyT@bQYr+r(i3yr%=!4p5!=jx;`1r1Q$>wI-GJetCGE-Jpgt|Ms)5st(D+#>Nn9N?7 z^6lh&$-yAp$F*A4E4+n!@sU9i`?K^i<&QpAt<1jp6b$I`oRHqE$Zv=QcH|qv9-~Uw zoHjjpjBnrVS~h=!zD*9_D7eKmJCl?6;QH$M{+Wufl#R28V(AR+o*r!w=nQ&pA|Z2p z$+5tjTkVY^d&J}9vJHam6#S`np%iayw>w(TCvW#!#x!Szh>`DxyBqzQ^=a#GRI|Hx zt=Z#ktas>T*&MW$#mcI2@$AIq%71=z8H3O?yNjfJr}&8}GA=G)#uYz# z0b8w(%U%Ukx>fLC&%Azhi_aQ!xICOTC<~oN-7sZdF-$M%c=X#^^JF}TS+e9H2yGwl zoX0h^a$fGj`3_FY6>O*G2K{YrF@3XirorWYbtUT~#{#qV+EFFip(F4HNSn$2&<{SS zdV=pCt5hYl|ChG_90D1xSxtpQU=Nu0laG*nPhWCu4 zXSH=84dDF^O||F)!ye5SwZfG_0+o$o$ej^#8fWZG^Ik#+dl$xP~x(PyAwTW;*!+r{rVUYoL{u@Ir#Jx2?JWZK>8F(!S&gGq*L^b=ZwdlTw0 zg?5On@f*MW>iSmb5#SkU&?Lr3MbiKi$9c&Ki)u_`xLU5p6-ZWVtl7#OVo>byqj%fE z+In`;{jh@3ZFI23u0Us? z)NYRcZorr*<{m+L_4AHAOmREck2muMy`Hj#2yMdGLk0QDj$d}zqpCft3>zp^f$b^U z=f!;MWg2g|fKx?lo5O;VC>2c$Y$zBH62Y6fdj&Hh`rTq*HIbB)AlrTqGQ8GARbym=*l8lQC#(o6F6~jm9!6Pr35HM_*96#mUjbFe*X@)~e z=d1>DO3q@c-&UG~N)+Pl0@?0{xPubv=|NeS+?$JsK%#i-Ua}N!(|Z$lnXOJgG_W&@ zm#oqh5}!A8s<)&ZPue!~i1Ou7qM8$FWxCcU0BcDu;wvp-No`%v&UqDpW`!@Voo!nh zgIp$^K5LDahJ8j*e&{-$Q{dzr2Kg!mzi}zOvszy z?dQynDf#)yk+2FffMuuZ8Q51sR7e9&N6jA=932D`CS70>nWuNeg{t2kr(g|?#9Hr9 zx%^6bN+V!Jn`Xb|`SN;e%8xCQdvG9-h4ABsy={fV)Jb7G2vXy{nBtsubv z&79!EuQHQY$s$&?N%Eeyt2;0oWx47wkxhA@Q8kaTjbg_e=u$Wb)c+g;DzkcP2~ra5 z$Knmy9aIJm3g3#xL9gE1urPjLb1$yZ#V(aRqz&nLk4U3MQMtP>Coq00 zqU!G%JtJH@{7M0&rwCvv2@`jEN)No2p1S~aNdUi1gwjiz-Fv(%vlA(Z`#@z2vNQ}Bq{8{^I-s~i*;oKefu^+55GgDxAB>i zQ%S8cI&6j6Ucw|hX^5QXH2&fAyXV;+F{+tp`(!E6!~f#!E5q9Awr;6Fix(>nr9dg} z?oiy_p}4zCptQxUxVyW%yE`Pfy9Em_H|_hL^PO|Q^WEp(n;&_yCE3|)uC?|YV~)Az z45(g67H)b3;aCYF0b8ZFtjNW}xpt|!?AyL4zF87mm~w59Qdp~N&0DShUxJFDi6DIw zJc%YL7M*KinO}9)#24xDd=!pjUN+R)ofxYcBHg~$E$$U*9qI?KSZv9$Em%)RlSPyV z-Ct_BkFd>D?>b-);S56^Y(`F`=lJ}O&whwdmo7H1h&TNg6*Ohl(Do@RI1#bIa9)wf z!-aGBs;$%VP4Zi$3vY5`+z1=p?=B|T;1jE^Qu4~1%+ak?d1Vvn3q3Nrve0lj?*NN^r0(pW0OlI9T~(~|S8@$Wa7&v8G{~!~ zKAg=7*svAn-7Op)HUF0dsVVoT$b7a(t3=2?@vid3EuY*;zQ_ z99<=uO`gM%-^e7xmQPkkFN(&BPlo~f&I5GfFaz{!9yZ&lL%02)4%D=GN`NRW9k!;l_MDJojfgM*0 zVQ}WvYxvil28~bAqQVC(ip~&%RiE&KPxz&@G8`>Gu8oi$R2U7)^oI<|FmpEfAHhzX zbemicpL~B(h^Me;o6_zVeaOf&NQ~orpeQWEduhSbr%u=z?(tHM82RVR?jzjE(VnQJ zK#TGZ1urzYNz%Xbc^~|On3Z{a*F?yRi3yC$D{4)Q`${lB4-e8Umon5R325mjo|J# zoS1CgtDq&-%vQ$*Gm+24O`UYIV?v;R|M6RC6H0uPfZ}(ix;vPOQ{|Lg7KT(<#P<~+ zQXjb|HA-BC+pJd;-JD%9BboXg zZ9WS@^+&r6T%{Ddq0@tJT-Azgvz<-1yFOMS;?wuNyY~Fz z&9|xX2jY}BBoZy*&5c;29N0fH^;(w$_NjbAW4;sr%4rMgHxXvd`O3n+QAl;%IwB$% zr1y<{In+eFKjoT?u~Nl}h->m*!uwSlb!`tek8oCZVE;TkBXgPYX*242*(2T{;&b@T z8u6LSHnHbb=7TeuR;MIQ4WTAtu*%IkWdn2*!f<9S^dC7+o^#^RJ z5B4v1p56$T-W*5P_`H64d*}8!ZeM-sebxc(-saBNL;x!A2Bit*A!`?3DB<-c`qd5c zl}`B?fi28T=6EL}vi`=Y_Re17$0w^^le&U8oQ}OB6F6cPG11JscsMohQCSsK_f5># z9ncpd&YJJq9#xi=Q)zpjw-nz~6B0ZQxYW{j0bhLkZY=q}+7#z44tipx8x}RXCda8@ zZ${gMDb1#@$fvRywsogB3RzKuIv)5+FOdl>QAE^N8Ja9P0F%Q?#h`4Du`?49@ThOU z`i|QZ@o%r-Xe%!nI$24CfkfE>(g=?6^u~r+Si%D#)r~2H!~~flu%`}Z)r3a875=Od zJDGU!kBEH)jnKXddl8f_QZExRu!Gi4+HViKi524ND1;E;`flTPTroq z;Z4tb_3ne+y75x=Q)0tn@Y%`YkM=FGxd%Cn^lP3$M8gj=5(CaewqmR77H)fdx1d5~N47#3+u!l=0HoPO@!ZHK*##HonG^xkkrr1OC|ipi&AJ-prw@a(F;KrHL}8nC4IwzL@|k5BMi zNABAJ`BoX}#0|v)idX3P_90-I3@5%~^F3Xkco@j-x|er^6X%ou3-2O+Kq@=Wp?d2c z9T7E~V0{QM#Iu2AONd7tU{0=6Put_T&J*^?7mqNLzAJQZT{5BK(8$RW%;hy_akxLE z)oCavnyJ*vfj=|{xzi12M}An7>U?*;5i(}lt1}!}kJq{C*IF4$XnVA6)UUq4k^#t< zGSg{6c$`;K)*}qAjHgTv^LuBoK?!?-ZGnfEMv5~GGBc%|2-PFA)H4w?01)! zwCQUcmvGAtp7}u-Hrhr@P*x?7p0JVZ%iFV9^7!8ia{s=neU}b8(+DUD3cG)kNzgZG z0*U`x?b=`}@;B@B*U2QG2>-thrFOz2DlutrI!+uSW4sIh=g;-nanlGL7i6x{qKN!` zh2L!L+D~W%wmBQo`sH^tC_=-ar2Mk{1VDFS5J8*ywGlotIsG#WzFrEZW=>4Yr8 z$r#z2rJm@0ZxMWf@rloc#6MeoP_rd&){)|jC)QB{O8dOV{iwg*IlG?rO&)rOOWN=_ z`Q;r1miz8S!xT@xAPKE1yBm?fDA}2%fXYvzVsQhiC3{NX4gy=k^k4VW(I*q% zx+%vaU9PzvJkz`FdzqW6SWz>_sDJY4Y+{$w#W!pa8~kPv2#MxPul+Ji7ls1nVwU?% z!OxMJ>k zK5DtBw$?^c@?(6~e=>0-xc9!L3P{}~4l%YMIRw#>@RQ;elYGn14!gT}b8{nrrE^aF z1KN+?N_72peVI!UZD;LgW~qZDZwZ%2AJs@iLz#mo?ol?)iHxgW3KVBsf>#;C_YuxS za(W_DvE=%5Q8_h%9knS50h>M^v6~n;3xO<)TjAii>3`vllx*?D;>U(4PK-^CU3B?p zX1Lq9qNbG?+z!kg!hFbrS<~;+mcGb}!Qa<|vq#?mw~+G8mv6{^!!ZL)QE~NwJbsd& z2}m`4tv6n-=&Xi(groUo$C?x4-AS>bn$2(Y-U$SdfWZ=UG(Bc)nYU$Y#W%>urn2aG z7LgevAFkS-Wt=vB@^6*hZ4+_T5!+>;bujkAmVX|pn0?A!l?@UY*9pP!Q)$g*3e&4iq7m1)bJeW#f+aB4^%=4f!l zrbuq`Gz99Ww#Mb3PY(uyHXUc=t6bSV>9{@L+uT{5+^?ukg}3$CMsQ5RkgubpJ&ieN zuH3ltl_>}YeX^X_1k#TgYNnu#g8R%Zw`R&*ITtWH&ms+!4F+i2lDT({eZfi2xOBAU#Ne2esrNVaa_02!oi!(MTs<8g6{Gs1cb8;AN}74&FLA=gb|hs_=0`h| zR+wTqc5GTAHkL5a4NGy(HZ2O*2F6keEKf7_d%h}*Yd#@A>2nGM`j6}GfC3;(w@cGB z1rNOKHzkFp*xlmR)~S3BdO*zp^Wx;3UadJzo*zA*Uy($lCNX>7nCX$1Sw^Ss5+@9^;oJfwpQ;Ob4)^Z%?o#%b@!>lH|?en5%3|#-ZHgtMrEJRALkpDBoMhjKE zcD2S=n0Gbcv`4T72kS^se;S$!Y%Z#~_QNAtbm2m2`Ej5&A+s#Bk=0JV@PK zT>HQ3-n@jjOeej38b3o`YAZ`fY(0Z#8wc+kt+?LyHQRRZ`o1OmcizQ>l#pL6*0KgG#ekj}^1l4ak( zKY2AqR=whO%g#h3*Qdh=(|#b8_05CoXTv9lW?Hn-3Ge6YT8YZXzMHtBste!_e)dkG zh(Bm>`pWHz$Gc}(dXtiwX83<%lSs(9L-v5JEf)&Rf=VCVMJyW+Bc11bAdFb8%M;#r zyek~QV7S*yvMhO_W%QceknL0J<0Agi6W55T{U39Q!wsg8S5{U}{x5cD)19u65GBQeq#D5_dO}|GK4Tqk*nLvavLgJe zAlrOp`t-p|hDcsVs)N|nncFa<()LM5nctBYX6b(fzY@qEoYYQ85?oOgrc2xoc?2+b z5{D=1+avlX>wkhKQu0qBt)r77pwM)*R4&5YGL{G8ojj~Bl zbieN(gnTR(zFvgpLAE@gKh=TP#tuf0?Vp0J zWI6IoMGddNj!^=WTTfc$=>bOng*w@t-r6}n+wyY7y2t}(v{X^7{KbRpV%+>I5z^X| z0ofARA&6Uz41PSdopULOeV0)~UX}7aFkI~Y-xSdF#I-@iR>ej*rY36Jh^N>Qs8zIb zOR57P%OEgEPsZvte<7dP&Y0b4Vatd66EMea zGT(;aHW5<&MHXF3m2yYU%h7*;{$?)i2tm=FnplA!b(mnBbh7Ao#Sk5d><|3@2LPWe znoAkrNa|3UKXrkH^>5? zq>-_XD`rjuCrklHwMEioayI>Y)_O?QOF~eqZhXuTW^2fl2dJWQFKSAhHBrKCjsAB1 z)uVUW4}lW*Jw*IkmjgU5#t~^!3D=-Jv}`yX2QH;Bx}l<@A9bx_PF^&OC>e5TLw_p( zLTI3e_gnkRuA&ce>dK;7IrpU}b+YsWQD**Tu0Foa(9hVU=Rc1jJpgT0vYd%hxh zz$ZEtsEN8Jm!6%3Xw5?xQ806zn$!}#;hcHisq;QK)FPqyVQ%7gMF~3+Qe>c}!d=^> zd7`7%aoLK@B9kmyw9r%7x5BL%+TZB3yoEI7a%K2*F|}(nmN;(hNA0%3U2Mit5yp-R z#K75f&vd75lrOfoU7^X69K#qGGOWu?$z8#QZ_j|VyB4F901BDd4!q`9R8b z{HVr8Rg~{Ir#=z(F66%`7`;6I_TdoGkqO&rN&wd7mkeK7_8YCX7nrRmuvjXDT-N9( zH|mBhZK08Inuc2b=0yt^gLj`-i0Vp1m*TtQlB+_+*y#nit3zB}+17zk>JJkp=VB@d zp+0&`O>Kmgp%spM(3JGrIcGm38RpHz=!imxH!92T3R=F*<{@K_Eukjj?j=Vk?H&WJ zIZ~y5ETGvzV|?!*yAh5xX4K;)ZOK^M?fTE^G_DiiHrEy-BptiQg(y;gyju&0n=YMiJ4zG6o z{PQ(*w*x4@6%JXa=~=}sK{4N-MN>`?QUk_y(=qo7 zJ{9nak9>D7U}Y_^V1iS6&Q+i&(i2Q?Ly*!YZNrlb4)})_z!x9?L2R!@SxmAMRbs<= zX|&X=uMr1Ha?9Ba`E|+*0~0=3t3|P!SQe+YZa3@yftWE~3%E)u5B zame*HkxAl2E&hKNkX-62m48i)>OI1Rd+GnhghsbF_~&~RFZoGF?P?`e;Lt%9E6+q$ ze$Ff+bP1qXOXrk^hTwj%S77sFy5k^9P@|*7w4n3P{_cJbrctG_b!OQ%?_E->9mg>? zC$uWEuTHvK4u{4lsp_3d)Wkd9&wOL^n2OkCCdR>Gq})`bRQ!s684;tZe&Z{Ah}vlW z;dkVEJmK%TtI5i5WM~EB-eXqQtdr47@=T^N(Xk)}j_3g&%2VsXTeM4Ht9rST;2dg91>_-m*m*RHv)>4x|tL;Cp_(pLVS?5=Oj6;NAe-Tu(E z?9{3XE7-pN^~>{ToKoA1ZP!iuTQs)k>7HF)x$`cZx6bGesr`%V;T7SsE%{HclqT5& zby{DN&jo@w79lke_ibGJ`DTkxH+Eme611Y^=N>Z7mxHItU`%yfrb+Ij;zAvAieiR5uG zSEAS?$Sh%}{oQ>yK{girohl<@9Zmy!&!+jFH zVi%yXVxhn@H9aLi-BrgI6&s3}aVPhZUGppzo?a@Gtbu|2<*zFRaWq;uq+B{YAkr zGWxIRqgjX{54y&{L$Ca2w}AoDiYVIo)CtUAq|D#@zmZ_PC(Qdkfdd=09AvZ&Y9BhNCBwIn9^`9Ze zYYqPP)4Pek4S44Ne4;4wTQ6mQu_rO0(buFBl92j7fN?@_b9?jX?h+HZjo}(iF-zlN z>v|6J=2!X?2=;*;-JdQsR*Q(_cuz`s(WZcGQY>Cd`wW#)+rzgGC1R;ZbBTay9NLgx zut?S2e{1C$+($G@mMUNzml^py?yXn2X9As{ba>ia;QE5Xq0r)YHMLs9;DQw3gowCVO|MQT+a$FOpFXPvFddsKRyi<;;7@RkZ}4596FSSZ z9*g%>?a>DgkM+O94?uU?;C%vdP!pO-qVL>}qoupP$@~14D}0mhkttOMrQ@gZZMlT( zyzg;0=+yGti3>XMBbtBIu358{n6O~{g`Bj`RM`p&pir`cP^QM$e;4p{PuZ{R6)NM-IyUw5q=dS*&f|M}lB9@-AXh1EGqW3QUVG=+bd&35vHeTIqY)^%fA@lo z?K#R-5@4u%vv-+#L-!CWTaU6iQrfe8YZ$XkKee&}yTNEe*E@0hhM=D=gNkv@LaaNq z@YIKaT(8^l;5jo}xRc}lu&4Zyu_@I@N-UY!=YqUO!yRW7!8;x9%#krMY){Eyt%{Jr zKynbapLj3aJz>k(H6!g-uZC@*Gb(6oxjv)rf2J&8{X^_CK0JjyhgN4HPssCn2WAjP zwwllYiqWd9^EW%V3%p^MXK2aj?zA?J$JYxSBPOmNMbNc!9x>=v&cM_n?5TU)J_03o ze07iM?~q78J>pjnqd_fK7gnxqFi5IJw#v9$%pQh5(h+#IKgjlRH z1v849l3#($7lSg>N~Ixv!4XAGcx5bazU>HtQT~!{Yt1;-tJ*h$C8{H4+*flLm~nN? zUl}g`$VV^oNgg|Qfbo*4efMnJvrV6wy)9t7O!b%E0kmSGDSDJ5{c`sSeRumVZB7$U z0o_~nXeqY=#VdTlBMC;%P_}Zd>^f5}HG*VKR7&HUf-7cwTo~u9WX3r`(Z2VkCiWAs z`i77%<6Ki`2digGy3_UOzQIC=7vRW(HM~=T^XiPKMixQun6ecXq15aK4xV9rH@lYHo{`DOLut|*X zg|tL4vA6ecEUd@y$9IA^CflxibGzX0Cb!&KuC& zcEzJapR&^vgf5xP8>$`s9|Y$dPYV-Cdv%;&52QnfeD!UKih8!c&Mcm?T{mkBSmreM z%4(aSh;BPRtW3M5u6}f}pwlkw;$g*q?tK=tJ_Pvwfei>QA8Z`uWRci9zA^axZ zbAs(6*M}AHJCgIZsmyWrNHPF**>QWvAt5Dc0s1+|Boh4IrNCSH)SoS1*&t!hVVA~R zm7&gb7Nyxye0^_&1R0MS}fYtt^2%e+YwU$U{{H4{FikCqQzAUk*3%&)|4F0(#+Dra)Z?AWKwjqoJ40Xdg7{ zcXmXLTnmADx~c7<^NBiHE}uLm_U<#!{P4MNC0gv2kXaHOSFWkYlDuB{$G8eddmPdc z+eR8_CPWYRD8ni`v_9*G3A1VG_F34Va@%!Z!zXJ0oLhV4RHOdG_MO^n8>TqSsKPgI z(cgaWHE6TBHT`d}(DgJe)K~8_YY~0I)ITH!973C{YOpU@VI4g@+Jp1-C1gY$l_#pR zb;;Fz0tGIavUbXPj=00xtC97Dk^4%T0~6DvDo#H5wtX_w{Vqd1S$SVxq2pvQ)Q%rb z#G;1$f|bayB>bxwuWxY#oRIHZ*LJhz0+I>*Qc##V*>PY=X)8aGc_&|nZETNrXcMAS z>`~sLu2hGHY=x&&v%4t9VgYiXtJl4xu;psFA!z(elvi>p)zz@Ux82*Oguc6fioHyK zcZ1=gWOr2fADzVo8kFn#BEO-o?!^tQ$aPylnp9J>mzHiR*pvcQl>94%aat8u32LNC zd_hZ_`r4^-B*EZC`kQh%Gn6FF?=-ZZ4a~bGG-KSdc#XCHI~;qdaj|hmNoF)|>=N|@ zVHYw!Oem~Fkde_t-w|aa%A8|3<{6bRN5zGjio>a~$uDHOkEOWdlisriKI6a&txo^Q zmKi=~*k9fXa(-97Y1u=YAavTbx(;HAx$Az7*e)1a<~tT0%Ud3%BPreVeRUpg2y+C! zat$n?;(OBV6w5CPg~sBFt38I*nRto}N%&{VvHp#rdF8fvZ#iD|jCiHY)kU0Ao9}rA zoGpAb6Z>L)`~^b2H?5{0WZ4746u#+V@@GwI}-Ny1ZR#rL4QRdZ__1$`RSc&V_z{;oR zJjjjtyghWl8ch8W;7h;Op_-mTR;M|1|CGNvKFh}UJUZ;PgSTzthqh;^n9%G+iH}i= zBcz)$x_xxB_Li3FTYO0R@rOfS))IFXRGs?hAwZZmhxo_m}d2v6ZL zpWkwZPv6cDH!R%cI@E~r#O?-4$@XX|Enj4p3A-K3=}#T^Z5}nM6ri(47km#0j0h8k zcSds}$lRP*Y)v2V{Li9*sR1tS!yeBAeg-VSkGWZD`R`#jW7>U|#UUAlXf-PT4t}lI z?}2A1V}^r0ttP*nLzB=hr7ZNSMw`!>=4PX>gkT~}9(wCWharN`|{ zwBHW-AFo_GG}Bf6=YoQ8rxro*-}~N@e2M5>{4AuqKp1+^-18f+{B?fc^j|`D3AMj> zKzq@~AO7<1GZ^>9|3JXMz7ak479MdMDDuyXy`3CCg-85@NdDfJfYVJzZRnlp2Q-QnIJ@)y~h0U zua8E7a?rn|7F?W7Xc&VgqTug^^rWc-y%F|wbeStc*D4DIy6OBc*>1-(dR!x8<73l! zZ|_ZLln^!AUEptV2i1{Z@DN(hr1N+5zbV?A`mad#B1g$vQYw0Jh5~dXfB7GRLYjeJ z-^yowb~|+^q6+NG_?CBf)^Nn4nzlR9sWjtKl<}qdW)NISc}l|nSdMsE-l<;U_xzOM zNBDfjMbSjFKHOB63R+A<^|0}xF<(Re*3SKCC1a*YQhdtyg_Cc<0|yZSxX*&F`V!DSdDSsdXJ^Y03lbmSTkU(cYtk*)ou z0b4C$_Bk6cPzw1sNK1e4pX0oD6BSIX^zmQ%z3Z&Y`-`hH=9kULP_=+aF*iwN9N{ECEwj|7J_H}^rRu4H*3UYZhn z+hGhqLSGeIC{3%HH+qdh@>1%SXZ%@1R&qCemq$#_x~lL5>gsJpsa>T=-@fVZPi_tVcWy!rW`lf}K;ODkDrs$JBcO5KI`D$jAzqZ?7fw z9<3k2sI)3YG|1lW^7N_By${M$cn{KV^wRUiu6c{nX%AJq6Q}Qvs;iqga2m?2?2H6> zTYrE6wl%w12jvgh!{r;X{J^GQq4_Z#Xpk|cy|m(;WB-)x0skZMYKl7B5|3X~7TkyK$h?#;$>qjF6fC##!&Da~(LMz0 zR%WrV@@LilgO(~X=hn3Rq;zZ0(2y|K>Su{K(Kidum9efZ)h(O8& zH_FHllf|OO*)Y;0oWC?)?ou!Q1M@~&^WL!zbj?Bc0rrfQl@&|KYJz8SEMo|RZtyNg zgdNZ7yVa6Vkwfcd1$daR;lF;{4UgAH{rRCdVw*;%h?bjZ2DJ@$il4XyG?1g=`|GaF zP3Bqox{WHX6qtHgcM!zCS{8ndvUj^_eJ)08s`fN>++=#_pfUnoU~nMcu1Ln@e)L(z zPKT+BY5SPB+*OYwM^2~7BMZ}pH*d9dIp>VsndAM*)b&Z4kWS=+?$xiS3m^BrgF~?e zx&2ww)k$b-z1FQ4R({@K<8%4t^?iA4<$TUpS|h1C<>&%OOq;fRa0!hdFgk*2@v zma1a5kXaSqkDN-zzIffBJ!&0u)&bdUU`XD?Unhk4MvB*2>`t9uc=xia9l7xG{9(yW zEtoc~F@)g-Xd#5ZFPYt>+A(E(TO9_bt&L_n%EyidmhWl*gW8i!*Gm}m0X*m8{OQuP zF_&7{b4dH~YC){nA;dl=8hkhew`{?E@4GPOofTn`J`>@xl3%*(lS>MS)U(C32D%c> ze>j}cZ@o0h=TY?q@?QqVjoZY3M5rg42Cp;~Oxg*wp~d_2biz}t#M#Od5)y*=$$R#r za}SAm@#Sf=;yim$}d>VX&l9rpH(!Ha(&wb6Q}pG$#Cn2ADc&N z$dYN#t=avTKMChaU+f%dGH5JDs^?KEMd>G4@IQGz-qk#wW4$MWXjxKFa<(=$19cya zH*l*9ue6dzH@!~!Uc!7c6IX{3h^i>5%(v)i#Ome{gs{~PwOVE)r1;NZD>9Jf=0^ZL zytkbO6twdUw32msT|{O0q?klm*Ftt*_(vWlBMh?_giFO6oQ&HuA5@9z9Gsje2()@Y zwuK&VnmsR1<4_*&eh?+T;ypmNm6vGC>|{pc+fVD0h@W50J(+-0QR6mt3e}OM*J^vO zyz_Z(xsXpOiuXLBFO-7l%BytQIX+knA2P*R-?hVXXGRa)D542-aW?OWF>+(wVBDgi z`6c|=WN)eDn4$M-$3sPVYp8*RrIZytmeYMPx_ax-R!!=;7L1d)e9+3nUl)F83m;^8 zVzU2*XD30XdbKj*;wF5zkpK|}CW}P>1x(P|=V_hAA*`kuYEVIDs5@efzGv9XSva0Q z8L4Ao8)VbAC~N&&ns@bn6YuMz?c`b?>!JlMF4jHx!GX^+Q8KO;x)s92u72c>0;$U+ z)|x8CGKA?xivvn=^@7fiym%9ErK@e4qzINAa`q9ssNwG z?mLsUg0V|Hsy4&?IxNURPi9{wS9Z90sM|-RhDcVq+1Xiy1*I4r`7&}#@XUcb5#VZy zB$Y6drgvIQc>kiP#?4n)P^|5J$!b~Ym`$teY1iC%sW&UjrJ3n5-7&cC&?!RB;XU=m z`FUjvgzI+Jh1dI9xQYI>?cgr=ft;FU^%JX%ZB-xg-WF6B$OU!>xLL^icwE;*0#`uT zgro@h+_6kIu?L9snFtK7SqgIwc=*tiP%vg0qe^C_Ix!mO6{n&sqdB%{#~26p#B zxxP5{cCL`vDZ=_7u%9tWPa zRb4OKbpQuuck<)ymx*|H1M^KQJTk8(c)LhPBd4XLaxun3Q+D6)2e_Cv zW^XMD(-00uKpMjqUV>8II8i6ed6a55?j1}$qYeBE7#J9I(}Vh-KLL1n2`h$&&~50; zMEK`VKQ$ZdeS|-ozc}i?y!rD9#*P%)(SE-^>`O;gFznF%b;dXQED9Q=e;i`WBBQZV zBPM_O=S&6=bW>Wx#Lb5E_vK(<8bW2*|9ldd`aNwlaE4mZ&ecfOvd*7bZ(11@otLF9 zR4xtHjR$qyjE6=R7D1Y89ea`bY}pPHs71@-!0zg(Wz;w!5LGRHN8IwrVytVPJTZ1m za&IexUWd(=mjd5^`)`Y3k)KSB!`@@%j*StgOqY)D%v8xF*Hm%Pj=h}MZ1AoI#uzWP z`Fvg+uD#}e2=jK4t5u9Ddn)g|k?RjL#DlmE0KYf0SvZ>$Y_j7!OE-sU7#I~=?K7!x zme2SUm!>y{vg?Q-Vi&Q1B3~O~kjBAZ;B}Acn!>bQ5d@*Yz9>z)RX&wx2SxL|3ECz|^0BBw~#4PObIS zxaLj>^k(PtM3K&YjiXF0g5oQ@mYHn3rp!ZKkIB1 zpL0P;GJ^w(vpdTR&EADW4oXI_Ja|W~IpZkpIT2j_I<8-H3XPU^dF7k6x7`a7-0x@Y zwywGCphb3ujVfhTU8d5pEc??RWVoJDbl&0Ke%4Qrn+6o0G8I%VZ zha8a$9kmBU@F5eAtayAb^3Mw#G^E7>`zO>CIMMwcB=jEhgNI@7z-1JWEjTIDh?bK2 zdnByoN@345H*L!C2T?IPKeF87f+k4~UhqLLzYAqdQh9D|vopBKhgn2k5IXd#a zqwS;4doN`vK$XByHW?A{b(NFwu|cGJXf|qrH#!vJbPzas-LMd7I@)`YByK?5KJAH$ zN1rygQAm;IX6jRdtP**ceuQA;U;4&94x=UqxmcycbnqKpRr0;@o8L!}6U z3-6+1{P&0AQmN2#-tjp#c-HgkB~Pe6xvz*XKhq5E4TIj7CY>s3nZz+|gL;7`wXU$_ z&S8h+Ta~&dh- zy%3*0GjMq$4zq!luE}A*fgN2Qb5u3LkeDZ)Iu(-C6SVfaa$qO#CTE|c%=qsWWKKbs^i4$y1K^C|Mw z!x~mS9COx!KqJX&{hn_wAI{irv*W6%efC|JtDPIEc8saXx0E<$KUD*E+7YZ^dy`CE z54DrI4=Bv)zTZ;G%0xRp>+OTDBktQ|5O#7zR`gf!6fOHJ2oQIRJ5<@9UIq8r_b12guYjMFbM?H-qABDKwd2)H2r85GzWlac4cWJ8T~Gi${;Sf~SFgxmD~=mYrQ6b-2zlUuvnE z>HB70+10+^LOFQw6ZE^w<7YqPDeOoRqKVt-RWPhs$B(guN*oHq=K$Az53jk?8V`a^ z`8E-s?jVL^54>hg{nFYtf%T?!eM3=X$>%`cf&e9Lt|$6{83rcv4|w*TM!6=G%p!{F zQJf#I1C?Xh>iSA?ThsfAhn*to3tLcMb{PG}o-d8)bPJP4p#A-6)gpv!@RvTb(a{s? zo!kZLUVHn}yNjQT2u-stSFdVQAHNXK@)Z&vx5#OYKTC?;eQaO(yifw>sS*Shc6;oP z%DR`lEcMw#qfHM((P_)qtdo$%MwZyA7;CvpS!ri^8dsI_MN6kK7Nav^E@Sy1!9+V~ z5|Xmcc*KUwWSnH5Qu)*K^6Y{idt+sl>0QQ8`jzEM*cOumwJImZ^ zd0VmGD~AZt+iH+*Nw10q-tocIH_E|Fiyp%P4fS`7n>HwymK`H1A|f_k`Dm&Fudw-N zGfkg0+8+n9&yf$6^&^;ppN$QlthySui<%bPX?6d}0N|$4k1s)cuZY)U#f(pxE^nh$ zjmL$9if59O{X}VBA5kogUNQ2p)OJz18YotJS$gMF9%Y|H>Ri9D)pW6;1t4Ncl*f@Z z)|u0sX~!SJ{CJ&F*voIt-oxE&XiPbG->CbrY{`}0s=TUZF&*E{x)dm2Ma^?jrBlv^~TfRy71he7PeLRfEYzQQ3^5<(Owwr|H|WTH1F^P zyFT6)_*7eHVY@$*K|w~EEic8kTR8VQp)D+Rb)ddr?CPz3%NEE zz^{Sk)rNV^Q%5AyntBlAODP=OS3NF7qtf{N2=|#PCZ6%uTAlQ~tC`KUv+zSuDxbA= zKZHycYCaAE#V!lnweuI25puVRI1J_U$DFiJvNJE;RWw^VGBZf^5P`NJRnz(vZa4j- zUDb9xJdc`cm-s8!Mdzk|3eJ#Nb8XAbEwx3+%`)nKTgQFTVf=Y~$%I$(jFWJE=mYse zg}}iHk?KTTHtfX|dAk}PwM)qh)61&pS#Ev8n?p$FVCmgcT>xaXLm_paRoSaw)|&cY zHb^+E^7<&jnX!*Q*zH~)Ib}Lt$JJ8Ky6g^$Ogy9qp|%gr1>7#3IKIRoZQh*ZCbXXR(@@edjkiB*{u(gmn{GaI^ob zYD6N=A#Yk;9*&&bUWu+dqaOcFbgPGxWxn^LH>jqJp0|h4o0S3JW9|LrRvrs(<~Of2Zymfqd&)+v+_tN; zX5-hh_LrQGz*fKxt4uExEIBeRYX4?FI^q68Z3L8b-&TTbA8YNZK=S!cY|TtYgz z$V^^q$r*>^@%OsHneqTKa!#{Glr5(0OPBQNv)0Brt-G=*V=*GFZKwO2nhWo4O&vD8 z;cF2T6W*d%sSlY-_2L!hN?KPlae@LDw*?LfeU>^qj#rz30YkdhYdkl>jPb#nnYf4w zVycq$;pFGsAiH^tZp}{m^mqxAaIfr~5rP^U!305XckbHeo{}}Zsci=>WwB_# zIcvV@PNnt{sT$bxx1|h@EIaNy_@o8){-LnU`U+J`=Hi6<`myV^a`QH0wb`zl=Jma)ok>F0^`JeXOY)!e`*!v>@Vah zYRtyeo$*ov#E(Q*ETNgaj90zld~|=3{Zr*{f?}#a0RzVi!hafSiPwcxm}`7rJdMI65QTwQ&0*A7 zaaP@STDaJnEAI*vfc#7xL#%xPD?K_Ysss)3kq@!NmV$ATG?DN|9~UODprkLR@KDKXVuTQ1`PqmyV8D73)sL^yIl#k%6_@W9 z(!!)3S?1O(vCqrs0#k+CX1&#obLF|>;1?2{Ix_EECkI}bZU3gq>50<+t=o@yu2U^4 zuZnlXRqXTlODF!nVhCy^FlW^P>pY8%0L{)Jcy@mLRL=8K_tj7&wU}ylECK&Lg2@<8 z^v}HQ8D%v(gL&aQ5h6I7)x@)f7b`kE`8Na)@=x~qvhl?2Ksny~Gis3cq0eqryk+ss z)h}l%a(Qp*TzS;U`nzw^4L7+whsQc$9;;K_a}`a(B(u&?3#qr)aVAccTG5t$8V}SD zmRf12@&edR<8e6gXbxdgoR5RNiR+u*RI)>u!4=?A-#jxiDnLK57X~D)oWfRA?W|B{C*Fsf!nj zJ(?Ru9-3XHFoYEpo7U~Pt9ob{AT}*h1FkqF@($9^r(SXc-9v^ap9h3?p>`#Nr|}YnMJGyd-HZ;exCBoK2`YE z{=bW}F2#=j6BUjNo80p6wdN{knsbo5P78w*b= zw|5WIeKVHwbY#?^bxtdA;PJ($s?9U{>1S?+H&v2^JXkTAPt>=GQ2kBS%AE`--&S&; zGw(D!wOQ~pp*S{DW>qnH;Bxng0`S-ABAkVjP;v+A81H8S0^V-cX|g0`zTU1hfP{d! z=Gejexfa*1zz3cvtiQ#_E8}sT2jIJ|;6!H&1cKkNEU_26R}Ky=>>c3ExAQN8Or6NH z?(gOtMdFs&$$N395>?X2?-IJwGc{m;TpN;eiWiT{W7*N^SFwwYW)9vC5#bo7aug*j z?Z)4*=A1kaf7gZe(nv z_3)&oC!^#Zl3`0%bo>nWaTKF%Ophg>Iy5LUQ-YEov_J?}vQAYB!re2}gn&(pFGk_t z7E?itWaK!7gYQa+-{5u{QB+s$P8yg@Y*Y{%C_*;bi6M>`B1I6I=zYZnHK$|;r?Za~ zFZDkFoX)$Q;+|*WXq630sx|?J_6&9eC*T0d-qs3inKF2p&;vKma|@2jocm-GM^fi zav4{r?5;Bq{U_iVYug_s{;Gk8i}^Qi2Dr ziDtXJ!^Vm)ygql|5gMY3?<}r%d!@`6_+Q;{J=8JTZYm=yED|&oB`_RLmK@wwQM8vt z+NcWPQG?Dq&NR#vsgJnwOuXu=JRTn0Jyi!qts7SGn#_lM+x*!7gmuRJ zboF$$y!8EL43KQ(|C!%u-3g? z{eyiNxoV>RBxthq;{OTbKmO|2LTQ3{!qO0oiB!`g^C2gG2-lR|NyXJS)Xi^L9pQ>b);{44EIFo&CAs}ip7g8+Q z9UO?oI?rGy##w(IE_oZ781->;dBB7=^jp;$+v)shSis!`zfbEzefqeksQMWs?0nME zL&A^7LJ+zKKX`pJOhQ>SdeK_tq~SGIfHAjPl#3hVaD&~!U~E4(l?tw1bP@RRKQ&NF z%ii5FF@02ndG{8=T4nUIu=eEc>4D%;PxwGFE}`q9ZYq2TtI9#hI(Fl0_nrcq<&Zee zSV!Tm`Z{hPJ-s!SRB&!*+l* z(4MvYm_ExMxI(Z0wTAKb6?!?`NkG2e=rCi`1azKJeM<&pZt)4R|C!jmj5YyM?yirWXiL21~Y|! z4F4m!KA6@UistWS+UCK2DGNeKTon@`X9f~LMfn_GeHKA+RaKt%K;m{|;*Yp5DZWAA zxap?Ld(pRdc7ITGM^I#(sDhqZlwrWX6(y>QX~y0Ma5DseIgw`(jReC^N>s(3D3avX zzvJ*DJuXTUigSL=IN|I}``-~M+)*SrGEc@h@UKj@KmPvof5k(IEYtja-w5t(2r7Oyf?xNaJ1nZCrxa!$5|e?5 zJKQpj^z3@rCW|XA-6NwJaT*eH#A<|S?XpX=GwxTYC24KTYR`z<3c9WkwueIf+ z^F9y|DH%~to5@+nDq!^IoTXO}SxMHwX~a{+()i{ZGyq-Q&YpffVWVL zHteCGGfI3FR=bD|yd{&&B^EIAXI9rqDNsz#_jM6XNK$t+BWAipCX%|@R4Sn8Q&KKK zJ%%r6%ooy1D>Kag+^qk#0Jb77D(#a7+wZSi6$MA{`;v+l-ZN~`j)wGc8L?S12=D;i z)hA~_*r8r5b9C}bs*R#bH;LjhPCdD0!Z!PP@*7m8Q{Qf+jdH}Z(g>ZZstXp;4noug zfRlTb#p=yqi933>^{(?%|MDpc)()R&YeZ}gzn`f^}jdT6nYNE&vb_`nbgq8eQb!KTJ!FTVX6X*kG_6EBbm1d5+j=RanO zavRfa%ICljYpy!f>g6Q3)nNv9jIp8+krzIS9C(9B#~Y(;Hq=WU4Vcl0?U_Ny+6%#25@M=m3qFRK2owm21rU`#mmdi4 zv?qE4HkaH-DGC+<|K1%=Q9Gp|Be!&7j@KEmX(q1pn2MH^FkaN!+P~>V^S+L2S~?A{ zyidy~3Geb59ucHP0$^1N*~qlITH++`O_l--$@g7!O4_NXO_Ndzx3vyUn)F%4>H z=KJpo6g&Z>4*TEZ*u|w1vvfP&V(Kld-=4WdmpjX(B($uMRJlY{(KBttMFEB5NZicr z5I^HOq;-SJ+Q20*?M;hlKBR_KIW^AgxxHQAb}DEfb|}(G@I(S7Z@8w>T|!txBO#-k zQBYCKU->ryBfyw!g%og~b=prDD8Mkr7`IzS>2;ztr|fXR96*?uk90*saOXB)-+EH2 z?C$N49=lD+N~FZX_<7vA2RrS4z}4JJaA*6sk0x(LtQC$@dOxrC#|>v_!~S8#+|kn2 z+Mx^5qtMMmx#W62IF%APWu1t+y4#5(m~hTrrdag`Q3H-}m>Vy+68EOfFDJb_8MW3UOdx9Vz;B?5iqE1- z79kZA2hYRxnA$NVbrRxxzMwpo~A zE8kKM7yz2vgzeN}F-|baiikH zxw9PFb}um!p^E>DKdu@83-=bR^h=|ghSMbSKJl1)p7aKl=6hI4d)|A+zFCHfI5YUd zieeQ3{8FwZq#J>9nciF+jgGo|e79nz&CMLGyWFUfh7`p_{D=mWLw!0l7Lve++u^FU zJqcAFm6{~b5U5|`i%|k94HDl~`p1Ge{6>0nA<%FS(;m=HoV#8EU5;J7V4GDxb8PYQEw=`mv6DdCuaEG6Iq8z_M~;_e&2AaN9&;-57|V(QkH#;`ocU} zmA?ln#vD)G&L7%!RWKbtEvzY)fC}BR7`^}EHHB=!J?wbjW?wb2*Dsq>Ac1ZwRG_6i zlJ|(7@K#I}LPz4ib^W4q@xfSQMVVo|*>66Hw$HjoA{xHE_SR{0dEx4hNB8gO-TxZ| zH443+o{U4Eam}#PGYtrq=uf0nW1Cduv62plS%2yvoBiE?RW^kCV?O}-!!sKX#_r%G z@bW9cU@81B65CZmRMmUh*RYI$>?M!rk9TUpOla}wV#cojD(d@p|GyKH#$UeuO=4tO z+20vpAMC(93vxUCDyLq8J11Ur826uw@#zZ=h`(v{Vrc(YCcpmAFS-BM9Q^;t@AyyX z{QnqR+h(Z zR58EJ@t1WF1AAe+_VK9Vx$IY?FI@>CYA<;m{_l)!!Ta>oUP(^Gi(aeuG-ytDt(nH4Nog7{ISvjz$_ZY{<6y?-8 z{7|MWscS8=lv&fpJseVT>BcsSek*=$R+4J`YG>6Q)T>?6$m=HAPm4c7yKF9JOJmT~ zyXF13{=q8E*a1JY#Gk#yVC=R+vDz`QU???`P^$TH7Lzqup`XP{e$&L{99)}Sa0sTw zilnWZTkl2-GP>0}1%eI-7r|qJtT1{52QRLjewK$nU`%4#?C9{ly0-RjNfB9XmGrrx zro8E;`rqHvKr`Z%2ctF?k0Q;A3N{}f?Tz^kzrMOaymP8wjKmziH!(K+T~@|tb%19# z@Wd=UWzPMGu{@Sp!g?Ojd?zVzl4d88oHv^ixLe{sTVg=7(6xsF;VT#tS@z<<*3q6n z`$N7zfBYA_Nt;P_l^ghmK$B!X*I_(jj<_%@W%Cy;O&+mFj-cho2gK7`PrG;~#Y*ce z^gt2R-wVIPHuIcnxw$HIo4U^Eh<@NeK(KcH+oZrM^O{c{fTmK&F<3kvh`8H6)lc>t z1KaWTR)yT=qUOB9$*oV~y;<$QVjK}#m)3?BatGQ6K#O2;0QGwpX3#j1&93WN5EXmn zHO`Zqj8e+jxD0_p0(ozf=<@B}QP0g1FDNml9bov`;lSWF*~8C$(+78Cc8}&`S>b6~ z^N3HQNHl)|=P}~#g9^PqLrB&7u=j7~u;Cqo<=t4b|9r!!(}U5SaCrQYm#hmdwX&Xe zE^e-lAKv@hjh*`2>_Ly4ssPw&-U2cgDp~IU0X>`MBpJL>f(VvAuN(#<38iEgi=*2d zihijmv}4nwoDieGrMn`*jq_|P?r{~!*_=jB~R z35|KwXtZc~bklXM8*`r9hM`hd`Fa+b$vZr!(=f!Io~gECk4h7-Fmb>EY%S--3FRf=Q-XWuMz;6O`5g#LgRKv^NB(eO9ie^wq%C&@!d%DB52F=Oz#abV zBv}_wdcnJ8@hNGI{+KtSa0UEV#bwR^7<#(vG8mEjrBr`uww+{-mi?B=HD6@aQ6S?) zZ(z;tcKLA`@}!g+yu@^XI~)y`V#Bu2cp-#f^i|8ju;Y8v5zRcILiGOG(O(@0U^ zhIV(lsj-zy;wKJA8^NbzJ%YEB!DW$CEMH`&E$HsuYvjSZTk#{0Wr_vv(-bSFYIAvr9S~j2 zog8bar)uQMXsT$(WS-(h?Bz?bOg3KCg=?PnrNxjxt;F2~@yHnPn_F2bnJQHkI4r3| zXhh2^HI^wF-zA&B7hM(WW>&{hz#Hyy>QHY#X(Ua`CxC>Sj+0T5bBY7FFHMH}?8|>< z){(GqiO@JQQ*Ste;Rd)X>NMO%FYQ#tYPbbfCxpqU4jkISLbMc{u2B>I+j{*GOU*BR zcV+MFe5Xm|qQYp=oXtT!-OE`S1G?Kr+_Z0g@>c~0hmpAX$%e%V;gMt!BB#e?QYu;QR3OTmpJi>aGX zg9{ez{rHQRBa5^6&fA@ww_$x_ro%#$I&N+WI-Qh0MNVk`fYd!%wqjuo7WBfWcAec8 zXl_^uhTGFBp~5cyVb$DXm#yC?7t0{k#Tg|Wt!G-AWPx0P+T5A5YDc87JG`|i zXReY|1WzP=vQ>u0hJSu*{JttwiQS(^nnV~(tP3Hfm!qFw_QDSz^MHe+Qpobl;0?>^ zpe2<~z+|1nqB8f%_Wb0@(kpJC2C2t)Bt;otfJN{|#-i12$Z^@VP9;VQ;~WEDswxpI zRHTBpWQ^(RJlqjD|(* z3a?fVJ2jXk9zGn(DBW&ubGV&W4mr84&yUbeWOboOm={VY=~~F5R2IeD{Ris&sVSV1jbXTXJa7XPlV5@ z=j7$>g;wZ*bvw2Ty`cfyyj{z5tML!B#QNVwN(qo`p>u) z!#+~$WHniqpNHjy#@gK$eN&RCniZgapKqvXXa2 zLQ=Ec*NiPBTV4hAw&N~5Ag8wqnQrn!P&rSi#d^4836?RTdL~2Lox}jN0vq#tU zHZ$okw0VV`ciStO5*!xPzi6GmEV=!1DZ*~FjbvxZFUOqkI@#_bXaJ=MG`T#c5xe5N_!f$yzPxV~P z_HhT>U$<&%?Fl)*v`WXMuC?Wd&J35B#2s-3S5ew&dB>c=c#PSnju3CMSG}20EIB|Z z^$BQ(%u2gjJ>jd}L_LLD_n`Rni6K3<>;n>TZ*#|@ng9IcKrtQ%{PKPJXyy?q8E+hk zgm?o-cxLAABHh_F2w)mb0EmSJ(qwq_u7_0JIUc|?I>fp9Ik8$hO}#$RN*OZB!DfWJ zM2tU86Td+lkriZA(?5hb+Mq^b!pr`JDmzS*9(-lO>qyZ5Z!`|Pll2wk|s~NKexX<4& zn^YJ`CPb1ilO=EXqofRS4|j#(h!wGzd2MpRc%0g&?%fNccb9Fk`L)^yqh~*Y`-^cUnyHzTSK4@{fQLyeCcNgR^l`aWN#JJ2I)rEy9S^C(b zNnr1pnX2~z%xSY@vP@cPfy}K+h~?W~CyP{@l2V5oThi+2y2IhMB=mkIe2}tS9B&Kh zatH01lV2_U=#fra@7W~|C2&hK!B=e^>!h4%aKLlg8oYpxcrV|$C*65k=--Lr>lVPeZV0G`z^ zna4%O(S@3}O3uCQ9AY^4%X61QS+TBL>&eOsI=4kS-DG){r@+PMN4i_Kf1Cuyc!MXs z(jn6Drlq%xkf7ipvbi4NCwmooTXgwsiD|&zZt5E^nw~DK9j@U*+UDMRq}=0b*5NAF z=FS>>f|cM!+A<*O+G6qk-BiTvJbh-nKi=9#FeTTLY~L;;w}8zK^srsso*nie3hoj4 z7(m%GwW0uR>Ch z;q8@S`U$+lMfy{+`4iYqQwdJHHZ#6Z6(2%+Zlm$?R^9nERJQv?4M&T^k6>XRdh6z~ zJ1Rn+2i?b4~?93tXryMtXxNZPSEj5w8>3d2`=XC zB*S-65WRG`6iHxP#!2n+>T|f*v2(9EY_(hCo(m+1%8#`Gzpi>O-Q8_z4Ks$fUBPwe z;N4NPQ{?0@PtQ1F+V)xmr?ASQ%{C_;2|I`PDT9s#cWaDB`Wi|^tnQYApnwY7yiemB zp;abUyc4v43eeN(_^z^2h3D+ zBd-3Fh$^8vL;jXX_h%Q^ccQesv^%6VSDe3f2!;qHg4fDOWQJGTs)oEr|S+ zj~{&O)GCauIcXWw_kSKe5Mu`e$C*xaMAgZ(r3(+2g*;rR)6)F=b=XfrmyX{VhW!}i zIzZDVqQ3=W(KShk67uV);DS#HYj69VXSfJ=O(9{ zMw3!qfT`c!gU99O$$V|9*Ljy)dxo}VhtjX0YDo)s?+!f8v@P_W7|8;S<%G z2C+2QEIvC{#Rh4Fc|(`q-YiyY^`RTIoCEp_ZR@r$vulw}druACs*_`zwGt9LniKHp zWYJ9R2Xkv9y~T<3J(W>E>na6(IsaWS{-XslWG~XTY1b;8ZuF<+Gwc&ewFOH2P7S%R zsJ)L~TeL9g9L!ADg>pi@Q%|D5%-E%UumaG?mR)>1PD-P9!lXwy+B)1gH(AW?c@`*n zMankyxV&kd>tZH6d_-%DMT(igV-PIHBLieqr25y#)^`kO{V~K5kBHHJP$^CX#Ii<` z@}vDR+z(kR)q)TZI1A5v0d!z=cAzbb44ntu5f7zwa@`yKCW1>p>_+It#_DyR3hd!u z6BSI)5ij4Nd_sbp4v|6fTtlSSxugE{pw<#mQ3B;~e1tXQ^J;#QPpseMvk#ZZV|p_` z2coWm>4U-Tu;y#aeMQz0MdEPYOk=;miQs14U$pR#A~1*U@HNBVTYF(Y2Njw@56w)& z;BojHT@!Kyg-K|;Q;+Fh}G7R!6W4*PV9HU?aE`2K{L;WAgoU3g-1$J9z~MI7!OC(Gmy+=+?h zy-t2}>+LTpga2-&X!$$QDRUb%tuE)@anTKXU%Gjh=VncCKo=B?sbIaHsE zbvMUl-nlb^Zw(A1l01O_MbU-_f~m2Ml16=ga->kyCD>SZtwKg zip3eeT-I=lPL_oj+;M5AXo7tTZF0w>mS$@h;FVA6NPeNg)B$l>Zt%igv-I`CNS&k% znedIuyQ29o=Le1L-Ie7;M=^)iP|}fN6RQs+F|L%U*&cz@CLF!*wejsT4AyL|x|^-Z zfeOuEt_|--?6TfpyIDpT;`Fv*bBWg#I!(xP-sA7?`FvmNNO)k+sS2epS=i5HDEZOV z#foAy8bg3_QhVm^ysD!nbvuF)tR4P3l2bMGs#9jI@Ihh>uYEfxjdXDwHYN9i>(A(T z%52(wA}t8_){1+?;|V6d;R_FQ1Cj6;Y?@@pZJ~X{Cz!_zjo<@r*^SvUn^Lgucw-RP z%GM1%WFp_^e66-KL4TQBqBvR4sHy6n!k36dtnbY*^f##K`r=m^Zbh#y2Y2R8vnuVL2@9TJZ-@~MrBYj$aeR0(|?6$*#QHNif!c%!oFd>(Vyz|n3quf>MZ zENI)_UhAiX>HoR9|CLuvj+=0DA%O06za3EA_VCst$$427HbAN_d*%l&y1yajyju7! z1gtMwZshBTJ9I`@)VbdC?=TakZDzQ-o;acNlr_C;HS>>Qs#n(EWFBZW4@y7qUSa3U z8jjh&Gy^GWH}U2Rt3%@kKSsCG+Oj1DG+i>M$!m zJ+{1rkr}kKjtI@EI>9i3F0`DQr-b>GRY==|yzBVw7@D6^ADF*#r zR2lpRfE-bHjeJ7|o%1tH7ogJARtn$t&E(oKY%4OG$(4MYpDQWMuAn^|8Yb+MDP_Gt zn#kl<>|DG?@uiYhEd_=9+x;)FW{@Ifdg}S$gM-j$&QMR*c|S4QCTiBkc^V4}xx*SU zp)SKGbiUcH%1Y=_`=a?O#&d%Lh?9;0%Wl!uE|om$o0p6HDWNCgT?;17;yiT?d8bWY zkIRE^PsAgnS6+MVG>_jry+Z=&pQXBDl%%5qQ)V%DG_J*y75EjhV@NZ@xcx}3msQO1 zO22+;)p05F*4iZ!Zu^+k=NsP>BKY-1KX)IpZ-phN6508RF4iY3Z-*668G4&ORM#UA zJ+kZ`ztT4;l^Z`5qBwoxW3XINKRJ8TSNeg|(baf4$YhDo?j}aj>h^W(J*%it%k23( z8c2rr>F6fs#Fc0&mUha^Ef==Aq za0PvC!YeQf(#ZmSLCh|V;;{cAS)0CJ{?x{|>JV#n{hFCX_8lJS8 zHo^np>b=Q{%_H9ZArS6RDrIipFpRHtTbf&l)$BiafHfXL;-sn#DnD zv%BdgZ~9?Z7O!#MNNAyEk_9zCGzXt&2dwWBI^A=|a-9?Qso?$EUYw_@5nE#wPa>Z^ z=4$1`5+;=9arEusT*hDIH_~J!G4Py5tDkZHV}JIk>pm^a}6< z;d6^`;;GwLPx!rkHHRs`FS#X3>NWYH{F!fn^{5BP`gMMWYmH1S)QLye;I%&NFV-GN z@2&fenwZ@t;pT&}?fve)E|bMHRd4&q63DxYb+x-9L3W z$|YVO8@v5qseuj)(fr?=Xvlv4yF`)EBEe?>JA(O-3&6lT@#CL+&{Iyd_=QEgJ~^NT z2K6+IJh4AlCdz*|9tIBVC#l%|Z9|Wjp|0*q{N5zVAG;S6M8_qe`up9mRqkI^`~N06 zB@+fNFb{Wp_2-`IKM#bk4cFPoX=n;bJ6m)h2z#m6f(!h3M};HwApjN^f%!G`XH+V{ zC|zQIU>UWA`d!jn#pwxI5M?WqQW`|OQIu%z&e2{wAg`uWk55Pl>Xi>ULgNhdFWJu@ zLdo6*w$F@H4ew&6m(iuv;;QYdaTV5dgf4HluV1X$|71&%hP~keeiI^1B~6ozmd-Ib zxPLKZfURr%ev6i}7*#ZB0_A`?)Q+_-=88T0yEl}2y$E9o2$B|0NptF+O~}Z>s6bEe z_{@g-+7xMV2`@}xYHsev@wuAJ23#LAa&E5&!!a}N^tY}J+UA9Yt<^C8&?X0(>nP~X zA+4h90cHc&z2f5Hze}jP9qW2F?F}8+$FOkv0d!I*<4m?5ToX4BsyDa~8DHe{Cw_GQ zF(0@qF>p&sD=Q*mp zy108dzd+o{xuu&AaHNpZd4gb`RB}iu`}J(92FA$n$tCD0(S{-jGkHH}_UfQFa`7 z+2ig}JjxuYZM!LpGz>zA@qq;a*k#6t1i}Jd)I8}CqFmA}tW~tqED2=D5$k6+roT&5 z%m3Je;VN)Bc@`s!L5 zP4I~w6egq}{|;@q8@2L1@-$VIp#el)+X(svMQZKVkhxu#uWF)QPB7(X?59KalIueR zU!$XuUwiXLx#};}$?K5M*I0p17ew$aDZxh|VCVnD?mh3yAT)AB7A0vW3HMTX)LoPs z|02K`dp_I%!u;HplIA`xF4n*95Cp*H4G;o5tO+Q_y0^&%eX!BH=e1ZO;$Aro$891f zwcM=n)H+K8nYqGEcZ)t)36*75$%Y(KN=8uA9M81r^T3?nI0qO%d~#+{DP!B|vf9Ri z7h(6vh-uu;>L?lhXdZjK6YoDPjqRzn0;v& zx?U}X>PZVazG_tvh=DfTGo-Z%K|KP0VfwuV0Rg+J!aVT|$;^uWC`LPjp;b&AXlzr~jBI zOYUF4a6gWBW#%Y+8LpDat1zeMjC(T*2biNdEka6GXo%B_05daApR0A6IBN1S&zvk^Y`U3L2QKrZie z88F}SEQ$E-tsuNYaHV`bLr_F$PP;lW?E(|Fm%ET$~@%zD2`H+X5bhem>(U zAM?}X^zvmz&>^&jyjBBl+f~yR6YpHD5sNfD!HQfRZVJj6f1cI5Hg&hfsAr|hnA`q{ zakPHDx4bQ@@@fF0zxq(W8zfvHE+y}E&`|F}Kz0YX63*d@dn2WnJW7_M-)TG*e`&iWNH#s+6H8;R z=V0|Crke&u>z6;L1q@v2w1E4!@16Zm*AeUSajt=HA%T-jjI;N$lz;7emySzm-||vd zciig~cbUhFn>=dee6-@jOxtj=tz2_KcxN}Qy_q1?kW$4@nd1CkOM0UYhg3c;bdsKF zB?iju80Fqdz7zh94Xg}m^un2UOn2UnDXwqtLs`#e!pUYCkEOJ&`gL)vDR6L(-{Y=L zrk}^S#Fu;aOXIs4WB7qt)y<-qx&wkWqGa4kJnzs4FEiX6ZHB1VE7>O*CT`9~KU}UF z+mh{QC8`fs%MlMqFHe&->!6b=YAN=98~aW@vW;5)?4-2FcMjYcLa@>0Jb~)B%_|w5 zOKV|ijGbg2YnTc=J2xvK-OsmT3=v{NZZCjEwsnc_d0l&);8w1W_ha7k74YmU1?h?{ zTX`Paq^Ot}Og+B)J6}eVVd>gbt64VOig<$;%Zl=d#X6TefY^t(!s{KS{=Cm+HLZ_o zNe7};D~6;?uw znP!ZysnfR!S?cf`TuzzOV+R@L4*FUWS0+Z?(P9eSE(SOm+Nazg7coo|W z6p^v`E5_Oqi?c2CZ=Mx98hSFZ#IFCGVqr!5grx6G9=BPN0TnLaCr*eRw!Ef2+^kmk zz==y5ZzNTh+FTiH!h245@6EeCl)AoCZh&HKp@xpoU9|aU(%#TEk~#K>@;4xpq(Y^V z9Pe1H{l3jg>U#5lx$8l1riUqDpg2=g(9Qmi#b$LCT3J?QwOy%47YJW;7>okzY#I6c zAg9AXH-1`nUEH>uv2UgVb8}L$e&J2pJ!&hL?=WnT=$(_x_Z4vTvJBB^67;gZ;(>u% zUC6kNMCxjo(($wu?Rvhc(xbe_wjn*U%HA8A1EGapMGMtw38!Q?x4UoP>I+!Cob@9` zhkj+`!geQyXF`Tx$0c8nK(p$n&vr*#UPcl3bRl|1Zq{&=80kR<^oC`N%DvSkW4pRV zWEyhqmk5YB$+$lolsz#+#Sy-QwXo&2nROJ?q6UM{g=^}0P`oG2arzQM{U6=l1?$@(Yc>0LlQzdd|R6n>2~dD8OWZg*9zC8PVRmEaLH=!o0BG zHqJvV;H}tTOU@!pJDn|16ElGR5VB&X?NjQ|%B8F5rp+SJmc{aQS8T+tGly6nhAXV- z3;aaK=j_h+!(h_{1{`eiRPQhK#4i#}3lv;YEVJ``N%!V#&-XHM?W~D1!D+Odtq2J} zN?jdkWcuZwn)9&2qmGllHj2R`eh|#42?~v2Y>ZW!RzT-&eUuFfDvye{Diqax7X$Eo zvk*gY+eI!9j#X`a(Vn@4m%%x*uO|D_st`aq*46nH9O{~FJ45u2G}*sm8%N7pIaSyU zw!ig6RHKxlF!*4q*&D6qvhxETkPevy#Ft>}WD1-El1I zNG$%xv{yD4pOQSW+)D(7xsqe7V#pGpZPcJPmzY)^U%|?`-;P;Ys|HLbX6~(d=24Qe zTEK+5GKi%%$4(H#1nAtK=e@d~FZFgBGpGX}*tvQPFG%)cC|5X~XlowJoI{=Qq|Q`u zW2#$iM%%%{Yn9bbrDp6gmE^_QKP|4RSb0Jvw_h7ueUlqZ_t%_`=f4H~(sG=pvG2XturE%-fRN zW2(l%$Y)q9y3AHyO)DI$S@^doZ>A)hpk=SVdEvsj6CyR`N_K-Cdnor?pknMHTmldm z@4Sh_bv#qp{)TH7CYRMepNwjOhKwdJ#sV+Z1vTac7Ew{5Y4AweTye9@?cfy_U!iy( zL66UwbeGJDXBbe)nspLYPoR3Lz@|?xQm#31XW& zHg6r6a@Q0^^VO^JmxT_z-+}H2vUx(OksWzEYBdpx+Rk!Oiq8}@)U932A&<$pM0IyxUjti<}RBNIb)F2awuI^u}Uuzcs&L3;+3$F#s>doa-x7v+%ojmZ_qi>h}6cu zk7ukt2k)Q7@DdfLevJd%vI9rXz-1WUaYnM%;1}}=>Uk(u9c#mF9wQyK`(Y_u;rb^z zsAmB)v62qn0L&pduL}O3oi&7*1RNYXbwlRJ3PhTPxB&c9w4o45b5aKFvH9D_3_g>{xC25E?-nesvM z*u>UTCcZkSXKj3Zwj{ZI<63Q=!v`{@`51EE%(my1p1(img}(HLw+o+|xz_Q$HT`n> z>tcq*pG3?y&)&9U>#<)}>tc2q^$S8Ba%TRmTT#1q?@oVHab4QB$Mj->@KGTlhMh5a zhjQn(F>d2sTrVZjR{L3sr?9&I3>AOFFTX!b`k5bMc$#;F98=d`w|%*R+aEJ|pW-_yuqgQ6JJToZ&Z~&+mv1F4 zx`%!4c^xw@Weh^c_4>%rOf_syIV&Y6CX9)+#dQj0Rrin?6r+5OtMQN%lp zr(CvC@MM?aT5U0}E{Eg@sHgwtn8iQwFS+w_%QlT~-~Y3Jt=apgrXkJ`v;^PN)z4*} HQ$iB}@eowo literal 0 HcmV?d00001 diff --git a/phpunit-dama-doctrine.xml.dist b/phpunit-dama-doctrine.xml.dist index 6999b9364..81a68ab06 100644 --- a/phpunit-dama-doctrine.xml.dist +++ b/phpunit-dama-doctrine.xml.dist @@ -13,7 +13,7 @@ - + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 63f6c1368..b1d4bb9b3 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -12,7 +12,7 @@ - + From cd42774090069b0d88589fafc1e33af0f50fcef8 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Mon, 10 Oct 2022 21:08:37 +0200 Subject: [PATCH 04/13] [feat] add make migrations (#309) --- .gitattributes | 9 ++--- .github/workflows/ci.yml | 11 +------ Makefile | 16 ++++++++- README.md | 9 ++++- bin/doctrine | 14 ++++++++ config/cli-config.php | 26 +++++++++++++++ tests/Fixtures/Entity/Comment.php | 2 +- .../Migrations/Version20220925092226.php | 2 +- .../Migrations/Version20220925092634.php | 2 +- .../Migrations/Version20221010154036.php | 33 +++++++++++++++++++ 10 files changed, 105 insertions(+), 19 deletions(-) create mode 100755 bin/doctrine create mode 100644 config/cli-config.php create mode 100644 tests/Fixtures/Migrations/Version20221010154036.php diff --git a/.gitattributes b/.gitattributes index a02d25904..6899bdb8d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,18 +1,19 @@ * text=auto -/.github export-ignore -/tests export-ignore -/bin export-ignore /.codecov.yml export-ignore /.gitattributes export-ignore +/.github export-ignore /.gitignore export-ignore /.php-cs-fixer.dist.php export-ignore /.scrutinizer.yml export-ignore /.symfony.bundle.yaml export-ignore +/bin export-ignore +/config export-ignore /docker export-ignore /docker-compose.yaml export-ignore /Makefile export-ignore -/phpunit.xml.dist export-ignore /phpunit-dama-doctrine.xml.dist export-ignore +/phpunit.xml.dist export-ignore /psalm.xml export-ignore /run-tests export-ignore +/tests export-ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9078158c7..958c0854d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -398,17 +398,8 @@ jobs: docker-stack: name: CI with docker stack - strategy: - matrix: - os: - - ubuntu-latest - # - macos-latest - # - windows-latest - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest steps: - - uses: docker-practice/actions-setup-docker@master - if: ${{ matrix.os == 'macos-latest' }} - - name: Checkout code uses: actions/checkout@v2.3.3 diff --git a/Makefile b/Makefile index 3c7f1f38c..539911f3b 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ endif help: @fgrep -h "###" $(MAKEFILE_LIST) | fgrep -v fgrep | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -validate: fixcs sca test-full ### Run fixcs, sca and full test suite +validate: fixcs sca test-full database-validate-mapping ### Run fixcs, sca, full test suite and validate migrations test-full: docker-start vendor ### Run full PHPunit (MySQL + Mongo) @$(eval filter ?= '.') @@ -79,6 +79,20 @@ sca: docker-start bin/tools/psalm/vendor ### Run Psalm bin/tools/psalm/vendor: vendor bin/tools/psalm/composer.json bin/tools/psalm/composer.lock @${DOCKER_PHP} composer bin psalm update +database-generate-migration: docker-start vendor ### Generate new migration based on mapping in Zenstruck\Foundry\Tests\Fixtures\Entity + @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:migrate --no-interaction --allow-no-migration # first, let's load into db existing migrations + @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:diff --no-interaction + @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:migrate --no-interaction # load the new migration + +database-validate-mapping: docker-start vendor database-drop-schema ### Validate mapping in Zenstruck\Foundry\Tests\Fixtures\Entity + @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:migrate --no-interaction --allow-no-migration + @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php bin/doctrine orm:validate-schema + +database-drop-schema: docker-start vendor ### Drop database schema + @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php bin/doctrine orm:schema-tool:drop --force + @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:sync-metadata-storage # prevents the next command to fail if migrations table does not exist + @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php bin/doctrine dbal:run-sql "TRUNCATE doctrine_migration_versions" --quiet + vendor: composer.json $(wildcard composer.lock) @${DOCKER_PHP} composer update diff --git a/README.md b/README.md index 580bc693b..eeb773a06 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Each target will build and start the docker stack and install composer only if n ```shell $ make help -validate Run fixcs, sca and full test suite +validate Run fixcs, sca, full test suite and validate migrations test-full Run full PHPunit (MySQL + Mongo) test-fast Run PHPunit with SQLite test-mysql Run PHPunit with mysql @@ -52,6 +52,9 @@ test-postgresql Run PHPunit with postgreSQL test-mongo Run PHPunit with Mongo fixcs Run PHP CS-Fixer sca Run Psalm +database-generate-migration Generate new migration based on mapping in Zenstruck\Foundry\Tests\Fixtures\Entity +database-validate-mapping Validate mapping in Zenstruck\Foundry\Tests\Fixtures\Entity +database-drop-schema Drop database schema docker-start Build and run containers docker-stop Stop containers docker-purge Purge containers @@ -94,6 +97,10 @@ create a server called `FOUNDRY` in your PHP Remote Debug, with the IDE key `xde If for any reason docker is not available on your computer, the target `make test-fast` will run tests with your local php version, and sqlite will be used as database. Results may differ from the CI! +## Migrations + +Whenever an entity in the fixtures is added or updated a migration must be generated with `make migrations-generate` + ## Credit The [AAA](https://www.thephilocoder.com/unit-testing-aaa-pattern/) style of testing was first introduced to me by diff --git a/bin/doctrine b/bin/doctrine new file mode 100755 index 000000000..655f5db97 --- /dev/null +++ b/bin/doctrine @@ -0,0 +1,14 @@ +#!/usr/bin/env php + true, 'url' => getenv('DATABASE_URL')], $ORMconfig); + +ConsoleRunner::run(new SingleManagerProvider($entityManager)); diff --git a/config/cli-config.php b/config/cli-config.php new file mode 100644 index 000000000..f019a82c5 --- /dev/null +++ b/config/cli-config.php @@ -0,0 +1,26 @@ + true, 'url' => getenv('DATABASE_URL')], $ORMconfig); + +return DependencyFactory::fromEntityManager( + new ConfigurationArray([ + 'table_storage' => [ + 'table_name' => 'doctrine_migration_versions', + ], + + 'migrations_paths' => [ + 'Zenstruck\Foundry\Tests\Fixtures\Migrations' => './tests/Fixtures/Migrations', + ], + ]), + new ExistingEntityManager($entityManager) +); + diff --git a/tests/Fixtures/Entity/Comment.php b/tests/Fixtures/Entity/Comment.php index 0d5a3bca8..85e6f82f0 100644 --- a/tests/Fixtures/Entity/Comment.php +++ b/tests/Fixtures/Entity/Comment.php @@ -18,7 +18,7 @@ class Comment private $id; /** - * @ORM\ManyToOne(targetEntity=User::class) + * @ORM\ManyToOne(targetEntity=User::class, inversedBy="comments") * @ORM\JoinColumn(nullable=false, onDelete="CASCADE") */ private $user; diff --git a/tests/Fixtures/Migrations/Version20220925092226.php b/tests/Fixtures/Migrations/Version20220925092226.php index cb4f7bc37..c49c37447 100644 --- a/tests/Fixtures/Migrations/Version20220925092226.php +++ b/tests/Fixtures/Migrations/Version20220925092226.php @@ -14,7 +14,7 @@ final class Version20220925092226 extends AbstractMigration { public function getDescription(): string { - return ''; + return 'Fourth migration.'; } public function up(Schema $schema): void diff --git a/tests/Fixtures/Migrations/Version20220925092634.php b/tests/Fixtures/Migrations/Version20220925092634.php index 49f6cd5d1..29d26c4ba 100644 --- a/tests/Fixtures/Migrations/Version20220925092634.php +++ b/tests/Fixtures/Migrations/Version20220925092634.php @@ -14,7 +14,7 @@ final class Version20220925092634 extends AbstractMigration { public function getDescription(): string { - return ''; + return 'Fifth migration.'; } public function up(Schema $schema): void diff --git a/tests/Fixtures/Migrations/Version20221010154036.php b/tests/Fixtures/Migrations/Version20221010154036.php new file mode 100644 index 000000000..5826a3148 --- /dev/null +++ b/tests/Fixtures/Migrations/Version20221010154036.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE posts CHANGE type type VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE posts RENAME INDEX idx_985dbafad126f52 TO IDX_885DBAFA20DBE482'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE posts CHANGE type type VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT \'simple\' NOT NULL COLLATE `utf8mb4_unicode_ci`'); + $this->addSql('ALTER TABLE posts RENAME INDEX idx_885dbafa20dbe482 TO IDX_985DBAFAD126F52'); + } +} From cf7d75e56647b89854c9ef04c5f37761ede13823 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Tue, 11 Oct 2022 10:08:36 -0400 Subject: [PATCH 05/13] [minor] remove unneeded bin script (#310) --- .gitattributes | 1 - bin/run-tests | 33 --------------------------------- 2 files changed, 34 deletions(-) delete mode 100755 bin/run-tests diff --git a/.gitattributes b/.gitattributes index 6899bdb8d..e90f1066b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,5 +15,4 @@ /phpunit-dama-doctrine.xml.dist export-ignore /phpunit.xml.dist export-ignore /psalm.xml export-ignore -/run-tests export-ignore /tests export-ignore diff --git a/bin/run-tests b/bin/run-tests deleted file mode 100755 index cf8e21d75..000000000 --- a/bin/run-tests +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -echo "Running without FoundryBundle and without DamaDoctrineTestBundle" -echo "================================================================" -echo "" -USE_FOUNDRY_BUNDLE=0 vendor/bin/simple-phpunit - -echo "" -echo "Running with FoundryBundle and without DamaDoctrineTestBundle" -echo "=============================================================" -echo "" -USE_FOUNDRY_BUNDLE=1 vendor/bin/simple-phpunit - -echo "Running without FoundryBundle and with DamaDoctrineTestBundle" -echo "=============================================================" -echo "" -USE_FOUNDRY_BUNDLE=0 vendor/bin/simple-phpunit -c phpunit-dama-doctrine.xml - -echo "" -echo "Running with FoundryBundle and with DamaDoctrineTestBundle" -echo "==========================================================" -echo "" -USE_FOUNDRY_BUNDLE=1 vendor/bin/simple-phpunit -c phpunit-dama-doctrine.xml - -echo "Running with DoctineMigrationsBundle and without DamaDoctrineTestBundle" -echo "=======================================================================" -echo "" -USE_FOUNDRY_BUNDLE=0 FOUNDRY_RESET_MODE=migrate vendor/bin/simple-phpunit - -echo "Running with DoctineMigrationsBundle and with DamaDoctrineTestBundle" -echo "====================================================================" -echo "" -USE_FOUNDRY_BUNDLE=0 FOUNDRY_RESET_MODE=migrate vendor/bin/simple-phpunit -c phpunit-dama-doctrine.xml From a3eefc1601d9c18c3c65591fad546fdc49e4527f Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Wed, 12 Oct 2022 17:49:15 -0400 Subject: [PATCH 06/13] [minor] remove branch alias --- composer.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/composer.json b/composer.json index e3de02002..c8eb7eadf 100644 --- a/composer.json +++ b/composer.json @@ -53,9 +53,6 @@ } }, "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - }, "bamarni-bin": { "target-directory": "bin/tools" } From d120b1ca4855a970d0c88817dff8d376348efd83 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Wed, 12 Oct 2022 17:51:21 -0400 Subject: [PATCH 07/13] [minor] fix `bamarni/composer-bin-plugin` deprecations --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c8eb7eadf..9c327082e 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,9 @@ }, "extra": { "bamarni-bin": { - "target-directory": "bin/tools" + "target-directory": "bin/tools", + "bin-links": true, + "forward-command": false } }, "minimum-stability": "dev", From cada0cf64381dbbb5be98ed93ceaaf05c8469903 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Wed, 19 Oct 2022 18:23:51 +0200 Subject: [PATCH 08/13] [feature] pass an index to `FactoryCollection` attributes (#318) --- Makefile | 4 ++-- docs/index.rst | 8 ++++++++ src/Factory.php | 2 +- src/FactoryCollection.php | 14 ++++++++------ tests/Functional/ModelFactoryTest.php | 16 ++++++++++++++++ tests/Unit/FactoryTest.php | 4 ++-- 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 539911f3b..d14ecece7 100644 --- a/Makefile +++ b/Makefile @@ -71,13 +71,13 @@ fixcs: docker-start bin/tools/cs-fixer/vendor ### Run PHP CS-Fixer @${DOCKER_PHP} bin/tools/cs-fixer/vendor/friendsofphp/php-cs-fixer/php-cs-fixer --no-interaction --diff -v fix bin/tools/cs-fixer/vendor: vendor bin/tools/cs-fixer/composer.json bin/tools/cs-fixer/composer.lock - @${DOCKER_PHP} composer bin cs-fixer update + @${DOCKER_PHP} composer bin cs-fixer install sca: docker-start bin/tools/psalm/vendor ### Run Psalm @${DOCKER_PHP} bin/tools/psalm/vendor/vimeo/psalm/psalm --config=./psalm.xml bin/tools/psalm/vendor: vendor bin/tools/psalm/composer.json bin/tools/psalm/composer.lock - @${DOCKER_PHP} composer bin psalm update + @${DOCKER_PHP} composer bin psalm install database-generate-migration: docker-start vendor ### Generate new migration based on mapping in Zenstruck\Foundry\Tests\Fixtures\Entity @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:migrate --no-interaction --allow-no-migration # first, let's load into db existing migrations diff --git a/docs/index.rst b/docs/index.rst index 1100d1a15..ccfce969d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -278,6 +278,14 @@ Using your Factory PostFactory::createMany(5); // returns Post[]|Proxy[] PostFactory::createMany(5, ['title' => 'My Title']); + // Create 5 posts with incremental title + PostFactory::createMany( + 5, + static function(int $i) { + return ['title' => "Title $i"]; // "Title 1", "Title 2", ... "Title 5" + } + ); + // find a persisted object for the given attributes, if not found, create with the attributes PostFactory::findOrCreate(['title' => 'My Title']); // returns Post|Proxy diff --git a/src/Factory.php b/src/Factory.php index cb2086f6f..79d8a3b98 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -307,7 +307,7 @@ final protected function class(): string */ private static function normalizeAttributes($attributes): array { - return \is_callable($attributes) ? $attributes(self::faker()) : $attributes; + return \is_callable($attributes) ? $attributes() : $attributes; } /** diff --git a/src/FactoryCollection.php b/src/FactoryCollection.php index a8322aee7..30f148d06 100644 --- a/src/FactoryCollection.php +++ b/src/FactoryCollection.php @@ -73,12 +73,14 @@ public static function sequence(Factory $factory, iterable $sequence): self */ public function create($attributes = []): array { - return \array_map( - static function(Factory $factory) use ($attributes) { - return $factory->create($attributes); - }, - $this->all() - ); + $objects = []; + foreach ($this->all() as $i => $factory) { + $objects[] = $factory->create( + \is_callable($attributes) ? $attributes($i + 1) : $attributes + ); + } + + return $objects; } /** diff --git a/tests/Functional/ModelFactoryTest.php b/tests/Functional/ModelFactoryTest.php index fda305f72..625c8f293 100644 --- a/tests/Functional/ModelFactoryTest.php +++ b/tests/Functional/ModelFactoryTest.php @@ -330,6 +330,22 @@ static function(): \Generator { ]; } + /** + * @test + */ + public function can_create_many_objects_with_index(): void + { + $categoryFactoryClass = $this->categoryFactoryClass(); + $categoryFactoryClass::createMany(2, static function(int $i) { + return [ + 'name' => "foo {$i}", + ]; + }); + + $categoryFactoryClass::assert()->exists(['name' => 'foo 1']); + $categoryFactoryClass::assert()->exists(['name' => 'foo 2']); + } + /** * @test * @dataProvider factoryCollectionAsDataProvider diff --git a/tests/Unit/FactoryTest.php b/tests/Unit/FactoryTest.php index ad0e1f8e7..94a19f2ae 100644 --- a/tests/Unit/FactoryTest.php +++ b/tests/Unit/FactoryTest.php @@ -27,7 +27,7 @@ final class FactoryTest extends TestCase public function can_instantiate_object(): void { $attributeArray = ['title' => 'title', 'body' => 'body']; - $attributeCallback = static function(Faker\Generator $faker) { + $attributeCallback = static function() { return ['title' => 'title', 'body' => 'body']; }; @@ -46,7 +46,7 @@ public function can_instantiate_object(): void public function can_instantiate_many_objects_legacy(): void { $attributeArray = ['title' => 'title', 'body' => 'body']; - $attributeCallback = static function(Faker\Generator $faker) { + $attributeCallback = static function() { return ['title' => 'title', 'body' => 'body']; }; From e417945e3d587959966f395566c9355a62b78a43 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Tue, 8 Nov 2022 14:43:30 +0100 Subject: [PATCH 09/13] [feat] [remove bundleless usge] use config instead of environment variables (#320) fixes https://github.com/zenstruck/foundry/issues/311 --- .github/workflows/ci.yml | 30 ++++++- docker/xdebug.ini | 2 + docs/index.rst | 79 ++++++++++++++++--- .../DependencyInjection/Configuration.php | 32 ++++++++ .../ZenstruckFoundryExtension.php | 37 +++++++++ src/Bundle/Resources/config/services.xml | 4 + src/Configuration.php | 54 ++++++++++++- src/Test/AbstractSchemaResetter.php | 11 +++ src/Test/DatabaseResetter.php | 52 +++++++++--- src/Test/ODMSchemaResetter.php | 9 ++- src/Test/ORMDatabaseResetter.php | 44 +++++++++-- src/Test/ResetDatabase.php | 40 ++++++++-- src/Test/TestState.php | 4 +- tests/Fixtures/Kernel.php | 14 ++-- 14 files changed, 366 insertions(+), 46 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 958c0854d..f35799bbf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,6 +75,7 @@ jobs: - name: 'Test: MySQL' run: vendor/bin/simple-phpunit -v env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Test: MySQL, FoundryBundle' @@ -86,6 +87,7 @@ jobs: - name: 'Test: MySQL, DAMABundle' run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Test: MySQL, FoundryBundle, DAMABundle' @@ -97,18 +99,21 @@ jobs: - name: 'Test: MySQL, DoctrineMigrationsBundle' run: vendor/bin/simple-phpunit -v env: - FOUNDRY_RESET_MODE: migrate + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 + USE_MIGRATIONS: 1 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Test: MySQL, DoctrineMigrationsBundle, DAMABundle' run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist env: - FOUNDRY_RESET_MODE: migrate + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 + USE_MIGRATIONS: 1 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Test: PostgreSQL' run: vendor/bin/simple-phpunit -v env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - name: 'Test: PostgreSQL, FoundryBundle' @@ -131,6 +136,7 @@ jobs: - name: 'Test: SQLite' run: vendor/bin/simple-phpunit -v env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Test: SQLite, FoundryBundle' @@ -142,17 +148,20 @@ jobs: - name: 'Test: SQLite, DAMABundle' run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Test: SQLite, FoundryBundle, DAMABundle' run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 # USE_FOUNDRY_BUNDLE: 1 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Test: MySQL, Mongo' run: vendor/bin/simple-phpunit -v env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb @@ -166,12 +175,14 @@ jobs: - name: 'Test: MySQL, Mongo, DAMABundle' run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - name: 'Test: Mongo standalone' run: vendor/bin/simple-phpunit -v env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb code-coverage: @@ -220,6 +231,7 @@ jobs: - name: 'Coverage: MySQL' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql.clover env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Coverage: MySQL, FoundryBundle' @@ -231,6 +243,7 @@ jobs: - name: 'Coverage: MySQL, DAMABundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-dama.clover --configuration phpunit-dama-doctrine.xml.dist env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Coverage: MySQL, FoundryBundle, DAMABundle' @@ -242,18 +255,21 @@ jobs: - name: 'Test: MySQL, DoctrineMigrationsBundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-migrations.clover env: - FOUNDRY_RESET_MODE: migrate + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 + USE_MIGRATIONS: 1 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Test: MySQL, DoctrineMigrationsBundle, DAMABundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-migrations-dama.clover --configuration phpunit-dama-doctrine.xml.dist env: - FOUNDRY_RESET_MODE: migrate + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 + USE_MIGRATIONS: 1 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Coverage: PostgreSQL' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=postgres.clover env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - name: 'Coverage: PostgreSQL, FoundryBundle' @@ -276,6 +292,7 @@ jobs: - name: 'Coverage: SQLite' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=sqlite.clover env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Coverage: SQLite, FoundryBundle' @@ -287,17 +304,20 @@ jobs: - name: 'Coverage: SQLite, DAMABundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=sqlite-dama.clover --configuration phpunit-dama-doctrine.xml.dist env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Coverage: SQLite, FoundryBundle, DAMABundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=sqlite-foundry-dama.clover --configuration phpunit-dama-doctrine.xml.dist env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 # USE_FOUNDRY_BUNDLE: 1 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Test: MySQL, Mongo' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-mongo.clover env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb @@ -311,12 +331,14 @@ jobs: - name: 'Test: MySQL, Mongo, DAMABundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-mongo-dama.clover --configuration phpunit-dama-doctrine.xml.dist env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - name: 'Test: Mongo standalone' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mongo.clover env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - name: Publish coverage report to Codecov diff --git a/docker/xdebug.ini b/docker/xdebug.ini index 736355870..d969fde6c 100644 --- a/docker/xdebug.ini +++ b/docker/xdebug.ini @@ -1,3 +1,5 @@ +memory_limit=1024M + [xdebug] xdebug.mode=debug xdebug.start_with_request=yes diff --git a/docs/index.rst b/docs/index.rst index ccfce969d..2cb9fa40c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1154,10 +1154,10 @@ this for you. Before the first test using the ``ResetDatabase`` trait, it drops (if exists) and creates the test database. Then, by default, before each test, it resets the schema using ``doctrine:schema:drop``/``doctrine:schema:create``. -Alternatively, you can have it run your migrations instead by setting the env variable ``FOUNDRY_RESET_MODE=migrate`` -(in your ``.env.test``). When using this *mode*, before each test, the database is dropped/created and your migrations -run (via ``doctrine:migrations:migrate``). This mode can really make your test suite slow (especially if you have a lot -of migrations). It is highly recommended to use `DamaDoctrineTestBundle`_ to improve the +Alternatively, you can have it run your migrations instead by modifying the ``reset_mode`` option in configuration file. +When using this *mode*, before each test, the database is dropped/created and your migrations run (via +``doctrine:migrations:migrate``). This mode can really make your test suite slow (especially if you have a lot of +migrations). It is highly recommended to use `DamaDoctrineTestBundle`_ to improve the speed. When this bundle is enabled, the database is dropped/created and migrated only once for the suite. .. tip:: @@ -1170,15 +1170,28 @@ speed. When this bundle is enabled, the database is dropped/created and migrated required. By default, ``ResetDatabase`` resets the default configured connection's database and default configured object manager's -schema. To customize the connection's and object manager's to be reset (or reset multiple connections/managers), set the -following environment variables: +schema. To customize the connection's and object manager's to be reset (or reset multiple connections/managers), use the +bundle's configuration: -.. code-block:: bash +.. configuration-block:: - # .env.test + .. code-block:: yaml - FOUNDRY_RESET_CONNECTIONS=connection1,connection2 - FOUNDRY_RESET_OBJECT_MANAGERS=manager1,manager2 + # config/packages/zenstruck_foundry.yaml + when@dev: # see Bundle Configuration section about sharing this in the test environment + zenstruck_foundry: + orm: + connections: + - orm_connection_1 + - orm_connection_2 + object_managers: + - orm_object_manager_1 + - orm_object_manager_2 + reset_mode: schema + odm: + object_managers: + - odm_object_manager_1 + - odm_object_manager_2 Object Proxy ~~~~~~~~~~~~ @@ -1920,6 +1933,27 @@ Full Default Bundle Configuration # Customize the instantiator service. service: null # Example: my_instantiator + # Configure the database reset mechanism + database_resetter: + + # Config related to ORM + orm: + + # Connections to reset. If empty, the default connection is used. + connections: [] + + # Object managers to reset. If empty, the default manager is used. + object_managers: [] + + # Whether to use doctrine:schema:update or migrations when resetting schema. + reset_mode: schema # "schema" or "migration" + + # Config related to ODM + odm: + + # Object managers to reset. If empty, the default manager is used. + object_managers: [] + .. code-block:: php $config->extension('zenstruck_foundry', [ @@ -1955,4 +1989,29 @@ Full Default Bundle Configuration // Customize the instantiator service. 'service' => null ] + + // Configure the database reset mechanism + 'database_resetter' => [ + + // Config related to ORM + 'orm' => [ + + // Connections to reset. If empty, the default connection is used. + 'connections' => [], + + // Whether or not to allow extra attributes. + 'object_managers' => false, + + // Whether to use doctrine:schema:update or migrations when resetting schema. + 'reset_mode' => 'schema', // 'schema' or 'migration' + ], + + // Config related to ODM + 'odm' => [ + + // Whether or not to allow extra attributes. + 'object_managers' => false, + ], + + ] ]); diff --git a/src/Bundle/DependencyInjection/Configuration.php b/src/Bundle/DependencyInjection/Configuration.php index 9662e3f95..d8b6c469e 100644 --- a/src/Bundle/DependencyInjection/Configuration.php +++ b/src/Bundle/DependencyInjection/Configuration.php @@ -94,6 +94,38 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->end() ->end() + ->arrayNode('database_resetter') + ->canBeDisabled() + ->addDefaultsIfNotSet() + ->info('Configure database reset mechanism.') + ->children() + ->arrayNode('orm') + ->children() + ->arrayNode('connections') + ->scalarPrototype()->end() + ->info('Connections to reset. If empty, the default connection is used.') + ->end() + ->arrayNode('object_managers') + ->scalarPrototype()->end() + ->info('Object managers to reset. If empty, the default manager is used.') + ->end() + ->enumNode('reset_mode') + ->info('Whether to use doctrine:schema:update or migrations when resetting schema.') + ->values(['schema', 'migrate']) + ->defaultValue('schema') + ->end() + ->end() + ->end() + ->arrayNode('odm') + ->children() + ->arrayNode('object_managers') + ->scalarPrototype()->end() + ->info('Object managers to reset. If empty, the default manager is used.') + ->end() + ->end() + ->end() + ->end() + ->end() ->end() ; diff --git a/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php b/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php index 67dcde2c1..7c81c4e90 100644 --- a/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php +++ b/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php @@ -2,6 +2,8 @@ namespace Zenstruck\Foundry\Bundle\DependencyInjection; +use Doctrine\Bundle\DoctrineBundle\DoctrineBundle; +use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle; use Symfony\Bundle\MakerBundle\Maker\AbstractMaker; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -34,6 +36,7 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container $this->configureFaker($mergedConfig['faker'], $container); $this->configureDefaultInstantiator($mergedConfig['instantiator'], $container); + $this->configureDatabaseResetter($mergedConfig['database_resetter'], $container); if (true === $mergedConfig['auto_refresh_proxies']) { $container->getDefinition(Configuration::class)->addMethodCall('enableDefaultProxyAutoRefresh'); @@ -88,4 +91,38 @@ private function configureDefaultInstantiator(array $config, ContainerBuilder $c $definition->addMethodCall('alwaysForceProperties'); } } + + private function configureDatabaseResetter(array $config, ContainerBuilder $container): void + { + $configurationDefinition = $container->getDefinition(Configuration::class); + + if (false === $config['enabled']) { + $configurationDefinition->addMethodCall('disableDatabaseReset'); + } + + if (isset($config['orm']) && !self::isBundleLoaded($container, DoctrineBundle::class)) { + throw new \InvalidArgumentException('doctrine/doctrine-bundle should be enabled to use config under "database_resetter.orm".'); + } + + if (isset($config['odm']) && !self::isBundleLoaded($container, DoctrineMongoDBBundle::class)) { + throw new \InvalidArgumentException('doctrine/mongodb-odm-bundle should be enabled to use config under "database_resetter.odm".'); + } + + $configurationDefinition->setArgument('$ormConnectionsToReset', $config['orm']['connections'] ?? []); + $configurationDefinition->setArgument('$ormObjectManagersToReset', $config['orm']['object_managers'] ?? []); + $configurationDefinition->setArgument('$ormResetMode', $config['orm']['reset_mode'] ?? 'schema'); + $configurationDefinition->setArgument('$odmObjectManagersToReset', $config['odm']['object_managers'] ?? []); + } + + /** + * @psalm-suppress UndefinedDocblockClass + */ + private static function isBundleLoaded(ContainerBuilder $container, string $bundleName): bool + { + return \in_array( + $bundleName, + \is_array($bundles = $container->getParameter('kernel.bundles')) ? $bundles : [], + true + ); + } } diff --git a/src/Bundle/Resources/config/services.xml b/src/Bundle/Resources/config/services.xml index b32d3f793..7e822917c 100644 --- a/src/Bundle/Resources/config/services.xml +++ b/src/Bundle/Resources/config/services.xml @@ -11,6 +11,10 @@ + + + + diff --git a/src/Configuration.php b/src/Configuration.php index d38640e96..ae0bbaf88 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -35,12 +35,32 @@ final class Configuration /** @var bool */ private $flushEnabled = true; - public function __construct() + /** @var bool */ + private $databaseResetEnabled = true; + + /** @var list */ + private $ormConnectionsToReset; + + /** @var list */ + private $ormObjectManagersToReset; + + /** @var string */ + private $ormResetMode; + + /** @var list */ + private $odmObjectManagersToReset; + + public function __construct(array $ormConnectionsToReset, array $ormObjectManagersToReset, string $ormResetMode, array $odmObjectManagersToReset) { $this->stories = new StoryManager([]); $this->factories = new ModelFactoryManager([]); $this->faker = Faker\Factory::create(); $this->instantiator = new Instantiator(); + + $this->ormConnectionsToReset = $ormConnectionsToReset; + $this->ormObjectManagersToReset = $ormObjectManagersToReset; + $this->ormResetMode = $ormResetMode; + $this->odmObjectManagersToReset = $odmObjectManagersToReset; } public function stories(): StoryManager @@ -132,6 +152,18 @@ public function isFlushingEnabled(): bool return $this->flushEnabled; } + public function disableDatabaseReset(): self + { + $this->databaseResetEnabled = false; + + return $this; + } + + public function isDatabaseResetEnabled(): bool + { + return $this->databaseResetEnabled; + } + public function delayFlush(callable $callback): void { $this->flushEnabled = false; @@ -187,6 +219,26 @@ public function hasManagerRegistry(): bool return null !== $this->managerRegistry; } + public function getOrmConnectionsToReset(): array + { + return $this->ormConnectionsToReset; + } + + public function getOrmObjectManagersToReset(): array + { + return $this->ormObjectManagersToReset; + } + + public function getOrmResetMode(): string + { + return $this->ormResetMode; + } + + public function getOdmObjectManagersToReset(): array + { + return $this->odmObjectManagersToReset; + } + private function managerRegistry(): ManagerRegistry { if (!$this->hasManagerRegistry()) { diff --git a/src/Test/AbstractSchemaResetter.php b/src/Test/AbstractSchemaResetter.php index 8eabc0d17..4df4ace92 100644 --- a/src/Test/AbstractSchemaResetter.php +++ b/src/Test/AbstractSchemaResetter.php @@ -24,4 +24,15 @@ protected function runCommand(Application $application, string $command, array $ throw new \RuntimeException(\sprintf('Error running "%s": %s', $command, $output->fetch())); } } + + /** + * @param list $availableObjectsToReset + * @param list $candidateObjectsToReset + */ + protected static function validateObjectsToReset(string $objectsType, array $availableObjectsToReset, array $candidateObjectsToReset): void + { + if ($invalidObjectsToReset = \array_diff($candidateObjectsToReset, $availableObjectsToReset)) { + throw new \InvalidArgumentException(\sprintf('Cannot reset %s schema: invalid value "%s" given as %s. Available values are "%s"', ORMDatabaseResetter::class === static::class ? 'ORM' : 'ODM', \json_encode($invalidObjectsToReset), $objectsType, \json_encode($availableObjectsToReset))); + } + } } diff --git a/src/Test/DatabaseResetter.php b/src/Test/DatabaseResetter.php index df6ecc788..a8ebe650e 100644 --- a/src/Test/DatabaseResetter.php +++ b/src/Test/DatabaseResetter.php @@ -4,7 +4,9 @@ use DAMA\DoctrineTestBundle\Doctrine\DBAL\StaticDriver; use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\KernelInterface; +use Zenstruck\Foundry\Configuration; use Zenstruck\Foundry\Factory; /** @@ -19,10 +21,6 @@ final class DatabaseResetter public static function hasBeenReset(): bool { - if (isset($_SERVER['FOUNDRY_DISABLE_DATABASE_RESET'])) { - return true; - } - return self::$hasBeenReset; } @@ -37,8 +35,7 @@ public static function resetDatabase(KernelInterface $kernel): void return; } - $application = self::createApplication($kernel); - $databaseResetter = new ORMDatabaseResetter($application, $kernel->getContainer()->get('doctrine')); + $databaseResetter = self::createORMDatabaseResetter(self::createApplication($kernel), $kernel); $databaseResetter->resetDatabase(); @@ -60,18 +57,18 @@ public static function resetSchema(KernelInterface $kernel): void self::bootFoundry($kernel); } - /** @retrun array */ + /** @return array */ private static function schemaResetters(KernelInterface $kernel): array { $application = self::createApplication($kernel); $databaseResetters = []; if ($kernel->getContainer()->has('doctrine')) { - $databaseResetters[] = new ORMDatabaseResetter($application, $kernel->getContainer()->get('doctrine')); + $databaseResetters[] = self::createORMDatabaseResetter($application, $kernel); } if ($kernel->getContainer()->has('doctrine_mongodb')) { - $databaseResetters[] = new ODMSchemaResetter($application, $kernel->getContainer()->get('doctrine_mongodb')); + $databaseResetters[] = self::createODMSchemaResetter($application, $kernel); } return $databaseResetters; @@ -93,4 +90,41 @@ private static function createApplication(KernelInterface $kernel): Application return $application; } + + private static function createORMDatabaseResetter(Application $application, KernelInterface $kernel): ORMDatabaseResetter + { + $container = $kernel->getContainer(); + $configuration = self::getConfiguration($container); + + return new ORMDatabaseResetter( + $application, + $container->get('doctrine'), + $configuration ? $configuration->getOrmConnectionsToReset() : [], + $configuration ? $configuration->getOrmObjectManagersToReset() : [], + $configuration ? $configuration->getOrmResetMode() : 'schema' + ); + } + + private static function createODMSchemaResetter(Application $application, KernelInterface $kernel): ODMSchemaResetter + { + $container = $kernel->getContainer(); + $configuration = self::getConfiguration($container); + + return new ODMSchemaResetter( + $application, + $container->get('doctrine_mongodb'), + $configuration ? $configuration->getOdmObjectManagersToReset() : [] + ); + } + + private static function getConfiguration(ContainerInterface $container): ?Configuration + { + if ($container->has(Configuration::class)) { + return $container->get(Configuration::class); + } + + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of foundry without the bundle is deprecated and will not be possible anymore in 2.0.'); + + return null; + } } diff --git a/src/Test/ODMSchemaResetter.php b/src/Test/ODMSchemaResetter.php index a2b227f91..e19b8d885 100644 --- a/src/Test/ODMSchemaResetter.php +++ b/src/Test/ODMSchemaResetter.php @@ -14,11 +14,16 @@ final class ODMSchemaResetter extends AbstractSchemaResetter private $application; /** @var ManagerRegistry */ private $registry; + /** @var list */ + private $objectManagersToReset; - public function __construct(Application $application, ManagerRegistry $registry) + public function __construct(Application $application, ManagerRegistry $registry, array $objectManagersToReset) { $this->application = $application; $this->registry = $registry; + + self::validateObjectsToReset('object manager', \array_keys($registry->getManagerNames()), $objectManagersToReset); + $this->objectManagersToReset = $objectManagersToReset; } public function resetSchema(): void @@ -48,6 +53,6 @@ public function resetSchema(): void /** @return list */ private function objectManagersToReset(): array { - return [$this->registry->getDefaultManagerName()]; + return $this->objectManagersToReset ?: [$this->registry->getDefaultManagerName()]; } } diff --git a/src/Test/ORMDatabaseResetter.php b/src/Test/ORMDatabaseResetter.php index 887e78048..69ac63233 100644 --- a/src/Test/ORMDatabaseResetter.php +++ b/src/Test/ORMDatabaseResetter.php @@ -14,11 +14,29 @@ final class ORMDatabaseResetter extends AbstractSchemaResetter private $application; /** @var ManagerRegistry */ private $registry; - - public function __construct(Application $application, ManagerRegistry $registry) + /** @var list */ + private $connectionsToReset; + /** @var list */ + private $objectManagersToReset; + /** @var string */ + private $resetMode; + + /** + * @param list $connectionsToReset + * @param list $objectManagersToReset + */ + public function __construct(Application $application, ManagerRegistry $registry, array $connectionsToReset, array $objectManagersToReset, string $resetMode) { $this->application = $application; $this->registry = $registry; + + self::validateObjectsToReset('connection', \array_keys($registry->getConnectionNames()), $connectionsToReset); + $this->connectionsToReset = $connectionsToReset; + + self::validateObjectsToReset('object manager', \array_keys($registry->getManagerNames()), $objectManagersToReset); + $this->objectManagersToReset = $objectManagersToReset; + + $this->resetMode = $resetMode; } public function resetDatabase(): void @@ -40,7 +58,7 @@ public function resetSchema(): void private function createSchema(): void { - if (self::isResetUsingMigrations()) { + if ($this->isResetUsingMigrations()) { $this->runCommand($this->application, 'doctrine:migrations:migrate', ['-n' => true]); return; @@ -59,7 +77,7 @@ private function createSchema(): void private function dropSchema(): void { - if (self::isResetUsingMigrations()) { + if ($this->isResetUsingMigrations()) { $this->dropAndResetDatabase(); return; @@ -103,24 +121,34 @@ private function dropAndResetDatabase(): void private function connectionsToReset(): array { if (isset($_SERVER['FOUNDRY_RESET_CONNECTIONS'])) { + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of environment variable "FOUNDRY_RESET_CONNECTIONS" is deprecated. Please use bundle configuration: "database_resetter.orm.connections: true".'); + return \explode(',', $_SERVER['FOUNDRY_RESET_CONNECTIONS']); } - return [$this->registry->getDefaultConnectionName()]; + return $this->connectionsToReset ?: [$this->registry->getDefaultConnectionName()]; } /** @return list */ private function objectManagersToReset(): array { if (isset($_SERVER['FOUNDRY_RESET_OBJECT_MANAGERS'])) { + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of environment variable "FOUNDRY_RESET_OBJECT_MANAGERS" is deprecated. Please use bundle configuration: "database_resetter.orm.object_managers: true".'); + return \explode(',', $_SERVER['FOUNDRY_RESET_OBJECT_MANAGERS']); } - return [$this->registry->getDefaultManagerName()]; + return $this->objectManagersToReset ?: [$this->registry->getDefaultManagerName()]; } - private static function isResetUsingMigrations(): bool + private function isResetUsingMigrations(): bool { - return 'migrate' === ($_SERVER['FOUNDRY_RESET_MODE'] ?? 'schema'); + if (isset($_SERVER['FOUNDRY_RESET_MODE'])) { + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of environment variable "FOUNDRY_RESET_MODE" is deprecated. Please use bundle configuration: "database_resetter.orm.reset_mode: true".'); + + return 'migrate' === $_SERVER['FOUNDRY_RESET_MODE']; + } + + return 'migrate' === $this->resetMode; } } diff --git a/src/Test/ResetDatabase.php b/src/Test/ResetDatabase.php index 1b4f1577d..608fbdd02 100644 --- a/src/Test/ResetDatabase.php +++ b/src/Test/ResetDatabase.php @@ -4,6 +4,9 @@ use DAMA\DoctrineTestBundle\Doctrine\DBAL\StaticDriver; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpKernel\KernelInterface; +use Zenstruck\Foundry\Configuration; /** * @mixin KernelTestCase @@ -18,23 +21,22 @@ trait ResetDatabase */ public static function _resetDatabase(): void { - if (DatabaseResetter::hasBeenReset()) { - return; - } - if (!\is_subclass_of(static::class, KernelTestCase::class)) { throw new \RuntimeException(\sprintf('The "%s" trait can only be used on TestCases that extend "%s".', __TRAIT__, KernelTestCase::class)); } if ($isDAMADoctrineTestBundleEnabled = DatabaseResetter::isDAMADoctrineTestBundleEnabled()) { // disable static connections for this operation + // :warning: the kernel should not be booted before calling this! StaticDriver::setKeepStaticConnections(false); } $kernel = static::createKernel(); $kernel->boot(); - DatabaseResetter::resetDatabase($kernel); + if (self::shouldReset($kernel)) { + DatabaseResetter::resetDatabase($kernel); + } if ($isDAMADoctrineTestBundleEnabled) { // re-enable static connections @@ -61,4 +63,32 @@ public static function _resetSchema(): void $kernel->shutdown(); } + + private static function shouldReset(KernelInterface $kernel): bool + { + if (isset($_SERVER['FOUNDRY_DISABLE_DATABASE_RESET'])) { + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of environment variable "FOUNDRY_DISABLE_DATABASE_RESET" is deprecated. Please use bundle configuration: "database_resetter.disabled: true".'); + + return false; + } + + $configuration = self::getConfiguration($kernel->getContainer()); + + if ($configuration && !$configuration->isDatabaseResetEnabled()) { + return false; + } + + return !DatabaseResetter::hasBeenReset(); + } + + private static function getConfiguration(ContainerInterface $container): ?Configuration + { + if ($container->has(Configuration::class)) { + return $container->get(Configuration::class); + } + + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of foundry without the bundle is deprecated and will not be possible anymore in 2.0.'); + + return null; + } } diff --git a/src/Test/TestState.php b/src/Test/TestState.php index f92a2604d..071243a4b 100644 --- a/src/Test/TestState.php +++ b/src/Test/TestState.php @@ -73,7 +73,7 @@ public static function addGlobalState(callable $callback): void public static function bootFoundry(?Configuration $configuration = null): void { - $configuration = $configuration ?? new Configuration(); + $configuration = $configuration ?? new Configuration([], [], 'schema', []); if (self::$instantiator) { $configuration->setInstantiator(self::$instantiator); @@ -121,7 +121,7 @@ public static function bootFromContainer(ContainerInterface $container): void return; } - $configuration = new Configuration(); + $configuration = new Configuration([], [], 'schema', []); try { $configuration->setManagerRegistry(self::initializeChainManagerRegistry($container)); diff --git a/tests/Fixtures/Kernel.php b/tests/Fixtures/Kernel.php index 9874c1ff1..722c412df 100644 --- a/tests/Fixtures/Kernel.php +++ b/tests/Fixtures/Kernel.php @@ -43,7 +43,7 @@ public function registerBundles(): iterable yield new DAMADoctrineTestBundle(); } - if ('migrate' === \getenv('FOUNDRY_RESET_MODE')) { + if (\getenv('USE_MIGRATIONS')) { yield new DoctrineMigrationsBundle(); } @@ -96,12 +96,16 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load } if (\getenv('USE_FOUNDRY_BUNDLE')) { - $c->loadFromExtension('zenstruck_foundry', [ - 'auto_refresh_proxies' => false, - ]); + $foundryConfig = ['auto_refresh_proxies' => false]; + + if (\getenv('DATABASE_URL') && \getenv('USE_MIGRATIONS')) { + $foundryConfig['database_resetter'] = ['orm' => ['reset_mode' => 'migrate']]; + } + + $c->loadFromExtension('zenstruck_foundry', $foundryConfig); } - if ('migrate' === \getenv('FOUNDRY_RESET_MODE')) { + if (\getenv('USE_MIGRATIONS')) { $c->loadFromExtension('doctrine_migrations', [ 'migrations_paths' => [ 'Zenstruck\Foundry\Tests\Fixtures\Migrations' => '%kernel.project_dir%/tests/Fixtures/Migrations', From 759846773bd8146bc60c8a4d3decc48dab69b6e2 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Wed, 9 Nov 2022 17:04:12 +0100 Subject: [PATCH 10/13] [feat] [remove bundleless usge] configure global state with config (#322) --- Makefile | 2 +- docs/index.rst | 38 +++++---- .../DependencyInjection/Configuration.php | 4 + .../DependencyInjection/GlobalStatePass.php | 81 +++++++++++++++++++ src/Bundle/Resources/config/services.xml | 3 + src/Test/DatabaseResetter.php | 8 +- src/Test/GlobalStateRegistry.php | 62 ++++++++++++++ src/Test/ResetDatabase.php | 6 ++ src/Test/TestState.php | 12 ++- src/ZenstruckFoundryBundle.php | 2 + tests/Fixtures/Document/Tag.php | 31 +++++++ tests/Fixtures/Factories/ODM/TagFactory.php | 22 +++++ tests/Fixtures/Kernel.php | 22 ++++- tests/Fixtures/Stories/ODMTagStory.php | 14 ++++ .../Stories/ODMTagStoryAsAService.php | 16 ++++ tests/Fixtures/Stories/TagStory.php | 1 - .../Stories/TagStoryAsInvokableService.php | 13 +++ tests/Functional/GlobalStateTest.php | 37 ++++++--- tests/Functional/ODMGlobalStateTest.php | 32 ++++++++ tests/Functional/ORMGlobalStateTest.php | 28 +++++++ tests/Functional/ORMModelFactoryTest.php | 36 +++++++-- tests/bootstrap.php | 7 -- 22 files changed, 425 insertions(+), 52 deletions(-) create mode 100644 src/Bundle/DependencyInjection/GlobalStatePass.php create mode 100644 src/Test/GlobalStateRegistry.php create mode 100644 tests/Fixtures/Document/Tag.php create mode 100644 tests/Fixtures/Factories/ODM/TagFactory.php create mode 100644 tests/Fixtures/Stories/ODMTagStory.php create mode 100644 tests/Fixtures/Stories/ODMTagStoryAsAService.php create mode 100644 tests/Fixtures/Stories/TagStoryAsInvokableService.php create mode 100644 tests/Functional/ODMGlobalStateTest.php create mode 100644 tests/Functional/ORMGlobalStateTest.php diff --git a/Makefile b/Makefile index d14ecece7..ab19a6205 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ test-postgresql: docker-start vendor ### Run PHPunit with postgreSQL test-mongo: docker-start vendor ### Run PHPunit with Mongo @$(eval filter ?= '.') - @${DC_EXEC} -e MONGO_URL=${MONGO_URL} php vendor/bin/simple-phpunit --configuration phpunit.xml.dist --filter=$(filter) + @${DC_EXEC} -e USE_FOUNDRY_BUNDLE=1 -e MONGO_URL=${MONGO_URL} php vendor/bin/simple-phpunit --configuration phpunit.xml.dist --filter=$(filter) fixcs: docker-start bin/tools/cs-fixer/vendor ### Run PHP CS-Fixer @${DOCKER_PHP} bin/tools/cs-fixer/vendor/friendsofphp/php-cs-fixer/php-cs-fixer --no-interaction --diff -v fix diff --git a/docs/index.rst b/docs/index.rst index 2cb9fa40c..3d3f1a188 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1397,29 +1397,21 @@ Both object proxies and your ModelFactory have helpful PHPUnit assertions: Global State ~~~~~~~~~~~~ -If you have an initial database state you want for all tests, you can set this in your ``tests/bootstrap.php``: +If you have an initial database state you want for all tests, you can set this in the config of the bundle. Accepted +values are: stories as service, "global" stories and invokable services. -.. code-block:: php - - // tests/bootstrap.php - // ... - - Zenstruck\Foundry\Test\TestState::addGlobalState(function () { - CategoryFactory::createOne(['name' => 'php']); - CategoryFactory::createOne(['name' => 'symfony']); - }); - -To avoid your bootstrap file from becoming too complex, it is best to wrap your global state into a -:ref:`Story `: - -.. code-block:: php +.. configuration-block:: - // tests/bootstrap.php - // ... + .. code-block:: yaml - Zenstruck\Foundry\Test\TestState::addGlobalState(function () { - GlobalStory::load(); - }); + # config/packages/zenstruck_foundry.yaml + when@test: # see Bundle Configuration section about sharing this in the test environment + zenstruck_foundry: + global_state: + - App\Stories\StoryThatIsAService + - App\Stories\GlobalStory + - invokable.service # just a service with ::invoke() + - ... .. note:: @@ -1954,6 +1946,9 @@ Full Default Bundle Configuration # Object managers to reset. If empty, the default manager is used. object_managers: [] + # Add global state. + global_state: [] + .. code-block:: php $config->extension('zenstruck_foundry', [ @@ -2013,5 +2008,8 @@ Full Default Bundle Configuration 'object_managers' => false, ], + // Add global state + 'global_state' => [] + ] ]); diff --git a/src/Bundle/DependencyInjection/Configuration.php b/src/Bundle/DependencyInjection/Configuration.php index d8b6c469e..5036f1e02 100644 --- a/src/Bundle/DependencyInjection/Configuration.php +++ b/src/Bundle/DependencyInjection/Configuration.php @@ -126,6 +126,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->end() ->end() + ->arrayNode('global_state') + ->scalarPrototype()->end() + ->info('Array of stories that should be used as global state.') + ->end() ->end() ; diff --git a/src/Bundle/DependencyInjection/GlobalStatePass.php b/src/Bundle/DependencyInjection/GlobalStatePass.php new file mode 100644 index 000000000..a47a7a696 --- /dev/null +++ b/src/Bundle/DependencyInjection/GlobalStatePass.php @@ -0,0 +1,81 @@ +hasDefinition(FoundryConfiguration::class)) { + return; + } + + $globalStateRegistryDefinition = $container->getDefinition(GlobalStateRegistry::class); + + foreach ($this->getBundleConfiguration($container)['global_state'] as $globalStateItem) { + if ($this->isStoryAsService($container, $globalStateItem)) { + $globalStateRegistryDefinition->addMethodCall('addStoryAsService', [new Reference($globalStateItem)]); + + continue; + } + + if ($this->isInvokableService($container, $globalStateItem)) { + $globalStateRegistryDefinition->addMethodCall('addInvokableService', [new Reference($globalStateItem)]); + + continue; + } + + if ($this->isStandaloneStory($container, $globalStateItem)) { + $globalStateRegistryDefinition->addMethodCall('addStandaloneStory', [$globalStateItem]); + + continue; + } + + throw new \InvalidArgumentException("Given global state \"{$globalStateItem}\" is invalid. Allowed values are invokable services, stories as service or regular stories."); + } + } + + private function isStoryAsService(ContainerBuilder $container, string $globalStateItem): bool + { + if (!$container->has($globalStateItem)) { + return false; + } + + $globalStateItemDefinition = $container->getDefinition($globalStateItem); + + return \count($globalStateItemDefinition->getTag('foundry.story')) > 0; + } + + private function isInvokableService(ContainerBuilder $container, string $globalStateItem): bool + { + if (!$container->has($globalStateItem)) { + return false; + } + + $globalStateItemDefinition = $container->getDefinition($globalStateItem); + + return (new \ReflectionClass($globalStateItemDefinition->getClass()))->hasMethod('__invoke'); + } + + private function isStandaloneStory(ContainerBuilder $container, string $globalStateItem): bool + { + if ($container->has($globalStateItem)) { + return false; + } + + return \class_exists($globalStateItem) && \is_a($globalStateItem, Story::class, true); + } + + private function getBundleConfiguration(ContainerBuilder $container): array + { + return (new Processor())->processConfiguration(new Configuration(), $container->getExtensionConfig('zenstruck_foundry')); + } +} diff --git a/src/Bundle/Resources/config/services.xml b/src/Bundle/Resources/config/services.xml index 7e822917c..06634b2e1 100644 --- a/src/Bundle/Resources/config/services.xml +++ b/src/Bundle/Resources/config/services.xml @@ -53,5 +53,8 @@ + + + diff --git a/src/Test/DatabaseResetter.php b/src/Test/DatabaseResetter.php index a8ebe650e..bfe7fa9ab 100644 --- a/src/Test/DatabaseResetter.php +++ b/src/Test/DatabaseResetter.php @@ -76,11 +76,15 @@ private static function schemaResetters(KernelInterface $kernel): array private static function bootFoundry(KernelInterface $kernel): void { + $container = $kernel->getContainer(); + if (!Factory::isBooted()) { - TestState::bootFromContainer($kernel->getContainer()); + TestState::bootFromContainer($container); } - TestState::flushGlobalState(); + TestState::flushGlobalState( + $container->has(GlobalStateRegistry::class) ? $container->get(GlobalStateRegistry::class) : null + ); } private static function createApplication(KernelInterface $kernel): Application diff --git a/src/Test/GlobalStateRegistry.php b/src/Test/GlobalStateRegistry.php new file mode 100644 index 000000000..6dfa7f17f --- /dev/null +++ b/src/Test/GlobalStateRegistry.php @@ -0,0 +1,62 @@ + */ + private $storiesAsService = []; + + /** @var list */ + private $invokableServices = []; + + /** @var list> */ + private $standaloneStories = []; + + public function addStoryAsService(Story $storyAsService): void + { + $this->storiesAsService[] = $storyAsService; + } + + public function addInvokableService(callable $invokableService): void + { + $this->invokableServices[] = $invokableService; + } + + /** + * @param class-string $storyClass + */ + public function addStandaloneStory(string $storyClass): void + { + $this->standaloneStories[] = $storyClass; + } + + /** + * @return list + */ + public function getGlobalStates(): array + { + return \array_merge( + \array_map( + static function(Story $story) { + return static function() use ($story) {$story->build(); }; + }, + $this->storiesAsService + ), + $this->invokableServices, + \array_map( + static function(string $storyClassName) { + return static function() use ($storyClassName) {$storyClassName::load(); }; + }, + $this->standaloneStories + ) + ); + } +} diff --git a/src/Test/ResetDatabase.php b/src/Test/ResetDatabase.php index 608fbdd02..358539223 100644 --- a/src/Test/ResetDatabase.php +++ b/src/Test/ResetDatabase.php @@ -34,6 +34,12 @@ public static function _resetDatabase(): void $kernel = static::createKernel(); $kernel->boot(); + try { + $kernel->getBundle('ZenstruckFoundryBundle'); + } catch (\InvalidArgumentException $exception) { + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of ResetDatabase trait without Foundry bundle is deprecated and will create an error in 2.0.'); + } + if (self::shouldReset($kernel)) { DatabaseResetter::resetDatabase($kernel); } diff --git a/src/Test/TestState.php b/src/Test/TestState.php index 071243a4b..02754f2b9 100644 --- a/src/Test/TestState.php +++ b/src/Test/TestState.php @@ -68,6 +68,8 @@ public static function withoutBundle(): void public static function addGlobalState(callable $callback): void { + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of TestState::addGlobalState() is deprecated. Please use bundle configuration under "global_state" key.'); + self::$globalStates[] = $callback; } @@ -103,7 +105,7 @@ public static function shutdownFoundry(): void */ public static function bootFactory(Configuration $configuration): Configuration { - trigger_deprecation('zenstruck\foundry', '1.4.0', 'TestState::bootFactory() is deprecated, use TestState::bootFoundry().'); + trigger_deprecation('zenstruck/foundry', '1.4.0', 'TestState::bootFactory() is deprecated, use TestState::bootFoundry().'); self::bootFoundry($configuration); @@ -158,7 +160,7 @@ public static function initializeChainManagerRegistry(ContainerInterface $contai /** * @internal */ - public static function flushGlobalState(): void + public static function flushGlobalState(?GlobalStateRegistry $globalStateRegistry): void { StoryManager::globalReset(); @@ -166,6 +168,12 @@ public static function flushGlobalState(): void $callback(); } + if ($globalStateRegistry) { + foreach ($globalStateRegistry->getGlobalStates() as $callback) { + $callback(); + } + } + StoryManager::setGlobalState(); } } diff --git a/src/ZenstruckFoundryBundle.php b/src/ZenstruckFoundryBundle.php index 5459884c0..00721c7a5 100644 --- a/src/ZenstruckFoundryBundle.php +++ b/src/ZenstruckFoundryBundle.php @@ -6,6 +6,7 @@ use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\HttpKernel\Bundle\Bundle; use Zenstruck\Foundry\Bundle\DependencyInjection\ChainManagerRegistryPass; +use Zenstruck\Foundry\Bundle\DependencyInjection\GlobalStatePass; use Zenstruck\Foundry\Bundle\DependencyInjection\ZenstruckFoundryExtension; /** @@ -27,6 +28,7 @@ public function build(ContainerBuilder $container): void parent::build($container); $container->addCompilerPass(new ChainManagerRegistryPass()); + $container->addCompilerPass(new GlobalStatePass()); } protected function createContainerExtension(): ?ExtensionInterface diff --git a/tests/Fixtures/Document/Tag.php b/tests/Fixtures/Document/Tag.php new file mode 100644 index 000000000..bbdc74cda --- /dev/null +++ b/tests/Fixtures/Document/Tag.php @@ -0,0 +1,31 @@ +name = $name; + } + + public function getName(): ?string + { + return $this->name; + } +} diff --git a/tests/Fixtures/Factories/ODM/TagFactory.php b/tests/Fixtures/Factories/ODM/TagFactory.php new file mode 100644 index 000000000..2687aedf4 --- /dev/null +++ b/tests/Fixtures/Factories/ODM/TagFactory.php @@ -0,0 +1,22 @@ + + */ +final class TagFactory extends ModelFactory +{ + protected static function getClass(): string + { + return Tag::class; + } + + protected function getDefaults(): array + { + return ['name' => self::faker()->sentence()]; + } +} diff --git a/tests/Fixtures/Kernel.php b/tests/Fixtures/Kernel.php index 722c412df..158ab9244 100644 --- a/tests/Fixtures/Kernel.php +++ b/tests/Fixtures/Kernel.php @@ -15,7 +15,11 @@ use Symfony\Component\Routing\RouteCollectionBuilder; use Zenstruck\Foundry\Tests\Fixtures\Factories\CategoryFactory; use Zenstruck\Foundry\Tests\Fixtures\Factories\CategoryServiceFactory; +use Zenstruck\Foundry\Tests\Fixtures\Stories\ODMTagStory; +use Zenstruck\Foundry\Tests\Fixtures\Stories\ODMTagStoryAsAService; use Zenstruck\Foundry\Tests\Fixtures\Stories\ServiceStory; +use Zenstruck\Foundry\Tests\Fixtures\Stories\TagStory; +use Zenstruck\Foundry\Tests\Fixtures\Stories\TagStoryAsInvokableService; use Zenstruck\Foundry\ZenstruckFoundryBundle; /** @@ -55,6 +59,7 @@ public function registerBundles(): iterable protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader): void { $c->register(Service::class); + $c->register(TagStoryAsInvokableService::class); $c->register(ServiceStory::class) ->setAutoconfigured(true) ->setAutowired(true) @@ -97,11 +102,24 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load if (\getenv('USE_FOUNDRY_BUNDLE')) { $foundryConfig = ['auto_refresh_proxies' => false]; + $globalState = []; - if (\getenv('DATABASE_URL') && \getenv('USE_MIGRATIONS')) { - $foundryConfig['database_resetter'] = ['orm' => ['reset_mode' => 'migrate']]; + if (\getenv('DATABASE_URL')) { + $globalState[] = TagStory::class; + $globalState[] = TagStoryAsInvokableService::class; + + if (\getenv('USE_MIGRATIONS')) { + $foundryConfig['database_resetter'] = ['orm' => ['reset_mode' => 'migrate']]; + } + } + + if (\getenv('MONGO_URL') && !\getenv('USE_DAMA_DOCTRINE_TEST_BUNDLE')) { + $globalState[] = ODMTagStory::class; + $globalState[] = ODMTagStoryAsAService::class; } + $foundryConfig['global_state'] = $globalState; + $c->loadFromExtension('zenstruck_foundry', $foundryConfig); } diff --git a/tests/Fixtures/Stories/ODMTagStory.php b/tests/Fixtures/Stories/ODMTagStory.php new file mode 100644 index 000000000..217fd3242 --- /dev/null +++ b/tests/Fixtures/Stories/ODMTagStory.php @@ -0,0 +1,14 @@ +addState('dev', TagFactory::new()->create(['name' => 'dev'])); + } +} diff --git a/tests/Fixtures/Stories/ODMTagStoryAsAService.php b/tests/Fixtures/Stories/ODMTagStoryAsAService.php new file mode 100644 index 000000000..9fe825cfb --- /dev/null +++ b/tests/Fixtures/Stories/ODMTagStoryAsAService.php @@ -0,0 +1,16 @@ +addState('design', TagFactory::new()->create(['name' => 'design'])); + } +} diff --git a/tests/Fixtures/Stories/TagStory.php b/tests/Fixtures/Stories/TagStory.php index affb6ecbb..37a0b005c 100644 --- a/tests/Fixtures/Stories/TagStory.php +++ b/tests/Fixtures/Stories/TagStory.php @@ -13,6 +13,5 @@ final class TagStory extends Story public function build(): void { $this->addState('dev', TagFactory::new()->create(['name' => 'dev'])); - $this->addState('design', TagFactory::new()->create(['name' => 'design'])); } } diff --git a/tests/Fixtures/Stories/TagStoryAsInvokableService.php b/tests/Fixtures/Stories/TagStoryAsInvokableService.php new file mode 100644 index 000000000..90d7fe010 --- /dev/null +++ b/tests/Fixtures/Stories/TagStoryAsInvokableService.php @@ -0,0 +1,13 @@ +create(['name' => 'design']); + } +} diff --git a/tests/Functional/GlobalStateTest.php b/tests/Functional/GlobalStateTest.php index afc2dd0cc..d79fef2ef 100644 --- a/tests/Functional/GlobalStateTest.php +++ b/tests/Functional/GlobalStateTest.php @@ -3,23 +3,25 @@ namespace Zenstruck\Foundry\Tests\Functional; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Zenstruck\Foundry\Factory; +use Zenstruck\Foundry\Story; use Zenstruck\Foundry\Test\Factories; use Zenstruck\Foundry\Test\ResetDatabase; -use Zenstruck\Foundry\Tests\Fixtures\Factories\TagFactory; -use Zenstruck\Foundry\Tests\Fixtures\Stories\TagStory; /** * @author Kevin Bond */ -final class GlobalStateTest extends KernelTestCase +abstract class GlobalStateTest extends KernelTestCase { use Factories, ResetDatabase; protected function setUp(): void { - if (false === \getenv('DATABASE_URL')) { - self::markTestSkipped('doctrine/orm not enabled.'); + if (!\getenv('USE_FOUNDRY_BUNDLE')) { + $this->markTestSkipped('ZenstruckFoundryBundle not enabled.'); } + + parent::setUp(); } /** @@ -27,9 +29,10 @@ protected function setUp(): void */ public function tag_story_is_added_as_global_state(): void { - TagFactory::repository()->assert()->count(2); - TagFactory::repository()->assert()->exists(['name' => 'dev']); - TagFactory::repository()->assert()->exists(['name' => 'design']); + $tagFactoryClass = $this->getTagFactoryClass(); + $tagFactoryClass::repository()->assert()->count(2); + $tagFactoryClass::repository()->assert()->exists(['name' => 'dev']); + $tagFactoryClass::repository()->assert()->exists(['name' => 'design']); } /** @@ -37,9 +40,21 @@ public function tag_story_is_added_as_global_state(): void */ public function ensure_global_story_is_not_loaded_again(): void { - TagStory::load(); - TagStory::load(); + $tagStoryClass = $this->getTagStoryClass(); + $tagStoryClass::load(); + $tagStoryClass::load(); - TagFactory::repository()->assert()->count(2); + $tagFactoryClass = $this->getTagFactoryClass(); + $tagFactoryClass::repository()->assert()->count(2); } + + /** + * @return class-string + */ + abstract protected function getTagFactoryClass(): string; + + /** + * @return class-string + */ + abstract protected function getTagStoryClass(): string; } diff --git a/tests/Functional/ODMGlobalStateTest.php b/tests/Functional/ODMGlobalStateTest.php new file mode 100644 index 000000000..96892fd03 --- /dev/null +++ b/tests/Functional/ODMGlobalStateTest.php @@ -0,0 +1,32 @@ +assertCount(3, $post->getTags()); - TagFactory::assert()->count(5); // 3 created by this test and 2 in global state + TagFactory::assert()->count( + \getenv('USE_FOUNDRY_BUNDLE') + ? 5 // 3 created by this test and 2 in global state + : 3 + ); PostFactory::assert()->count(1); } @@ -285,7 +289,11 @@ public function many_to_many_with_two_relationships_same_entity(): void $this->assertCount(3, $post->getTags()); $this->assertCount(3, $post->getSecondaryTags()); - TagFactory::assert()->count(8); // 3 created by this test and 2 in global state + TagFactory::assert()->count( + \getenv('USE_FOUNDRY_BUNDLE') + ? 8 // 6 created by this test and 2 in global state + : 6 + ); PostFactory::assert()->count(1); } @@ -327,7 +335,11 @@ public function inverse_many_to_many_with_nested_collection_relationship(): void ]); $this->assertCount(3, $tag->getPosts()); - TagFactory::assert()->count(3); // 1 created by this test and 2 in global state + TagFactory::assert()->count( + \getenv('USE_FOUNDRY_BUNDLE') + ? 3 // 1 created by this test and 2 in global state + : 1 + ); PostFactory::assert()->count(3); } @@ -343,7 +355,11 @@ public function inverse_many_to_many_with_two_relationships_same_entity(): void $this->assertCount(3, $tag->getPosts()); $this->assertCount(3, $tag->getSecondaryPosts()); - TagFactory::assert()->count(3); // 1 created by this test and 2 in global state + TagFactory::assert()->count( + \getenv('USE_FOUNDRY_BUNDLE') + ? 3 // 1 created by this test and 2 in global state + : 1 + ); PostFactory::assert()->count(6); } @@ -386,7 +402,11 @@ public function create_multiple_many_to_many_with_nested_collection_relationship $this->assertCount(3, $posts[0]->getTags()); $this->assertCount(3, $posts[1]->getTags()); - TagFactory::assert()->count(8); // 6 created by this test and 2 in global state + TagFactory::assert()->count( + \getenv('USE_FOUNDRY_BUNDLE') + ? 8 // 6 created by this test and 2 in global state + : 6 + ); PostFactory::assert()->count(2); } @@ -415,7 +435,11 @@ public function unpersisted_many_to_many_with_nested_collection_relationship(): ]); $this->assertCount(3, $post->getTags()); - TagFactory::assert()->count(2); // 2 created in global state + TagFactory::assert()->count( + \getenv('USE_FOUNDRY_BUNDLE') + ? 2 // 2 created in global state + : 0 + ); PostFactory::assert()->empty(); } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 8ec499ad4..eae8bc83e 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -2,16 +2,9 @@ use Symfony\Component\Filesystem\Filesystem; use Zenstruck\Foundry\Test\TestState; -use Zenstruck\Foundry\Tests\Fixtures\Stories\TagStory; require \dirname(__DIR__).'/vendor/autoload.php'; (new Filesystem())->remove(__DIR__.'/../var'); TestState::disableDefaultProxyAutoRefresh(); - -if (\getenv('DATABASE_URL')) { - TestState::addGlobalState(static function() { - TagStory::load(); - }); -} From 358827451674781c8132715f2903298267f631fe Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Thu, 10 Nov 2022 18:15:44 +0100 Subject: [PATCH 11/13] [feature] Allow to use foundry without Doctrine (#323) --- .github/workflows/ci.yml | 22 -------- docs/index.rst | 49 ++++++----------- phpunit-dama-doctrine.xml.dist | 2 +- phpunit.xml.dist | 2 +- .../ChainManagerRegistryPass.php | 4 -- src/ChainManagerRegistry.php | 4 -- src/Test/Factories.php | 2 +- src/Test/TestState.php | 54 ++++++++++++++++--- tests/Fixtures/Kernel.php | 36 ++++++++++--- .../Functional/Bundle/Maker/MakerTestCase.php | 4 ++ .../WithDoctrineDisabledKernelTest.php | 48 +++++++++++++++++ tests/bootstrap.php | 3 -- 12 files changed, 149 insertions(+), 81 deletions(-) create mode 100644 tests/Functional/WithDoctrineDisabledKernelTest.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f35799bbf..06dd30ad3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,7 +75,6 @@ jobs: - name: 'Test: MySQL' run: vendor/bin/simple-phpunit -v env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Test: MySQL, FoundryBundle' @@ -87,7 +86,6 @@ jobs: - name: 'Test: MySQL, DAMABundle' run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Test: MySQL, FoundryBundle, DAMABundle' @@ -99,21 +97,18 @@ jobs: - name: 'Test: MySQL, DoctrineMigrationsBundle' run: vendor/bin/simple-phpunit -v env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 USE_MIGRATIONS: 1 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Test: MySQL, DoctrineMigrationsBundle, DAMABundle' run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 USE_MIGRATIONS: 1 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Test: PostgreSQL' run: vendor/bin/simple-phpunit -v env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - name: 'Test: PostgreSQL, FoundryBundle' @@ -136,7 +131,6 @@ jobs: - name: 'Test: SQLite' run: vendor/bin/simple-phpunit -v env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Test: SQLite, FoundryBundle' @@ -148,20 +142,17 @@ jobs: - name: 'Test: SQLite, DAMABundle' run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Test: SQLite, FoundryBundle, DAMABundle' run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 # USE_FOUNDRY_BUNDLE: 1 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Test: MySQL, Mongo' run: vendor/bin/simple-phpunit -v env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb @@ -175,14 +166,12 @@ jobs: - name: 'Test: MySQL, Mongo, DAMABundle' run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - name: 'Test: Mongo standalone' run: vendor/bin/simple-phpunit -v env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb code-coverage: @@ -231,7 +220,6 @@ jobs: - name: 'Coverage: MySQL' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql.clover env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Coverage: MySQL, FoundryBundle' @@ -243,7 +231,6 @@ jobs: - name: 'Coverage: MySQL, DAMABundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-dama.clover --configuration phpunit-dama-doctrine.xml.dist env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Coverage: MySQL, FoundryBundle, DAMABundle' @@ -255,21 +242,18 @@ jobs: - name: 'Test: MySQL, DoctrineMigrationsBundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-migrations.clover env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 USE_MIGRATIONS: 1 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Test: MySQL, DoctrineMigrationsBundle, DAMABundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-migrations-dama.clover --configuration phpunit-dama-doctrine.xml.dist env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 USE_MIGRATIONS: 1 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - name: 'Coverage: PostgreSQL' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=postgres.clover env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - name: 'Coverage: PostgreSQL, FoundryBundle' @@ -292,7 +276,6 @@ jobs: - name: 'Coverage: SQLite' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=sqlite.clover env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Coverage: SQLite, FoundryBundle' @@ -304,20 +287,17 @@ jobs: - name: 'Coverage: SQLite, DAMABundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=sqlite-dama.clover --configuration phpunit-dama-doctrine.xml.dist env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Coverage: SQLite, FoundryBundle, DAMABundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=sqlite-foundry-dama.clover --configuration phpunit-dama-doctrine.xml.dist env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 # USE_FOUNDRY_BUNDLE: 1 DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - name: 'Test: MySQL, Mongo' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-mongo.clover env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb @@ -331,14 +311,12 @@ jobs: - name: 'Test: MySQL, Mongo, DAMABundle' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-mongo-dama.clover --configuration phpunit-dama-doctrine.xml.dist env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - name: 'Test: Mongo standalone' run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mongo.clover env: - SYMFONY_DEPRECATIONS_HELPER: max[direct]=0&max[self]=99999 MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - name: Publish coverage report to Codecov diff --git a/docs/index.rst b/docs/index.rst index 3d3f1a188..e6f682454 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1609,9 +1609,7 @@ Foundry can be used in standard PHPUnit unit tests (TestCase's that just extend ``Symfony\Bundle\FrameworkBundle\Test\KernelTestCase``). These tests still require using the ``Factories`` trait to boot Foundry but will not have doctrine available. Factories created in these tests will not be persisted (calling ``->withoutPersisting()`` is not necessary). Because the bundle is not available in these tests, -any bundle configuration you have will not be picked up. You will need to add -`Test-Only Configuration`_. Unfortunately, this may mean duplicating your bundle configuration -here. +any bundle configuration you have will not be picked up. .. code-block:: php @@ -1631,52 +1629,37 @@ here. } } -.. note:: - - `Factories as Services`_ and `Stories as Services`_ with required - constructor arguments are not usable in non-Kernel tests. The container is not available to resolve their dependencies. - The easiest work-around is to make the test an instance of ``Symfony\Bundle\FrameworkBundle\Test\KernelTestCase`` so the - container is available. - -Test-Only Configuration -~~~~~~~~~~~~~~~~~~~~~~~ - -Foundry can be configured statically, with pure PHP, in your ``tests/bootstrap.php``. This is useful if you have a mix -of Kernel and `non-Kernel tests`_ or if `Using Without the Bundle`_: +You will need to configure manually Foundry. Unfortunately, this may mean duplicating your bundle configuration here. .. code-block:: php // tests/bootstrap.php // ... - // configure a default instantiator - Zenstruck\Foundry\Test\TestState::setInstantiator( - (new Zenstruck\Foundry\Instantiator()) + Zenstruck\Foundry\Test\TestState::configure( + instantiator: (new Zenstruck\Foundry\Instantiator()) ->withoutConstructor() ->allowExtraAttributes() - ->alwaysForceProperties() + ->alwaysForceProperties(), + faker: Faker\Factory::create('fr_FR') ); - // configure a custom faker - Zenstruck\Foundry\Test\TestState::setFaker(Faker\Factory::create('fr_FR')); +.. note:: - // enable auto-refreshing "globally" - Zenstruck\Foundry\Test\TestState::enableDefaultProxyAutoRefresh(); + `Factories as Services`_ and `Stories as Services`_ with required + constructor arguments are not usable in non-Kernel tests. The container is not available to resolve their dependencies. + The easiest work-around is to make the test an instance of ``Symfony\Bundle\FrameworkBundle\Test\KernelTestCase`` so the + container is available. - // disable auto-refreshing "globally" - Zenstruck\Foundry\Test\TestState::disableDefaultProxyAutoRefresh(); +Using in Unit Tests +~~~~~~~~~~~~~~~~~~~ -.. note:: +When using foundry in unit tests, by using ``PHPUnit\Framework\TestCase``, Foundry simply creates the object instancies +but does not try to persist them (this is also true for any object not managed by Doctrine). - If using `bundle configuration`_ as well, *test-only configuration* will override the - bundle configuration. +You can still configure Foundry statically: -Using without the Bundle -~~~~~~~~~~~~~~~~~~~~~~~~ -The provided bundle is not strictly required to use Foundry for tests. You can have all your factories, stories, and -configuration live in your ``tests/`` directory. You can configure foundry with -`Test-Only Configuration`_. .. _stories: diff --git a/phpunit-dama-doctrine.xml.dist b/phpunit-dama-doctrine.xml.dist index 81a68ab06..1e7a491d4 100644 --- a/phpunit-dama-doctrine.xml.dist +++ b/phpunit-dama-doctrine.xml.dist @@ -12,7 +12,7 @@ - + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b1d4bb9b3..9d1b27c3b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -11,7 +11,7 @@ - + diff --git a/src/Bundle/DependencyInjection/ChainManagerRegistryPass.php b/src/Bundle/DependencyInjection/ChainManagerRegistryPass.php index 383649fab..b9517d415 100644 --- a/src/Bundle/DependencyInjection/ChainManagerRegistryPass.php +++ b/src/Bundle/DependencyInjection/ChainManagerRegistryPass.php @@ -25,10 +25,6 @@ public function process(ContainerBuilder $container): void $managerRegistries[] = new Reference('doctrine_mongodb'); } - if (0 === \count($managerRegistries)) { - throw new \LogicException('Neither doctrine/orm nor mongodb-odm are present.'); - } - $container->getDefinition(ChainManagerRegistry::class) ->setArgument('$managerRegistries', $managerRegistries) ; diff --git a/src/ChainManagerRegistry.php b/src/ChainManagerRegistry.php index 0af03cd75..fbd4c4acd 100644 --- a/src/ChainManagerRegistry.php +++ b/src/ChainManagerRegistry.php @@ -18,10 +18,6 @@ final class ChainManagerRegistry implements ManagerRegistry /** @param list $managerRegistries */ public function __construct(array $managerRegistries) { - if (0 === \count($managerRegistries)) { - throw new \InvalidArgumentException('no manager registry provided'); - } - $this->managerRegistries = $managerRegistries; } diff --git a/src/Test/Factories.php b/src/Test/Factories.php index 11de6e79d..ed12edec7 100644 --- a/src/Test/Factories.php +++ b/src/Test/Factories.php @@ -19,7 +19,7 @@ trait Factories public static function _setUpFactories(): void { if (!\is_subclass_of(static::class, KernelTestCase::class)) { - TestState::bootFoundry(); + TestState::bootFoundryForUnitTest(); return; } diff --git a/src/Test/TestState.php b/src/Test/TestState.php index 02754f2b9..cd83d16b6 100644 --- a/src/Test/TestState.php +++ b/src/Test/TestState.php @@ -9,6 +9,7 @@ use Zenstruck\Foundry\ChainManagerRegistry; use Zenstruck\Foundry\Configuration; use Zenstruck\Foundry\Factory; +use Zenstruck\Foundry\Instantiator; use Zenstruck\Foundry\StoryManager; /** @@ -28,23 +29,43 @@ final class TestState /** @var callable[] */ private static $globalStates = []; + /** + * @deprecated Use TestState::configure() + */ public static function setInstantiator(callable $instantiator): void { + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of TestState::setInstantiator() is deprecated. Please use TestState::configure().'); + self::$instantiator = $instantiator; } + /** + * @deprecated Use TestState::configure() + */ public static function setFaker(Faker\Generator $faker): void { + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of TestState::setFaker() is deprecated. Please use TestState::configure().'); + self::$faker = $faker; } + /** + * @deprecated Use bundle configuration + */ public static function enableDefaultProxyAutoRefresh(): void { + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of TestState::enableDefaultProxyAutoRefresh() is deprecated. Please use bundle configuration under "auto_refresh_proxies" key.'); + self::$defaultProxyAutoRefresh = true; } + /** + * @deprecated Use bundle configuration + */ public static function disableDefaultProxyAutoRefresh(): void { + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of TestState::disableDefaultProxyAutoRefresh() is deprecated. Please use bundle configuration under "auto_refresh_proxies" key.'); + self::$defaultProxyAutoRefresh = false; } @@ -66,6 +87,9 @@ public static function withoutBundle(): void trigger_deprecation('zenstruck\foundry', '1.4.0', 'TestState::withoutBundle() is deprecated, the bundle is now auto-detected.'); } + /** + * @deprecated Use bundle configuration under "global_state" key + */ public static function addGlobalState(callable $callback): void { trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of TestState::addGlobalState() is deprecated. Please use bundle configuration under "global_state" key.'); @@ -73,9 +97,12 @@ public static function addGlobalState(callable $callback): void self::$globalStates[] = $callback; } - public static function bootFoundry(?Configuration $configuration = null): void + /** + * @internal + */ + public static function bootFoundryForUnitTest(): void { - $configuration = $configuration ?? new Configuration([], [], 'schema', []); + $configuration = new Configuration([], [], 'schema', []); if (self::$instantiator) { $configuration->setInstantiator(self::$instantiator); @@ -91,9 +118,20 @@ public static function bootFoundry(?Configuration $configuration = null): void $configuration->disableDefaultProxyAutoRefresh(); } + self::bootFoundry($configuration); + } + + /** + * @internal + */ + public static function bootFoundry(Configuration $configuration): void + { Factory::boot($configuration); } + /** + * @internal + */ public static function shutdownFoundry(): void { Factory::shutdown(); @@ -123,6 +161,8 @@ public static function bootFromContainer(ContainerInterface $container): void return; } + trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of foundry without the bundle is deprecated and will not be possible anymore in 2.0.'); + $configuration = new Configuration([], [], 'schema', []); try { @@ -150,10 +190,6 @@ public static function initializeChainManagerRegistry(ContainerInterface $contai $managerRegistries[] = $container->get('doctrine_mongodb'); } - if (0 === \count($managerRegistries)) { - throw new \LogicException('Neither doctrine/orm nor doctrine/mongodb-odm are present.'); - } - return new ChainManagerRegistry($managerRegistries); } @@ -176,4 +212,10 @@ public static function flushGlobalState(?GlobalStateRegistry $globalStateRegistr StoryManager::setGlobalState(); } + + public static function configure(?Instantiator $instantiator = null, ?Faker\Generator $faker = null): void + { + self::$instantiator = $instantiator; + self::$faker = $faker; + } } diff --git a/tests/Fixtures/Kernel.php b/tests/Fixtures/Kernel.php index 158ab9244..4110e7709 100644 --- a/tests/Fixtures/Kernel.php +++ b/tests/Fixtures/Kernel.php @@ -29,11 +29,27 @@ class Kernel extends BaseKernel { use MicroKernelTrait; + /** @var string|null */ + private $databaseUrl; + /** @var string|null */ + private $mongoUrl; + + public function __construct( + bool $useDatabase = true + ) { + if ($useDatabase) { + $this->databaseUrl = \getenv('DATABASE_URL') ?: null; + $this->mongoUrl = \getenv('MONGO_URL') ?: null; + } + + parent::__construct('test', true); + } + public function registerBundles(): iterable { yield new FrameworkBundle(); - if (\getenv('DATABASE_URL')) { + if ($this->databaseUrl) { yield new DoctrineBundle(); } @@ -51,11 +67,19 @@ public function registerBundles(): iterable yield new DoctrineMigrationsBundle(); } - if (\getenv('MONGO_URL')) { + if ($this->mongoUrl) { yield new DoctrineMongoDBBundle(); } } + public function getCacheDir(): string + { + return \sprintf( + "{$this->getProjectDir()}/var/cache/test/%s", + \md5(\json_encode([$this->databaseUrl, $this->mongoUrl])) + ); + } + protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader): void { $c->register(Service::class); @@ -78,7 +102,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load 'test' => true, ]); - if (\getenv('DATABASE_URL')) { + if ($this->databaseUrl) { $c->loadFromExtension( 'doctrine', [ @@ -104,7 +128,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load $foundryConfig = ['auto_refresh_proxies' => false]; $globalState = []; - if (\getenv('DATABASE_URL')) { + if ($this->databaseUrl) { $globalState[] = TagStory::class; $globalState[] = TagStoryAsInvokableService::class; @@ -113,7 +137,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load } } - if (\getenv('MONGO_URL') && !\getenv('USE_DAMA_DOCTRINE_TEST_BUNDLE')) { + if ($this->mongoUrl && !\getenv('USE_DAMA_DOCTRINE_TEST_BUNDLE')) { $globalState[] = ODMTagStory::class; $globalState[] = ODMTagStoryAsAService::class; } @@ -131,7 +155,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load ]); } - if (\getenv('MONGO_URL')) { + if ($this->mongoUrl) { $c->loadFromExtension('doctrine_mongodb', [ 'connections' => [ 'default' => ['server' => '%env(resolve:MONGO_URL)%'], diff --git a/tests/Functional/Bundle/Maker/MakerTestCase.php b/tests/Functional/Bundle/Maker/MakerTestCase.php index 7a8733911..f39781c76 100644 --- a/tests/Functional/Bundle/Maker/MakerTestCase.php +++ b/tests/Functional/Bundle/Maker/MakerTestCase.php @@ -18,6 +18,10 @@ public function skipIfNotUsingFoundryBundle(): void if (!\getenv('USE_FOUNDRY_BUNDLE')) { $this->markTestSkipped('ZenstruckFoundryBundle not enabled.'); } + + if (!\getenv('DOCTRINE_URL') && !\getenv('MONGO_URL')) { + $this->markTestSkipped('Generating factories for classes not managed by doctrine is not supported.'); + } } /** diff --git a/tests/Functional/WithDoctrineDisabledKernelTest.php b/tests/Functional/WithDoctrineDisabledKernelTest.php new file mode 100644 index 000000000..f90ffce3d --- /dev/null +++ b/tests/Functional/WithDoctrineDisabledKernelTest.php @@ -0,0 +1,48 @@ +withoutPersisting()->create(['value' => 'test'])->object(); + Assert::that($address)->isInstanceOf(Address::class); + Assert::that($address->getValue())->is('test'); + + $address = AddressFactory::createOne(['value' => 'test'])->object(); + Assert::that($address)->isInstanceOf(Address::class); + Assert::that($address->getValue())->is('test'); + } + + protected static function createKernel(array $options = []): KernelInterface + { + return new Kernel(false); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index eae8bc83e..e12d5b77f 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,10 +1,7 @@ remove(__DIR__.'/../var'); - -TestState::disableDefaultProxyAutoRefresh(); From f43b06708608f9f46691183d4417eebe967fbc94 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Thu, 10 Nov 2022 19:40:33 +0100 Subject: [PATCH 12/13] [chore] clean up CI (#324) --- .github/workflows/ci.yml | 286 ++++-------------- Makefile | 40 +-- docker-compose.yaml | 16 - .../DependencyInjection/Configuration.php | 5 +- .../ZenstruckFoundryExtension.php | 3 +- src/Test/DatabaseResetter.php | 2 +- src/Test/ORMDatabaseResetter.php | 7 +- src/Test/TestState.php | 4 +- tests/Fixtures/Kernel.php | 50 +-- .../Bundle/Maker/MakeFactoryTest.php | 34 ++- .../Functional/Bundle/Maker/MakerTestCase.php | 2 +- .../Functional/FactoryDoctrineCascadeTest.php | 2 +- tests/Functional/FactoryTest.php | 2 +- tests/Functional/ModelFactoryServiceTest.php | 2 +- tests/Functional/ODMAnonymousFactoryTest.php | 2 +- tests/Functional/ODMGlobalStateTest.php | 2 +- tests/Functional/ODMModelFactoryTest.php | 2 +- tests/Functional/ODMProxyTest.php | 2 +- tests/Functional/ODMRepositoryProxyTest.php | 2 +- tests/Functional/ORMAnonymousFactoryTest.php | 2 +- tests/Functional/ORMDatabaseResetterTest.php | 59 ++++ tests/Functional/ORMGlobalStateTest.php | 2 +- tests/Functional/ORMModelFactoryTest.php | 2 +- tests/Functional/ORMProxyTest.php | 2 +- tests/Functional/ORMRepositoryProxyTest.php | 2 +- tests/Functional/StoryTest.php | 2 +- .../WithDoctrineDisabledKernelTest.php | 6 +- tests/Functional/WithMigrationTest.php | 49 +++ 28 files changed, 260 insertions(+), 331 deletions(-) create mode 100644 tests/Functional/ORMDatabaseResetterTest.php create mode 100644 tests/Functional/WithMigrationTest.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06dd30ad3..268cc23c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,35 @@ on: jobs: tests: - name: PHP ${{ matrix.php }}, SF ${{ matrix.symfony }} - ${{ matrix.deps }} + name: PHP ${{ matrix.php }}, SF ${{ matrix.symfony }} - ${{ matrix.deps }} ${{ matrix.use-orm == '1' && '- ORM' || '' }} ${{ matrix.use-odm == '1' && '- ODM' || '' }} ${{ matrix.use-dama == '1' && '- DAMA' || '' }} runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: [7.2, 7.4, 8.0, 8.1] + symfony: [4.4.*, 5.4.*, 6.0.*, 6.1.*] + deps: [highest] + use-orm: [1] + use-odm: [1] + use-dama: [1] + exclude: + - {use-orm: 0, use-odm: 0} # tested directly in a test case + - {use-orm: 0, use-dama: 1} # cannot happen + # conflicts + - {php: 7.2, symfony: 6.0.*} + - {php: 7.2, symfony: 6.1.*} + - {php: 7.4, symfony: 6.0.*} + - {php: 7.4, symfony: 6.1.*} + - {php: 8.0, symfony: 6.1.*} + include: + - {php: 7.2, symfony: 4.4.*, use-orm: 1, use-odm: 0, use-dama: 0, deps: lowest} + - {php: 7.2, symfony: 4.4.*, use-orm: 1, use-odm: 1, use-dama: 0, deps: lowest} + - {php: 7.2, symfony: 4.4.*, use-orm: 0, use-odm: 1, use-dama: 0, deps: lowest} + - {php: 8.1, symfony: 6.1.*, use-orm: 1, use-odm: 0, use-dama: 0, deps: highest} + - {php: 8.1, symfony: 6.1.*, use-orm: 1, use-odm: 1, use-dama: 0, deps: highest} + - {php: 8.1, symfony: 6.1.*, use-orm: 1, use-odm: 0, use-dama: 1, deps: highest} + - {php: 8.1, symfony: 6.1.*, use-orm: 0, use-odm: 1, use-dama: 0, deps: highest} + services: mysql: image: mysql:5.7 @@ -18,37 +45,15 @@ jobs: ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 - postgres: - image: postgres:11 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: 1234 - ports: - - 5432:5432 - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 mongo: image: mongo:4 ports: - 27017:27017 - strategy: - matrix: - php: [7.4, 8.0, 8.1] - symfony: [4.4.*, 5.4.*] - deps: [highest] - include: - - php: 7.2 - symfony: '*' - deps: lowest - versions: lowest - - php: 8.0 - symfony: 6.0.* - deps: highest - - php: 8.1 - symfony: 6.0.* - deps: highest - - php: 8.1 - symfony: 6.1.* - deps: highest + + env: + DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 + MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb + steps: - name: Checkout code uses: actions/checkout@v2.3.3 @@ -72,107 +77,17 @@ jobs: env: SYMFONY_REQUIRE: ${{ matrix.symfony }} - - name: 'Test: MySQL' - run: vendor/bin/simple-phpunit -v - env: - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Test: MySQL, FoundryBundle' - run: vendor/bin/simple-phpunit -v - env: - USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Test: MySQL, DAMABundle' - run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist - env: - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Test: MySQL, FoundryBundle, DAMABundle' - run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist - env: - USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Test: MySQL, DoctrineMigrationsBundle' - run: vendor/bin/simple-phpunit -v - env: - USE_MIGRATIONS: 1 - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Test: MySQL, DoctrineMigrationsBundle, DAMABundle' - run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist - env: - USE_MIGRATIONS: 1 - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Test: PostgreSQL' - run: vendor/bin/simple-phpunit -v - env: - DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - - - name: 'Test: PostgreSQL, FoundryBundle' - run: vendor/bin/simple-phpunit -v - env: - USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - -# - name: 'Test: PostgreSQL, DAMABundle' -# run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist -# env: -# DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - -# - name: 'Test: PostgreSQL, FoundryBundle, DAMABundle' -# run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist -# env: -# USE_FOUNDRY_BUNDLE: 1 -# DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - - - name: 'Test: SQLite' - run: vendor/bin/simple-phpunit -v - env: - DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - - - name: 'Test: SQLite, FoundryBundle' - run: vendor/bin/simple-phpunit -v - env: - USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - - - name: 'Test: SQLite, DAMABundle' - run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist - env: - DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - - - name: 'Test: SQLite, FoundryBundle, DAMABundle' - run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist - env: -# USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - - - name: 'Test: MySQL, Mongo' - run: vendor/bin/simple-phpunit -v - env: - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb + - name: 'Test' + run: | + if [ "${{ matrix.use-dama }}" == "1" ]; then + CONFIGURATION="--configuration phpunit-dama-doctrine.xml.dist" + fi - - name: 'Test: MySQL, Mongo, FoundryBundle' - run: vendor/bin/simple-phpunit -v + vendor/bin/simple-phpunit -v ${CONFIGURATION} env: + USE_ORM: ${{ matrix.use-orm }} + USE_ODM: ${{ matrix.use-odm }} USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - - - name: 'Test: MySQL, Mongo, DAMABundle' - run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist - env: - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - - - name: 'Test: Mongo standalone' - run: vendor/bin/simple-phpunit -v - env: - MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb code-coverage: name: Code Coverage @@ -185,18 +100,15 @@ jobs: ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 - postgres: - image: postgres:11 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: 1234 - ports: - - 5432:5432 - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 mongo: image: mongo:4 ports: - 27017:27017 + + env: + DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 + MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb + steps: - name: Checkout code uses: actions/checkout@v2.3.3 @@ -207,7 +119,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 extensions: pgsql, sqlite coverage: xdebug ini-values: xdebug.mode=coverage @@ -216,108 +128,14 @@ jobs: uses: ramsey/composer-install@v1 with: composer-options: --prefer-dist + dependency-versions: "highest" - - name: 'Coverage: MySQL' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql.clover - env: - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Coverage: MySQL, FoundryBundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-foundry.clover + - name: 'Coverage' + run: vendor/bin/simple-phpunit -v --configuration phpunit-dama-doctrine.xml.dist --coverage-text --coverage-clover=foundry.clover env: + USE_ORM: 1 + USE_ODM: 1 USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Coverage: MySQL, DAMABundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-dama.clover --configuration phpunit-dama-doctrine.xml.dist - env: - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Coverage: MySQL, FoundryBundle, DAMABundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-foundry-dama.clover --configuration phpunit-dama-doctrine.xml.dist - env: - USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Test: MySQL, DoctrineMigrationsBundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-migrations.clover - env: - USE_MIGRATIONS: 1 - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Test: MySQL, DoctrineMigrationsBundle, DAMABundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-migrations-dama.clover --configuration phpunit-dama-doctrine.xml.dist - env: - USE_MIGRATIONS: 1 - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - - - name: 'Coverage: PostgreSQL' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=postgres.clover - env: - DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - - - name: 'Coverage: PostgreSQL, FoundryBundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=postgres-foundry.clover - env: - USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - -# - name: 'Coverage: PostgreSQL, DAMABundle' -# run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=postgres-dama.clover --configuration phpunit-dama-doctrine.xml.dist -# env: -# DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - -# - name: 'Coverage: PostgreSQL, FoundryBundle, DAMABundle' -# run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=postgres-foundry-dama.clover --configuration phpunit-dama-doctrine.xml.dist -# env: -# USE_FOUNDRY_BUNDLE: 1 -# DATABASE_URL: postgresql://postgres:1234@127.0.0.1:5432/zenstruck_foundry?charset=utf8 - - - name: 'Coverage: SQLite' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=sqlite.clover - env: - DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - - - name: 'Coverage: SQLite, FoundryBundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=sqlite-foundry.clover - env: - USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - - - name: 'Coverage: SQLite, DAMABundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=sqlite-dama.clover --configuration phpunit-dama-doctrine.xml.dist - env: - DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - - - name: 'Coverage: SQLite, FoundryBundle, DAMABundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=sqlite-foundry-dama.clover --configuration phpunit-dama-doctrine.xml.dist - env: -# USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: sqlite:///%kernel.cache_dir%/app.db - - - name: 'Test: MySQL, Mongo' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-mongo.clover - env: - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - - - name: 'Test: MySQL, Mongo, FoundryBundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-mongo-foundry.clover - env: - USE_FOUNDRY_BUNDLE: 1 - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - - - name: 'Test: MySQL, Mongo, DAMABundle' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mysql-mongo-dama.clover --configuration phpunit-dama-doctrine.xml.dist - env: - DATABASE_URL: mysql://root:1234@127.0.0.1:3306/zenstruck_foundry?serverVersion=5.7 - MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - - - name: 'Test: Mongo standalone' - run: vendor/bin/simple-phpunit -v --coverage-text --coverage-clover=mongo.clover - env: - MONGO_URL: mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb - name: Publish coverage report to Codecov uses: codecov/codecov-action@v1 diff --git a/Makefile b/Makefile index ab19a6205..bc04dc30c 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,7 @@ .PHONY: $(filter-out vendor bin/tools/psalm/vendor bin/tools/cs-fixer/vendor,$(MAKECMDGOALS)) MYSQL_URL="mysql://root:root@mysql:3306/zenstruck_foundry?charset=utf8" -POSTGRESQL_URL="postgresql://root:root@postgres:5432/zenstruck_foundry?charset=utf8&serverVersion=13" MONGO_URL="mongodb://mongo:mongo@mongo:27017/mongo?compressors=disabled&gssapiServiceName=mongodb&authSource=mongo" -SQLITE_URL="sqlite://./var/app.db" ifeq ($(shell docker --help | grep "compose"),) DOCKER_COMPOSE=docker-compose @@ -13,9 +11,9 @@ endif INTERACTIVE:=$(shell [ -t 0 ] && echo 1) ifdef INTERACTIVE - DC_EXEC=$(DOCKER_COMPOSE) exec + DC_EXEC=$(DOCKER_COMPOSE) exec -e USE_FOUNDRY_BUNDLE=1 -e DATABASE_URL=${MYSQL_URL} -e MONGO_URL=${MONGO_URL} else - DC_EXEC=$(DOCKER_COMPOSE) exec -T + DC_EXEC=$(DOCKER_COMPOSE) exec -e USE_FOUNDRY_BUNDLE=1 -e DATABASE_URL=${MYSQL_URL} -e MONGO_URL=${MONGO_URL} -T endif DOCKER_PHP=${DC_EXEC} php @@ -45,27 +43,15 @@ validate: fixcs sca test-full database-validate-mapping ### Run fixcs, sca, full test-full: docker-start vendor ### Run full PHPunit (MySQL + Mongo) @$(eval filter ?= '.') - @${DC_EXEC} -e USE_FOUNDRY_BUNDLE=1 -e DATABASE_URL=${MYSQL_URL} -e MONGO_URL=${MONGO_URL} php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) - -test-fast: docker-start vendor ### Run PHPunit with SQLite - @$(eval filter ?= '.') -ifeq ($(shell which docker),) - @DATABASE_URL=${SQLITE_URL} php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) -else - @${DC_EXEC} -e DATABASE_URL=${SQLITE_URL} php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) -endif + @${DC_EXEC} -e USE_ORM=1 -e USE_ODM=1 php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) test-mysql: docker-start vendor ### Run PHPunit with mysql @$(eval filter ?= '.') - @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) - -test-postgresql: docker-start vendor ### Run PHPunit with postgreSQL - @$(eval filter ?= '.') - @${DC_EXEC} -e DATABASE_URL=${POSTGRESQL_URL} php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) + @${DC_EXEC} -e USE_ORM=1 php vendor/bin/simple-phpunit --configuration phpunit-dama-doctrine.xml.dist --filter=$(filter) test-mongo: docker-start vendor ### Run PHPunit with Mongo @$(eval filter ?= '.') - @${DC_EXEC} -e USE_FOUNDRY_BUNDLE=1 -e MONGO_URL=${MONGO_URL} php vendor/bin/simple-phpunit --configuration phpunit.xml.dist --filter=$(filter) + @${DC_EXEC} -e USE_ODM=1 php vendor/bin/simple-phpunit --configuration phpunit.xml.dist --filter=$(filter) fixcs: docker-start bin/tools/cs-fixer/vendor ### Run PHP CS-Fixer @${DOCKER_PHP} bin/tools/cs-fixer/vendor/friendsofphp/php-cs-fixer/php-cs-fixer --no-interaction --diff -v fix @@ -80,18 +66,18 @@ bin/tools/psalm/vendor: vendor bin/tools/psalm/composer.json bin/tools/psalm/com @${DOCKER_PHP} composer bin psalm install database-generate-migration: docker-start vendor ### Generate new migration based on mapping in Zenstruck\Foundry\Tests\Fixtures\Entity - @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:migrate --no-interaction --allow-no-migration # first, let's load into db existing migrations - @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:diff --no-interaction - @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:migrate --no-interaction # load the new migration + @${DOCKER_PHP} vendor/bin/doctrine-migrations migrations:migrate --no-interaction --allow-no-migration # first, let's load into db existing migrations + @${DOCKER_PHP} vendor/bin/doctrine-migrations migrations:diff --no-interaction + @${DOCKER_PHP} vendor/bin/doctrine-migrations migrations:migrate --no-interaction # load the new migration database-validate-mapping: docker-start vendor database-drop-schema ### Validate mapping in Zenstruck\Foundry\Tests\Fixtures\Entity - @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:migrate --no-interaction --allow-no-migration - @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php bin/doctrine orm:validate-schema + @${DOCKER_PHP} vendor/bin/doctrine-migrations migrations:migrate --no-interaction --allow-no-migration + @${DOCKER_PHP} bin/doctrine orm:validate-schema database-drop-schema: docker-start vendor ### Drop database schema - @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php bin/doctrine orm:schema-tool:drop --force - @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php vendor/bin/doctrine-migrations migrations:sync-metadata-storage # prevents the next command to fail if migrations table does not exist - @${DC_EXEC} -e DATABASE_URL=${MYSQL_URL} php bin/doctrine dbal:run-sql "TRUNCATE doctrine_migration_versions" --quiet + @${DOCKER_PHP} bin/doctrine orm:schema-tool:drop --force + @${DOCKER_PHP} vendor/bin/doctrine-migrations migrations:sync-metadata-storage # prevents the next command to fail if migrations table does not exist + @${DOCKER_PHP} bin/doctrine dbal:run-sql "TRUNCATE doctrine_migration_versions" --quiet vendor: composer.json $(wildcard composer.lock) @${DOCKER_PHP} composer update diff --git a/docker-compose.yaml b/docker-compose.yaml index d2457b835..5f03ad3d0 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -9,8 +9,6 @@ services: depends_on: mysql: condition: service_healthy - postgres: - condition: service_healthy mongo: condition: service_healthy volumes: @@ -34,20 +32,6 @@ services: retries: 60 interval: 2s - postgres: - container_name: foundry_postgres - image: postgres:13 - environment: - POSTGRES_DB: zenstruck_foundry - POSTGRES_PASSWORD: root - POSTGRES_USER: root - ports: - - ${POSTGRES_PORT:-5432}:5432 - healthcheck: - test: /usr/bin/pg_isready - timeout: 10s - retries: 10 - mongo: container_name: foundry_mongo image: mongo:4.4 diff --git a/src/Bundle/DependencyInjection/Configuration.php b/src/Bundle/DependencyInjection/Configuration.php index 5036f1e02..f6df15146 100644 --- a/src/Bundle/DependencyInjection/Configuration.php +++ b/src/Bundle/DependencyInjection/Configuration.php @@ -4,6 +4,7 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; +use Zenstruck\Foundry\Test\ORMDatabaseResetter; /** * @author Kevin Bond @@ -111,8 +112,8 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->enumNode('reset_mode') ->info('Whether to use doctrine:schema:update or migrations when resetting schema.') - ->values(['schema', 'migrate']) - ->defaultValue('schema') + ->values([ORMDatabaseResetter::RESET_MODE_SCHEMA, ORMDatabaseResetter::RESET_MODE_MIGRATE]) + ->defaultValue(ORMDatabaseResetter::RESET_MODE_SCHEMA) ->end() ->end() ->end() diff --git a/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php b/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php index 7c81c4e90..052e7f0fa 100644 --- a/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php +++ b/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php @@ -14,6 +14,7 @@ use Zenstruck\Foundry\Configuration; use Zenstruck\Foundry\ModelFactory; use Zenstruck\Foundry\Story; +use Zenstruck\Foundry\Test\ORMDatabaseResetter; /** * @author Kevin Bond @@ -110,7 +111,7 @@ private function configureDatabaseResetter(array $config, ContainerBuilder $cont $configurationDefinition->setArgument('$ormConnectionsToReset', $config['orm']['connections'] ?? []); $configurationDefinition->setArgument('$ormObjectManagersToReset', $config['orm']['object_managers'] ?? []); - $configurationDefinition->setArgument('$ormResetMode', $config['orm']['reset_mode'] ?? 'schema'); + $configurationDefinition->setArgument('$ormResetMode', $config['orm']['reset_mode'] ?? ORMDatabaseResetter::RESET_MODE_SCHEMA); $configurationDefinition->setArgument('$odmObjectManagersToReset', $config['odm']['object_managers'] ?? []); } diff --git a/src/Test/DatabaseResetter.php b/src/Test/DatabaseResetter.php index bfe7fa9ab..0b3854a80 100644 --- a/src/Test/DatabaseResetter.php +++ b/src/Test/DatabaseResetter.php @@ -105,7 +105,7 @@ private static function createORMDatabaseResetter(Application $application, Kern $container->get('doctrine'), $configuration ? $configuration->getOrmConnectionsToReset() : [], $configuration ? $configuration->getOrmObjectManagersToReset() : [], - $configuration ? $configuration->getOrmResetMode() : 'schema' + $configuration ? $configuration->getOrmResetMode() : ORMDatabaseResetter::RESET_MODE_SCHEMA ); } diff --git a/src/Test/ORMDatabaseResetter.php b/src/Test/ORMDatabaseResetter.php index 69ac63233..55d83583d 100644 --- a/src/Test/ORMDatabaseResetter.php +++ b/src/Test/ORMDatabaseResetter.php @@ -10,6 +10,9 @@ */ final class ORMDatabaseResetter extends AbstractSchemaResetter { + public const RESET_MODE_SCHEMA = 'schema'; + public const RESET_MODE_MIGRATE = 'migrate'; + /** @var Application */ private $application; /** @var ManagerRegistry */ @@ -146,9 +149,9 @@ private function isResetUsingMigrations(): bool if (isset($_SERVER['FOUNDRY_RESET_MODE'])) { trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of environment variable "FOUNDRY_RESET_MODE" is deprecated. Please use bundle configuration: "database_resetter.orm.reset_mode: true".'); - return 'migrate' === $_SERVER['FOUNDRY_RESET_MODE']; + return self::RESET_MODE_MIGRATE === $_SERVER['FOUNDRY_RESET_MODE']; } - return 'migrate' === $this->resetMode; + return self::RESET_MODE_MIGRATE === $this->resetMode; } } diff --git a/src/Test/TestState.php b/src/Test/TestState.php index cd83d16b6..6c44285a8 100644 --- a/src/Test/TestState.php +++ b/src/Test/TestState.php @@ -102,7 +102,7 @@ public static function addGlobalState(callable $callback): void */ public static function bootFoundryForUnitTest(): void { - $configuration = new Configuration([], [], 'schema', []); + $configuration = new Configuration([], [], ORMDatabaseResetter::RESET_MODE_SCHEMA, []); if (self::$instantiator) { $configuration->setInstantiator(self::$instantiator); @@ -163,7 +163,7 @@ public static function bootFromContainer(ContainerInterface $container): void trigger_deprecation('zenstruck\foundry', '1.23', 'Usage of foundry without the bundle is deprecated and will not be possible anymore in 2.0.'); - $configuration = new Configuration([], [], 'schema', []); + $configuration = new Configuration([], [], ORMDatabaseResetter::RESET_MODE_SCHEMA, []); try { $configuration->setManagerRegistry(self::initializeChainManagerRegistry($container)); diff --git a/tests/Fixtures/Kernel.php b/tests/Fixtures/Kernel.php index 4110e7709..6a83203d7 100644 --- a/tests/Fixtures/Kernel.php +++ b/tests/Fixtures/Kernel.php @@ -13,6 +13,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\Routing\RouteCollectionBuilder; +use Zenstruck\Foundry\Test\ORMDatabaseResetter; use Zenstruck\Foundry\Tests\Fixtures\Factories\CategoryFactory; use Zenstruck\Foundry\Tests\Fixtures\Factories\CategoryServiceFactory; use Zenstruck\Foundry\Tests\Fixtures\Stories\ODMTagStory; @@ -29,27 +30,28 @@ class Kernel extends BaseKernel { use MicroKernelTrait; - /** @var string|null */ - private $databaseUrl; - /** @var string|null */ - private $mongoUrl; - - public function __construct( - bool $useDatabase = true - ) { - if ($useDatabase) { - $this->databaseUrl = \getenv('DATABASE_URL') ?: null; - $this->mongoUrl = \getenv('MONGO_URL') ?: null; - } + /** @var bool */ + private $enableDoctrine = true; + /** @var string */ + private $ormResetMode = ORMDatabaseResetter::RESET_MODE_SCHEMA; + + public static function create( + bool $enableDoctrine = true, + string $ormResetMode = ORMDatabaseResetter::RESET_MODE_SCHEMA + ): self { + $kernel = new self('test', true); + + $kernel->enableDoctrine = $enableDoctrine; + $kernel->ormResetMode = $ormResetMode; - parent::__construct('test', true); + return $kernel; } public function registerBundles(): iterable { yield new FrameworkBundle(); - if ($this->databaseUrl) { + if ($this->enableDoctrine && \getenv('USE_ORM')) { yield new DoctrineBundle(); } @@ -63,11 +65,11 @@ public function registerBundles(): iterable yield new DAMADoctrineTestBundle(); } - if (\getenv('USE_MIGRATIONS')) { + if (ORMDatabaseResetter::RESET_MODE_MIGRATE === $this->ormResetMode && $this->enableDoctrine && \getenv('USE_ORM')) { yield new DoctrineMigrationsBundle(); } - if ($this->mongoUrl) { + if ($this->enableDoctrine && \getenv('USE_ODM')) { yield new DoctrineMongoDBBundle(); } } @@ -76,7 +78,7 @@ public function getCacheDir(): string { return \sprintf( "{$this->getProjectDir()}/var/cache/test/%s", - \md5(\json_encode([$this->databaseUrl, $this->mongoUrl])) + \md5(\json_encode([$this->enableDoctrine, $this->ormResetMode])) ); } @@ -102,7 +104,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load 'test' => true, ]); - if ($this->databaseUrl) { + if ($this->enableDoctrine && \getenv('USE_ORM')) { $c->loadFromExtension( 'doctrine', [ @@ -128,16 +130,14 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load $foundryConfig = ['auto_refresh_proxies' => false]; $globalState = []; - if ($this->databaseUrl) { + if ($this->enableDoctrine && \getenv('USE_ORM')) { $globalState[] = TagStory::class; $globalState[] = TagStoryAsInvokableService::class; - if (\getenv('USE_MIGRATIONS')) { - $foundryConfig['database_resetter'] = ['orm' => ['reset_mode' => 'migrate']]; - } + $foundryConfig['database_resetter'] = ['orm' => ['reset_mode' => $this->ormResetMode]]; } - if ($this->mongoUrl && !\getenv('USE_DAMA_DOCTRINE_TEST_BUNDLE')) { + if ($this->enableDoctrine && \getenv('USE_ODM') && !\getenv('USE_DAMA_DOCTRINE_TEST_BUNDLE')) { $globalState[] = ODMTagStory::class; $globalState[] = ODMTagStoryAsAService::class; } @@ -147,7 +147,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load $c->loadFromExtension('zenstruck_foundry', $foundryConfig); } - if (\getenv('USE_MIGRATIONS')) { + if (ORMDatabaseResetter::RESET_MODE_MIGRATE === $this->ormResetMode) { $c->loadFromExtension('doctrine_migrations', [ 'migrations_paths' => [ 'Zenstruck\Foundry\Tests\Fixtures\Migrations' => '%kernel.project_dir%/tests/Fixtures/Migrations', @@ -155,7 +155,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load ]); } - if ($this->mongoUrl) { + if ($this->enableDoctrine && \getenv('USE_ODM')) { $c->loadFromExtension('doctrine_mongodb', [ 'connections' => [ 'default' => ['server' => '%env(resolve:MONGO_URL)%'], diff --git a/tests/Functional/Bundle/Maker/MakeFactoryTest.php b/tests/Functional/Bundle/Maker/MakeFactoryTest.php index aa98f541b..84d4d14be 100644 --- a/tests/Functional/Bundle/Maker/MakeFactoryTest.php +++ b/tests/Functional/Bundle/Maker/MakeFactoryTest.php @@ -20,6 +20,10 @@ final class MakeFactoryTest extends MakerTestCase */ public function can_create_factory(): void { + if (!\getenv('USE_ORM')) { + self::markTestSkipped('doctrine/orm not enabled.'); + } + $tester = new CommandTester((new Application(self::bootKernel()))->find('make:factory')); $this->assertFileDoesNotExist(self::tempFile('src/Factory/CategoryFactory.php')); @@ -95,6 +99,10 @@ protected static function getClass(): string */ public function can_create_factory_interactively(): void { + if (!\getenv('USE_ORM')) { + self::markTestSkipped('doctrine/orm not enabled.'); + } + $tester = new CommandTester((new Application(self::bootKernel()))->find('make:factory')); $this->assertFileDoesNotExist(self::tempFile('src/Factory/TagFactory.php')); @@ -174,6 +182,10 @@ protected static function getClass(): string */ public function can_create_factory_in_test_dir(): void { + if (!\getenv('USE_ORM')) { + self::markTestSkipped('doctrine/orm not enabled.'); + } + $tester = new CommandTester((new Application(self::bootKernel()))->find('make:factory')); $this->assertFileDoesNotExist(self::tempFile('tests/Factory/CategoryFactory.php')); @@ -249,6 +261,10 @@ protected static function getClass(): string */ public function can_create_factory_in_test_dir_interactively(): void { + if (!\getenv('USE_ORM')) { + self::markTestSkipped('doctrine/orm not enabled.'); + } + $tester = new CommandTester((new Application(self::bootKernel()))->find('make:factory')); $this->assertFileDoesNotExist(self::tempFile('tests/Factory/TagFactory.php')); @@ -349,6 +365,10 @@ public function invalid_entity_throws_exception(): void */ public function can_customize_namespace(): void { + if (!\getenv('USE_ORM')) { + self::markTestSkipped('doctrine/orm not enabled.'); + } + $tester = new CommandTester((new Application(self::bootKernel()))->find('make:factory')); $expectedFile = self::tempFile('src/My/Namespace/TagFactory.php'); @@ -366,6 +386,10 @@ public function can_customize_namespace(): void */ public function can_customize_namespace_with_test_flag(): void { + if (!\getenv('USE_ORM')) { + self::markTestSkipped('doctrine/orm not enabled.'); + } + $tester = new CommandTester((new Application(self::bootKernel()))->find('make:factory')); $expectedFile = self::tempFile('tests/My/Namespace/TagFactory.php'); @@ -383,6 +407,10 @@ public function can_customize_namespace_with_test_flag(): void */ public function can_customize_namespace_with_root_namespace_prefix(): void { + if (!\getenv('USE_ORM')) { + self::markTestSkipped('doctrine/orm not enabled.'); + } + $tester = new CommandTester((new Application(self::bootKernel()))->find('make:factory')); $expectedFile = self::tempFile('src/My/Namespace/TagFactory.php'); @@ -400,6 +428,10 @@ public function can_customize_namespace_with_root_namespace_prefix(): void */ public function can_customize_namespace_with_test_flag_with_root_namespace_prefix(): void { + if (!\getenv('USE_ORM')) { + self::markTestSkipped('doctrine/orm not enabled.'); + } + $tester = new CommandTester((new Application(self::bootKernel()))->find('make:factory')); $expectedFile = self::tempFile('tests/My/Namespace/TagFactory.php'); @@ -441,7 +473,7 @@ public function can_create_factory_with_all_interactively(): void */ public function can_create_factory_for_odm(string $class, string $file): void { - if (false === \getenv('MONGO_URL')) { + if (!\getenv('USE_ODM')) { self::markTestSkipped('doctrine/odm not enabled.'); } diff --git a/tests/Functional/Bundle/Maker/MakerTestCase.php b/tests/Functional/Bundle/Maker/MakerTestCase.php index f39781c76..86adc9f02 100644 --- a/tests/Functional/Bundle/Maker/MakerTestCase.php +++ b/tests/Functional/Bundle/Maker/MakerTestCase.php @@ -19,7 +19,7 @@ public function skipIfNotUsingFoundryBundle(): void $this->markTestSkipped('ZenstruckFoundryBundle not enabled.'); } - if (!\getenv('DOCTRINE_URL') && !\getenv('MONGO_URL')) { + if (!\getenv('USE_ORM') && !\getenv('USE_ODM')) { $this->markTestSkipped('Generating factories for classes not managed by doctrine is not supported.'); } } diff --git a/tests/Functional/FactoryDoctrineCascadeTest.php b/tests/Functional/FactoryDoctrineCascadeTest.php index d20ffda20..5358015d1 100644 --- a/tests/Functional/FactoryDoctrineCascadeTest.php +++ b/tests/Functional/FactoryDoctrineCascadeTest.php @@ -24,7 +24,7 @@ final class FactoryDoctrineCascadeTest extends KernelTestCase protected function setUp(): void { - if (false === \getenv('DATABASE_URL')) { + if (!\getenv('USE_ORM')) { self::markTestSkipped('doctrine/orm not enabled.'); } } diff --git a/tests/Functional/FactoryTest.php b/tests/Functional/FactoryTest.php index 4e3d0b76e..407cf2ef8 100644 --- a/tests/Functional/FactoryTest.php +++ b/tests/Functional/FactoryTest.php @@ -22,7 +22,7 @@ final class FactoryTest extends KernelTestCase protected function setUp(): void { - if (false === \getenv('DATABASE_URL')) { + if (!\getenv('USE_ORM')) { self::markTestSkipped('doctrine/orm not enabled.'); } } diff --git a/tests/Functional/ModelFactoryServiceTest.php b/tests/Functional/ModelFactoryServiceTest.php index 75165b838..28f9ea131 100644 --- a/tests/Functional/ModelFactoryServiceTest.php +++ b/tests/Functional/ModelFactoryServiceTest.php @@ -17,7 +17,7 @@ final class ModelFactoryServiceTest extends KernelTestCase protected function setUp(): void { - if (false === \getenv('DATABASE_URL')) { + if (!\getenv('USE_ORM')) { self::markTestSkipped('doctrine/orm not enabled.'); } } diff --git a/tests/Functional/ODMAnonymousFactoryTest.php b/tests/Functional/ODMAnonymousFactoryTest.php index 3009643f8..eedf03a8b 100644 --- a/tests/Functional/ODMAnonymousFactoryTest.php +++ b/tests/Functional/ODMAnonymousFactoryTest.php @@ -11,7 +11,7 @@ final class ODMAnonymousFactoryTest extends AnonymousFactoryTest { protected function setUp(): void { - if (false === \getenv('MONGO_URL')) { + if (!\getenv('USE_ODM')) { self::markTestSkipped('doctrine/odm not enabled.'); } } diff --git a/tests/Functional/ODMGlobalStateTest.php b/tests/Functional/ODMGlobalStateTest.php index 96892fd03..e93896660 100644 --- a/tests/Functional/ODMGlobalStateTest.php +++ b/tests/Functional/ODMGlobalStateTest.php @@ -9,7 +9,7 @@ final class ODMGlobalStateTest extends GlobalStateTest { protected function setUp(): void { - if (!\getenv('MONGO_URL')) { + if (!\getenv('USE_ODM')) { self::markTestSkipped('doctrine/odm not enabled.'); } diff --git a/tests/Functional/ODMModelFactoryTest.php b/tests/Functional/ODMModelFactoryTest.php index 83079969c..7db9bba6e 100644 --- a/tests/Functional/ODMModelFactoryTest.php +++ b/tests/Functional/ODMModelFactoryTest.php @@ -18,7 +18,7 @@ final class ODMModelFactoryTest extends ModelFactoryTest { protected function setUp(): void { - if (false === \getenv('MONGO_URL')) { + if (!\getenv('USE_ODM')) { self::markTestSkipped('doctrine/odm not enabled.'); } } diff --git a/tests/Functional/ODMProxyTest.php b/tests/Functional/ODMProxyTest.php index b9f4c71a8..78d7c70c1 100644 --- a/tests/Functional/ODMProxyTest.php +++ b/tests/Functional/ODMProxyTest.php @@ -12,7 +12,7 @@ final class ODMProxyTest extends ProxyTest { protected function setUp(): void { - if (false === \getenv('MONGO_URL')) { + if (!\getenv('USE_ODM')) { self::markTestSkipped('doctrine/odm not enabled.'); } } diff --git a/tests/Functional/ODMRepositoryProxyTest.php b/tests/Functional/ODMRepositoryProxyTest.php index d64da57a3..a8f376c67 100644 --- a/tests/Functional/ODMRepositoryProxyTest.php +++ b/tests/Functional/ODMRepositoryProxyTest.php @@ -12,7 +12,7 @@ final class ODMRepositoryProxyTest extends RepositoryProxyTest { protected function setUp(): void { - if (false === \getenv('MONGO_URL')) { + if (!\getenv('USE_ODM')) { self::markTestSkipped('doctrine/odm not enabled.'); } } diff --git a/tests/Functional/ORMAnonymousFactoryTest.php b/tests/Functional/ORMAnonymousFactoryTest.php index 0af201b21..34614c89f 100644 --- a/tests/Functional/ORMAnonymousFactoryTest.php +++ b/tests/Functional/ORMAnonymousFactoryTest.php @@ -11,7 +11,7 @@ final class ORMAnonymousFactoryTest extends AnonymousFactoryTest { protected function setUp(): void { - if (false === \getenv('DATABASE_URL')) { + if (!\getenv('USE_ORM')) { self::markTestSkipped('doctrine/orm not enabled.'); } } diff --git a/tests/Functional/ORMDatabaseResetterTest.php b/tests/Functional/ORMDatabaseResetterTest.php new file mode 100644 index 000000000..9112b0db3 --- /dev/null +++ b/tests/Functional/ORMDatabaseResetterTest.php @@ -0,0 +1,59 @@ + $resetMode]); + $kernel->boot(); + $container = $kernel->getContainer(); + + $application = new Application($kernel); + $application->setAutoExit(false); + + $resetter = new ORMDatabaseResetter($application, $container->get('doctrine'), [], [], $resetMode); + + $resetter->resetDatabase(); + + $validator = new SchemaValidator($container->get('doctrine')->getManager()); + self::assertEmpty($validator->validateMapping()); + self::assertTrue($validator->schemaInSyncWithMetadata()); + } + + public function databaseResetterProvider(): iterable + { + yield [ORMDatabaseResetter::RESET_MODE_SCHEMA]; + yield [ORMDatabaseResetter::RESET_MODE_MIGRATE]; + } + + protected static function createKernel(array $options = []): KernelInterface + { + return Kernel::create(true, $options['ormResetMode']); + } +} diff --git a/tests/Functional/ORMGlobalStateTest.php b/tests/Functional/ORMGlobalStateTest.php index 3e25c7950..4c7359c0b 100644 --- a/tests/Functional/ORMGlobalStateTest.php +++ b/tests/Functional/ORMGlobalStateTest.php @@ -9,7 +9,7 @@ final class ORMGlobalStateTest extends GlobalStateTest { protected function setUp(): void { - if (false === \getenv('DATABASE_URL')) { + if (!\getenv('USE_ORM')) { self::markTestSkipped('doctrine/orm not enabled.'); } diff --git a/tests/Functional/ORMModelFactoryTest.php b/tests/Functional/ORMModelFactoryTest.php index 26ddce2b8..7293e9b25 100644 --- a/tests/Functional/ORMModelFactoryTest.php +++ b/tests/Functional/ORMModelFactoryTest.php @@ -23,7 +23,7 @@ final class ORMModelFactoryTest extends ModelFactoryTest { protected function setUp(): void { - if (false === \getenv('DATABASE_URL')) { + if (!\getenv('USE_ORM')) { self::markTestSkipped('doctrine/orm not enabled.'); } } diff --git a/tests/Functional/ORMProxyTest.php b/tests/Functional/ORMProxyTest.php index 4a0097b39..c126c86dc 100644 --- a/tests/Functional/ORMProxyTest.php +++ b/tests/Functional/ORMProxyTest.php @@ -16,7 +16,7 @@ final class ORMProxyTest extends ProxyTest { protected function setUp(): void { - if (false === \getenv('DATABASE_URL')) { + if (!\getenv('USE_ORM')) { self::markTestSkipped('doctrine/orm not enabled.'); } } diff --git a/tests/Functional/ORMRepositoryProxyTest.php b/tests/Functional/ORMRepositoryProxyTest.php index e7f79cdf3..e5e555a37 100644 --- a/tests/Functional/ORMRepositoryProxyTest.php +++ b/tests/Functional/ORMRepositoryProxyTest.php @@ -16,7 +16,7 @@ final class ORMRepositoryProxyTest extends RepositoryProxyTest { protected function setUp(): void { - if (false === \getenv('DATABASE_URL')) { + if (!\getenv('USE_ORM')) { self::markTestSkipped('doctrine/orm not enabled.'); } } diff --git a/tests/Functional/StoryTest.php b/tests/Functional/StoryTest.php index e896674ae..b0e1b55bb 100644 --- a/tests/Functional/StoryTest.php +++ b/tests/Functional/StoryTest.php @@ -22,7 +22,7 @@ final class StoryTest extends KernelTestCase protected function setUp(): void { - if (false === \getenv('DATABASE_URL')) { + if (!\getenv('USE_ORM')) { self::markTestSkipped('doctrine/orm not enabled.'); } } diff --git a/tests/Functional/WithDoctrineDisabledKernelTest.php b/tests/Functional/WithDoctrineDisabledKernelTest.php index f90ffce3d..36bebc8d8 100644 --- a/tests/Functional/WithDoctrineDisabledKernelTest.php +++ b/tests/Functional/WithDoctrineDisabledKernelTest.php @@ -21,10 +21,6 @@ public static function setUpBeforeClass(): void if (\getenv('USE_DAMA_DOCTRINE_TEST_BUNDLE')) { self::markTestSkipped('dama/doctrine-test-bundle should not be enabled.'); } - - if (\getenv('USE_MIGRATIONS')) { - self::markTestSkipped('Cannot use migrations with doctrine disabled.'); - } } /** @@ -43,6 +39,6 @@ public function create_object(): void protected static function createKernel(array $options = []): KernelInterface { - return new Kernel(false); + return Kernel::create(false); } } diff --git a/tests/Functional/WithMigrationTest.php b/tests/Functional/WithMigrationTest.php new file mode 100644 index 000000000..fd1c54e5b --- /dev/null +++ b/tests/Functional/WithMigrationTest.php @@ -0,0 +1,49 @@ +getContainer()->get('doctrine')->getManager()); + self::assertEmpty($validator->validateMapping()); + self::assertTrue($validator->schemaInSyncWithMetadata()); + } + + /** + * @test + */ + public function it_can_use_schema_reset_with_migration(): void + { + PostFactory::createOne(); + PostFactory::assert()->count(1); + } + + protected static function createKernel(array $options = []): KernelInterface + { + // ResetDatabase trait uses @beforeClass annotation which would always be called before setUpBeforeClass() + // but it also calls "static::createKernel()" which we can use to skip test if USE_ORM is false. + if (!\getenv('USE_ORM')) { + self::markTestSkipped('doctrine/orm not enabled.'); + } + + return Kernel::create(true, ORMDatabaseResetter::RESET_MODE_MIGRATE); + } +} From a3f3cdb397c70237ca743192aaeb4a4407f7e1d3 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Thu, 10 Nov 2022 13:43:03 -0500 Subject: [PATCH 13/13] [changelog] update changelog [skip ci] --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5eefc0077..5491ee6fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # CHANGELOG +## [v1.23.0](https://github.com/zenstruck/foundry/releases/tag/v1.23.0) + +November 10th, 2022 - [v1.22.1...v1.23.0](https://github.com/zenstruck/foundry/compare/v1.22.1...v1.23.0) + +* f43b067 [chore] clean up CI (#324) by @nikophil +* 3588274 [feature] Allow to use foundry without Doctrine (#323) by @nikophil +* 7598467 [feature] [remove bundleless usge] configure global state with config (#322) by @nikophil +* e417945 [feature] [remove bundleless usge] use config instead of environment variables (#320) by @nikophil +* cada0cf [feature] pass an index to `FactoryCollection` attributes (#318) by @nikophil +* d120b1c [minor] fix `bamarni/composer-bin-plugin` deprecations (#313) by @kbond +* a3eefc1 [minor] remove branch alias (#313) by @kbond +* cf7d75e [minor] remove unneeded bin script (#310) by @kbond +* cd42774 [feature] add make migrations (#309) by @nikophil +* cb9a4ec [feature] add a docker stack (#306) by @nikophil + ## [v1.22.1](https://github.com/zenstruck/foundry/releases/tag/v1.22.1) September 28th, 2022 - [v1.22.0...v1.22.1](https://github.com/zenstruck/foundry/compare/v1.22.0...v1.22.1)