├── .github └── workflows │ └── phpunit.yml ├── .gitignore ├── LICENSE ├── README.md ├── benchmark └── bechmark.php ├── composer.json ├── composer.lock ├── src ├── Bus │ └── EventBusTrait.php ├── EventEmitter.php ├── EventEmitterExtraArgs.php ├── EventEmitterExtraArgsTrait.php ├── EventEmitterInterface.php ├── EventEmitterTrait.php ├── EventExtraArgsEmitter.php ├── EventHandler.php ├── Filter │ ├── FilterEmitter.php │ ├── FilterEmitterExtraArgsTrait.php │ ├── FilterEmitterInterface.php │ ├── FilterEmitterTrait.php │ └── FilterExtraArgsEmitter.php └── StopPropagation.php └── test ├── benchmarks ├── EventsBench.php └── FilterBench.php ├── phpbench.json ├── phpunit.xml └── unit ├── Bus └── EventBusTraitTest.php ├── Event ├── EventHandlerTest.php ├── EventsEmitterExtraArgsTest.php └── EventsEmitterTest.php └── Filter ├── FiltersEmitterTest.php └── FiltersExtraArgsEmitterTest.php /.github/workflows/phpunit.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions 2 | 3 | name: phpunit 4 | 5 | on: 6 | pull_request: {} 7 | release: {} 8 | push: 9 | branches: [ master ] 10 | 11 | jobs: 12 | tests: 13 | name: unit tests 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | php-versions: [ 8.1, 8.2, 8.3, 8.4 ] 19 | 20 | # permissions: 21 | # contents: read 22 | # pull-requests: write 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: php-actions/composer@v6 27 | - name: phpunit tests ${{ matrix.php-versions }} 28 | uses: php-actions/phpunit@v4 29 | with: 30 | bootstrap: vendor/autoload.php 31 | configuration: test/phpunit.xml 32 | php_extensions: pcov 33 | php_version: ${{ matrix.php-versions }} 34 | version: 10.5 35 | #vendored_phpunit_path: vendor/bin/phpunit 36 | 37 | - name: coverage monitor 38 | uses: slavcodev/coverage-monitor-action@1.10.0 39 | with: 40 | github_token: ${{ secrets.GITHUB_TOKEN }} 41 | coverage_path: test/clover.xml 42 | comment_footer: false 43 | 44 | - name: Upload coverage to Codecov 45 | uses: codecov/codecov-action@v3 46 | with: 47 | token: ${{ secrets.CODECOV_TOKEN }} # require for private repo 48 | files: test/clover.xml 49 | name: github-ci 50 | verbose: true 51 | 52 | # - name: phpunit-coverage-badge 53 | # uses: timkrase/phpunit-coverage-badge@v1.2.0 54 | # with: 55 | # report: test/clover.xml 56 | # coverage_badge_path: test/coverage.svg 57 | # push_badge: true 58 | # repo_token: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /vendor/ 3 | test/clover.xml 4 | test/.phpunit.result.cache 5 | 6 | composer.phar -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Alexpts 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-simple-events 2 | 3 | ![unit tests](https://github.com/alexpts/php-simple-events/actions/workflows/phpunit.yml/badge.svg) 4 | [![codecov](https://codecov.io/gh/alexpts/php-simple-events/branch/master/graph/badge.svg?token=8Q3KC7BICL)](https://codecov.io/gh/alexpts/php-simple-events) 5 | 6 | ## EventEmitter 7 | It is very fast event emitter and filters. 8 | 9 | ## Installation 10 | 11 | ```$ composer require alexpts/php-simple-events``` 12 | 13 | ## Usage 14 | 15 | ### Creating an Emitter 16 | ```php 17 | $emitter = new \PTS\Events\EventEmitter; 18 | ``` 19 | 20 | ### Adding Listeners 21 | 22 | Callable handler 23 | ```php 24 | $emitter->on('user.created', function (User $user) use ($logger) { 25 | $logger->log(sprintf("User '%s' was created.", $user->getLogin())); 26 | }); 27 | ``` 28 | 29 | With priority 30 | ```php 31 | $emitter->on('user.created', $handler, 100); 32 | ``` 33 | 34 | With extra arguments for EventEmitterExtraArgs instance (EventEmitter instance ignores extra args) 35 | ```php 36 | $emitter = new \PTS\Events\EventEmitterExtraArgs; 37 | 38 | $extra1 = 1; 39 | $extra2 = 'some'; 40 | 41 | $handler = function(string $log, int $extra1, string $extra2) { 42 | // ... 43 | }; 44 | 45 | $emitter->on('log', $handler, 50, [$extra1, $extra2]); 46 | $emitter->emit('log', ['some log']); 47 | ``` 48 | 49 | 50 | ### Removing Listeners 51 | 52 | Remove concrete handler 53 | ```php 54 | $handler = fn() => 'log'; 55 | $emitter->on('log', $handler) 56 | $emitter->off('log', $handler); 57 | ``` 58 | 59 | Remove all handlers 60 | ```php 61 | $emitter->off('log'); 62 | ``` 63 | 64 | Remove concrete handler with priority 65 | ```php 66 | $emitter->off('log', $handler, 100); 67 | ``` 68 | 69 | 70 | ## Emitting Events 71 | 72 | Simple emit 73 | ```php 74 | $emitter->emit('log'); 75 | ``` 76 | 77 | Pass arguments on emit 78 | ```php 79 | $emitter->on('log', function(string $log, int $a2, bool $a3) { 80 | // ... 81 | }); 82 | $emitter->emit('log', ['arg1', 2, true]); 83 | ``` 84 | 85 | 86 | 87 | 88 | ## Interface 89 | 90 | 91 | ```php 92 | emit(string $name, array $args = []): self; 93 | on(string $name, callable $handler, int $priority = 50, array $extraArgs = []): self; 94 | once(string $name, callable $handler, int $priority = 50, array $extraArgs = []): self; 95 | off(string $event, callable $handler = null, int $priority = null): self; 96 | 97 | listeners(string $event = null): array; 98 | eventNames(): array; 99 | ``` 100 | 101 | #### EventHandler 102 | EventHandler must be `callable` 103 | 104 | ```php 105 | $eventsBus = new \PTS\Events\EventEmitter; 106 | 107 | $eventsBus->on('some:event', function(){ ... }); 108 | $eventsBus->on('some:event', 'trim'); 109 | $eventsBus->on('some', ['ClassName', 'method']); 110 | $eventsBus->on('some', [$this, 'method']); 111 | $eventsBus->once('some', $instanceWithInvokeMethod); 112 | ``` 113 | 114 | #### Order handlers 115 | Listeners have priority. All listeners invoke by priority 116 | 117 | ```php 118 | $events->on('post:title', 'trim', 10); // second 119 | $events->on('post:title', 'prepareTitle', 70); // first 120 | ``` 121 | 122 | #### Remove handler 123 | ```php 124 | // remove handler 'trim' with priority = 10 125 | $events->on('post:title', 'trim', 10); 126 | $events->off('post:title', 'trim', 10); 127 | 128 | // remove all handler 'trim' with any priority 129 | $events->on('post:title', 'trim', 10); 130 | $events->off('post:title', 'trim'); 131 | 132 | // remove all handlers 133 | $events->on('post:title', 'trim', 10); 134 | $events->off('post:title'); 135 | ``` 136 | 137 | #### StopPropagation 138 | 139 | ```php 140 | $events->on('eventName', function() { ... }); 141 | $events->on('eventName', function() { throw new StopPropagation; }); 142 | $events->on('eventName', function() { ... }); // it does not call 143 | ``` 144 | 145 | ## Filters 146 | 147 | ### API Filters 148 | Filters is very similar to EventEmitter. Filter passes first value through all listeners and returns modified value. 149 | 150 | ```php 151 | emit(string $name, $value, array $args = []); 152 | on(string $name, callable $handler, int $priority = 50, array $extraArgs = []): self; 153 | once(string $name, callable $handler, int $priority = 50, array $extraArgs = []): self; 154 | off(string $event, callable $handler = null, int $priority = null): self; 155 | 156 | listeners(string $event = null): array; 157 | eventNames(): array; 158 | ``` 159 | 160 | Example 161 | ```php 162 | $filters = new \PTS\Events\Filters; 163 | 164 | $filters->on('post:title', 'trim'); 165 | $title = $filters->filter('post:title', ' Raw title '); // `Raw title` 166 | ``` 167 | 168 | 169 | ### Inject EventEmitter / FilterEmitter 170 | 171 | 1. Event/Filter Bus. 172 | 173 | ```php 174 | use PTS\Events\Bus\EventBusTrait; 175 | 176 | class Service { 177 | use EventBusTrait; 178 | 179 | public function getPost() 180 | { 181 | $post = ...; 182 | // you can to modify $post via filter/event 183 | $post = $this->filter('getPost', $post); // from EventBusTrait 184 | return $post; 185 | } 186 | } 187 | ``` 188 | 189 | 2. Event/Filter for any object. 190 | 191 | Extend from EventEmitter: 192 | ```php 193 | use PTS\Events\Filter\FilterEmitter; 194 | use PTS\Events\EventEmitter; 195 | 196 | class Request extend FilterEmitter { // extend EventEmitter 197 | 198 | public function parseHeader() 199 | { 200 | $rawHttpRequest = '...'; 201 | $headers = $this->filter('parseHeader', $rawHttpRequest); 202 | return $headers; 203 | } 204 | } 205 | 206 | $request = new Request; 207 | $parseHeader = new ParserHeader; 208 | $request->on('parseHeader', [$parseHeader, 'parse']); 209 | $headers = $request->parseHeader(); 210 | ``` 211 | 212 | Use trait: 213 | 214 | ```php 215 | use PTS\Events\Filter\FilterEmitterTrait; 216 | use PTS\Events\EventEmitterTrait; 217 | 218 | class Request 219 | 220 | use FilterEmitterTrait; 221 | 222 | public function parseHeader() 223 | { 224 | $rawHttpRequest = '...'; 225 | $headers = $this->filter('parseHeader', $rawHttpRequest); 226 | return $headers; 227 | } 228 | } 229 | 230 | $request = new Request; 231 | $parseHeader = new ParserHeader; 232 | $request->on('parseHeader', [$parseHeader, 'parse']); 233 | $headers = $request->parseHeader(); 234 | ``` -------------------------------------------------------------------------------- /benchmark/bechmark.php: -------------------------------------------------------------------------------- 1 | createProbe(new Configuration); 19 | } 20 | 21 | $startTime = microtime(true); 22 | 23 | $events = new EventEmitter; 24 | $events2 = new EventEmitterExtraArgs(); 25 | 26 | $filters = new FilterEmitter; 27 | $filters2 = new FilterExtraArgsEmitter; 28 | 29 | $events 30 | ->on('event-a', fn(int|null $b = null) => $b) 31 | ->on('event-a', fn(int|null $b = null) => $b); 32 | 33 | $events2 34 | ->on('event-a', fn(int|null $a = null) => $a, 50, [1, 2]) 35 | ->on('event-a', fn(int|null $b = null) => $b); 36 | 37 | $filters 38 | ->on('filter-a', fn(int $a = 1, int $b = 2) => $a, 50, [1, 2]) 39 | ->on('filter-a', fn(int $a = 1, int $b = 2) => $a); 40 | 41 | $filters2 42 | ->on('filter-a', fn(int $a = 1, int $b = 2) => $a, 50, [1, 2]) 43 | ->on('filter-a', fn(int $a = 1, int $b = 2) => $a); 44 | 45 | 46 | function test(string $title, callable $func, int $iterations) { 47 | $startTime = microtime(true); 48 | 49 | while ($iterations--) { 50 | $func(); 51 | } 52 | 53 | $diff = (microtime(true) - $startTime) * 1000; 54 | $duration = sprintf('%2.3f ms', $diff); 55 | echo $title . ': ' . $duration . PHP_EOL; 56 | } 57 | 58 | echo 'Events:' . PHP_EOL; 59 | 60 | test('with args in emit', function() use ($events){ 61 | $events->emit('event-a', [1]); 62 | }, $iterations); 63 | 64 | test('EA with args in emit', function() use ($events2){ 65 | $events2->emit('event-a', [1]); 66 | }, $iterations); 67 | 68 | 69 | test('without args in emit', function() use ($events){ 70 | $events->emit('event-a'); 71 | }, $iterations); 72 | 73 | test('EA without args in emit', function() use ($events2){ 74 | $events2->emit('event-a'); 75 | }, $iterations); 76 | 77 | 78 | 79 | echo PHP_EOL . 'Filter:' . PHP_EOL; 80 | 81 | test('with args in emit', function() use ($filters){ 82 | $filters->emit('filter-a', 1, [3]); 83 | }, $iterations); 84 | 85 | test('EA with args in emit', function() use ($filters2){ 86 | $filters2->emit('filter-a', 1, [3]); 87 | }, $iterations); 88 | 89 | 90 | test('without args in emit', function() use ($filters){ 91 | $filters->emit('filter-a', 1); 92 | }, $iterations); 93 | 94 | test('EA without args in emit', function() use ($filters2){ 95 | $filters2->emit('filter-a', 1); 96 | }, $iterations); 97 | 98 | 99 | 100 | echo "\n" . memory_get_peak_usage()/1024; 101 | 102 | if ($blackfire) { 103 | $client->endProbe($probe); 104 | } 105 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alexpts/php-simple-events", 3 | "description": "Simple events and filters", 4 | "homepage": "https://github.com/alexpts/php-simple-events", 5 | "license": "MIT", 6 | "type": "library", 7 | "keywords": [ 8 | "event", 9 | "filter", 10 | "emitter", 11 | "event-emitter", 12 | "event-dispatcher" 13 | ], 14 | "authors": [{ 15 | "name": "Alexpts", 16 | "email": "alexpts3@gmail.com" 17 | }], 18 | "minimum-stability": "stable", 19 | "config": { 20 | "optimize-autoloader": true 21 | }, 22 | "require": { 23 | "php": ">=8.1" 24 | }, 25 | "require-dev": { 26 | "phpunit/phpunit": "^10.5", 27 | "blackfire/php-sdk": "^1.35", 28 | "phpbench/phpbench": "^1.4" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "PTS\\Events\\": "src" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "PTS\\Events\\Test\\": "test/unit" 38 | } 39 | }, 40 | "scripts": { 41 | "bench": "vendor/bin/phpbench run --config=test/phpbench.json --report=aggregate", 42 | "test": "vendor/bin/phpunit --config=test/phpunit.xml" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "2749ed38a6255a52e289a2ef1667b786", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "blackfire/php-sdk", 12 | "version": "v1.35.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/blackfireio/php-sdk.git", 16 | "reference": "2c5950ff2ad29c2af96c69810eb304f0f350177d" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/blackfireio/php-sdk/zipball/2c5950ff2ad29c2af96c69810eb304f0f350177d", 21 | "reference": "2c5950ff2ad29c2af96c69810eb304f0f350177d", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "composer/ca-bundle": "^1.0", 26 | "php": ">=5.2.0" 27 | }, 28 | "require-dev": { 29 | "behat/behat": "^3.8", 30 | "friends-of-behat/mink-browserkit-driver": "^1.4", 31 | "friends-of-behat/mink-extension": "^2.5", 32 | "guzzlehttp/psr7": "^1.6", 33 | "illuminate/console": "^8.81", 34 | "illuminate/queue": "^8.81", 35 | "illuminate/support": "^8.81", 36 | "laravel/octane": "^1.2", 37 | "phpunit/phpunit": "^9.5", 38 | "psr/http-message": "^1.0", 39 | "symfony/browser-kit": "^5.1", 40 | "symfony/framework-bundle": "^5.1", 41 | "symfony/http-client": "^5.1", 42 | "symfony/messenger": "^5.1", 43 | "symfony/panther": "^1.0", 44 | "symfony/phpunit-bridge": "^5.2" 45 | }, 46 | "suggest": { 47 | "ext-blackfire": "The C version of the Blackfire probe", 48 | "ext-zlib": "To push config to remote profiling targets", 49 | "symfony/panther": "To use Symfony web test cases with Blackfire" 50 | }, 51 | "type": "library", 52 | "extra": { 53 | "branch-alias": { 54 | "dev-master": "1.36-dev" 55 | } 56 | }, 57 | "autoload": { 58 | "files": [ 59 | "src/autostart.php" 60 | ], 61 | "psr-4": { 62 | "Blackfire\\": "src/Blackfire" 63 | } 64 | }, 65 | "notification-url": "https://packagist.org/downloads/", 66 | "license": [ 67 | "MIT" 68 | ], 69 | "authors": [ 70 | { 71 | "name": "Blackfire.io", 72 | "email": "support@blackfire.io" 73 | } 74 | ], 75 | "description": "Blackfire.io PHP SDK", 76 | "keywords": [ 77 | "performance", 78 | "profiler", 79 | "uprofiler", 80 | "xhprof" 81 | ], 82 | "support": { 83 | "issues": "https://github.com/blackfireio/php-sdk/issues", 84 | "source": "https://github.com/blackfireio/php-sdk/tree/v1.35.0" 85 | }, 86 | "time": "2023-04-06T09:37:28+00:00" 87 | }, 88 | { 89 | "name": "composer/ca-bundle", 90 | "version": "1.5.5", 91 | "source": { 92 | "type": "git", 93 | "url": "https://github.com/composer/ca-bundle.git", 94 | "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6" 95 | }, 96 | "dist": { 97 | "type": "zip", 98 | "url": "https://api.github.com/repos/composer/ca-bundle/zipball/08c50d5ec4c6ced7d0271d2862dec8c1033283e6", 99 | "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6", 100 | "shasum": "" 101 | }, 102 | "require": { 103 | "ext-openssl": "*", 104 | "ext-pcre": "*", 105 | "php": "^7.2 || ^8.0" 106 | }, 107 | "require-dev": { 108 | "phpstan/phpstan": "^1.10", 109 | "phpunit/phpunit": "^8 || ^9", 110 | "psr/log": "^1.0 || ^2.0 || ^3.0", 111 | "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" 112 | }, 113 | "type": "library", 114 | "extra": { 115 | "branch-alias": { 116 | "dev-main": "1.x-dev" 117 | } 118 | }, 119 | "autoload": { 120 | "psr-4": { 121 | "Composer\\CaBundle\\": "src" 122 | } 123 | }, 124 | "notification-url": "https://packagist.org/downloads/", 125 | "license": [ 126 | "MIT" 127 | ], 128 | "authors": [ 129 | { 130 | "name": "Jordi Boggiano", 131 | "email": "j.boggiano@seld.be", 132 | "homepage": "http://seld.be" 133 | } 134 | ], 135 | "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", 136 | "keywords": [ 137 | "cabundle", 138 | "cacert", 139 | "certificate", 140 | "ssl", 141 | "tls" 142 | ], 143 | "support": { 144 | "irc": "irc://irc.freenode.org/composer", 145 | "issues": "https://github.com/composer/ca-bundle/issues", 146 | "source": "https://github.com/composer/ca-bundle/tree/1.5.5" 147 | }, 148 | "funding": [ 149 | { 150 | "url": "https://packagist.com", 151 | "type": "custom" 152 | }, 153 | { 154 | "url": "https://github.com/composer", 155 | "type": "github" 156 | }, 157 | { 158 | "url": "https://tidelift.com/funding/github/packagist/composer/composer", 159 | "type": "tidelift" 160 | } 161 | ], 162 | "time": "2025-01-08T16:17:16+00:00" 163 | }, 164 | { 165 | "name": "doctrine/annotations", 166 | "version": "2.0.2", 167 | "source": { 168 | "type": "git", 169 | "url": "https://github.com/doctrine/annotations.git", 170 | "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7" 171 | }, 172 | "dist": { 173 | "type": "zip", 174 | "url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7", 175 | "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7", 176 | "shasum": "" 177 | }, 178 | "require": { 179 | "doctrine/lexer": "^2 || ^3", 180 | "ext-tokenizer": "*", 181 | "php": "^7.2 || ^8.0", 182 | "psr/cache": "^1 || ^2 || ^3" 183 | }, 184 | "require-dev": { 185 | "doctrine/cache": "^2.0", 186 | "doctrine/coding-standard": "^10", 187 | "phpstan/phpstan": "^1.10.28", 188 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", 189 | "symfony/cache": "^5.4 || ^6.4 || ^7", 190 | "vimeo/psalm": "^4.30 || ^5.14" 191 | }, 192 | "suggest": { 193 | "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" 194 | }, 195 | "type": "library", 196 | "autoload": { 197 | "psr-4": { 198 | "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" 199 | } 200 | }, 201 | "notification-url": "https://packagist.org/downloads/", 202 | "license": [ 203 | "MIT" 204 | ], 205 | "authors": [ 206 | { 207 | "name": "Guilherme Blanco", 208 | "email": "guilhermeblanco@gmail.com" 209 | }, 210 | { 211 | "name": "Roman Borschel", 212 | "email": "roman@code-factory.org" 213 | }, 214 | { 215 | "name": "Benjamin Eberlei", 216 | "email": "kontakt@beberlei.de" 217 | }, 218 | { 219 | "name": "Jonathan Wage", 220 | "email": "jonwage@gmail.com" 221 | }, 222 | { 223 | "name": "Johannes Schmitt", 224 | "email": "schmittjoh@gmail.com" 225 | } 226 | ], 227 | "description": "Docblock Annotations Parser", 228 | "homepage": "https://www.doctrine-project.org/projects/annotations.html", 229 | "keywords": [ 230 | "annotations", 231 | "docblock", 232 | "parser" 233 | ], 234 | "support": { 235 | "issues": "https://github.com/doctrine/annotations/issues", 236 | "source": "https://github.com/doctrine/annotations/tree/2.0.2" 237 | }, 238 | "time": "2024-09-05T10:17:24+00:00" 239 | }, 240 | { 241 | "name": "doctrine/lexer", 242 | "version": "3.0.1", 243 | "source": { 244 | "type": "git", 245 | "url": "https://github.com/doctrine/lexer.git", 246 | "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" 247 | }, 248 | "dist": { 249 | "type": "zip", 250 | "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", 251 | "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", 252 | "shasum": "" 253 | }, 254 | "require": { 255 | "php": "^8.1" 256 | }, 257 | "require-dev": { 258 | "doctrine/coding-standard": "^12", 259 | "phpstan/phpstan": "^1.10", 260 | "phpunit/phpunit": "^10.5", 261 | "psalm/plugin-phpunit": "^0.18.3", 262 | "vimeo/psalm": "^5.21" 263 | }, 264 | "type": "library", 265 | "autoload": { 266 | "psr-4": { 267 | "Doctrine\\Common\\Lexer\\": "src" 268 | } 269 | }, 270 | "notification-url": "https://packagist.org/downloads/", 271 | "license": [ 272 | "MIT" 273 | ], 274 | "authors": [ 275 | { 276 | "name": "Guilherme Blanco", 277 | "email": "guilhermeblanco@gmail.com" 278 | }, 279 | { 280 | "name": "Roman Borschel", 281 | "email": "roman@code-factory.org" 282 | }, 283 | { 284 | "name": "Johannes Schmitt", 285 | "email": "schmittjoh@gmail.com" 286 | } 287 | ], 288 | "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", 289 | "homepage": "https://www.doctrine-project.org/projects/lexer.html", 290 | "keywords": [ 291 | "annotations", 292 | "docblock", 293 | "lexer", 294 | "parser", 295 | "php" 296 | ], 297 | "support": { 298 | "issues": "https://github.com/doctrine/lexer/issues", 299 | "source": "https://github.com/doctrine/lexer/tree/3.0.1" 300 | }, 301 | "funding": [ 302 | { 303 | "url": "https://www.doctrine-project.org/sponsorship.html", 304 | "type": "custom" 305 | }, 306 | { 307 | "url": "https://www.patreon.com/phpdoctrine", 308 | "type": "patreon" 309 | }, 310 | { 311 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", 312 | "type": "tidelift" 313 | } 314 | ], 315 | "time": "2024-02-05T11:56:58+00:00" 316 | }, 317 | { 318 | "name": "myclabs/deep-copy", 319 | "version": "1.13.0", 320 | "source": { 321 | "type": "git", 322 | "url": "https://github.com/myclabs/DeepCopy.git", 323 | "reference": "024473a478be9df5fdaca2c793f2232fe788e414" 324 | }, 325 | "dist": { 326 | "type": "zip", 327 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", 328 | "reference": "024473a478be9df5fdaca2c793f2232fe788e414", 329 | "shasum": "" 330 | }, 331 | "require": { 332 | "php": "^7.1 || ^8.0" 333 | }, 334 | "conflict": { 335 | "doctrine/collections": "<1.6.8", 336 | "doctrine/common": "<2.13.3 || >=3 <3.2.2" 337 | }, 338 | "require-dev": { 339 | "doctrine/collections": "^1.6.8", 340 | "doctrine/common": "^2.13.3 || ^3.2.2", 341 | "phpspec/prophecy": "^1.10", 342 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" 343 | }, 344 | "type": "library", 345 | "autoload": { 346 | "files": [ 347 | "src/DeepCopy/deep_copy.php" 348 | ], 349 | "psr-4": { 350 | "DeepCopy\\": "src/DeepCopy/" 351 | } 352 | }, 353 | "notification-url": "https://packagist.org/downloads/", 354 | "license": [ 355 | "MIT" 356 | ], 357 | "description": "Create deep copies (clones) of your objects", 358 | "keywords": [ 359 | "clone", 360 | "copy", 361 | "duplicate", 362 | "object", 363 | "object graph" 364 | ], 365 | "support": { 366 | "issues": "https://github.com/myclabs/DeepCopy/issues", 367 | "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" 368 | }, 369 | "funding": [ 370 | { 371 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", 372 | "type": "tidelift" 373 | } 374 | ], 375 | "time": "2025-02-12T12:17:51+00:00" 376 | }, 377 | { 378 | "name": "nikic/php-parser", 379 | "version": "v5.4.0", 380 | "source": { 381 | "type": "git", 382 | "url": "https://github.com/nikic/PHP-Parser.git", 383 | "reference": "447a020a1f875a434d62f2a401f53b82a396e494" 384 | }, 385 | "dist": { 386 | "type": "zip", 387 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", 388 | "reference": "447a020a1f875a434d62f2a401f53b82a396e494", 389 | "shasum": "" 390 | }, 391 | "require": { 392 | "ext-ctype": "*", 393 | "ext-json": "*", 394 | "ext-tokenizer": "*", 395 | "php": ">=7.4" 396 | }, 397 | "require-dev": { 398 | "ircmaxell/php-yacc": "^0.0.7", 399 | "phpunit/phpunit": "^9.0" 400 | }, 401 | "bin": [ 402 | "bin/php-parse" 403 | ], 404 | "type": "library", 405 | "extra": { 406 | "branch-alias": { 407 | "dev-master": "5.0-dev" 408 | } 409 | }, 410 | "autoload": { 411 | "psr-4": { 412 | "PhpParser\\": "lib/PhpParser" 413 | } 414 | }, 415 | "notification-url": "https://packagist.org/downloads/", 416 | "license": [ 417 | "BSD-3-Clause" 418 | ], 419 | "authors": [ 420 | { 421 | "name": "Nikita Popov" 422 | } 423 | ], 424 | "description": "A PHP parser written in PHP", 425 | "keywords": [ 426 | "parser", 427 | "php" 428 | ], 429 | "support": { 430 | "issues": "https://github.com/nikic/PHP-Parser/issues", 431 | "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" 432 | }, 433 | "time": "2024-12-30T11:07:19+00:00" 434 | }, 435 | { 436 | "name": "phar-io/manifest", 437 | "version": "2.0.4", 438 | "source": { 439 | "type": "git", 440 | "url": "https://github.com/phar-io/manifest.git", 441 | "reference": "54750ef60c58e43759730615a392c31c80e23176" 442 | }, 443 | "dist": { 444 | "type": "zip", 445 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", 446 | "reference": "54750ef60c58e43759730615a392c31c80e23176", 447 | "shasum": "" 448 | }, 449 | "require": { 450 | "ext-dom": "*", 451 | "ext-libxml": "*", 452 | "ext-phar": "*", 453 | "ext-xmlwriter": "*", 454 | "phar-io/version": "^3.0.1", 455 | "php": "^7.2 || ^8.0" 456 | }, 457 | "type": "library", 458 | "extra": { 459 | "branch-alias": { 460 | "dev-master": "2.0.x-dev" 461 | } 462 | }, 463 | "autoload": { 464 | "classmap": [ 465 | "src/" 466 | ] 467 | }, 468 | "notification-url": "https://packagist.org/downloads/", 469 | "license": [ 470 | "BSD-3-Clause" 471 | ], 472 | "authors": [ 473 | { 474 | "name": "Arne Blankerts", 475 | "email": "arne@blankerts.de", 476 | "role": "Developer" 477 | }, 478 | { 479 | "name": "Sebastian Heuer", 480 | "email": "sebastian@phpeople.de", 481 | "role": "Developer" 482 | }, 483 | { 484 | "name": "Sebastian Bergmann", 485 | "email": "sebastian@phpunit.de", 486 | "role": "Developer" 487 | } 488 | ], 489 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 490 | "support": { 491 | "issues": "https://github.com/phar-io/manifest/issues", 492 | "source": "https://github.com/phar-io/manifest/tree/2.0.4" 493 | }, 494 | "funding": [ 495 | { 496 | "url": "https://github.com/theseer", 497 | "type": "github" 498 | } 499 | ], 500 | "time": "2024-03-03T12:33:53+00:00" 501 | }, 502 | { 503 | "name": "phar-io/version", 504 | "version": "3.2.1", 505 | "source": { 506 | "type": "git", 507 | "url": "https://github.com/phar-io/version.git", 508 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" 509 | }, 510 | "dist": { 511 | "type": "zip", 512 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 513 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 514 | "shasum": "" 515 | }, 516 | "require": { 517 | "php": "^7.2 || ^8.0" 518 | }, 519 | "type": "library", 520 | "autoload": { 521 | "classmap": [ 522 | "src/" 523 | ] 524 | }, 525 | "notification-url": "https://packagist.org/downloads/", 526 | "license": [ 527 | "BSD-3-Clause" 528 | ], 529 | "authors": [ 530 | { 531 | "name": "Arne Blankerts", 532 | "email": "arne@blankerts.de", 533 | "role": "Developer" 534 | }, 535 | { 536 | "name": "Sebastian Heuer", 537 | "email": "sebastian@phpeople.de", 538 | "role": "Developer" 539 | }, 540 | { 541 | "name": "Sebastian Bergmann", 542 | "email": "sebastian@phpunit.de", 543 | "role": "Developer" 544 | } 545 | ], 546 | "description": "Library for handling version information and constraints", 547 | "support": { 548 | "issues": "https://github.com/phar-io/version/issues", 549 | "source": "https://github.com/phar-io/version/tree/3.2.1" 550 | }, 551 | "time": "2022-02-21T01:04:05+00:00" 552 | }, 553 | { 554 | "name": "phpbench/container", 555 | "version": "2.2.2", 556 | "source": { 557 | "type": "git", 558 | "url": "https://github.com/phpbench/container.git", 559 | "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33" 560 | }, 561 | "dist": { 562 | "type": "zip", 563 | "url": "https://api.github.com/repos/phpbench/container/zipball/a59b929e00b87b532ca6d0edd8eca0967655af33", 564 | "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33", 565 | "shasum": "" 566 | }, 567 | "require": { 568 | "psr/container": "^1.0|^2.0", 569 | "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0" 570 | }, 571 | "require-dev": { 572 | "friendsofphp/php-cs-fixer": "^2.16", 573 | "phpstan/phpstan": "^0.12.52", 574 | "phpunit/phpunit": "^8" 575 | }, 576 | "type": "library", 577 | "extra": { 578 | "branch-alias": { 579 | "dev-master": "2.x-dev" 580 | } 581 | }, 582 | "autoload": { 583 | "psr-4": { 584 | "PhpBench\\DependencyInjection\\": "lib/" 585 | } 586 | }, 587 | "notification-url": "https://packagist.org/downloads/", 588 | "license": [ 589 | "MIT" 590 | ], 591 | "authors": [ 592 | { 593 | "name": "Daniel Leech", 594 | "email": "daniel@dantleech.com" 595 | } 596 | ], 597 | "description": "Simple, configurable, service container.", 598 | "support": { 599 | "issues": "https://github.com/phpbench/container/issues", 600 | "source": "https://github.com/phpbench/container/tree/2.2.2" 601 | }, 602 | "time": "2023-10-30T13:38:26+00:00" 603 | }, 604 | { 605 | "name": "phpbench/phpbench", 606 | "version": "1.4.0", 607 | "source": { 608 | "type": "git", 609 | "url": "https://github.com/phpbench/phpbench.git", 610 | "reference": "4248817222514421cba466bfa7adc7d8932345d4" 611 | }, 612 | "dist": { 613 | "type": "zip", 614 | "url": "https://api.github.com/repos/phpbench/phpbench/zipball/4248817222514421cba466bfa7adc7d8932345d4", 615 | "reference": "4248817222514421cba466bfa7adc7d8932345d4", 616 | "shasum": "" 617 | }, 618 | "require": { 619 | "doctrine/annotations": "^2.0", 620 | "ext-dom": "*", 621 | "ext-json": "*", 622 | "ext-pcre": "*", 623 | "ext-reflection": "*", 624 | "ext-spl": "*", 625 | "ext-tokenizer": "*", 626 | "php": "^8.1", 627 | "phpbench/container": "^2.2", 628 | "psr/log": "^1.1 || ^2.0 || ^3.0", 629 | "seld/jsonlint": "^1.1", 630 | "symfony/console": "^6.1 || ^7.0", 631 | "symfony/filesystem": "^6.1 || ^7.0", 632 | "symfony/finder": "^6.1 || ^7.0", 633 | "symfony/options-resolver": "^6.1 || ^7.0", 634 | "symfony/process": "^6.1 || ^7.0", 635 | "webmozart/glob": "^4.6" 636 | }, 637 | "require-dev": { 638 | "dantleech/invoke": "^2.0", 639 | "ergebnis/composer-normalize": "^2.39", 640 | "friendsofphp/php-cs-fixer": "^3.0", 641 | "jangregor/phpstan-prophecy": "^1.0", 642 | "phpspec/prophecy": "dev-master", 643 | "phpstan/extension-installer": "^1.1", 644 | "phpstan/phpstan": "^1.0", 645 | "phpstan/phpstan-phpunit": "^1.0", 646 | "phpunit/phpunit": "^10.4 || ^11.0", 647 | "rector/rector": "^1.2", 648 | "symfony/error-handler": "^6.1 || ^7.0", 649 | "symfony/var-dumper": "^6.1 || ^7.0" 650 | }, 651 | "suggest": { 652 | "ext-xdebug": "For Xdebug profiling extension." 653 | }, 654 | "bin": [ 655 | "bin/phpbench" 656 | ], 657 | "type": "library", 658 | "extra": { 659 | "branch-alias": { 660 | "dev-master": "1.2-dev" 661 | } 662 | }, 663 | "autoload": { 664 | "files": [ 665 | "lib/Report/Func/functions.php" 666 | ], 667 | "psr-4": { 668 | "PhpBench\\": "lib/", 669 | "PhpBench\\Extensions\\XDebug\\": "extensions/xdebug/lib/" 670 | } 671 | }, 672 | "notification-url": "https://packagist.org/downloads/", 673 | "license": [ 674 | "MIT" 675 | ], 676 | "authors": [ 677 | { 678 | "name": "Daniel Leech", 679 | "email": "daniel@dantleech.com" 680 | } 681 | ], 682 | "description": "PHP Benchmarking Framework", 683 | "keywords": [ 684 | "benchmarking", 685 | "optimization", 686 | "performance", 687 | "profiling", 688 | "testing" 689 | ], 690 | "support": { 691 | "issues": "https://github.com/phpbench/phpbench/issues", 692 | "source": "https://github.com/phpbench/phpbench/tree/1.4.0" 693 | }, 694 | "funding": [ 695 | { 696 | "url": "https://github.com/dantleech", 697 | "type": "github" 698 | } 699 | ], 700 | "time": "2025-01-26T19:54:45+00:00" 701 | }, 702 | { 703 | "name": "phpunit/php-code-coverage", 704 | "version": "10.1.16", 705 | "source": { 706 | "type": "git", 707 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 708 | "reference": "7e308268858ed6baedc8704a304727d20bc07c77" 709 | }, 710 | "dist": { 711 | "type": "zip", 712 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", 713 | "reference": "7e308268858ed6baedc8704a304727d20bc07c77", 714 | "shasum": "" 715 | }, 716 | "require": { 717 | "ext-dom": "*", 718 | "ext-libxml": "*", 719 | "ext-xmlwriter": "*", 720 | "nikic/php-parser": "^4.19.1 || ^5.1.0", 721 | "php": ">=8.1", 722 | "phpunit/php-file-iterator": "^4.1.0", 723 | "phpunit/php-text-template": "^3.0.1", 724 | "sebastian/code-unit-reverse-lookup": "^3.0.0", 725 | "sebastian/complexity": "^3.2.0", 726 | "sebastian/environment": "^6.1.0", 727 | "sebastian/lines-of-code": "^2.0.2", 728 | "sebastian/version": "^4.0.1", 729 | "theseer/tokenizer": "^1.2.3" 730 | }, 731 | "require-dev": { 732 | "phpunit/phpunit": "^10.1" 733 | }, 734 | "suggest": { 735 | "ext-pcov": "PHP extension that provides line coverage", 736 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 737 | }, 738 | "type": "library", 739 | "extra": { 740 | "branch-alias": { 741 | "dev-main": "10.1.x-dev" 742 | } 743 | }, 744 | "autoload": { 745 | "classmap": [ 746 | "src/" 747 | ] 748 | }, 749 | "notification-url": "https://packagist.org/downloads/", 750 | "license": [ 751 | "BSD-3-Clause" 752 | ], 753 | "authors": [ 754 | { 755 | "name": "Sebastian Bergmann", 756 | "email": "sebastian@phpunit.de", 757 | "role": "lead" 758 | } 759 | ], 760 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 761 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 762 | "keywords": [ 763 | "coverage", 764 | "testing", 765 | "xunit" 766 | ], 767 | "support": { 768 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", 769 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", 770 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" 771 | }, 772 | "funding": [ 773 | { 774 | "url": "https://github.com/sebastianbergmann", 775 | "type": "github" 776 | } 777 | ], 778 | "time": "2024-08-22T04:31:57+00:00" 779 | }, 780 | { 781 | "name": "phpunit/php-file-iterator", 782 | "version": "4.1.0", 783 | "source": { 784 | "type": "git", 785 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 786 | "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" 787 | }, 788 | "dist": { 789 | "type": "zip", 790 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", 791 | "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", 792 | "shasum": "" 793 | }, 794 | "require": { 795 | "php": ">=8.1" 796 | }, 797 | "require-dev": { 798 | "phpunit/phpunit": "^10.0" 799 | }, 800 | "type": "library", 801 | "extra": { 802 | "branch-alias": { 803 | "dev-main": "4.0-dev" 804 | } 805 | }, 806 | "autoload": { 807 | "classmap": [ 808 | "src/" 809 | ] 810 | }, 811 | "notification-url": "https://packagist.org/downloads/", 812 | "license": [ 813 | "BSD-3-Clause" 814 | ], 815 | "authors": [ 816 | { 817 | "name": "Sebastian Bergmann", 818 | "email": "sebastian@phpunit.de", 819 | "role": "lead" 820 | } 821 | ], 822 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 823 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 824 | "keywords": [ 825 | "filesystem", 826 | "iterator" 827 | ], 828 | "support": { 829 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", 830 | "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", 831 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" 832 | }, 833 | "funding": [ 834 | { 835 | "url": "https://github.com/sebastianbergmann", 836 | "type": "github" 837 | } 838 | ], 839 | "time": "2023-08-31T06:24:48+00:00" 840 | }, 841 | { 842 | "name": "phpunit/php-invoker", 843 | "version": "4.0.0", 844 | "source": { 845 | "type": "git", 846 | "url": "https://github.com/sebastianbergmann/php-invoker.git", 847 | "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" 848 | }, 849 | "dist": { 850 | "type": "zip", 851 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", 852 | "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", 853 | "shasum": "" 854 | }, 855 | "require": { 856 | "php": ">=8.1" 857 | }, 858 | "require-dev": { 859 | "ext-pcntl": "*", 860 | "phpunit/phpunit": "^10.0" 861 | }, 862 | "suggest": { 863 | "ext-pcntl": "*" 864 | }, 865 | "type": "library", 866 | "extra": { 867 | "branch-alias": { 868 | "dev-main": "4.0-dev" 869 | } 870 | }, 871 | "autoload": { 872 | "classmap": [ 873 | "src/" 874 | ] 875 | }, 876 | "notification-url": "https://packagist.org/downloads/", 877 | "license": [ 878 | "BSD-3-Clause" 879 | ], 880 | "authors": [ 881 | { 882 | "name": "Sebastian Bergmann", 883 | "email": "sebastian@phpunit.de", 884 | "role": "lead" 885 | } 886 | ], 887 | "description": "Invoke callables with a timeout", 888 | "homepage": "https://github.com/sebastianbergmann/php-invoker/", 889 | "keywords": [ 890 | "process" 891 | ], 892 | "support": { 893 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues", 894 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" 895 | }, 896 | "funding": [ 897 | { 898 | "url": "https://github.com/sebastianbergmann", 899 | "type": "github" 900 | } 901 | ], 902 | "time": "2023-02-03T06:56:09+00:00" 903 | }, 904 | { 905 | "name": "phpunit/php-text-template", 906 | "version": "3.0.1", 907 | "source": { 908 | "type": "git", 909 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 910 | "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" 911 | }, 912 | "dist": { 913 | "type": "zip", 914 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", 915 | "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", 916 | "shasum": "" 917 | }, 918 | "require": { 919 | "php": ">=8.1" 920 | }, 921 | "require-dev": { 922 | "phpunit/phpunit": "^10.0" 923 | }, 924 | "type": "library", 925 | "extra": { 926 | "branch-alias": { 927 | "dev-main": "3.0-dev" 928 | } 929 | }, 930 | "autoload": { 931 | "classmap": [ 932 | "src/" 933 | ] 934 | }, 935 | "notification-url": "https://packagist.org/downloads/", 936 | "license": [ 937 | "BSD-3-Clause" 938 | ], 939 | "authors": [ 940 | { 941 | "name": "Sebastian Bergmann", 942 | "email": "sebastian@phpunit.de", 943 | "role": "lead" 944 | } 945 | ], 946 | "description": "Simple template engine.", 947 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 948 | "keywords": [ 949 | "template" 950 | ], 951 | "support": { 952 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues", 953 | "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", 954 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" 955 | }, 956 | "funding": [ 957 | { 958 | "url": "https://github.com/sebastianbergmann", 959 | "type": "github" 960 | } 961 | ], 962 | "time": "2023-08-31T14:07:24+00:00" 963 | }, 964 | { 965 | "name": "phpunit/php-timer", 966 | "version": "6.0.0", 967 | "source": { 968 | "type": "git", 969 | "url": "https://github.com/sebastianbergmann/php-timer.git", 970 | "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" 971 | }, 972 | "dist": { 973 | "type": "zip", 974 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", 975 | "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", 976 | "shasum": "" 977 | }, 978 | "require": { 979 | "php": ">=8.1" 980 | }, 981 | "require-dev": { 982 | "phpunit/phpunit": "^10.0" 983 | }, 984 | "type": "library", 985 | "extra": { 986 | "branch-alias": { 987 | "dev-main": "6.0-dev" 988 | } 989 | }, 990 | "autoload": { 991 | "classmap": [ 992 | "src/" 993 | ] 994 | }, 995 | "notification-url": "https://packagist.org/downloads/", 996 | "license": [ 997 | "BSD-3-Clause" 998 | ], 999 | "authors": [ 1000 | { 1001 | "name": "Sebastian Bergmann", 1002 | "email": "sebastian@phpunit.de", 1003 | "role": "lead" 1004 | } 1005 | ], 1006 | "description": "Utility class for timing", 1007 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 1008 | "keywords": [ 1009 | "timer" 1010 | ], 1011 | "support": { 1012 | "issues": "https://github.com/sebastianbergmann/php-timer/issues", 1013 | "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" 1014 | }, 1015 | "funding": [ 1016 | { 1017 | "url": "https://github.com/sebastianbergmann", 1018 | "type": "github" 1019 | } 1020 | ], 1021 | "time": "2023-02-03T06:57:52+00:00" 1022 | }, 1023 | { 1024 | "name": "phpunit/phpunit", 1025 | "version": "10.5.45", 1026 | "source": { 1027 | "type": "git", 1028 | "url": "https://github.com/sebastianbergmann/phpunit.git", 1029 | "reference": "bd68a781d8e30348bc297449f5234b3458267ae8" 1030 | }, 1031 | "dist": { 1032 | "type": "zip", 1033 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8", 1034 | "reference": "bd68a781d8e30348bc297449f5234b3458267ae8", 1035 | "shasum": "" 1036 | }, 1037 | "require": { 1038 | "ext-dom": "*", 1039 | "ext-json": "*", 1040 | "ext-libxml": "*", 1041 | "ext-mbstring": "*", 1042 | "ext-xml": "*", 1043 | "ext-xmlwriter": "*", 1044 | "myclabs/deep-copy": "^1.12.1", 1045 | "phar-io/manifest": "^2.0.4", 1046 | "phar-io/version": "^3.2.1", 1047 | "php": ">=8.1", 1048 | "phpunit/php-code-coverage": "^10.1.16", 1049 | "phpunit/php-file-iterator": "^4.1.0", 1050 | "phpunit/php-invoker": "^4.0.0", 1051 | "phpunit/php-text-template": "^3.0.1", 1052 | "phpunit/php-timer": "^6.0.0", 1053 | "sebastian/cli-parser": "^2.0.1", 1054 | "sebastian/code-unit": "^2.0.0", 1055 | "sebastian/comparator": "^5.0.3", 1056 | "sebastian/diff": "^5.1.1", 1057 | "sebastian/environment": "^6.1.0", 1058 | "sebastian/exporter": "^5.1.2", 1059 | "sebastian/global-state": "^6.0.2", 1060 | "sebastian/object-enumerator": "^5.0.0", 1061 | "sebastian/recursion-context": "^5.0.0", 1062 | "sebastian/type": "^4.0.0", 1063 | "sebastian/version": "^4.0.1" 1064 | }, 1065 | "suggest": { 1066 | "ext-soap": "To be able to generate mocks based on WSDL files" 1067 | }, 1068 | "bin": [ 1069 | "phpunit" 1070 | ], 1071 | "type": "library", 1072 | "extra": { 1073 | "branch-alias": { 1074 | "dev-main": "10.5-dev" 1075 | } 1076 | }, 1077 | "autoload": { 1078 | "files": [ 1079 | "src/Framework/Assert/Functions.php" 1080 | ], 1081 | "classmap": [ 1082 | "src/" 1083 | ] 1084 | }, 1085 | "notification-url": "https://packagist.org/downloads/", 1086 | "license": [ 1087 | "BSD-3-Clause" 1088 | ], 1089 | "authors": [ 1090 | { 1091 | "name": "Sebastian Bergmann", 1092 | "email": "sebastian@phpunit.de", 1093 | "role": "lead" 1094 | } 1095 | ], 1096 | "description": "The PHP Unit Testing framework.", 1097 | "homepage": "https://phpunit.de/", 1098 | "keywords": [ 1099 | "phpunit", 1100 | "testing", 1101 | "xunit" 1102 | ], 1103 | "support": { 1104 | "issues": "https://github.com/sebastianbergmann/phpunit/issues", 1105 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy", 1106 | "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45" 1107 | }, 1108 | "funding": [ 1109 | { 1110 | "url": "https://phpunit.de/sponsors.html", 1111 | "type": "custom" 1112 | }, 1113 | { 1114 | "url": "https://github.com/sebastianbergmann", 1115 | "type": "github" 1116 | }, 1117 | { 1118 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", 1119 | "type": "tidelift" 1120 | } 1121 | ], 1122 | "time": "2025-02-06T16:08:12+00:00" 1123 | }, 1124 | { 1125 | "name": "psr/cache", 1126 | "version": "3.0.0", 1127 | "source": { 1128 | "type": "git", 1129 | "url": "https://github.com/php-fig/cache.git", 1130 | "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" 1131 | }, 1132 | "dist": { 1133 | "type": "zip", 1134 | "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", 1135 | "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", 1136 | "shasum": "" 1137 | }, 1138 | "require": { 1139 | "php": ">=8.0.0" 1140 | }, 1141 | "type": "library", 1142 | "extra": { 1143 | "branch-alias": { 1144 | "dev-master": "1.0.x-dev" 1145 | } 1146 | }, 1147 | "autoload": { 1148 | "psr-4": { 1149 | "Psr\\Cache\\": "src/" 1150 | } 1151 | }, 1152 | "notification-url": "https://packagist.org/downloads/", 1153 | "license": [ 1154 | "MIT" 1155 | ], 1156 | "authors": [ 1157 | { 1158 | "name": "PHP-FIG", 1159 | "homepage": "https://www.php-fig.org/" 1160 | } 1161 | ], 1162 | "description": "Common interface for caching libraries", 1163 | "keywords": [ 1164 | "cache", 1165 | "psr", 1166 | "psr-6" 1167 | ], 1168 | "support": { 1169 | "source": "https://github.com/php-fig/cache/tree/3.0.0" 1170 | }, 1171 | "time": "2021-02-03T23:26:27+00:00" 1172 | }, 1173 | { 1174 | "name": "psr/container", 1175 | "version": "2.0.2", 1176 | "source": { 1177 | "type": "git", 1178 | "url": "https://github.com/php-fig/container.git", 1179 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" 1180 | }, 1181 | "dist": { 1182 | "type": "zip", 1183 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", 1184 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", 1185 | "shasum": "" 1186 | }, 1187 | "require": { 1188 | "php": ">=7.4.0" 1189 | }, 1190 | "type": "library", 1191 | "extra": { 1192 | "branch-alias": { 1193 | "dev-master": "2.0.x-dev" 1194 | } 1195 | }, 1196 | "autoload": { 1197 | "psr-4": { 1198 | "Psr\\Container\\": "src/" 1199 | } 1200 | }, 1201 | "notification-url": "https://packagist.org/downloads/", 1202 | "license": [ 1203 | "MIT" 1204 | ], 1205 | "authors": [ 1206 | { 1207 | "name": "PHP-FIG", 1208 | "homepage": "https://www.php-fig.org/" 1209 | } 1210 | ], 1211 | "description": "Common Container Interface (PHP FIG PSR-11)", 1212 | "homepage": "https://github.com/php-fig/container", 1213 | "keywords": [ 1214 | "PSR-11", 1215 | "container", 1216 | "container-interface", 1217 | "container-interop", 1218 | "psr" 1219 | ], 1220 | "support": { 1221 | "issues": "https://github.com/php-fig/container/issues", 1222 | "source": "https://github.com/php-fig/container/tree/2.0.2" 1223 | }, 1224 | "time": "2021-11-05T16:47:00+00:00" 1225 | }, 1226 | { 1227 | "name": "psr/log", 1228 | "version": "3.0.2", 1229 | "source": { 1230 | "type": "git", 1231 | "url": "https://github.com/php-fig/log.git", 1232 | "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" 1233 | }, 1234 | "dist": { 1235 | "type": "zip", 1236 | "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", 1237 | "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", 1238 | "shasum": "" 1239 | }, 1240 | "require": { 1241 | "php": ">=8.0.0" 1242 | }, 1243 | "type": "library", 1244 | "extra": { 1245 | "branch-alias": { 1246 | "dev-master": "3.x-dev" 1247 | } 1248 | }, 1249 | "autoload": { 1250 | "psr-4": { 1251 | "Psr\\Log\\": "src" 1252 | } 1253 | }, 1254 | "notification-url": "https://packagist.org/downloads/", 1255 | "license": [ 1256 | "MIT" 1257 | ], 1258 | "authors": [ 1259 | { 1260 | "name": "PHP-FIG", 1261 | "homepage": "https://www.php-fig.org/" 1262 | } 1263 | ], 1264 | "description": "Common interface for logging libraries", 1265 | "homepage": "https://github.com/php-fig/log", 1266 | "keywords": [ 1267 | "log", 1268 | "psr", 1269 | "psr-3" 1270 | ], 1271 | "support": { 1272 | "source": "https://github.com/php-fig/log/tree/3.0.2" 1273 | }, 1274 | "time": "2024-09-11T13:17:53+00:00" 1275 | }, 1276 | { 1277 | "name": "sebastian/cli-parser", 1278 | "version": "2.0.1", 1279 | "source": { 1280 | "type": "git", 1281 | "url": "https://github.com/sebastianbergmann/cli-parser.git", 1282 | "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" 1283 | }, 1284 | "dist": { 1285 | "type": "zip", 1286 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", 1287 | "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", 1288 | "shasum": "" 1289 | }, 1290 | "require": { 1291 | "php": ">=8.1" 1292 | }, 1293 | "require-dev": { 1294 | "phpunit/phpunit": "^10.0" 1295 | }, 1296 | "type": "library", 1297 | "extra": { 1298 | "branch-alias": { 1299 | "dev-main": "2.0-dev" 1300 | } 1301 | }, 1302 | "autoload": { 1303 | "classmap": [ 1304 | "src/" 1305 | ] 1306 | }, 1307 | "notification-url": "https://packagist.org/downloads/", 1308 | "license": [ 1309 | "BSD-3-Clause" 1310 | ], 1311 | "authors": [ 1312 | { 1313 | "name": "Sebastian Bergmann", 1314 | "email": "sebastian@phpunit.de", 1315 | "role": "lead" 1316 | } 1317 | ], 1318 | "description": "Library for parsing CLI options", 1319 | "homepage": "https://github.com/sebastianbergmann/cli-parser", 1320 | "support": { 1321 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues", 1322 | "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", 1323 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" 1324 | }, 1325 | "funding": [ 1326 | { 1327 | "url": "https://github.com/sebastianbergmann", 1328 | "type": "github" 1329 | } 1330 | ], 1331 | "time": "2024-03-02T07:12:49+00:00" 1332 | }, 1333 | { 1334 | "name": "sebastian/code-unit", 1335 | "version": "2.0.0", 1336 | "source": { 1337 | "type": "git", 1338 | "url": "https://github.com/sebastianbergmann/code-unit.git", 1339 | "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" 1340 | }, 1341 | "dist": { 1342 | "type": "zip", 1343 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", 1344 | "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", 1345 | "shasum": "" 1346 | }, 1347 | "require": { 1348 | "php": ">=8.1" 1349 | }, 1350 | "require-dev": { 1351 | "phpunit/phpunit": "^10.0" 1352 | }, 1353 | "type": "library", 1354 | "extra": { 1355 | "branch-alias": { 1356 | "dev-main": "2.0-dev" 1357 | } 1358 | }, 1359 | "autoload": { 1360 | "classmap": [ 1361 | "src/" 1362 | ] 1363 | }, 1364 | "notification-url": "https://packagist.org/downloads/", 1365 | "license": [ 1366 | "BSD-3-Clause" 1367 | ], 1368 | "authors": [ 1369 | { 1370 | "name": "Sebastian Bergmann", 1371 | "email": "sebastian@phpunit.de", 1372 | "role": "lead" 1373 | } 1374 | ], 1375 | "description": "Collection of value objects that represent the PHP code units", 1376 | "homepage": "https://github.com/sebastianbergmann/code-unit", 1377 | "support": { 1378 | "issues": "https://github.com/sebastianbergmann/code-unit/issues", 1379 | "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" 1380 | }, 1381 | "funding": [ 1382 | { 1383 | "url": "https://github.com/sebastianbergmann", 1384 | "type": "github" 1385 | } 1386 | ], 1387 | "time": "2023-02-03T06:58:43+00:00" 1388 | }, 1389 | { 1390 | "name": "sebastian/code-unit-reverse-lookup", 1391 | "version": "3.0.0", 1392 | "source": { 1393 | "type": "git", 1394 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 1395 | "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" 1396 | }, 1397 | "dist": { 1398 | "type": "zip", 1399 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", 1400 | "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", 1401 | "shasum": "" 1402 | }, 1403 | "require": { 1404 | "php": ">=8.1" 1405 | }, 1406 | "require-dev": { 1407 | "phpunit/phpunit": "^10.0" 1408 | }, 1409 | "type": "library", 1410 | "extra": { 1411 | "branch-alias": { 1412 | "dev-main": "3.0-dev" 1413 | } 1414 | }, 1415 | "autoload": { 1416 | "classmap": [ 1417 | "src/" 1418 | ] 1419 | }, 1420 | "notification-url": "https://packagist.org/downloads/", 1421 | "license": [ 1422 | "BSD-3-Clause" 1423 | ], 1424 | "authors": [ 1425 | { 1426 | "name": "Sebastian Bergmann", 1427 | "email": "sebastian@phpunit.de" 1428 | } 1429 | ], 1430 | "description": "Looks up which function or method a line of code belongs to", 1431 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 1432 | "support": { 1433 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", 1434 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" 1435 | }, 1436 | "funding": [ 1437 | { 1438 | "url": "https://github.com/sebastianbergmann", 1439 | "type": "github" 1440 | } 1441 | ], 1442 | "time": "2023-02-03T06:59:15+00:00" 1443 | }, 1444 | { 1445 | "name": "sebastian/comparator", 1446 | "version": "5.0.3", 1447 | "source": { 1448 | "type": "git", 1449 | "url": "https://github.com/sebastianbergmann/comparator.git", 1450 | "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" 1451 | }, 1452 | "dist": { 1453 | "type": "zip", 1454 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", 1455 | "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", 1456 | "shasum": "" 1457 | }, 1458 | "require": { 1459 | "ext-dom": "*", 1460 | "ext-mbstring": "*", 1461 | "php": ">=8.1", 1462 | "sebastian/diff": "^5.0", 1463 | "sebastian/exporter": "^5.0" 1464 | }, 1465 | "require-dev": { 1466 | "phpunit/phpunit": "^10.5" 1467 | }, 1468 | "type": "library", 1469 | "extra": { 1470 | "branch-alias": { 1471 | "dev-main": "5.0-dev" 1472 | } 1473 | }, 1474 | "autoload": { 1475 | "classmap": [ 1476 | "src/" 1477 | ] 1478 | }, 1479 | "notification-url": "https://packagist.org/downloads/", 1480 | "license": [ 1481 | "BSD-3-Clause" 1482 | ], 1483 | "authors": [ 1484 | { 1485 | "name": "Sebastian Bergmann", 1486 | "email": "sebastian@phpunit.de" 1487 | }, 1488 | { 1489 | "name": "Jeff Welch", 1490 | "email": "whatthejeff@gmail.com" 1491 | }, 1492 | { 1493 | "name": "Volker Dusch", 1494 | "email": "github@wallbash.com" 1495 | }, 1496 | { 1497 | "name": "Bernhard Schussek", 1498 | "email": "bschussek@2bepublished.at" 1499 | } 1500 | ], 1501 | "description": "Provides the functionality to compare PHP values for equality", 1502 | "homepage": "https://github.com/sebastianbergmann/comparator", 1503 | "keywords": [ 1504 | "comparator", 1505 | "compare", 1506 | "equality" 1507 | ], 1508 | "support": { 1509 | "issues": "https://github.com/sebastianbergmann/comparator/issues", 1510 | "security": "https://github.com/sebastianbergmann/comparator/security/policy", 1511 | "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" 1512 | }, 1513 | "funding": [ 1514 | { 1515 | "url": "https://github.com/sebastianbergmann", 1516 | "type": "github" 1517 | } 1518 | ], 1519 | "time": "2024-10-18T14:56:07+00:00" 1520 | }, 1521 | { 1522 | "name": "sebastian/complexity", 1523 | "version": "3.2.0", 1524 | "source": { 1525 | "type": "git", 1526 | "url": "https://github.com/sebastianbergmann/complexity.git", 1527 | "reference": "68ff824baeae169ec9f2137158ee529584553799" 1528 | }, 1529 | "dist": { 1530 | "type": "zip", 1531 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", 1532 | "reference": "68ff824baeae169ec9f2137158ee529584553799", 1533 | "shasum": "" 1534 | }, 1535 | "require": { 1536 | "nikic/php-parser": "^4.18 || ^5.0", 1537 | "php": ">=8.1" 1538 | }, 1539 | "require-dev": { 1540 | "phpunit/phpunit": "^10.0" 1541 | }, 1542 | "type": "library", 1543 | "extra": { 1544 | "branch-alias": { 1545 | "dev-main": "3.2-dev" 1546 | } 1547 | }, 1548 | "autoload": { 1549 | "classmap": [ 1550 | "src/" 1551 | ] 1552 | }, 1553 | "notification-url": "https://packagist.org/downloads/", 1554 | "license": [ 1555 | "BSD-3-Clause" 1556 | ], 1557 | "authors": [ 1558 | { 1559 | "name": "Sebastian Bergmann", 1560 | "email": "sebastian@phpunit.de", 1561 | "role": "lead" 1562 | } 1563 | ], 1564 | "description": "Library for calculating the complexity of PHP code units", 1565 | "homepage": "https://github.com/sebastianbergmann/complexity", 1566 | "support": { 1567 | "issues": "https://github.com/sebastianbergmann/complexity/issues", 1568 | "security": "https://github.com/sebastianbergmann/complexity/security/policy", 1569 | "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" 1570 | }, 1571 | "funding": [ 1572 | { 1573 | "url": "https://github.com/sebastianbergmann", 1574 | "type": "github" 1575 | } 1576 | ], 1577 | "time": "2023-12-21T08:37:17+00:00" 1578 | }, 1579 | { 1580 | "name": "sebastian/diff", 1581 | "version": "5.1.1", 1582 | "source": { 1583 | "type": "git", 1584 | "url": "https://github.com/sebastianbergmann/diff.git", 1585 | "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" 1586 | }, 1587 | "dist": { 1588 | "type": "zip", 1589 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", 1590 | "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", 1591 | "shasum": "" 1592 | }, 1593 | "require": { 1594 | "php": ">=8.1" 1595 | }, 1596 | "require-dev": { 1597 | "phpunit/phpunit": "^10.0", 1598 | "symfony/process": "^6.4" 1599 | }, 1600 | "type": "library", 1601 | "extra": { 1602 | "branch-alias": { 1603 | "dev-main": "5.1-dev" 1604 | } 1605 | }, 1606 | "autoload": { 1607 | "classmap": [ 1608 | "src/" 1609 | ] 1610 | }, 1611 | "notification-url": "https://packagist.org/downloads/", 1612 | "license": [ 1613 | "BSD-3-Clause" 1614 | ], 1615 | "authors": [ 1616 | { 1617 | "name": "Sebastian Bergmann", 1618 | "email": "sebastian@phpunit.de" 1619 | }, 1620 | { 1621 | "name": "Kore Nordmann", 1622 | "email": "mail@kore-nordmann.de" 1623 | } 1624 | ], 1625 | "description": "Diff implementation", 1626 | "homepage": "https://github.com/sebastianbergmann/diff", 1627 | "keywords": [ 1628 | "diff", 1629 | "udiff", 1630 | "unidiff", 1631 | "unified diff" 1632 | ], 1633 | "support": { 1634 | "issues": "https://github.com/sebastianbergmann/diff/issues", 1635 | "security": "https://github.com/sebastianbergmann/diff/security/policy", 1636 | "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" 1637 | }, 1638 | "funding": [ 1639 | { 1640 | "url": "https://github.com/sebastianbergmann", 1641 | "type": "github" 1642 | } 1643 | ], 1644 | "time": "2024-03-02T07:15:17+00:00" 1645 | }, 1646 | { 1647 | "name": "sebastian/environment", 1648 | "version": "6.1.0", 1649 | "source": { 1650 | "type": "git", 1651 | "url": "https://github.com/sebastianbergmann/environment.git", 1652 | "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" 1653 | }, 1654 | "dist": { 1655 | "type": "zip", 1656 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", 1657 | "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", 1658 | "shasum": "" 1659 | }, 1660 | "require": { 1661 | "php": ">=8.1" 1662 | }, 1663 | "require-dev": { 1664 | "phpunit/phpunit": "^10.0" 1665 | }, 1666 | "suggest": { 1667 | "ext-posix": "*" 1668 | }, 1669 | "type": "library", 1670 | "extra": { 1671 | "branch-alias": { 1672 | "dev-main": "6.1-dev" 1673 | } 1674 | }, 1675 | "autoload": { 1676 | "classmap": [ 1677 | "src/" 1678 | ] 1679 | }, 1680 | "notification-url": "https://packagist.org/downloads/", 1681 | "license": [ 1682 | "BSD-3-Clause" 1683 | ], 1684 | "authors": [ 1685 | { 1686 | "name": "Sebastian Bergmann", 1687 | "email": "sebastian@phpunit.de" 1688 | } 1689 | ], 1690 | "description": "Provides functionality to handle HHVM/PHP environments", 1691 | "homepage": "https://github.com/sebastianbergmann/environment", 1692 | "keywords": [ 1693 | "Xdebug", 1694 | "environment", 1695 | "hhvm" 1696 | ], 1697 | "support": { 1698 | "issues": "https://github.com/sebastianbergmann/environment/issues", 1699 | "security": "https://github.com/sebastianbergmann/environment/security/policy", 1700 | "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" 1701 | }, 1702 | "funding": [ 1703 | { 1704 | "url": "https://github.com/sebastianbergmann", 1705 | "type": "github" 1706 | } 1707 | ], 1708 | "time": "2024-03-23T08:47:14+00:00" 1709 | }, 1710 | { 1711 | "name": "sebastian/exporter", 1712 | "version": "5.1.2", 1713 | "source": { 1714 | "type": "git", 1715 | "url": "https://github.com/sebastianbergmann/exporter.git", 1716 | "reference": "955288482d97c19a372d3f31006ab3f37da47adf" 1717 | }, 1718 | "dist": { 1719 | "type": "zip", 1720 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", 1721 | "reference": "955288482d97c19a372d3f31006ab3f37da47adf", 1722 | "shasum": "" 1723 | }, 1724 | "require": { 1725 | "ext-mbstring": "*", 1726 | "php": ">=8.1", 1727 | "sebastian/recursion-context": "^5.0" 1728 | }, 1729 | "require-dev": { 1730 | "phpunit/phpunit": "^10.0" 1731 | }, 1732 | "type": "library", 1733 | "extra": { 1734 | "branch-alias": { 1735 | "dev-main": "5.1-dev" 1736 | } 1737 | }, 1738 | "autoload": { 1739 | "classmap": [ 1740 | "src/" 1741 | ] 1742 | }, 1743 | "notification-url": "https://packagist.org/downloads/", 1744 | "license": [ 1745 | "BSD-3-Clause" 1746 | ], 1747 | "authors": [ 1748 | { 1749 | "name": "Sebastian Bergmann", 1750 | "email": "sebastian@phpunit.de" 1751 | }, 1752 | { 1753 | "name": "Jeff Welch", 1754 | "email": "whatthejeff@gmail.com" 1755 | }, 1756 | { 1757 | "name": "Volker Dusch", 1758 | "email": "github@wallbash.com" 1759 | }, 1760 | { 1761 | "name": "Adam Harvey", 1762 | "email": "aharvey@php.net" 1763 | }, 1764 | { 1765 | "name": "Bernhard Schussek", 1766 | "email": "bschussek@gmail.com" 1767 | } 1768 | ], 1769 | "description": "Provides the functionality to export PHP variables for visualization", 1770 | "homepage": "https://www.github.com/sebastianbergmann/exporter", 1771 | "keywords": [ 1772 | "export", 1773 | "exporter" 1774 | ], 1775 | "support": { 1776 | "issues": "https://github.com/sebastianbergmann/exporter/issues", 1777 | "security": "https://github.com/sebastianbergmann/exporter/security/policy", 1778 | "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2" 1779 | }, 1780 | "funding": [ 1781 | { 1782 | "url": "https://github.com/sebastianbergmann", 1783 | "type": "github" 1784 | } 1785 | ], 1786 | "time": "2024-03-02T07:17:12+00:00" 1787 | }, 1788 | { 1789 | "name": "sebastian/global-state", 1790 | "version": "6.0.2", 1791 | "source": { 1792 | "type": "git", 1793 | "url": "https://github.com/sebastianbergmann/global-state.git", 1794 | "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" 1795 | }, 1796 | "dist": { 1797 | "type": "zip", 1798 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", 1799 | "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", 1800 | "shasum": "" 1801 | }, 1802 | "require": { 1803 | "php": ">=8.1", 1804 | "sebastian/object-reflector": "^3.0", 1805 | "sebastian/recursion-context": "^5.0" 1806 | }, 1807 | "require-dev": { 1808 | "ext-dom": "*", 1809 | "phpunit/phpunit": "^10.0" 1810 | }, 1811 | "type": "library", 1812 | "extra": { 1813 | "branch-alias": { 1814 | "dev-main": "6.0-dev" 1815 | } 1816 | }, 1817 | "autoload": { 1818 | "classmap": [ 1819 | "src/" 1820 | ] 1821 | }, 1822 | "notification-url": "https://packagist.org/downloads/", 1823 | "license": [ 1824 | "BSD-3-Clause" 1825 | ], 1826 | "authors": [ 1827 | { 1828 | "name": "Sebastian Bergmann", 1829 | "email": "sebastian@phpunit.de" 1830 | } 1831 | ], 1832 | "description": "Snapshotting of global state", 1833 | "homepage": "https://www.github.com/sebastianbergmann/global-state", 1834 | "keywords": [ 1835 | "global state" 1836 | ], 1837 | "support": { 1838 | "issues": "https://github.com/sebastianbergmann/global-state/issues", 1839 | "security": "https://github.com/sebastianbergmann/global-state/security/policy", 1840 | "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" 1841 | }, 1842 | "funding": [ 1843 | { 1844 | "url": "https://github.com/sebastianbergmann", 1845 | "type": "github" 1846 | } 1847 | ], 1848 | "time": "2024-03-02T07:19:19+00:00" 1849 | }, 1850 | { 1851 | "name": "sebastian/lines-of-code", 1852 | "version": "2.0.2", 1853 | "source": { 1854 | "type": "git", 1855 | "url": "https://github.com/sebastianbergmann/lines-of-code.git", 1856 | "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" 1857 | }, 1858 | "dist": { 1859 | "type": "zip", 1860 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", 1861 | "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", 1862 | "shasum": "" 1863 | }, 1864 | "require": { 1865 | "nikic/php-parser": "^4.18 || ^5.0", 1866 | "php": ">=8.1" 1867 | }, 1868 | "require-dev": { 1869 | "phpunit/phpunit": "^10.0" 1870 | }, 1871 | "type": "library", 1872 | "extra": { 1873 | "branch-alias": { 1874 | "dev-main": "2.0-dev" 1875 | } 1876 | }, 1877 | "autoload": { 1878 | "classmap": [ 1879 | "src/" 1880 | ] 1881 | }, 1882 | "notification-url": "https://packagist.org/downloads/", 1883 | "license": [ 1884 | "BSD-3-Clause" 1885 | ], 1886 | "authors": [ 1887 | { 1888 | "name": "Sebastian Bergmann", 1889 | "email": "sebastian@phpunit.de", 1890 | "role": "lead" 1891 | } 1892 | ], 1893 | "description": "Library for counting the lines of code in PHP source code", 1894 | "homepage": "https://github.com/sebastianbergmann/lines-of-code", 1895 | "support": { 1896 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", 1897 | "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", 1898 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" 1899 | }, 1900 | "funding": [ 1901 | { 1902 | "url": "https://github.com/sebastianbergmann", 1903 | "type": "github" 1904 | } 1905 | ], 1906 | "time": "2023-12-21T08:38:20+00:00" 1907 | }, 1908 | { 1909 | "name": "sebastian/object-enumerator", 1910 | "version": "5.0.0", 1911 | "source": { 1912 | "type": "git", 1913 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1914 | "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" 1915 | }, 1916 | "dist": { 1917 | "type": "zip", 1918 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", 1919 | "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", 1920 | "shasum": "" 1921 | }, 1922 | "require": { 1923 | "php": ">=8.1", 1924 | "sebastian/object-reflector": "^3.0", 1925 | "sebastian/recursion-context": "^5.0" 1926 | }, 1927 | "require-dev": { 1928 | "phpunit/phpunit": "^10.0" 1929 | }, 1930 | "type": "library", 1931 | "extra": { 1932 | "branch-alias": { 1933 | "dev-main": "5.0-dev" 1934 | } 1935 | }, 1936 | "autoload": { 1937 | "classmap": [ 1938 | "src/" 1939 | ] 1940 | }, 1941 | "notification-url": "https://packagist.org/downloads/", 1942 | "license": [ 1943 | "BSD-3-Clause" 1944 | ], 1945 | "authors": [ 1946 | { 1947 | "name": "Sebastian Bergmann", 1948 | "email": "sebastian@phpunit.de" 1949 | } 1950 | ], 1951 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1952 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1953 | "support": { 1954 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", 1955 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" 1956 | }, 1957 | "funding": [ 1958 | { 1959 | "url": "https://github.com/sebastianbergmann", 1960 | "type": "github" 1961 | } 1962 | ], 1963 | "time": "2023-02-03T07:08:32+00:00" 1964 | }, 1965 | { 1966 | "name": "sebastian/object-reflector", 1967 | "version": "3.0.0", 1968 | "source": { 1969 | "type": "git", 1970 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1971 | "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" 1972 | }, 1973 | "dist": { 1974 | "type": "zip", 1975 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", 1976 | "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", 1977 | "shasum": "" 1978 | }, 1979 | "require": { 1980 | "php": ">=8.1" 1981 | }, 1982 | "require-dev": { 1983 | "phpunit/phpunit": "^10.0" 1984 | }, 1985 | "type": "library", 1986 | "extra": { 1987 | "branch-alias": { 1988 | "dev-main": "3.0-dev" 1989 | } 1990 | }, 1991 | "autoload": { 1992 | "classmap": [ 1993 | "src/" 1994 | ] 1995 | }, 1996 | "notification-url": "https://packagist.org/downloads/", 1997 | "license": [ 1998 | "BSD-3-Clause" 1999 | ], 2000 | "authors": [ 2001 | { 2002 | "name": "Sebastian Bergmann", 2003 | "email": "sebastian@phpunit.de" 2004 | } 2005 | ], 2006 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 2007 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 2008 | "support": { 2009 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues", 2010 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" 2011 | }, 2012 | "funding": [ 2013 | { 2014 | "url": "https://github.com/sebastianbergmann", 2015 | "type": "github" 2016 | } 2017 | ], 2018 | "time": "2023-02-03T07:06:18+00:00" 2019 | }, 2020 | { 2021 | "name": "sebastian/recursion-context", 2022 | "version": "5.0.0", 2023 | "source": { 2024 | "type": "git", 2025 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 2026 | "reference": "05909fb5bc7df4c52992396d0116aed689f93712" 2027 | }, 2028 | "dist": { 2029 | "type": "zip", 2030 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", 2031 | "reference": "05909fb5bc7df4c52992396d0116aed689f93712", 2032 | "shasum": "" 2033 | }, 2034 | "require": { 2035 | "php": ">=8.1" 2036 | }, 2037 | "require-dev": { 2038 | "phpunit/phpunit": "^10.0" 2039 | }, 2040 | "type": "library", 2041 | "extra": { 2042 | "branch-alias": { 2043 | "dev-main": "5.0-dev" 2044 | } 2045 | }, 2046 | "autoload": { 2047 | "classmap": [ 2048 | "src/" 2049 | ] 2050 | }, 2051 | "notification-url": "https://packagist.org/downloads/", 2052 | "license": [ 2053 | "BSD-3-Clause" 2054 | ], 2055 | "authors": [ 2056 | { 2057 | "name": "Sebastian Bergmann", 2058 | "email": "sebastian@phpunit.de" 2059 | }, 2060 | { 2061 | "name": "Jeff Welch", 2062 | "email": "whatthejeff@gmail.com" 2063 | }, 2064 | { 2065 | "name": "Adam Harvey", 2066 | "email": "aharvey@php.net" 2067 | } 2068 | ], 2069 | "description": "Provides functionality to recursively process PHP variables", 2070 | "homepage": "https://github.com/sebastianbergmann/recursion-context", 2071 | "support": { 2072 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues", 2073 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" 2074 | }, 2075 | "funding": [ 2076 | { 2077 | "url": "https://github.com/sebastianbergmann", 2078 | "type": "github" 2079 | } 2080 | ], 2081 | "time": "2023-02-03T07:05:40+00:00" 2082 | }, 2083 | { 2084 | "name": "sebastian/type", 2085 | "version": "4.0.0", 2086 | "source": { 2087 | "type": "git", 2088 | "url": "https://github.com/sebastianbergmann/type.git", 2089 | "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" 2090 | }, 2091 | "dist": { 2092 | "type": "zip", 2093 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", 2094 | "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", 2095 | "shasum": "" 2096 | }, 2097 | "require": { 2098 | "php": ">=8.1" 2099 | }, 2100 | "require-dev": { 2101 | "phpunit/phpunit": "^10.0" 2102 | }, 2103 | "type": "library", 2104 | "extra": { 2105 | "branch-alias": { 2106 | "dev-main": "4.0-dev" 2107 | } 2108 | }, 2109 | "autoload": { 2110 | "classmap": [ 2111 | "src/" 2112 | ] 2113 | }, 2114 | "notification-url": "https://packagist.org/downloads/", 2115 | "license": [ 2116 | "BSD-3-Clause" 2117 | ], 2118 | "authors": [ 2119 | { 2120 | "name": "Sebastian Bergmann", 2121 | "email": "sebastian@phpunit.de", 2122 | "role": "lead" 2123 | } 2124 | ], 2125 | "description": "Collection of value objects that represent the types of the PHP type system", 2126 | "homepage": "https://github.com/sebastianbergmann/type", 2127 | "support": { 2128 | "issues": "https://github.com/sebastianbergmann/type/issues", 2129 | "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" 2130 | }, 2131 | "funding": [ 2132 | { 2133 | "url": "https://github.com/sebastianbergmann", 2134 | "type": "github" 2135 | } 2136 | ], 2137 | "time": "2023-02-03T07:10:45+00:00" 2138 | }, 2139 | { 2140 | "name": "sebastian/version", 2141 | "version": "4.0.1", 2142 | "source": { 2143 | "type": "git", 2144 | "url": "https://github.com/sebastianbergmann/version.git", 2145 | "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" 2146 | }, 2147 | "dist": { 2148 | "type": "zip", 2149 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", 2150 | "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", 2151 | "shasum": "" 2152 | }, 2153 | "require": { 2154 | "php": ">=8.1" 2155 | }, 2156 | "type": "library", 2157 | "extra": { 2158 | "branch-alias": { 2159 | "dev-main": "4.0-dev" 2160 | } 2161 | }, 2162 | "autoload": { 2163 | "classmap": [ 2164 | "src/" 2165 | ] 2166 | }, 2167 | "notification-url": "https://packagist.org/downloads/", 2168 | "license": [ 2169 | "BSD-3-Clause" 2170 | ], 2171 | "authors": [ 2172 | { 2173 | "name": "Sebastian Bergmann", 2174 | "email": "sebastian@phpunit.de", 2175 | "role": "lead" 2176 | } 2177 | ], 2178 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 2179 | "homepage": "https://github.com/sebastianbergmann/version", 2180 | "support": { 2181 | "issues": "https://github.com/sebastianbergmann/version/issues", 2182 | "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" 2183 | }, 2184 | "funding": [ 2185 | { 2186 | "url": "https://github.com/sebastianbergmann", 2187 | "type": "github" 2188 | } 2189 | ], 2190 | "time": "2023-02-07T11:34:05+00:00" 2191 | }, 2192 | { 2193 | "name": "seld/jsonlint", 2194 | "version": "1.11.0", 2195 | "source": { 2196 | "type": "git", 2197 | "url": "https://github.com/Seldaek/jsonlint.git", 2198 | "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" 2199 | }, 2200 | "dist": { 2201 | "type": "zip", 2202 | "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", 2203 | "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", 2204 | "shasum": "" 2205 | }, 2206 | "require": { 2207 | "php": "^5.3 || ^7.0 || ^8.0" 2208 | }, 2209 | "require-dev": { 2210 | "phpstan/phpstan": "^1.11", 2211 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" 2212 | }, 2213 | "bin": [ 2214 | "bin/jsonlint" 2215 | ], 2216 | "type": "library", 2217 | "autoload": { 2218 | "psr-4": { 2219 | "Seld\\JsonLint\\": "src/Seld/JsonLint/" 2220 | } 2221 | }, 2222 | "notification-url": "https://packagist.org/downloads/", 2223 | "license": [ 2224 | "MIT" 2225 | ], 2226 | "authors": [ 2227 | { 2228 | "name": "Jordi Boggiano", 2229 | "email": "j.boggiano@seld.be", 2230 | "homepage": "https://seld.be" 2231 | } 2232 | ], 2233 | "description": "JSON Linter", 2234 | "keywords": [ 2235 | "json", 2236 | "linter", 2237 | "parser", 2238 | "validator" 2239 | ], 2240 | "support": { 2241 | "issues": "https://github.com/Seldaek/jsonlint/issues", 2242 | "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" 2243 | }, 2244 | "funding": [ 2245 | { 2246 | "url": "https://github.com/Seldaek", 2247 | "type": "github" 2248 | }, 2249 | { 2250 | "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", 2251 | "type": "tidelift" 2252 | } 2253 | ], 2254 | "time": "2024-07-11T14:55:45+00:00" 2255 | }, 2256 | { 2257 | "name": "symfony/console", 2258 | "version": "v7.2.1", 2259 | "source": { 2260 | "type": "git", 2261 | "url": "https://github.com/symfony/console.git", 2262 | "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3" 2263 | }, 2264 | "dist": { 2265 | "type": "zip", 2266 | "url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3", 2267 | "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3", 2268 | "shasum": "" 2269 | }, 2270 | "require": { 2271 | "php": ">=8.2", 2272 | "symfony/polyfill-mbstring": "~1.0", 2273 | "symfony/service-contracts": "^2.5|^3", 2274 | "symfony/string": "^6.4|^7.0" 2275 | }, 2276 | "conflict": { 2277 | "symfony/dependency-injection": "<6.4", 2278 | "symfony/dotenv": "<6.4", 2279 | "symfony/event-dispatcher": "<6.4", 2280 | "symfony/lock": "<6.4", 2281 | "symfony/process": "<6.4" 2282 | }, 2283 | "provide": { 2284 | "psr/log-implementation": "1.0|2.0|3.0" 2285 | }, 2286 | "require-dev": { 2287 | "psr/log": "^1|^2|^3", 2288 | "symfony/config": "^6.4|^7.0", 2289 | "symfony/dependency-injection": "^6.4|^7.0", 2290 | "symfony/event-dispatcher": "^6.4|^7.0", 2291 | "symfony/http-foundation": "^6.4|^7.0", 2292 | "symfony/http-kernel": "^6.4|^7.0", 2293 | "symfony/lock": "^6.4|^7.0", 2294 | "symfony/messenger": "^6.4|^7.0", 2295 | "symfony/process": "^6.4|^7.0", 2296 | "symfony/stopwatch": "^6.4|^7.0", 2297 | "symfony/var-dumper": "^6.4|^7.0" 2298 | }, 2299 | "type": "library", 2300 | "autoload": { 2301 | "psr-4": { 2302 | "Symfony\\Component\\Console\\": "" 2303 | }, 2304 | "exclude-from-classmap": [ 2305 | "/Tests/" 2306 | ] 2307 | }, 2308 | "notification-url": "https://packagist.org/downloads/", 2309 | "license": [ 2310 | "MIT" 2311 | ], 2312 | "authors": [ 2313 | { 2314 | "name": "Fabien Potencier", 2315 | "email": "fabien@symfony.com" 2316 | }, 2317 | { 2318 | "name": "Symfony Community", 2319 | "homepage": "https://symfony.com/contributors" 2320 | } 2321 | ], 2322 | "description": "Eases the creation of beautiful and testable command line interfaces", 2323 | "homepage": "https://symfony.com", 2324 | "keywords": [ 2325 | "cli", 2326 | "command-line", 2327 | "console", 2328 | "terminal" 2329 | ], 2330 | "support": { 2331 | "source": "https://github.com/symfony/console/tree/v7.2.1" 2332 | }, 2333 | "funding": [ 2334 | { 2335 | "url": "https://symfony.com/sponsor", 2336 | "type": "custom" 2337 | }, 2338 | { 2339 | "url": "https://github.com/fabpot", 2340 | "type": "github" 2341 | }, 2342 | { 2343 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2344 | "type": "tidelift" 2345 | } 2346 | ], 2347 | "time": "2024-12-11T03:49:26+00:00" 2348 | }, 2349 | { 2350 | "name": "symfony/deprecation-contracts", 2351 | "version": "v3.5.1", 2352 | "source": { 2353 | "type": "git", 2354 | "url": "https://github.com/symfony/deprecation-contracts.git", 2355 | "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" 2356 | }, 2357 | "dist": { 2358 | "type": "zip", 2359 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", 2360 | "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", 2361 | "shasum": "" 2362 | }, 2363 | "require": { 2364 | "php": ">=8.1" 2365 | }, 2366 | "type": "library", 2367 | "extra": { 2368 | "thanks": { 2369 | "url": "https://github.com/symfony/contracts", 2370 | "name": "symfony/contracts" 2371 | }, 2372 | "branch-alias": { 2373 | "dev-main": "3.5-dev" 2374 | } 2375 | }, 2376 | "autoload": { 2377 | "files": [ 2378 | "function.php" 2379 | ] 2380 | }, 2381 | "notification-url": "https://packagist.org/downloads/", 2382 | "license": [ 2383 | "MIT" 2384 | ], 2385 | "authors": [ 2386 | { 2387 | "name": "Nicolas Grekas", 2388 | "email": "p@tchwork.com" 2389 | }, 2390 | { 2391 | "name": "Symfony Community", 2392 | "homepage": "https://symfony.com/contributors" 2393 | } 2394 | ], 2395 | "description": "A generic function and convention to trigger deprecation notices", 2396 | "homepage": "https://symfony.com", 2397 | "support": { 2398 | "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" 2399 | }, 2400 | "funding": [ 2401 | { 2402 | "url": "https://symfony.com/sponsor", 2403 | "type": "custom" 2404 | }, 2405 | { 2406 | "url": "https://github.com/fabpot", 2407 | "type": "github" 2408 | }, 2409 | { 2410 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2411 | "type": "tidelift" 2412 | } 2413 | ], 2414 | "time": "2024-09-25T14:20:29+00:00" 2415 | }, 2416 | { 2417 | "name": "symfony/filesystem", 2418 | "version": "v7.2.0", 2419 | "source": { 2420 | "type": "git", 2421 | "url": "https://github.com/symfony/filesystem.git", 2422 | "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" 2423 | }, 2424 | "dist": { 2425 | "type": "zip", 2426 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", 2427 | "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", 2428 | "shasum": "" 2429 | }, 2430 | "require": { 2431 | "php": ">=8.2", 2432 | "symfony/polyfill-ctype": "~1.8", 2433 | "symfony/polyfill-mbstring": "~1.8" 2434 | }, 2435 | "require-dev": { 2436 | "symfony/process": "^6.4|^7.0" 2437 | }, 2438 | "type": "library", 2439 | "autoload": { 2440 | "psr-4": { 2441 | "Symfony\\Component\\Filesystem\\": "" 2442 | }, 2443 | "exclude-from-classmap": [ 2444 | "/Tests/" 2445 | ] 2446 | }, 2447 | "notification-url": "https://packagist.org/downloads/", 2448 | "license": [ 2449 | "MIT" 2450 | ], 2451 | "authors": [ 2452 | { 2453 | "name": "Fabien Potencier", 2454 | "email": "fabien@symfony.com" 2455 | }, 2456 | { 2457 | "name": "Symfony Community", 2458 | "homepage": "https://symfony.com/contributors" 2459 | } 2460 | ], 2461 | "description": "Provides basic utilities for the filesystem", 2462 | "homepage": "https://symfony.com", 2463 | "support": { 2464 | "source": "https://github.com/symfony/filesystem/tree/v7.2.0" 2465 | }, 2466 | "funding": [ 2467 | { 2468 | "url": "https://symfony.com/sponsor", 2469 | "type": "custom" 2470 | }, 2471 | { 2472 | "url": "https://github.com/fabpot", 2473 | "type": "github" 2474 | }, 2475 | { 2476 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2477 | "type": "tidelift" 2478 | } 2479 | ], 2480 | "time": "2024-10-25T15:15:23+00:00" 2481 | }, 2482 | { 2483 | "name": "symfony/finder", 2484 | "version": "v7.2.2", 2485 | "source": { 2486 | "type": "git", 2487 | "url": "https://github.com/symfony/finder.git", 2488 | "reference": "87a71856f2f56e4100373e92529eed3171695cfb" 2489 | }, 2490 | "dist": { 2491 | "type": "zip", 2492 | "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", 2493 | "reference": "87a71856f2f56e4100373e92529eed3171695cfb", 2494 | "shasum": "" 2495 | }, 2496 | "require": { 2497 | "php": ">=8.2" 2498 | }, 2499 | "require-dev": { 2500 | "symfony/filesystem": "^6.4|^7.0" 2501 | }, 2502 | "type": "library", 2503 | "autoload": { 2504 | "psr-4": { 2505 | "Symfony\\Component\\Finder\\": "" 2506 | }, 2507 | "exclude-from-classmap": [ 2508 | "/Tests/" 2509 | ] 2510 | }, 2511 | "notification-url": "https://packagist.org/downloads/", 2512 | "license": [ 2513 | "MIT" 2514 | ], 2515 | "authors": [ 2516 | { 2517 | "name": "Fabien Potencier", 2518 | "email": "fabien@symfony.com" 2519 | }, 2520 | { 2521 | "name": "Symfony Community", 2522 | "homepage": "https://symfony.com/contributors" 2523 | } 2524 | ], 2525 | "description": "Finds files and directories via an intuitive fluent interface", 2526 | "homepage": "https://symfony.com", 2527 | "support": { 2528 | "source": "https://github.com/symfony/finder/tree/v7.2.2" 2529 | }, 2530 | "funding": [ 2531 | { 2532 | "url": "https://symfony.com/sponsor", 2533 | "type": "custom" 2534 | }, 2535 | { 2536 | "url": "https://github.com/fabpot", 2537 | "type": "github" 2538 | }, 2539 | { 2540 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2541 | "type": "tidelift" 2542 | } 2543 | ], 2544 | "time": "2024-12-30T19:00:17+00:00" 2545 | }, 2546 | { 2547 | "name": "symfony/options-resolver", 2548 | "version": "v7.2.0", 2549 | "source": { 2550 | "type": "git", 2551 | "url": "https://github.com/symfony/options-resolver.git", 2552 | "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" 2553 | }, 2554 | "dist": { 2555 | "type": "zip", 2556 | "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", 2557 | "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", 2558 | "shasum": "" 2559 | }, 2560 | "require": { 2561 | "php": ">=8.2", 2562 | "symfony/deprecation-contracts": "^2.5|^3" 2563 | }, 2564 | "type": "library", 2565 | "autoload": { 2566 | "psr-4": { 2567 | "Symfony\\Component\\OptionsResolver\\": "" 2568 | }, 2569 | "exclude-from-classmap": [ 2570 | "/Tests/" 2571 | ] 2572 | }, 2573 | "notification-url": "https://packagist.org/downloads/", 2574 | "license": [ 2575 | "MIT" 2576 | ], 2577 | "authors": [ 2578 | { 2579 | "name": "Fabien Potencier", 2580 | "email": "fabien@symfony.com" 2581 | }, 2582 | { 2583 | "name": "Symfony Community", 2584 | "homepage": "https://symfony.com/contributors" 2585 | } 2586 | ], 2587 | "description": "Provides an improved replacement for the array_replace PHP function", 2588 | "homepage": "https://symfony.com", 2589 | "keywords": [ 2590 | "config", 2591 | "configuration", 2592 | "options" 2593 | ], 2594 | "support": { 2595 | "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" 2596 | }, 2597 | "funding": [ 2598 | { 2599 | "url": "https://symfony.com/sponsor", 2600 | "type": "custom" 2601 | }, 2602 | { 2603 | "url": "https://github.com/fabpot", 2604 | "type": "github" 2605 | }, 2606 | { 2607 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2608 | "type": "tidelift" 2609 | } 2610 | ], 2611 | "time": "2024-11-20T11:17:29+00:00" 2612 | }, 2613 | { 2614 | "name": "symfony/polyfill-ctype", 2615 | "version": "v1.31.0", 2616 | "source": { 2617 | "type": "git", 2618 | "url": "https://github.com/symfony/polyfill-ctype.git", 2619 | "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" 2620 | }, 2621 | "dist": { 2622 | "type": "zip", 2623 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", 2624 | "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", 2625 | "shasum": "" 2626 | }, 2627 | "require": { 2628 | "php": ">=7.2" 2629 | }, 2630 | "provide": { 2631 | "ext-ctype": "*" 2632 | }, 2633 | "suggest": { 2634 | "ext-ctype": "For best performance" 2635 | }, 2636 | "type": "library", 2637 | "extra": { 2638 | "thanks": { 2639 | "url": "https://github.com/symfony/polyfill", 2640 | "name": "symfony/polyfill" 2641 | } 2642 | }, 2643 | "autoload": { 2644 | "files": [ 2645 | "bootstrap.php" 2646 | ], 2647 | "psr-4": { 2648 | "Symfony\\Polyfill\\Ctype\\": "" 2649 | } 2650 | }, 2651 | "notification-url": "https://packagist.org/downloads/", 2652 | "license": [ 2653 | "MIT" 2654 | ], 2655 | "authors": [ 2656 | { 2657 | "name": "Gert de Pagter", 2658 | "email": "BackEndTea@gmail.com" 2659 | }, 2660 | { 2661 | "name": "Symfony Community", 2662 | "homepage": "https://symfony.com/contributors" 2663 | } 2664 | ], 2665 | "description": "Symfony polyfill for ctype functions", 2666 | "homepage": "https://symfony.com", 2667 | "keywords": [ 2668 | "compatibility", 2669 | "ctype", 2670 | "polyfill", 2671 | "portable" 2672 | ], 2673 | "support": { 2674 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" 2675 | }, 2676 | "funding": [ 2677 | { 2678 | "url": "https://symfony.com/sponsor", 2679 | "type": "custom" 2680 | }, 2681 | { 2682 | "url": "https://github.com/fabpot", 2683 | "type": "github" 2684 | }, 2685 | { 2686 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2687 | "type": "tidelift" 2688 | } 2689 | ], 2690 | "time": "2024-09-09T11:45:10+00:00" 2691 | }, 2692 | { 2693 | "name": "symfony/polyfill-intl-grapheme", 2694 | "version": "v1.31.0", 2695 | "source": { 2696 | "type": "git", 2697 | "url": "https://github.com/symfony/polyfill-intl-grapheme.git", 2698 | "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" 2699 | }, 2700 | "dist": { 2701 | "type": "zip", 2702 | "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", 2703 | "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", 2704 | "shasum": "" 2705 | }, 2706 | "require": { 2707 | "php": ">=7.2" 2708 | }, 2709 | "suggest": { 2710 | "ext-intl": "For best performance" 2711 | }, 2712 | "type": "library", 2713 | "extra": { 2714 | "thanks": { 2715 | "url": "https://github.com/symfony/polyfill", 2716 | "name": "symfony/polyfill" 2717 | } 2718 | }, 2719 | "autoload": { 2720 | "files": [ 2721 | "bootstrap.php" 2722 | ], 2723 | "psr-4": { 2724 | "Symfony\\Polyfill\\Intl\\Grapheme\\": "" 2725 | } 2726 | }, 2727 | "notification-url": "https://packagist.org/downloads/", 2728 | "license": [ 2729 | "MIT" 2730 | ], 2731 | "authors": [ 2732 | { 2733 | "name": "Nicolas Grekas", 2734 | "email": "p@tchwork.com" 2735 | }, 2736 | { 2737 | "name": "Symfony Community", 2738 | "homepage": "https://symfony.com/contributors" 2739 | } 2740 | ], 2741 | "description": "Symfony polyfill for intl's grapheme_* functions", 2742 | "homepage": "https://symfony.com", 2743 | "keywords": [ 2744 | "compatibility", 2745 | "grapheme", 2746 | "intl", 2747 | "polyfill", 2748 | "portable", 2749 | "shim" 2750 | ], 2751 | "support": { 2752 | "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" 2753 | }, 2754 | "funding": [ 2755 | { 2756 | "url": "https://symfony.com/sponsor", 2757 | "type": "custom" 2758 | }, 2759 | { 2760 | "url": "https://github.com/fabpot", 2761 | "type": "github" 2762 | }, 2763 | { 2764 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2765 | "type": "tidelift" 2766 | } 2767 | ], 2768 | "time": "2024-09-09T11:45:10+00:00" 2769 | }, 2770 | { 2771 | "name": "symfony/polyfill-intl-normalizer", 2772 | "version": "v1.31.0", 2773 | "source": { 2774 | "type": "git", 2775 | "url": "https://github.com/symfony/polyfill-intl-normalizer.git", 2776 | "reference": "3833d7255cc303546435cb650316bff708a1c75c" 2777 | }, 2778 | "dist": { 2779 | "type": "zip", 2780 | "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", 2781 | "reference": "3833d7255cc303546435cb650316bff708a1c75c", 2782 | "shasum": "" 2783 | }, 2784 | "require": { 2785 | "php": ">=7.2" 2786 | }, 2787 | "suggest": { 2788 | "ext-intl": "For best performance" 2789 | }, 2790 | "type": "library", 2791 | "extra": { 2792 | "thanks": { 2793 | "url": "https://github.com/symfony/polyfill", 2794 | "name": "symfony/polyfill" 2795 | } 2796 | }, 2797 | "autoload": { 2798 | "files": [ 2799 | "bootstrap.php" 2800 | ], 2801 | "psr-4": { 2802 | "Symfony\\Polyfill\\Intl\\Normalizer\\": "" 2803 | }, 2804 | "classmap": [ 2805 | "Resources/stubs" 2806 | ] 2807 | }, 2808 | "notification-url": "https://packagist.org/downloads/", 2809 | "license": [ 2810 | "MIT" 2811 | ], 2812 | "authors": [ 2813 | { 2814 | "name": "Nicolas Grekas", 2815 | "email": "p@tchwork.com" 2816 | }, 2817 | { 2818 | "name": "Symfony Community", 2819 | "homepage": "https://symfony.com/contributors" 2820 | } 2821 | ], 2822 | "description": "Symfony polyfill for intl's Normalizer class and related functions", 2823 | "homepage": "https://symfony.com", 2824 | "keywords": [ 2825 | "compatibility", 2826 | "intl", 2827 | "normalizer", 2828 | "polyfill", 2829 | "portable", 2830 | "shim" 2831 | ], 2832 | "support": { 2833 | "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" 2834 | }, 2835 | "funding": [ 2836 | { 2837 | "url": "https://symfony.com/sponsor", 2838 | "type": "custom" 2839 | }, 2840 | { 2841 | "url": "https://github.com/fabpot", 2842 | "type": "github" 2843 | }, 2844 | { 2845 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2846 | "type": "tidelift" 2847 | } 2848 | ], 2849 | "time": "2024-09-09T11:45:10+00:00" 2850 | }, 2851 | { 2852 | "name": "symfony/polyfill-mbstring", 2853 | "version": "v1.31.0", 2854 | "source": { 2855 | "type": "git", 2856 | "url": "https://github.com/symfony/polyfill-mbstring.git", 2857 | "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" 2858 | }, 2859 | "dist": { 2860 | "type": "zip", 2861 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", 2862 | "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", 2863 | "shasum": "" 2864 | }, 2865 | "require": { 2866 | "php": ">=7.2" 2867 | }, 2868 | "provide": { 2869 | "ext-mbstring": "*" 2870 | }, 2871 | "suggest": { 2872 | "ext-mbstring": "For best performance" 2873 | }, 2874 | "type": "library", 2875 | "extra": { 2876 | "thanks": { 2877 | "url": "https://github.com/symfony/polyfill", 2878 | "name": "symfony/polyfill" 2879 | } 2880 | }, 2881 | "autoload": { 2882 | "files": [ 2883 | "bootstrap.php" 2884 | ], 2885 | "psr-4": { 2886 | "Symfony\\Polyfill\\Mbstring\\": "" 2887 | } 2888 | }, 2889 | "notification-url": "https://packagist.org/downloads/", 2890 | "license": [ 2891 | "MIT" 2892 | ], 2893 | "authors": [ 2894 | { 2895 | "name": "Nicolas Grekas", 2896 | "email": "p@tchwork.com" 2897 | }, 2898 | { 2899 | "name": "Symfony Community", 2900 | "homepage": "https://symfony.com/contributors" 2901 | } 2902 | ], 2903 | "description": "Symfony polyfill for the Mbstring extension", 2904 | "homepage": "https://symfony.com", 2905 | "keywords": [ 2906 | "compatibility", 2907 | "mbstring", 2908 | "polyfill", 2909 | "portable", 2910 | "shim" 2911 | ], 2912 | "support": { 2913 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" 2914 | }, 2915 | "funding": [ 2916 | { 2917 | "url": "https://symfony.com/sponsor", 2918 | "type": "custom" 2919 | }, 2920 | { 2921 | "url": "https://github.com/fabpot", 2922 | "type": "github" 2923 | }, 2924 | { 2925 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2926 | "type": "tidelift" 2927 | } 2928 | ], 2929 | "time": "2024-09-09T11:45:10+00:00" 2930 | }, 2931 | { 2932 | "name": "symfony/process", 2933 | "version": "v7.2.4", 2934 | "source": { 2935 | "type": "git", 2936 | "url": "https://github.com/symfony/process.git", 2937 | "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" 2938 | }, 2939 | "dist": { 2940 | "type": "zip", 2941 | "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", 2942 | "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", 2943 | "shasum": "" 2944 | }, 2945 | "require": { 2946 | "php": ">=8.2" 2947 | }, 2948 | "type": "library", 2949 | "autoload": { 2950 | "psr-4": { 2951 | "Symfony\\Component\\Process\\": "" 2952 | }, 2953 | "exclude-from-classmap": [ 2954 | "/Tests/" 2955 | ] 2956 | }, 2957 | "notification-url": "https://packagist.org/downloads/", 2958 | "license": [ 2959 | "MIT" 2960 | ], 2961 | "authors": [ 2962 | { 2963 | "name": "Fabien Potencier", 2964 | "email": "fabien@symfony.com" 2965 | }, 2966 | { 2967 | "name": "Symfony Community", 2968 | "homepage": "https://symfony.com/contributors" 2969 | } 2970 | ], 2971 | "description": "Executes commands in sub-processes", 2972 | "homepage": "https://symfony.com", 2973 | "support": { 2974 | "source": "https://github.com/symfony/process/tree/v7.2.4" 2975 | }, 2976 | "funding": [ 2977 | { 2978 | "url": "https://symfony.com/sponsor", 2979 | "type": "custom" 2980 | }, 2981 | { 2982 | "url": "https://github.com/fabpot", 2983 | "type": "github" 2984 | }, 2985 | { 2986 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2987 | "type": "tidelift" 2988 | } 2989 | ], 2990 | "time": "2025-02-05T08:33:46+00:00" 2991 | }, 2992 | { 2993 | "name": "symfony/service-contracts", 2994 | "version": "v3.5.1", 2995 | "source": { 2996 | "type": "git", 2997 | "url": "https://github.com/symfony/service-contracts.git", 2998 | "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" 2999 | }, 3000 | "dist": { 3001 | "type": "zip", 3002 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", 3003 | "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", 3004 | "shasum": "" 3005 | }, 3006 | "require": { 3007 | "php": ">=8.1", 3008 | "psr/container": "^1.1|^2.0", 3009 | "symfony/deprecation-contracts": "^2.5|^3" 3010 | }, 3011 | "conflict": { 3012 | "ext-psr": "<1.1|>=2" 3013 | }, 3014 | "type": "library", 3015 | "extra": { 3016 | "thanks": { 3017 | "url": "https://github.com/symfony/contracts", 3018 | "name": "symfony/contracts" 3019 | }, 3020 | "branch-alias": { 3021 | "dev-main": "3.5-dev" 3022 | } 3023 | }, 3024 | "autoload": { 3025 | "psr-4": { 3026 | "Symfony\\Contracts\\Service\\": "" 3027 | }, 3028 | "exclude-from-classmap": [ 3029 | "/Test/" 3030 | ] 3031 | }, 3032 | "notification-url": "https://packagist.org/downloads/", 3033 | "license": [ 3034 | "MIT" 3035 | ], 3036 | "authors": [ 3037 | { 3038 | "name": "Nicolas Grekas", 3039 | "email": "p@tchwork.com" 3040 | }, 3041 | { 3042 | "name": "Symfony Community", 3043 | "homepage": "https://symfony.com/contributors" 3044 | } 3045 | ], 3046 | "description": "Generic abstractions related to writing services", 3047 | "homepage": "https://symfony.com", 3048 | "keywords": [ 3049 | "abstractions", 3050 | "contracts", 3051 | "decoupling", 3052 | "interfaces", 3053 | "interoperability", 3054 | "standards" 3055 | ], 3056 | "support": { 3057 | "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" 3058 | }, 3059 | "funding": [ 3060 | { 3061 | "url": "https://symfony.com/sponsor", 3062 | "type": "custom" 3063 | }, 3064 | { 3065 | "url": "https://github.com/fabpot", 3066 | "type": "github" 3067 | }, 3068 | { 3069 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 3070 | "type": "tidelift" 3071 | } 3072 | ], 3073 | "time": "2024-09-25T14:20:29+00:00" 3074 | }, 3075 | { 3076 | "name": "symfony/string", 3077 | "version": "v7.2.0", 3078 | "source": { 3079 | "type": "git", 3080 | "url": "https://github.com/symfony/string.git", 3081 | "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" 3082 | }, 3083 | "dist": { 3084 | "type": "zip", 3085 | "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", 3086 | "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", 3087 | "shasum": "" 3088 | }, 3089 | "require": { 3090 | "php": ">=8.2", 3091 | "symfony/polyfill-ctype": "~1.8", 3092 | "symfony/polyfill-intl-grapheme": "~1.0", 3093 | "symfony/polyfill-intl-normalizer": "~1.0", 3094 | "symfony/polyfill-mbstring": "~1.0" 3095 | }, 3096 | "conflict": { 3097 | "symfony/translation-contracts": "<2.5" 3098 | }, 3099 | "require-dev": { 3100 | "symfony/emoji": "^7.1", 3101 | "symfony/error-handler": "^6.4|^7.0", 3102 | "symfony/http-client": "^6.4|^7.0", 3103 | "symfony/intl": "^6.4|^7.0", 3104 | "symfony/translation-contracts": "^2.5|^3.0", 3105 | "symfony/var-exporter": "^6.4|^7.0" 3106 | }, 3107 | "type": "library", 3108 | "autoload": { 3109 | "files": [ 3110 | "Resources/functions.php" 3111 | ], 3112 | "psr-4": { 3113 | "Symfony\\Component\\String\\": "" 3114 | }, 3115 | "exclude-from-classmap": [ 3116 | "/Tests/" 3117 | ] 3118 | }, 3119 | "notification-url": "https://packagist.org/downloads/", 3120 | "license": [ 3121 | "MIT" 3122 | ], 3123 | "authors": [ 3124 | { 3125 | "name": "Nicolas Grekas", 3126 | "email": "p@tchwork.com" 3127 | }, 3128 | { 3129 | "name": "Symfony Community", 3130 | "homepage": "https://symfony.com/contributors" 3131 | } 3132 | ], 3133 | "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", 3134 | "homepage": "https://symfony.com", 3135 | "keywords": [ 3136 | "grapheme", 3137 | "i18n", 3138 | "string", 3139 | "unicode", 3140 | "utf-8", 3141 | "utf8" 3142 | ], 3143 | "support": { 3144 | "source": "https://github.com/symfony/string/tree/v7.2.0" 3145 | }, 3146 | "funding": [ 3147 | { 3148 | "url": "https://symfony.com/sponsor", 3149 | "type": "custom" 3150 | }, 3151 | { 3152 | "url": "https://github.com/fabpot", 3153 | "type": "github" 3154 | }, 3155 | { 3156 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 3157 | "type": "tidelift" 3158 | } 3159 | ], 3160 | "time": "2024-11-13T13:31:26+00:00" 3161 | }, 3162 | { 3163 | "name": "theseer/tokenizer", 3164 | "version": "1.2.3", 3165 | "source": { 3166 | "type": "git", 3167 | "url": "https://github.com/theseer/tokenizer.git", 3168 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" 3169 | }, 3170 | "dist": { 3171 | "type": "zip", 3172 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", 3173 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", 3174 | "shasum": "" 3175 | }, 3176 | "require": { 3177 | "ext-dom": "*", 3178 | "ext-tokenizer": "*", 3179 | "ext-xmlwriter": "*", 3180 | "php": "^7.2 || ^8.0" 3181 | }, 3182 | "type": "library", 3183 | "autoload": { 3184 | "classmap": [ 3185 | "src/" 3186 | ] 3187 | }, 3188 | "notification-url": "https://packagist.org/downloads/", 3189 | "license": [ 3190 | "BSD-3-Clause" 3191 | ], 3192 | "authors": [ 3193 | { 3194 | "name": "Arne Blankerts", 3195 | "email": "arne@blankerts.de", 3196 | "role": "Developer" 3197 | } 3198 | ], 3199 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 3200 | "support": { 3201 | "issues": "https://github.com/theseer/tokenizer/issues", 3202 | "source": "https://github.com/theseer/tokenizer/tree/1.2.3" 3203 | }, 3204 | "funding": [ 3205 | { 3206 | "url": "https://github.com/theseer", 3207 | "type": "github" 3208 | } 3209 | ], 3210 | "time": "2024-03-03T12:36:25+00:00" 3211 | }, 3212 | { 3213 | "name": "webmozart/glob", 3214 | "version": "4.7.0", 3215 | "source": { 3216 | "type": "git", 3217 | "url": "https://github.com/webmozarts/glob.git", 3218 | "reference": "8a2842112d6916e61e0e15e316465b611f3abc17" 3219 | }, 3220 | "dist": { 3221 | "type": "zip", 3222 | "url": "https://api.github.com/repos/webmozarts/glob/zipball/8a2842112d6916e61e0e15e316465b611f3abc17", 3223 | "reference": "8a2842112d6916e61e0e15e316465b611f3abc17", 3224 | "shasum": "" 3225 | }, 3226 | "require": { 3227 | "php": "^7.3 || ^8.0.0" 3228 | }, 3229 | "require-dev": { 3230 | "phpunit/phpunit": "^9.5", 3231 | "symfony/filesystem": "^5.3" 3232 | }, 3233 | "type": "library", 3234 | "extra": { 3235 | "branch-alias": { 3236 | "dev-master": "4.1-dev" 3237 | } 3238 | }, 3239 | "autoload": { 3240 | "psr-4": { 3241 | "Webmozart\\Glob\\": "src/" 3242 | } 3243 | }, 3244 | "notification-url": "https://packagist.org/downloads/", 3245 | "license": [ 3246 | "MIT" 3247 | ], 3248 | "authors": [ 3249 | { 3250 | "name": "Bernhard Schussek", 3251 | "email": "bschussek@gmail.com" 3252 | } 3253 | ], 3254 | "description": "A PHP implementation of Ant's glob.", 3255 | "support": { 3256 | "issues": "https://github.com/webmozarts/glob/issues", 3257 | "source": "https://github.com/webmozarts/glob/tree/4.7.0" 3258 | }, 3259 | "time": "2024-03-07T20:33:40+00:00" 3260 | } 3261 | ], 3262 | "aliases": [], 3263 | "minimum-stability": "stable", 3264 | "stability-flags": {}, 3265 | "prefer-stable": false, 3266 | "prefer-lowest": false, 3267 | "platform": { 3268 | "php": ">=8.1" 3269 | }, 3270 | "platform-dev": {}, 3271 | "plugin-api-version": "2.6.0" 3272 | } 3273 | -------------------------------------------------------------------------------- /src/Bus/EventBusTrait.php: -------------------------------------------------------------------------------- 1 | events = $events; 17 | } 18 | 19 | public function setFilters(FilterEmitterInterface $filters): void 20 | { 21 | $this->filters = $filters; 22 | } 23 | 24 | public function filter(string $name, mixed $value, array $arguments = []): mixed 25 | { 26 | return $this->filters ? $this->filters->emit($name, $value, $arguments) : $value; 27 | } 28 | 29 | public function emit(string $name, array $arguments = []): void 30 | { 31 | $this->events?->emit($name, $arguments); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/EventEmitter.php: -------------------------------------------------------------------------------- 1 | listeners[$name] ?? [] as $i => $listener) { 16 | match ($countArgs) { 17 | 0 => ($listener->handler)(...$listener->extraArgs), 18 | 1 => ($listener->handler)($args[0], ...$listener->extraArgs), 19 | 2 => ($listener->handler)($args[0], $args[1], ...$listener->extraArgs), 20 | default => ($listener->handler)(...$args, ...$listener->extraArgs), 21 | }; 22 | 23 | if ($listener->once) { 24 | unset($this->listeners[$name][$i]); 25 | if (count($this->listeners[$name]) === 0) { 26 | unset($this->listeners[$name]); 27 | } 28 | } 29 | } 30 | } catch (StopPropagation) { 31 | return; 32 | } 33 | } 34 | 35 | public function emitNoArgs(string $name): void 36 | { 37 | try { 38 | foreach ($this->listeners[$name] ?? [] as $i => $listener) { 39 | ($listener->handler)(...$listener->extraArgs); 40 | 41 | if ($listener->once) { 42 | unset($this->listeners[$name][$i]); 43 | if (count($this->listeners[$name]) === 0) { 44 | unset($this->listeners[$name]); 45 | } 46 | } 47 | } 48 | } catch (StopPropagation) { 49 | return; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/EventEmitterInterface.php: -------------------------------------------------------------------------------- 1 | listeners[$name] ?? [] as $i => $listener) { 17 | match ($countArgs) { 18 | 0 => ($listener->handler)(), 19 | 1 => ($listener->handler)($args[0]), 20 | 2 => ($listener->handler)($args[0], $args[1]), 21 | default => ($listener->handler)(...$args), 22 | }; 23 | 24 | if ($listener->once) { 25 | unset($this->listeners[$name][$i]); 26 | if (count($this->listeners[$name]) === 0) { 27 | unset($this->listeners[$name]); 28 | } 29 | } 30 | } 31 | } catch (StopPropagation) { 32 | return; 33 | } 34 | } 35 | 36 | public function emitNoArgs(string $name): void 37 | { 38 | try { 39 | foreach ($this->listeners[$name] ?? [] as $i => $listener) { 40 | ($listener->handler)(); 41 | 42 | if ($listener->once) { 43 | unset($this->listeners[$name][$i]); 44 | if (count($this->listeners[$name]) === 0) { 45 | unset($this->listeners[$name]); 46 | } 47 | } 48 | } 49 | } catch (StopPropagation) { 50 | return; 51 | } 52 | } 53 | 54 | public function listeners(?string $event = null): array 55 | { 56 | if ($event === null) { 57 | return $this->listeners; 58 | } 59 | 60 | return $this->listeners[$event] ?? []; 61 | } 62 | 63 | public function eventNames(): array 64 | { 65 | return array_keys($this->listeners()); 66 | } 67 | 68 | protected function sortEventHandler(string $name): void 69 | { 70 | $sorted = []; 71 | foreach ($this->listeners[$name] as $listener) { 72 | $sorted[$listener->priority][] = $listener; 73 | } 74 | 75 | krsort($sorted, SORT_NUMERIC); 76 | $this->listeners[$name] = array_merge(...$sorted); 77 | } 78 | 79 | public function on(string $name, callable $handler, int $priority = 50, array $extraArgs = []): static 80 | { 81 | $this->listeners[$name][] = new EventHandler($handler, $priority, $extraArgs); 82 | $this->sortEventHandler($name); 83 | 84 | return $this; 85 | } 86 | 87 | public function once(string $name, callable $handler, int $priority = 50, array $extraArgs = []): static 88 | { 89 | $eventHandler = new EventHandler($handler, $priority, $extraArgs); 90 | $eventHandler->once = true; 91 | $this->listeners[$name][] = $eventHandler; 92 | 93 | $this->sortEventHandler($name); 94 | 95 | return $this; 96 | } 97 | 98 | public function off(string $event, ?callable $handler = null, ?int $priority = null): static 99 | { 100 | if ($handler === null) { 101 | unset($this->listeners[$event]); 102 | return $this; 103 | } 104 | 105 | foreach ($this->listeners[$event] as $i => $listener) { 106 | if ($listener->isSame($handler, $priority)) { 107 | unset($this->listeners[$event][$i]); 108 | } 109 | } 110 | 111 | if (count($this->listeners[$event]) === 0) { 112 | unset($this->listeners[$event]); 113 | } 114 | 115 | return $this; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/EventExtraArgsEmitter.php: -------------------------------------------------------------------------------- 1 | id = $this->getHandlerId($handler); 19 | $this->handler = $handler; 20 | } 21 | 22 | protected function getHandlerId(callable $handler): string 23 | { 24 | if (is_array($handler)) { 25 | [$className, $method] = $handler; 26 | 27 | if (is_object($className)) { 28 | $className = get_class($className); 29 | } 30 | 31 | return "{$className}::{$method}"; 32 | } 33 | 34 | return is_string($handler) ? $handler : spl_object_hash($handler); 35 | } 36 | 37 | public function isSame(callable $handler, ?int $priority = null): bool 38 | { 39 | $withPriority = $priority !== null; 40 | if ($withPriority && $priority !== $this->priority) { 41 | return false; 42 | } 43 | 44 | return $this->id === $this->getHandlerId($handler); 45 | } 46 | } -------------------------------------------------------------------------------- /src/Filter/FilterEmitter.php: -------------------------------------------------------------------------------- 1 | listeners[$name] ?? [] as $i => $listener) { 19 | $value = match ($countArgs) { 20 | 0 => ($listener->handler)($value, ...$listener->extraArgs), 21 | 1 => ($listener->handler)($value, $args[0], ...$listener->extraArgs), 22 | 2 => ($listener->handler)($value, $args[0], $args[1], ...$listener->extraArgs), 23 | 3 => ($listener->handler)($value, $args[0], $args[1], $args[2], ...$listener->extraArgs), 24 | default => ($listener->handler)($value, ...$args, ...$listener->extraArgs), 25 | }; 26 | 27 | if ($listener->once) { 28 | unset($this->listeners[$name][$i]); 29 | if (count($this->listeners[$name]) === 0) { 30 | unset($this->listeners[$name]); 31 | } 32 | } 33 | } 34 | } catch (StopPropagation $e) { 35 | return $e->getValue(); 36 | } 37 | 38 | return $value; 39 | } 40 | 41 | public function emitNoArgs(string $name, mixed $value): mixed 42 | { 43 | try { 44 | foreach ($this->listeners[$name] ?? [] as $i => $listener) { 45 | $value = ($listener->handler)($value, ...$listener->extraArgs); 46 | 47 | if ($listener->once) { 48 | unset($this->listeners[$name][$i]); 49 | if (count($this->listeners[$name]) === 0) { 50 | unset($this->listeners[$name]); 51 | } 52 | } 53 | } 54 | } catch (StopPropagation $e) { 55 | return $e->getValue(); 56 | } 57 | 58 | return $value; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Filter/FilterEmitterInterface.php: -------------------------------------------------------------------------------- 1 | listeners[$name] ?? [] as $i => $listener) { 19 | $value = match ($countArgs) { 20 | 0 => ($listener->handler)($value), 21 | 1 => ($listener->handler)($value, $args[0]), 22 | 2 => ($listener->handler)($value, $args[0], $args[1]), 23 | 3 => ($listener->handler)($value, $args[0], $args[1], $args[2]), 24 | default => ($listener->handler)($value, ...$args), 25 | }; 26 | 27 | if ($listener->once) { 28 | unset($this->listeners[$name][$i]); 29 | if (count($this->listeners[$name]) === 0) { 30 | unset($this->listeners[$name]); 31 | } 32 | } 33 | } 34 | } catch (StopPropagation $e) { 35 | return $e->getValue(); 36 | } 37 | 38 | return $value; 39 | } 40 | 41 | public function emitNoArgs(string $name, mixed $value): mixed 42 | { 43 | try { 44 | foreach ($this->listeners[$name] ?? [] as $i => $listener) { 45 | $value = ($listener->handler)($value); 46 | 47 | if ($listener->once) { 48 | unset($this->listeners[$name][$i]); 49 | if (count($this->listeners[$name]) === 0) { 50 | unset($this->listeners[$name]); 51 | } 52 | } 53 | } 54 | } catch (StopPropagation $e) { 55 | return $e->getValue(); 56 | } 57 | 58 | return $value; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Filter/FilterExtraArgsEmitter.php: -------------------------------------------------------------------------------- 1 | value = $value; 15 | return $this; 16 | } 17 | 18 | public function getValue() 19 | { 20 | return $this->value; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/benchmarks/EventsBench.php: -------------------------------------------------------------------------------- 1 | emitter = new EventEmitter; 24 | $this->emitterEA = new EventEmitterExtraArgs; 25 | 26 | $this->emitter->on('some.event', static fn() => 1); 27 | $this->emitterEA->on('some.event', static fn() => 1); 28 | } 29 | 30 | /** 31 | * @Subject event emit 32 | * @Revs(100000) 33 | * @Iterations(20) 34 | * @BeforeMethods({"init"}) 35 | * @OutputTimeUnit("microseconds", precision=3) 36 | * @OutputMode("throughput") 37 | * @Warmup(1) 38 | */ 39 | public function emit(): void 40 | { 41 | $this->emitter->emit('some.event'); 42 | } 43 | 44 | /** 45 | * @Subject EA: event emit 46 | * @Revs(100000) 47 | * @Iterations(20) 48 | * @BeforeMethods({"init"}) 49 | * @OutputTimeUnit("microseconds", precision=3) 50 | * @OutputMode("throughput") 51 | * @Warmup(1) 52 | */ 53 | public function EA_emit(): void 54 | { 55 | $this->emitterEA->emit('some.event'); 56 | } 57 | 58 | /** 59 | * @Subject event emit no args 60 | * @Revs(100000) 61 | * @Iterations(20) 62 | * @BeforeMethods({"init"}) 63 | * @OutputTimeUnit("microseconds", precision=3) 64 | * @OutputMode("throughput") 65 | * @Warmup(1) 66 | */ 67 | public function emitNoArgs(): void 68 | { 69 | $this->emitter->emitNoArgs('some.event'); 70 | } 71 | 72 | /** 73 | * @Subject EA: event emitEA no args 74 | * @Revs(100000) 75 | * @Iterations(20) 76 | * @BeforeMethods({"init"}) 77 | * @OutputTimeUnit("microseconds", precision=3) 78 | * @OutputMode("throughput") 79 | * @Warmup(1) 80 | */ 81 | public function EA_emitNoArgs(): void 82 | { 83 | $this->emitterEA->emitNoArgs('some.event'); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /test/benchmarks/FilterBench.php: -------------------------------------------------------------------------------- 1 | filters = new FilterEmitter; 22 | $this->filters->on('some.filter', static fn($i) => $i++); 23 | } 24 | 25 | /** 26 | * @Subject event emit 27 | * @Revs(100000) 28 | * @Iterations(20) 29 | * @BeforeMethods({"init"}) 30 | * @OutputTimeUnit("microseconds", precision=3) 31 | * @OutputMode("throughput") 32 | * @Warmup(1) 33 | */ 34 | public function emit(): void 35 | { 36 | $this->filters->emit('some.filter', 1); 37 | } 38 | 39 | /** 40 | * @Subject event emit no args 41 | * @Revs(100000) 42 | * @Iterations(20) 43 | * @BeforeMethods({"init"}) 44 | * @OutputTimeUnit("microseconds", precision=3) 45 | * @OutputMode("throughput") 46 | * @Warmup(1) 47 | */ 48 | public function emitNoArgs(): void 49 | { 50 | $this->filters->emitNoArgs('some.event', 1); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/phpbench.json: -------------------------------------------------------------------------------- 1 | { 2 | "runner.bootstrap": "../vendor/autoload.php", 3 | "runner.path": "benchmarks", 4 | "runner.time_unit": "microseconds", 5 | "runner.progress": "blinken" 6 | } -------------------------------------------------------------------------------- /test/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ./unit/Event 17 | 18 | 19 | ./unit/Filter 20 | 21 | 22 | ./unit/Bus 23 | 24 | 25 | 26 | 27 | ../src/ 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/unit/Bus/EventBusTraitTest.php: -------------------------------------------------------------------------------- 1 | events = new EventEmitter; 31 | $this->filters = new FilterEmitter; 32 | } 33 | 34 | /** 35 | * @return EventBusTrait|MockObject 36 | */ 37 | protected function getTraitMock() 38 | { 39 | return $this->getMockBuilder(EventBusTrait::class)->getMockForTrait(); 40 | } 41 | 42 | /** 43 | * @param mixed $mock 44 | * @param string $prop 45 | * @return ReflectionProperty 46 | * @throws ReflectionException 47 | */ 48 | protected function getTraitProperty($mock, string $prop): ReflectionProperty 49 | { 50 | $class = new ReflectionClass($mock); 51 | $prop = $class->getProperty($prop); 52 | $prop->setAccessible(true); 53 | 54 | return $prop; 55 | } 56 | 57 | /** 58 | * @throws ReflectionException 59 | */ 60 | public function testSetEvent(): void 61 | { 62 | $emitter = $this->getTraitMock(); 63 | $emitter->setEvents($this->events); 64 | 65 | $prop = $this->getTraitProperty($emitter, 'events'); 66 | $actual = $prop->getValue($emitter); 67 | 68 | self::assertInstanceOf(EventEmitterInterface::class, $actual); 69 | } 70 | 71 | /** 72 | * @throws ReflectionException 73 | */ 74 | public function testSetFilters(): void 75 | { 76 | $emitter = $this->getTraitMock(); 77 | $emitter->setFilters($this->filters); 78 | 79 | $prop = $this->getTraitProperty($emitter, 'filters'); 80 | $actual = $prop->getValue($emitter); 81 | 82 | self::assertInstanceOf(FilterEmitterInterface::class, $actual); 83 | } 84 | 85 | /** 86 | * @param string $input 87 | * @param string $expected 88 | * @param bool $hasFilter 89 | */ 90 | #[DataProvider('dataProviderTestFilter')] 91 | public function testFilter(string $input, string $expected, bool $hasFilter = true): void 92 | { 93 | $this->filters->on('some.filter', 'trim'); 94 | $emitter = $this->getTraitMock(); 95 | 96 | if ($hasFilter) { 97 | $emitter->setFilters($this->filters); 98 | } 99 | 100 | $actual = $emitter->filter('some.filter', $input); 101 | self::assertSame($expected, $actual); 102 | } 103 | 104 | public static function dataProviderTestFilter(): array 105 | { 106 | return [ 107 | [ ' a ', 'a', true], 108 | [ ' a ', ' a ', false], 109 | ]; 110 | } 111 | 112 | public function testEmit(): void 113 | { 114 | $val = (object)['count' => 0]; 115 | $this->events->on('some.event', function (object $value) { 116 | $value->count++; 117 | }); 118 | 119 | $emitter = $this->getTraitMock(); 120 | 121 | $emitter->emit('some.event', [$val]); 122 | self::assertSame(0, $val->count); 123 | 124 | $emitter->setEvents($this->events); 125 | $emitter->emit('some.event', [$val]); 126 | self::assertSame(1, $val->count); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /test/unit/Event/EventHandlerTest.php: -------------------------------------------------------------------------------- 1 | 1; 15 | $callable2 = fn() => 2; 16 | 17 | $listener = new EventHandler($callable1, 0); 18 | static::assertTrue($listener->isSame($callable1)); 19 | static::assertTrue($listener->isSame($callable1, 0)); 20 | static::assertFalse($listener->isSame($callable1, 10)); 21 | static::assertFalse($listener->isSame($callable2)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/unit/Event/EventsEmitterExtraArgsTest.php: -------------------------------------------------------------------------------- 1 | events = new EventEmitterExtraArgs; 22 | $this->buffer = null; 23 | } 24 | 25 | public function testEmitNoArgs(): void 26 | { 27 | $handler = Closure::bind(function(string $title = 'default') { 28 | $this->buffer = $title; 29 | }, $this, get_class($this)); 30 | 31 | $this->events->on('some:event', $handler, 50, ['extraArg']); 32 | 33 | $this->events->emitNoArgs('some:event'); 34 | static::assertEquals('extraArg', $this->buffer); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/unit/Event/EventsEmitterTest.php: -------------------------------------------------------------------------------- 1 | events = new EventEmitter; 25 | $this->buffer = null; 26 | } 27 | 28 | public function customEventHandler(): void 29 | { 30 | $this->buffer = 'Work'; 31 | } 32 | 33 | public function testGetListeners(): void 34 | { 35 | static::assertCount(0, $this->events->listeners()); 36 | 37 | $this->events->on('some:event', 'trim'); 38 | static::assertCount(1, $this->events->listeners()); 39 | static::assertCount(1, $this->events->listeners('some:event')); 40 | static::assertCount(0, $this->events->listeners('not:defined')); 41 | } 42 | 43 | public function testSimpleEvent(): void 44 | { 45 | $this->events->on('some:event', [$this, 'customEventHandler']); 46 | static::assertNull($this->buffer); 47 | 48 | $this->events->emit('some:event'); 49 | static::assertEquals('Work', $this->buffer); 50 | } 51 | 52 | public function testDifferentCountArguments(): void 53 | { 54 | $handler = Closure::bind(function(...$args) { 55 | $this->buffer = array_sum($args); 56 | }, $this, get_class($this)); 57 | 58 | $this->events->on('some:event', $handler); 59 | 60 | $this->events->emit('some:event', []); 61 | static::assertEquals(0, $this->buffer); 62 | 63 | $this->events->emit('some:event', [2]); 64 | static::assertEquals(2, $this->buffer); 65 | 66 | $this->events->emit('some:event', [2, 4]); 67 | static::assertEquals(6, $this->buffer); 68 | 69 | $this->events->emit('some:event', [2, 4, 1]); 70 | static::assertEquals(7, $this->buffer); 71 | 72 | $this->events->emit('some:event', [2, 4, 1, 1]); 73 | static::assertEquals(8, $this->buffer); 74 | } 75 | 76 | public function testEmitNoArgs(): void 77 | { 78 | $handler = Closure::bind(function(string $title = 'default') { 79 | $this->buffer = $title; 80 | }, $this, get_class($this)); 81 | 82 | $this->events->on('some:event', $handler, 50, ['extraArg']); 83 | 84 | $this->events->emitNoArgs('some:event'); 85 | static::assertEquals('default', $this->buffer); 86 | } 87 | 88 | public function testEventWithoutListeners(): void 89 | { 90 | $this->events->emit('some:event'); 91 | static::assertNull($this->buffer); 92 | } 93 | 94 | public function testClosureHandler(): void 95 | { 96 | $handler = Closure::bind(function () { 97 | $this->buffer = 'closure'; 98 | }, $this, get_class($this)); 99 | 100 | $this->events->on('name', $handler); 101 | $this->events->emit('name'); 102 | 103 | static::assertEquals('closure', $this->buffer); 104 | } 105 | 106 | public function testChain(): void 107 | { 108 | $expected = EventEmitterInterface::class; 109 | static::assertInstanceOf($expected, $this->events->on('some', [$this, 'customEventHandler'])); 110 | static::assertInstanceOf($expected, $this->events->once('some', [$this, 'customEventHandler'])); 111 | static::assertInstanceOf($expected, $this->events->off('some', [$this, 'customEventHandler'])); 112 | } 113 | 114 | /** 115 | * @param string $method 116 | * @return void 117 | */ 118 | #[DataProvider('stopPropagationDataProvider')] 119 | public function testStopPropagation(string $method): void 120 | { 121 | $handler = Closure::bind(function () { 122 | $this->buffer = 'closure'; 123 | throw new StopPropagation; 124 | }, $this, get_class($this)); 125 | 126 | $handler2 = Closure::bind(function () { 127 | $this->buffer = 'closure2'; 128 | }, $this, get_class($this)); 129 | 130 | $this->events->on('name', $handler); 131 | $this->events->on('name', $handler2); 132 | 133 | $this->events->{$method}('name'); 134 | 135 | static::assertEquals('closure', $this->buffer); 136 | } 137 | 138 | public static function stopPropagationDataProvider(): array 139 | { 140 | return [ 141 | 0 => ['emit'] , 142 | 1 => ['emitNoArgs'] 143 | ]; 144 | } 145 | 146 | public function testEventNames(): void 147 | { 148 | static::assertCount(0, $this->events->eventNames()); 149 | 150 | $this->events->on('some:event', 'trim'); 151 | $names = $this->events->eventNames(); 152 | static::assertSame(['some:event'], $names); 153 | } 154 | 155 | public function testOnce(): void 156 | { 157 | $obj = new stdClass; 158 | $obj->count = 0; 159 | 160 | $this->events->once('once:test', fn(stdClass $obj) => $obj->count++); 161 | 162 | static::assertCount(1, $this->events->listeners()); 163 | $this->events->emit('once:test', [$obj]); 164 | static::assertCount(0, $this->events->listeners()); 165 | static::assertSame(1, $obj->count); 166 | 167 | $this->events->once('once:test2', function() { }); 168 | static::assertCount(1, $this->events->listeners()); 169 | $this->events->emitNoArgs('once:test2'); 170 | static::assertCount(0, $this->events->listeners()); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /test/unit/Filter/FiltersEmitterTest.php: -------------------------------------------------------------------------------- 1 | filters = new FilterEmitter; 20 | } 21 | 22 | public function testFilterWithExtraOnArguments(): void 23 | { 24 | $rawTitle = 'Hello world!!! '; 25 | $this->filters->on('before_output_title', [$this, 'customFilterHandler'], 50, [10]); 26 | $title = $this->filters->emit('before_output_title', $rawTitle); 27 | 28 | self::assertEquals('Hell', $title, 'must skip extra args from handler'); 29 | } 30 | 31 | public function testEmitNoArgs(): void 32 | { 33 | $handler = Closure::bind(function(string $value, ?string $extra = null) { 34 | return $extra ?? $value; 35 | }, $this, get_class($this)); 36 | 37 | $this->filters->on('some:event', $handler, 50, ['extraArg']); 38 | 39 | $actual = $this->filters->emitNoArgs('some:event', 'alex'); 40 | static::assertEquals('alex', $actual); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/unit/Filter/FiltersExtraArgsEmitterTest.php: -------------------------------------------------------------------------------- 1 | filters = new FilterExtraArgsEmitter; 23 | } 24 | 25 | public function customFilterHandler(string $value, int $length = 4): string 26 | { 27 | return substr($value, 0, $length); 28 | } 29 | 30 | public function testSimpleFilter(): void 31 | { 32 | $title = ' Hello world!!! '; 33 | $this->filters->on('before_output_title', 'trim'); 34 | $title = $this->filters->emit('before_output_title', $title); 35 | 36 | self::assertEquals(trim($title), $title); 37 | } 38 | 39 | public function testFilterWithoutListeners(): void 40 | { 41 | $rawTitle = ' Hello world!!! '; 42 | $title = $this->filters->emit('before_output_title', $rawTitle); 43 | 44 | self::assertEquals($rawTitle, $title); 45 | } 46 | 47 | public function testFilterWithExtraEmitArguments(): void 48 | { 49 | $rawTitle = 'Hello world!!! '; 50 | $this->filters->on('before_output_title', [$this, 'customFilterHandler']); 51 | $title = $this->filters->emit('before_output_title', $rawTitle, [5]); 52 | 53 | self::assertEquals('Hello', $title); 54 | } 55 | 56 | public function testFilterWithExtraOnArguments(): void 57 | { 58 | $rawTitle = 'Hello world!!! '; 59 | $this->filters->on('before_output_title', [$this, 'customFilterHandler'], 50, [5]); 60 | $title = $this->filters->emit('before_output_title', $rawTitle); 61 | 62 | self::assertEquals('Hello', $title); 63 | } 64 | 65 | public function testOffHandlerWithPriority(): void 66 | { 67 | $rawTitle = 'Hello world!!! '; 68 | $this->filters->on('before_output_title', 'trim', 30); 69 | $this->filters->off('before_output_title', 'trim', 30); 70 | $title = $this->filters->emit('before_output_title', $rawTitle); 71 | 72 | self::assertEquals($rawTitle, $title); 73 | self::assertCount(0, $this->filters->listeners()); 74 | } 75 | 76 | public function testOffHandlerWithoutPriority(): void 77 | { 78 | $rawTitle = 'Hello world!!! '; 79 | $this->filters->on('before_output_title', 'trim'); 80 | $this->filters->off('before_output_title', 'trim'); 81 | $title = $this->filters->emit('before_output_title', $rawTitle); 82 | 83 | self::assertEquals($rawTitle, $title); 84 | self::assertCount(0, $this->filters->listeners()); 85 | } 86 | 87 | public function testOffAllHandlers(): void 88 | { 89 | $rawTitle = 'Hello world!!! '; 90 | $this->filters->on('before_output_title', 'trim'); 91 | $this->filters->off('before_output_title'); 92 | $title = $this->filters->emit('before_output_title', $rawTitle); 93 | 94 | self::assertEquals($rawTitle, $title); 95 | self::assertCount(0, $this->filters->listeners()); 96 | } 97 | 98 | public function testOrderHandler(): void 99 | { 100 | $rawTitle = ' Hello world!!! '; 101 | $this->filters->on('before_output_title', 'trim', 30); 102 | $this->filters->on('before_output_title', [$this, 'customFilterHandler'], 20); 103 | $title = $this->filters->emit('before_output_title', $rawTitle); 104 | 105 | self::assertEquals('Hell', $title); 106 | } 107 | 108 | public function test2OrderHandler(): void 109 | { 110 | $rawTitle = ' Hello world!!! '; 111 | $this->filters->on('before_output_title', 'trim', 30); 112 | $this->filters->on('before_output_title', [$this, 'customFilterHandler'], 40); 113 | $title = $this->filters->emit('before_output_title', $rawTitle); 114 | 115 | self::assertEquals('He', $title); 116 | } 117 | 118 | public function testChain(): void 119 | { 120 | self::assertInstanceOf(FilterEmitterInterface::class, $this->filters->on('some', 'trim')); 121 | self::assertInstanceOf(FilterEmitterInterface::class, $this->filters->off('some', 'trim')); 122 | } 123 | 124 | /** 125 | * @param string $method 126 | * @return void 127 | */ 128 | #[DataProvider('stopPropagationDataProvider')] 129 | public function testStopPropagation(string $method): void 130 | { 131 | $rawTitle = ' Hello world!!! '; 132 | $this->filters->on('before_output_title', 'trim'); 133 | $this->filters->on('before_output_title', static function ($value) { 134 | throw (new StopPropagation)->setValue($value); 135 | }); 136 | $this->filters->on('before_output_title', [$this, 'customFilterHandler']); 137 | $title = $this->filters->{$method}('before_output_title', $rawTitle); 138 | 139 | self::assertEquals('Hello world!!!', $title); 140 | } 141 | 142 | public static function stopPropagationDataProvider(): array 143 | { 144 | return [ 145 | ['emit'], 146 | ['emitNoArgs'], 147 | ]; 148 | } 149 | 150 | public function testOnceHandler(): void 151 | { 152 | $rawTitle = ' Hello world!!! '; 153 | $this->filters->once('before_output_title', 'trim'); 154 | $title = $this->filters->emit('before_output_title', $rawTitle); 155 | self::assertEquals('Hello world!!!', $title); 156 | 157 | $title = $this->filters->emit('before_output_title', $rawTitle); 158 | self::assertEquals($rawTitle, $title); 159 | 160 | // noArgs 161 | $this->filters->once('before_output_title', 'trim'); 162 | $title = $this->filters->emitNoArgs('before_output_title', $rawTitle); 163 | self::assertEquals('Hello world!!!', $title); 164 | 165 | $title = $this->filters->emitNoArgs('before_output_title', $rawTitle); 166 | self::assertEquals($rawTitle, $title); 167 | } 168 | 169 | public function testDifferentCountArguments(): void 170 | { 171 | $handler = Closure::bind(function(int $value, ...$args) { 172 | return $value + array_sum($args); 173 | }, $this, get_class($this)); 174 | 175 | $this->filters->on('some:event', $handler); 176 | 177 | $actual = $this->filters->emit('some:event', 2, []); 178 | static::assertEquals(2, $actual); 179 | 180 | $actual = $this->filters->emit('some:event', 2, [2]); 181 | static::assertEquals(4, $actual); 182 | 183 | $actual = $this->filters->emit('some:event', 2, [2, 4]); 184 | static::assertEquals(8, $actual); 185 | 186 | $actual = $this->filters->emit('some:event', 2, [2, 4, 1]); 187 | static::assertEquals(9, $actual); 188 | 189 | $actual = $this->filters->emit('some:event', 2, [2, 4, 1, 1]); 190 | static::assertEquals(10, $actual); 191 | } 192 | 193 | public function testEmitNoArgs(): void 194 | { 195 | $handler = Closure::bind(function(string $value, ?string $extra) { 196 | return $extra ?? $value; 197 | }, $this, get_class($this)); 198 | 199 | $this->filters->on('some:event', $handler, 50, ['extraArg']); 200 | 201 | $actual = $this->filters->emitNoArgs('some:event', 'alex'); 202 | static::assertEquals('extraArg', $actual); 203 | } 204 | } 205 | --------------------------------------------------------------------------------