├── tests ├── input.txt └── CLI │ ├── TaskTest.php │ └── CLITest.php ├── .gitignore ├── phpstan.neon ├── .github └── workflows │ ├── codeql.yml │ ├── linter.yml │ └── test.yml ├── psalm.xml ├── phpunit.xml ├── src └── CLI │ ├── Task.php │ ├── Adapters │ ├── Generic.php │ └── Swoole.php │ ├── Adapter.php │ └── CLI.php ├── phpcs.xml ├── composer.json ├── LICENSE.md ├── README.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md └── composer.lock /tests/input.txt: -------------------------------------------------------------------------------- 1 | this is an answer -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /.idea/ 3 | .phpunit.result.cache 4 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 5 3 | paths: 4 | - src 5 | - tests -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: [pull_request] 4 | jobs: 5 | lint: 6 | name: CodeQL 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout repository 11 | uses: actions/checkout@v3 12 | 13 | - name: Run CodeQL 14 | run: | 15 | docker run --rm -v $PWD:/app composer sh -c \ 16 | "composer install --profile --ignore-platform-reqs && composer check" -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: "Linter" 2 | 3 | on: [pull_request] 4 | jobs: 5 | lint: 6 | name: Linter 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout repository 11 | uses: actions/checkout@v3 12 | with: 13 | fetch-depth: 2 14 | 15 | - run: git checkout HEAD^2 16 | 17 | - name: Run Linter 18 | run: | 19 | docker run --rm -v $PWD:/app composer sh -c \ 20 | "composer install --profile --ignore-platform-reqs && composer lint" -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | ./tests/ 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/CLI/Task.php: -------------------------------------------------------------------------------- 1 | name = $name; 22 | } 23 | 24 | /** 25 | * Get Name 26 | * 27 | * @return string 28 | */ 29 | public function getName(): string 30 | { 31 | return $this->name; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ./src 5 | ./tests 6 | 7 | 8 | 9 | 10 | * 11 | 12 | 13 | 14 | * 15 | 16 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "Tests" 2 | 3 | on: [pull_request] 4 | jobs: 5 | lint: 6 | name: Tests ${{ matrix.php-versions }} 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | php-versions: ['8.1', '8.2', '8.3', 'nightly'] 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v3 15 | 16 | - name: Setup PHP ${{ matrix.php-versions }} 17 | uses: shivammathur/setup-php@v2 18 | with: 19 | php-version: ${{ matrix.php-versions }} 20 | 21 | - name: Validate composer.json and composer.lock 22 | run: composer validate --strict 23 | 24 | - name: Compose install 25 | run: composer install --ignore-platform-reqs 26 | 27 | - name: Run tests 28 | run: composer test 29 | -------------------------------------------------------------------------------- /src/CLI/Adapters/Generic.php: -------------------------------------------------------------------------------- 1 | =7.4", 20 | "utopia-php/servers": "0.2.*" 21 | }, 22 | "require-dev": { 23 | "utopia-php/console": "0.0.*", 24 | "phpunit/phpunit": "^9.3", 25 | "squizlabs/php_codesniffer": "^3.6", 26 | "phpstan/phpstan": "^1.10", 27 | "laravel/pint": "1.2.*", 28 | "swoole/ide-helper": "4.8.8" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Eldad Fux 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/CLI/Adapter.php: -------------------------------------------------------------------------------- 1 | workerNum = $workerNum; 12 | } 13 | 14 | /** 15 | * Starts the Server. 16 | * 17 | * @param $callback 18 | * @return self 19 | */ 20 | abstract public function start($callback): self; 21 | 22 | /** 23 | * Stops the Server. 24 | * 25 | * @return self 26 | */ 27 | abstract public function stop(): self; 28 | 29 | /** 30 | * Is called when a Worker starts. 31 | * 32 | * @param callable $callback 33 | * @return self 34 | */ 35 | abstract public function onWorkerStart(callable $callback): self; 36 | 37 | /** 38 | * Is called when a Worker stops. 39 | * 40 | * @param callable $callback 41 | * @return self 42 | */ 43 | abstract public function onWorkerStop(callable $callback): self; 44 | 45 | /** 46 | * Is called when a job is processed. 47 | * 48 | * @param callable $callback 49 | * @return self 50 | */ 51 | abstract public function onJob(callable $callback): self; 52 | } 53 | -------------------------------------------------------------------------------- /src/CLI/Adapters/Swoole.php: -------------------------------------------------------------------------------- 1 | pool = new Pool($workerNum); 18 | } 19 | 20 | public function start($callback): self 21 | { 22 | Runtime::enableCoroutine(); 23 | $this->pool->set(['enable_coroutine' => true]); 24 | 25 | $this->onWorkerStart($callback); 26 | $this->onWorkerStop(fn () => $this->pool->shutdown()); 27 | $this->pool->start(); 28 | 29 | return $this; 30 | } 31 | 32 | public function stop(): self 33 | { 34 | $this->pool->shutdown(); 35 | 36 | return $this; 37 | } 38 | 39 | public function onWorkerStart($callback): self 40 | { 41 | $this->pool->on('WorkerStart', function (Pool $pool, string $workerId) use ($callback) { 42 | call_user_func($callback, $workerId); 43 | }); 44 | 45 | return $this; 46 | } 47 | 48 | public function onWorkerStop(callable $callback): self 49 | { 50 | $this->pool->on('WorkerStop', function (Pool $pool, string $workerId) use ($callback) { 51 | call_user_func($callback, $workerId); 52 | }); 53 | 54 | return $this; 55 | } 56 | 57 | public function onJob(callable $callback): self 58 | { 59 | call_user_func($callback); 60 | 61 | return $this; 62 | } 63 | 64 | public function getNative(): Pool 65 | { 66 | return $this->pool; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/CLI/TaskTest.php: -------------------------------------------------------------------------------- 1 | task = new Task('test'); 19 | } 20 | 21 | public function tearDown(): void 22 | { 23 | $this->task = null; 24 | } 25 | 26 | public function testName() 27 | { 28 | $this->assertEquals('test', $this->task->getName()); 29 | } 30 | 31 | public function testDescription() 32 | { 33 | $this->task->desc('test task'); 34 | 35 | $this->assertEquals('test task', $this->task->getDesc()); 36 | } 37 | 38 | public function testAction() 39 | { 40 | $this->task->action(function () { 41 | return 'result'; 42 | }); 43 | 44 | $this->assertEquals('result', $this->task->getAction()()); 45 | } 46 | 47 | public function testLabel() 48 | { 49 | $this->task->label('key', 'value'); 50 | 51 | $this->assertEquals('value', $this->task->getLabel('key', 'default')); 52 | $this->assertEquals('default', $this->task->getLabel('unknown', 'default')); 53 | } 54 | 55 | public function testParam() 56 | { 57 | $this->task->param('email', 'me@example.com', new Text(0), 'Param with valid email address', false); 58 | 59 | $this->assertCount(1, $this->task->getParams()); 60 | } 61 | 62 | public function testResources() 63 | { 64 | $this->assertEquals([], $this->task->getDependencies()); 65 | 66 | $this->task 67 | ->inject('user') 68 | ->inject('time') 69 | ->action(function () { 70 | }); 71 | 72 | $this->assertCount(2, $this->task->getDependencies()); 73 | $this->assertEquals('user', $this->task->getDependencies()[0]); 74 | $this->assertEquals('time', $this->task->getDependencies()[1]); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Utopia CLI 2 | 3 | [![Build Status](https://travis-ci.org/utopia-php/cli.svg?branch=master)](https://travis-ci.com/utopia-php/cli) 4 | ![Total Downloads](https://img.shields.io/packagist/dt/utopia-php/cli.svg) 5 | [![Discord](https://img.shields.io/discord/564160730845151244)](https://appwrite.io/discord) 6 | 7 | Utopia framework CLI library is simple and lite library for extending Utopia PHP Framework to be able to code command line applications. This library is aiming to be as simple and easy to learn and use. This library is maintained by the [Appwrite team](https://appwrite.io). 8 | 9 | Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project it is dependency free and can be used as standalone with any other PHP project or framework. 10 | 11 | ## Getting Started 12 | 13 | Install using composer: 14 | ```bash 15 | composer require utopia-php/cli 16 | ``` 17 | 18 | script.php 19 | ```php 20 | task('command-name') 32 | ->param('email', null, new Wildcard()) 33 | ->action(function ($email) { 34 | Console::success($email); 35 | }); 36 | 37 | $cli->run(); 38 | 39 | ``` 40 | 41 | And than, run from command line: 42 | 43 | ```bash 44 | php script.php command-name --email=me@example.com 45 | ``` 46 | 47 | ### Hooks 48 | 49 | There are three types of hooks, init hooks, shutdown hooks and error hooks. Init hooks are executed before the task is executed. Shutdown hook is executed after task is executed before application shuts down. Finally error hooks are executed whenever there's an error in the application lifecycle. You can provide multiple hooks for each stage. 50 | 51 | ```php 52 | require_once __DIR__ . '/../../vendor/autoload.php'; 53 | 54 | use Utopia\CLI\CLI; 55 | use Utopia\Console; 56 | use Utopia\Validator\Wildcard; 57 | 58 | CLI::setResource('res1', function() { 59 | return 'resource 1'; 60 | }) 61 | 62 | CLI::init() 63 | inject('res1') 64 | ->action(function($res1) { 65 | Console::info($res1); 66 | }); 67 | 68 | CLI::error() 69 | ->inject('error') 70 | ->action(function($error) { 71 | Console::error('Error occurred ' . $error); 72 | }); 73 | 74 | $cli = new CLI(); 75 | 76 | $cli 77 | ->task('command-name') 78 | ->param('email', null, new Wildcard()) 79 | ->action(function ($email) { 80 | Console::success($email); 81 | }); 82 | 83 | $cli->run(); 84 | ``` 85 | 86 | ## System Requirements 87 | 88 | Utopia Framework requires PHP 7.4 or later. We recommend using the latest PHP version whenever possible. 89 | 90 | ## Copyright and license 91 | 92 | The MIT License (MIT) [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php) 93 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity, expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at team@appwrite.io. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We would ❤️ for you to contribute to Utopia-php and help make it better! We want contributing to Utopia-php to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, new docs as well as updates and tweaks, blog posts, workshops, and more. 4 | 5 | ## How to Start? 6 | 7 | If you are worried or don’t know where to start, check out our next section explaining what kind of help we could use and where can you get involved. You can reach out with questions to [Eldad Fux (@eldadfux)](https://twitter.com/eldadfux) or anyone from the [Appwrite team on Discord](https://discord.gg/GSeTUeA). You can also submit an issue, and a maintainer can guide you! 8 | 9 | ## Code of Conduct 10 | 11 | Help us keep Utopia-php open and inclusive. Please read and follow our [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md). 12 | 13 | ## Submit a Pull Request 🚀 14 | 15 | Branch naming convention is as following 16 | 17 | `TYPE-ISSUE_ID-DESCRIPTION` 18 | 19 | example: 20 | 21 | ``` 22 | doc-548-submit-a-pull-request-section-to-contribution-guide 23 | ``` 24 | 25 | When `TYPE` can be: 26 | 27 | - **feat** - is a new feature 28 | - **doc** - documentation only changes 29 | - **cicd** - changes related to CI/CD system 30 | - **fix** - a bug fix 31 | - **refactor** - code change that neither fixes a bug nor adds a feature 32 | 33 | **All PRs must include a commit message with the changes description!** 34 | 35 | For the initial start, fork the project and use git clone command to download the repository to your computer. A standard procedure for working on an issue would be to: 36 | 37 | 1. `git pull`, before creating a new branch, pull the changes from upstream. Your master needs to be up to date. 38 | 39 | ``` 40 | $ git pull 41 | ``` 42 | 43 | 2. Create new branch from `master` like: `doc-548-submit-a-pull-request-section-to-contribution-guide`
44 | 45 | ``` 46 | $ git checkout -b [name_of_your_new_branch] 47 | ``` 48 | 49 | 3. Work - commit - repeat ( be sure to be in your branch ) 50 | 51 | 4. Push changes to GitHub 52 | 53 | ``` 54 | $ git push origin [name_of_your_new_branch] 55 | ``` 56 | 57 | 5. Submit your changes for review 58 | If you go to your repository on GitHub, you'll see a `Compare & pull request` button. Click on that button. 59 | 6. Start a Pull Request 60 | Now submit the pull request and click on `Create pull request`. 61 | 7. Get a code review approval/reject 62 | 8. After approval, merge your PR 63 | 9. GitHub will automatically delete the branch after the merge is done. (they can still be restored). 64 | 65 | ## Introducing New Features 66 | 67 | We would 💖 you to contribute to Utopia-php, but we would also like to make sure Utopia-php is as great as possible and loyal to its vision and mission statement 🙏. 68 | 69 | For us to find the right balance, please open an issue explaining your ideas before introducing a new pull request. 70 | 71 | This will allow the Utopia-php community to have sufficient discussion about the new feature value and how it fits in the product roadmap and vision. 72 | 73 | This is also important for the Utopia-php lead developers to be able to give technical input and different emphasis regarding the feature design and architecture. Some bigger features might need to go through our [RFC process](https://github.com/appwrite/rfc). 74 | 75 | ## Other Ways to Help 76 | 77 | Pull requests are great, but there are many other areas where you can help Utopia-php. 78 | 79 | ### Blogging & Speaking 80 | 81 | Blogging, speaking about, or creating tutorials about one of Utopia-php’s many features is great way to contribute and help our project grow. 82 | 83 | ### Presenting at Meetups 84 | 85 | Presenting at meetups and conferences about your Utopia-php projects. Your unique challenges and successes in building things with Utopia-php can provide great speaking material. We’d love to review your talk abstract/CFP, so get in touch with us if you’d like some help! 86 | 87 | ### Sending Feedbacks & Reporting Bugs 88 | 89 | Sending feedback is a great way for us to understand your different use cases of Utopia-php better. If you had any issues, bugs, or want to share about your experience, feel free to do so on our GitHub issues page or at our [Discord channel](https://discord.gg/GSeTUeA). 90 | 91 | ### Submitting New Ideas 92 | 93 | If you think Utopia-php could use a new feature, please open an issue on our GitHub repository, stating as much information as you can think about your new idea and it's implications. We would also use this issue to gather more information, get more feedback from the community, and have a proper discussion about the new feature. 94 | 95 | ### Improving Documentation 96 | 97 | Submitting documentation updates, enhancements, designs, or bug fixes. Spelling or grammar fixes will be very much appreciated. 98 | 99 | ### Helping Someone 100 | 101 | Searching for Utopia-php, GitHub or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to Utopia-php's repo! 102 | -------------------------------------------------------------------------------- /tests/CLI/CLITest.php: -------------------------------------------------------------------------------- 1 | setName('rand')->setCallback(fn () => rand()); 28 | 29 | $first = new Dependency(); 30 | $first->setName('first') 31 | ->inject('second') 32 | ->setCallback(fn ($second) => 'first-'.$second); 33 | 34 | $second = new Dependency(); 35 | $second->setName('second')->setCallback(fn () => 'second'); 36 | 37 | $cli->setResource($rand); 38 | $cli->setResource($first); 39 | $cli->setResource($second); 40 | 41 | $second = $cli->getResource('second'); 42 | $first = $cli->getResource('first'); 43 | $this->assertEquals('second', $second); 44 | $this->assertEquals('first-second', $first); 45 | 46 | $resource = $cli->getResource('rand'); 47 | 48 | $this->assertNotEmpty($resource); 49 | $this->assertEquals($resource, $cli->getResource('rand')); 50 | $this->assertEquals($resource, $cli->getResource('rand')); 51 | $this->assertEquals($resource, $cli->getResource('rand')); 52 | } 53 | 54 | public function testAppSuccess() 55 | { 56 | ob_start(); 57 | 58 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com']); // Mock command request 59 | 60 | $cli 61 | ->task('build') 62 | ->param('email', null, new Text(0), 'Valid email address') 63 | ->action(function ($email) { 64 | echo $email; 65 | }); 66 | 67 | $cli->run(); 68 | 69 | $result = ob_get_clean(); 70 | 71 | $this->assertEquals('me@example.com', $result); 72 | } 73 | 74 | public function testAppFailure() 75 | { 76 | ob_start(); 77 | 78 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me.example.com']); // Mock command request 79 | 80 | $cli 81 | ->task('build') 82 | ->param('email', null, new Text(10), 'Valid email address') 83 | ->action(function ($email) { 84 | echo $email; 85 | }); 86 | 87 | $cli->run(); 88 | 89 | $result = ob_get_clean(); 90 | 91 | $this->assertEquals('', $result); 92 | } 93 | 94 | public function testAppArray() 95 | { 96 | ob_start(); 97 | 98 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com', '--list=item1', '--list=item2']); // Mock command request 99 | 100 | $cli 101 | ->task('build') 102 | ->param('email', null, new Text(0), 'Valid email address') 103 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings') 104 | ->action(function ($email, $list) { 105 | echo $email.'-'.implode('-', $list); 106 | }); 107 | 108 | $cli->run(); 109 | 110 | $result = ob_get_clean(); 111 | 112 | $this->assertEquals('me@example.com-item1-item2', $result); 113 | } 114 | 115 | public function testGetTasks() 116 | { 117 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com', '--list=item1', '--list=item2']); // Mock command request 118 | 119 | $cli 120 | ->task('build1') 121 | ->param('email', null, new Text(0), 'Valid email address') 122 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings') 123 | ->action(function ($email, $list) { 124 | echo $email.'-'.implode('-', $list); 125 | }); 126 | 127 | $cli 128 | ->task('build2') 129 | ->param('email', null, new Text(0), 'Valid email address') 130 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings') 131 | ->action(function ($email, $list) { 132 | echo $email.'-'.implode('-', $list); 133 | }); 134 | 135 | $this->assertCount(2, $cli->getTasks()); 136 | } 137 | 138 | public function testGetArgs() 139 | { 140 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com', '--list=item1', '--list=item2']); // Mock command request 141 | 142 | $cli 143 | ->task('build1') 144 | ->param('email', null, new Text(0), 'Valid email address') 145 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings') 146 | ->action(function ($email, $list) { 147 | echo $email.'-'.implode('-', $list); 148 | }); 149 | 150 | $cli 151 | ->task('build2') 152 | ->param('email', null, new Text(0), 'Valid email address') 153 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings') 154 | ->action(function ($email, $list) { 155 | echo $email.'-'.implode('-', $list); 156 | }); 157 | 158 | $this->assertCount(2, $cli->getArgs()); 159 | $this->assertEquals(['email' => 'me@example.com', 'list' => ['item1', 'item2']], $cli->getArgs()); 160 | } 161 | 162 | public function testHook() 163 | { 164 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com', '--list=item1', '--list=item2']); 165 | 166 | $cli 167 | ->init() 168 | ->action(function () { 169 | echo '(init)-'; 170 | }); 171 | 172 | $cli 173 | ->shutdown() 174 | ->action(function () { 175 | echo '-(shutdown)'; 176 | }); 177 | 178 | $cli 179 | ->task('build') 180 | ->param('email', null, new Text(0), 'Valid email address') 181 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings') 182 | ->action(function ($email, $list) { 183 | echo $email.'-'.implode('-', $list); 184 | }); 185 | 186 | \ob_start(); 187 | 188 | $cli->run(); 189 | $result = \ob_get_clean(); 190 | 191 | $this->assertEquals('(init)-me@example.com-item1-item2-(shutdown)', $result); 192 | } 193 | 194 | public function testInjection() 195 | { 196 | ob_start(); 197 | 198 | $cli = new CLI(new Generic(), ['test.php', 'build', '--email=me@example.com']); 199 | 200 | $test = new Dependency(); 201 | $test->setName('test')->setCallback(fn () => 'test-value'); 202 | 203 | $cli->setResource($test); 204 | 205 | $cli->task('build') 206 | ->inject('test') 207 | ->param('email', null, new Text(15), 'valid email address') 208 | ->action(function ($test, $email) { 209 | echo $test.'-'.$email; 210 | }); 211 | 212 | $cli->run(); 213 | 214 | $result = ob_get_clean(); 215 | 216 | $this->assertEquals('test-value-me@example.com', $result); 217 | } 218 | 219 | public function testMatch() 220 | { 221 | $cli = new CLI(new Generic(), ['test.php', 'build2', '--email=me@example.com', '--list=item1', '--list=item2']); // Mock command request 222 | 223 | $cli 224 | ->task('build1') 225 | ->param('email', null, new Text(0), 'Valid email address') 226 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings') 227 | ->action(function ($email, $list) { 228 | echo $email.'-'.implode('-', $list); 229 | }); 230 | 231 | $cli 232 | ->task('build2') 233 | ->param('email', null, new Text(0), 'Valid email address') 234 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings') 235 | ->action(function ($email, $list) { 236 | echo $email.'-'.implode('-', $list); 237 | }); 238 | 239 | $this->assertEquals('build2', $cli->match()->getName()); 240 | 241 | $cli = new CLI(new Generic(), ['test.php', 'buildx', '--email=me@example.com', '--list=item1', '--list=item2']); // Mock command request 242 | 243 | $cli 244 | ->task('build1') 245 | ->param('email', null, new Text(0), 'Valid email address') 246 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings') 247 | ->action(function ($email, $list) { 248 | echo $email.'-'.implode('-', $list); 249 | }); 250 | 251 | $cli 252 | ->task('build2') 253 | ->param('email', null, new Text(0), 'Valid email address') 254 | ->param('list', null, new ArrayList(new Text(256)), 'List of strings') 255 | ->action(function ($email, $list) { 256 | echo $email.'-'.implode('-', $list); 257 | }); 258 | 259 | $this->assertEquals(null, $cli->match()); 260 | } 261 | 262 | public function testEscaping() 263 | { 264 | ob_start(); 265 | 266 | $database = 'appwrite://database_db_fra1_self_hosted_0_0?database=appwrite&namespace=_1'; 267 | 268 | $cli = new CLI(new Generic(), ['test.php', 'connect', '--database='.$database]); 269 | 270 | $cli 271 | ->task('connect') 272 | ->param('database', null, new Text(2048), 'Database DSN') 273 | ->action(function ($database) { 274 | echo $database; 275 | }); 276 | 277 | $cli->run(); 278 | 279 | $result = ob_get_clean(); 280 | 281 | $this->assertEquals($database, $result); 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /src/CLI/CLI.php: -------------------------------------------------------------------------------- 1 | args = $this->parse((! empty($args) || ! isset($_SERVER['argv'])) ? $args : $_SERVER['argv']); 97 | 98 | @\cli_set_process_title($this->command); 99 | 100 | $this->adapter = $adapter ?? new Generic(); 101 | $this->container = new Container(); 102 | } 103 | 104 | /** 105 | * Init 106 | * 107 | * Set a callback function that will be initialized on application start 108 | * 109 | * @return Hook 110 | */ 111 | public function init(): Hook 112 | { 113 | $hook = new Hook(); 114 | $this->init[] = $hook; 115 | 116 | return $hook; 117 | } 118 | 119 | /** 120 | * Shutdown 121 | * 122 | * Set a callback function that will be initialized on application end 123 | * 124 | * @return Hook 125 | */ 126 | public function shutdown(): Hook 127 | { 128 | $hook = new Hook(); 129 | $this->shutdown[] = $hook; 130 | 131 | return $hook; 132 | } 133 | 134 | /** 135 | * Error 136 | * 137 | * An error callback for failed or no matched requests 138 | * 139 | * @return Hook 140 | */ 141 | public function error(): Hook 142 | { 143 | $hook = new Hook(); 144 | $this->errors[] = $hook; 145 | 146 | return $hook; 147 | } 148 | 149 | /** 150 | * Task 151 | * 152 | * Add a new command task 153 | * 154 | * @param string $name 155 | * @return Task 156 | */ 157 | public function task(string $name): Task 158 | { 159 | $task = new Task($name); 160 | 161 | $this->tasks[$name] = $task; 162 | 163 | return $task; 164 | } 165 | 166 | /** 167 | * If a resource has been created return it, otherwise create it and then return it 168 | * 169 | * @param string $name 170 | * @return mixed 171 | * 172 | * @throws Exception 173 | */ 174 | public function getResource(string $name): mixed 175 | { 176 | if (! $this->container->has($name)) { 177 | throw new Exception('Failed to find resource: "'.$name.'"'); 178 | } 179 | 180 | return $this->container->get($name); 181 | } 182 | 183 | /** 184 | * Get Resources By List 185 | * 186 | * @param array $list 187 | * @return array 188 | * 189 | * @throws Exception 190 | */ 191 | public function getResources(array $list): array 192 | { 193 | $resources = []; 194 | 195 | foreach ($list as $name) { 196 | $resources[$name] = $this->getResource($name); 197 | } 198 | 199 | return $resources; 200 | } 201 | 202 | /** 203 | * Set a new resource callback 204 | * 205 | * @param Dependency $dependency 206 | * @return void 207 | * 208 | * @throws Exception 209 | */ 210 | public function setResource(Dependency $dependency): void 211 | { 212 | $this->container->set($dependency); 213 | } 214 | 215 | /** 216 | * task-name --foo=test 217 | * 218 | * @param array $args 219 | * @return array 220 | * 221 | * @throws Exception 222 | */ 223 | public function parse(array $args): array 224 | { 225 | \array_shift($args); // Remove script path from args 226 | 227 | if (isset($args[0])) { 228 | $this->command = \array_shift($args); 229 | } else { 230 | throw new Exception('Missing command'); 231 | } 232 | 233 | $output = []; 234 | 235 | foreach ($args as &$arg) { 236 | if (\substr($arg, 0, 2) === '--') { 237 | $arg = \substr($arg, 2); 238 | } 239 | } 240 | 241 | /** 242 | * Refer to this answer 243 | * https://stackoverflow.com/questions/18669499/php-issue-with-looping-over-an-array-twice-using-foreach-and-passing-value-by-re/18669732 244 | */ 245 | unset($arg); 246 | 247 | foreach ($args as $arg) { 248 | $pair = explode('=', $arg, 2); 249 | $key = $pair[0]; 250 | $value = $pair[1]; 251 | $output[$key][] = $value; 252 | } 253 | 254 | foreach ($output as $key => $value) { 255 | /** 256 | * If there is only one element in a particular key 257 | * unshift the value out of the array 258 | */ 259 | if (count($value) == 1) { 260 | $output[$key] = array_shift($output[$key]); 261 | } 262 | } 263 | 264 | return $output; 265 | } 266 | 267 | /** 268 | * Find the command that should be triggered 269 | * 270 | * @return Task|null 271 | */ 272 | public function match(): ?Task 273 | { 274 | return $this->tasks[$this->command] ?? null; 275 | } 276 | 277 | /** 278 | * Get Params 279 | * Get runtime params for the provided Hook 280 | * 281 | * @param Hook $hook 282 | * @return array 283 | * 284 | * @throws Exception 285 | */ 286 | protected function getParams(Hook $hook): array 287 | { 288 | $params = []; 289 | 290 | foreach ($hook->getParams() as $key => $param) { 291 | $value = (isset($this->args[$key])) ? $this->args[$key] : $param['default']; 292 | 293 | $this->validate($key, $param, $value); 294 | 295 | $params[$this->camelCaseIt($key)] = $value; 296 | } 297 | 298 | foreach ($hook->getDependencies() as $dependency) { 299 | if (array_key_exists($this->camelCaseIt($dependency), $params)) { 300 | continue; 301 | } 302 | 303 | $params[$this->camelCaseIt($dependency)] = $this->getResource($dependency); 304 | } 305 | 306 | return $params; 307 | } 308 | 309 | /** 310 | * Run 311 | * 312 | * @return $this 313 | * 314 | * @throws Exception 315 | */ 316 | public function run(): self 317 | { 318 | $this->adapter->start(function () { 319 | $command = $this->match(); 320 | 321 | try { 322 | if ($command) { 323 | foreach ($this->init as $hook) { 324 | \call_user_func_array($hook->getAction(), $this->getParams($hook)); 325 | } 326 | 327 | // Call the callback with the matched positions as params 328 | \call_user_func_array($command->getAction(), $this->getParams($command)); 329 | 330 | foreach ($this->shutdown as $hook) { 331 | \call_user_func_array($hook->getAction(), $this->getParams($hook)); 332 | } 333 | } else { 334 | throw new Exception('No command found'); 335 | } 336 | } catch (Exception $e) { 337 | foreach ($this->errors as $hook) { 338 | $error = new Dependency(); 339 | $error->setName('error')->setCallback(fn () => $e); 340 | 341 | $this->setResource($error); 342 | \call_user_func_array($hook->getAction(), $this->getParams($hook)); 343 | } 344 | } 345 | }); 346 | 347 | return $this; 348 | } 349 | 350 | /** 351 | * Get list of all tasks 352 | * 353 | * @return Task[] 354 | */ 355 | public function getTasks(): array 356 | { 357 | return $this->tasks; 358 | } 359 | 360 | /** 361 | * Get list of all args 362 | * 363 | * @return array 364 | */ 365 | public function getArgs(): array 366 | { 367 | return $this->args; 368 | } 369 | 370 | /** 371 | * Validate Param 372 | * 373 | * Creates an validator instance and validate given value with given rules. 374 | * 375 | * @param string $key 376 | * @param array $param 377 | * @param mixed $value 378 | * 379 | * @throws Exception 380 | */ 381 | protected function validate(string $key, array $param, $value): void 382 | { 383 | if ('' !== $value) { 384 | // checking whether the class exists 385 | $validator = $param['validator']; 386 | 387 | if (\is_callable($validator)) { 388 | $validator = $validator(); 389 | } 390 | 391 | // is the validator object an instance of the Validator class 392 | if (! $validator instanceof Validator) { 393 | throw new Exception('Validator object is not an instance of the Validator class', 500); 394 | } 395 | 396 | if (! $validator->isValid($value)) { 397 | throw new Exception('Invalid '.$key.': '.$validator->getDescription(), 400); 398 | } 399 | } else { 400 | if (! $param['optional']) { 401 | throw new Exception('Param "'.$key.'" is not optional.', 400); 402 | } 403 | } 404 | } 405 | 406 | public function setContainer($container): self 407 | { 408 | $this->container = $container; 409 | 410 | return $this; 411 | } 412 | 413 | public function reset(): void 414 | { 415 | $this->container = new Container(); 416 | } 417 | 418 | private function camelCaseIt($key): string 419 | { 420 | $key = str_replace('-', '_', $key); 421 | $camelCase = \lcfirst(\str_replace('_', '', \ucwords($key, '_'))); 422 | 423 | return $camelCase; 424 | } 425 | } 426 | -------------------------------------------------------------------------------- /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": "3a9f5f12fa406f92e927dc9b81050e77", 8 | "packages": [ 9 | { 10 | "name": "utopia-php/di", 11 | "version": "0.1.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/utopia-php/di.git", 15 | "reference": "22490c95f7ac3898ed1c33f1b1b5dd577305ee31" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/utopia-php/di/zipball/22490c95f7ac3898ed1c33f1b1b5dd577305ee31", 20 | "reference": "22490c95f7ac3898ed1c33f1b1b5dd577305ee31", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=8.2" 25 | }, 26 | "require-dev": { 27 | "laravel/pint": "^1.2", 28 | "phpbench/phpbench": "^1.2", 29 | "phpstan/phpstan": "^1.10", 30 | "phpunit/phpunit": "^9.5.25", 31 | "swoole/ide-helper": "4.8.3" 32 | }, 33 | "type": "library", 34 | "autoload": { 35 | "psr-4": { 36 | "Utopia\\": "src/", 37 | "Tests\\E2E\\": "tests/e2e" 38 | } 39 | }, 40 | "notification-url": "https://packagist.org/downloads/", 41 | "license": [ 42 | "MIT" 43 | ], 44 | "description": "A simple and lite library for managing dependency injections", 45 | "keywords": [ 46 | "framework", 47 | "http", 48 | "php", 49 | "upf" 50 | ], 51 | "support": { 52 | "issues": "https://github.com/utopia-php/di/issues", 53 | "source": "https://github.com/utopia-php/di/tree/0.1.0" 54 | }, 55 | "time": "2024-08-08T14:35:19+00:00" 56 | }, 57 | { 58 | "name": "utopia-php/servers", 59 | "version": "0.2.0", 60 | "source": { 61 | "type": "git", 62 | "url": "https://github.com/utopia-php/servers.git", 63 | "reference": "92de8b5cd52fe2dc4bc873c39f8f4e8bb2ef2332" 64 | }, 65 | "dist": { 66 | "type": "zip", 67 | "url": "https://api.github.com/repos/utopia-php/servers/zipball/92de8b5cd52fe2dc4bc873c39f8f4e8bb2ef2332", 68 | "reference": "92de8b5cd52fe2dc4bc873c39f8f4e8bb2ef2332", 69 | "shasum": "" 70 | }, 71 | "require": { 72 | "php": ">=8.0", 73 | "utopia-php/di": "0.1.*", 74 | "utopia-php/validators": "0.0.*" 75 | }, 76 | "require-dev": { 77 | "laravel/pint": "^0.2.3", 78 | "phpstan/phpstan": "^1.8", 79 | "phpunit/phpunit": "^9.5.5" 80 | }, 81 | "type": "library", 82 | "autoload": { 83 | "psr-4": { 84 | "Utopia\\Servers\\": "src/Servers" 85 | } 86 | }, 87 | "notification-url": "https://packagist.org/downloads/", 88 | "license": [ 89 | "MIT" 90 | ], 91 | "authors": [ 92 | { 93 | "name": "Team Appwrite", 94 | "email": "team@appwrite.io" 95 | } 96 | ], 97 | "description": "A base library for building Utopia style servers.", 98 | "keywords": [ 99 | "framework", 100 | "php", 101 | "servers", 102 | "upf", 103 | "utopia" 104 | ], 105 | "support": { 106 | "issues": "https://github.com/utopia-php/servers/issues", 107 | "source": "https://github.com/utopia-php/servers/tree/0.2.0" 108 | }, 109 | "time": "2025-10-21T08:56:24+00:00" 110 | }, 111 | { 112 | "name": "utopia-php/validators", 113 | "version": "0.0.2", 114 | "source": { 115 | "type": "git", 116 | "url": "https://github.com/utopia-php/validators.git", 117 | "reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b" 118 | }, 119 | "dist": { 120 | "type": "zip", 121 | "url": "https://api.github.com/repos/utopia-php/validators/zipball/894210695c5d35fa248fb65f7fe7237b6ff4fb0b", 122 | "reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b", 123 | "shasum": "" 124 | }, 125 | "require": { 126 | "php": ">=8.1" 127 | }, 128 | "require-dev": { 129 | "ext-xdebug": "*", 130 | "laravel/pint": "^1.2", 131 | "phpstan/phpstan": "1.*", 132 | "phpunit/phpunit": "^9.5.25" 133 | }, 134 | "type": "library", 135 | "autoload": { 136 | "psr-4": { 137 | "Utopia\\": "src/" 138 | } 139 | }, 140 | "notification-url": "https://packagist.org/downloads/", 141 | "license": [ 142 | "MIT" 143 | ], 144 | "description": "A lightweight collection of reusable validators for Utopia projects", 145 | "keywords": [ 146 | "php", 147 | "utopia", 148 | "validation", 149 | "validator" 150 | ], 151 | "support": { 152 | "issues": "https://github.com/utopia-php/validators/issues", 153 | "source": "https://github.com/utopia-php/validators/tree/0.0.2" 154 | }, 155 | "time": "2025-10-20T21:52:28+00:00" 156 | } 157 | ], 158 | "packages-dev": [ 159 | { 160 | "name": "doctrine/instantiator", 161 | "version": "2.0.0", 162 | "source": { 163 | "type": "git", 164 | "url": "https://github.com/doctrine/instantiator.git", 165 | "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" 166 | }, 167 | "dist": { 168 | "type": "zip", 169 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", 170 | "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", 171 | "shasum": "" 172 | }, 173 | "require": { 174 | "php": "^8.1" 175 | }, 176 | "require-dev": { 177 | "doctrine/coding-standard": "^11", 178 | "ext-pdo": "*", 179 | "ext-phar": "*", 180 | "phpbench/phpbench": "^1.2", 181 | "phpstan/phpstan": "^1.9.4", 182 | "phpstan/phpstan-phpunit": "^1.3", 183 | "phpunit/phpunit": "^9.5.27", 184 | "vimeo/psalm": "^5.4" 185 | }, 186 | "type": "library", 187 | "autoload": { 188 | "psr-4": { 189 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 190 | } 191 | }, 192 | "notification-url": "https://packagist.org/downloads/", 193 | "license": [ 194 | "MIT" 195 | ], 196 | "authors": [ 197 | { 198 | "name": "Marco Pivetta", 199 | "email": "ocramius@gmail.com", 200 | "homepage": "https://ocramius.github.io/" 201 | } 202 | ], 203 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 204 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html", 205 | "keywords": [ 206 | "constructor", 207 | "instantiate" 208 | ], 209 | "support": { 210 | "issues": "https://github.com/doctrine/instantiator/issues", 211 | "source": "https://github.com/doctrine/instantiator/tree/2.0.0" 212 | }, 213 | "funding": [ 214 | { 215 | "url": "https://www.doctrine-project.org/sponsorship.html", 216 | "type": "custom" 217 | }, 218 | { 219 | "url": "https://www.patreon.com/phpdoctrine", 220 | "type": "patreon" 221 | }, 222 | { 223 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", 224 | "type": "tidelift" 225 | } 226 | ], 227 | "time": "2022-12-30T00:23:10+00:00" 228 | }, 229 | { 230 | "name": "laravel/pint", 231 | "version": "v1.2.1", 232 | "source": { 233 | "type": "git", 234 | "url": "https://github.com/laravel/pint.git", 235 | "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1" 236 | }, 237 | "dist": { 238 | "type": "zip", 239 | "url": "https://api.github.com/repos/laravel/pint/zipball/e60e2112ee779ce60f253695b273d1646a17d6f1", 240 | "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1", 241 | "shasum": "" 242 | }, 243 | "require": { 244 | "ext-json": "*", 245 | "ext-mbstring": "*", 246 | "ext-tokenizer": "*", 247 | "ext-xml": "*", 248 | "php": "^8.0" 249 | }, 250 | "require-dev": { 251 | "friendsofphp/php-cs-fixer": "^3.11.0", 252 | "illuminate/view": "^9.32.0", 253 | "laravel-zero/framework": "^9.2.0", 254 | "mockery/mockery": "^1.5.1", 255 | "nunomaduro/larastan": "^2.2.0", 256 | "nunomaduro/termwind": "^1.14.0", 257 | "pestphp/pest": "^1.22.1" 258 | }, 259 | "bin": [ 260 | "builds/pint" 261 | ], 262 | "type": "project", 263 | "autoload": { 264 | "psr-4": { 265 | "App\\": "app/", 266 | "Database\\Seeders\\": "database/seeders/", 267 | "Database\\Factories\\": "database/factories/" 268 | } 269 | }, 270 | "notification-url": "https://packagist.org/downloads/", 271 | "license": [ 272 | "MIT" 273 | ], 274 | "authors": [ 275 | { 276 | "name": "Nuno Maduro", 277 | "email": "enunomaduro@gmail.com" 278 | } 279 | ], 280 | "description": "An opinionated code formatter for PHP.", 281 | "homepage": "https://laravel.com", 282 | "keywords": [ 283 | "format", 284 | "formatter", 285 | "lint", 286 | "linter", 287 | "php" 288 | ], 289 | "support": { 290 | "issues": "https://github.com/laravel/pint/issues", 291 | "source": "https://github.com/laravel/pint" 292 | }, 293 | "time": "2022-11-29T16:25:20+00:00" 294 | }, 295 | { 296 | "name": "myclabs/deep-copy", 297 | "version": "1.13.4", 298 | "source": { 299 | "type": "git", 300 | "url": "https://github.com/myclabs/DeepCopy.git", 301 | "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" 302 | }, 303 | "dist": { 304 | "type": "zip", 305 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", 306 | "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", 307 | "shasum": "" 308 | }, 309 | "require": { 310 | "php": "^7.1 || ^8.0" 311 | }, 312 | "conflict": { 313 | "doctrine/collections": "<1.6.8", 314 | "doctrine/common": "<2.13.3 || >=3 <3.2.2" 315 | }, 316 | "require-dev": { 317 | "doctrine/collections": "^1.6.8", 318 | "doctrine/common": "^2.13.3 || ^3.2.2", 319 | "phpspec/prophecy": "^1.10", 320 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" 321 | }, 322 | "type": "library", 323 | "autoload": { 324 | "files": [ 325 | "src/DeepCopy/deep_copy.php" 326 | ], 327 | "psr-4": { 328 | "DeepCopy\\": "src/DeepCopy/" 329 | } 330 | }, 331 | "notification-url": "https://packagist.org/downloads/", 332 | "license": [ 333 | "MIT" 334 | ], 335 | "description": "Create deep copies (clones) of your objects", 336 | "keywords": [ 337 | "clone", 338 | "copy", 339 | "duplicate", 340 | "object", 341 | "object graph" 342 | ], 343 | "support": { 344 | "issues": "https://github.com/myclabs/DeepCopy/issues", 345 | "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" 346 | }, 347 | "funding": [ 348 | { 349 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", 350 | "type": "tidelift" 351 | } 352 | ], 353 | "time": "2025-08-01T08:46:24+00:00" 354 | }, 355 | { 356 | "name": "nikic/php-parser", 357 | "version": "v5.6.1", 358 | "source": { 359 | "type": "git", 360 | "url": "https://github.com/nikic/PHP-Parser.git", 361 | "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" 362 | }, 363 | "dist": { 364 | "type": "zip", 365 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", 366 | "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", 367 | "shasum": "" 368 | }, 369 | "require": { 370 | "ext-ctype": "*", 371 | "ext-json": "*", 372 | "ext-tokenizer": "*", 373 | "php": ">=7.4" 374 | }, 375 | "require-dev": { 376 | "ircmaxell/php-yacc": "^0.0.7", 377 | "phpunit/phpunit": "^9.0" 378 | }, 379 | "bin": [ 380 | "bin/php-parse" 381 | ], 382 | "type": "library", 383 | "extra": { 384 | "branch-alias": { 385 | "dev-master": "5.x-dev" 386 | } 387 | }, 388 | "autoload": { 389 | "psr-4": { 390 | "PhpParser\\": "lib/PhpParser" 391 | } 392 | }, 393 | "notification-url": "https://packagist.org/downloads/", 394 | "license": [ 395 | "BSD-3-Clause" 396 | ], 397 | "authors": [ 398 | { 399 | "name": "Nikita Popov" 400 | } 401 | ], 402 | "description": "A PHP parser written in PHP", 403 | "keywords": [ 404 | "parser", 405 | "php" 406 | ], 407 | "support": { 408 | "issues": "https://github.com/nikic/PHP-Parser/issues", 409 | "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" 410 | }, 411 | "time": "2025-08-13T20:13:15+00:00" 412 | }, 413 | { 414 | "name": "phar-io/manifest", 415 | "version": "2.0.4", 416 | "source": { 417 | "type": "git", 418 | "url": "https://github.com/phar-io/manifest.git", 419 | "reference": "54750ef60c58e43759730615a392c31c80e23176" 420 | }, 421 | "dist": { 422 | "type": "zip", 423 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", 424 | "reference": "54750ef60c58e43759730615a392c31c80e23176", 425 | "shasum": "" 426 | }, 427 | "require": { 428 | "ext-dom": "*", 429 | "ext-libxml": "*", 430 | "ext-phar": "*", 431 | "ext-xmlwriter": "*", 432 | "phar-io/version": "^3.0.1", 433 | "php": "^7.2 || ^8.0" 434 | }, 435 | "type": "library", 436 | "extra": { 437 | "branch-alias": { 438 | "dev-master": "2.0.x-dev" 439 | } 440 | }, 441 | "autoload": { 442 | "classmap": [ 443 | "src/" 444 | ] 445 | }, 446 | "notification-url": "https://packagist.org/downloads/", 447 | "license": [ 448 | "BSD-3-Clause" 449 | ], 450 | "authors": [ 451 | { 452 | "name": "Arne Blankerts", 453 | "email": "arne@blankerts.de", 454 | "role": "Developer" 455 | }, 456 | { 457 | "name": "Sebastian Heuer", 458 | "email": "sebastian@phpeople.de", 459 | "role": "Developer" 460 | }, 461 | { 462 | "name": "Sebastian Bergmann", 463 | "email": "sebastian@phpunit.de", 464 | "role": "Developer" 465 | } 466 | ], 467 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 468 | "support": { 469 | "issues": "https://github.com/phar-io/manifest/issues", 470 | "source": "https://github.com/phar-io/manifest/tree/2.0.4" 471 | }, 472 | "funding": [ 473 | { 474 | "url": "https://github.com/theseer", 475 | "type": "github" 476 | } 477 | ], 478 | "time": "2024-03-03T12:33:53+00:00" 479 | }, 480 | { 481 | "name": "phar-io/version", 482 | "version": "3.2.1", 483 | "source": { 484 | "type": "git", 485 | "url": "https://github.com/phar-io/version.git", 486 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" 487 | }, 488 | "dist": { 489 | "type": "zip", 490 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 491 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 492 | "shasum": "" 493 | }, 494 | "require": { 495 | "php": "^7.2 || ^8.0" 496 | }, 497 | "type": "library", 498 | "autoload": { 499 | "classmap": [ 500 | "src/" 501 | ] 502 | }, 503 | "notification-url": "https://packagist.org/downloads/", 504 | "license": [ 505 | "BSD-3-Clause" 506 | ], 507 | "authors": [ 508 | { 509 | "name": "Arne Blankerts", 510 | "email": "arne@blankerts.de", 511 | "role": "Developer" 512 | }, 513 | { 514 | "name": "Sebastian Heuer", 515 | "email": "sebastian@phpeople.de", 516 | "role": "Developer" 517 | }, 518 | { 519 | "name": "Sebastian Bergmann", 520 | "email": "sebastian@phpunit.de", 521 | "role": "Developer" 522 | } 523 | ], 524 | "description": "Library for handling version information and constraints", 525 | "support": { 526 | "issues": "https://github.com/phar-io/version/issues", 527 | "source": "https://github.com/phar-io/version/tree/3.2.1" 528 | }, 529 | "time": "2022-02-21T01:04:05+00:00" 530 | }, 531 | { 532 | "name": "phpstan/phpstan", 533 | "version": "1.12.32", 534 | "dist": { 535 | "type": "zip", 536 | "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8", 537 | "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8", 538 | "shasum": "" 539 | }, 540 | "require": { 541 | "php": "^7.2|^8.0" 542 | }, 543 | "conflict": { 544 | "phpstan/phpstan-shim": "*" 545 | }, 546 | "bin": [ 547 | "phpstan", 548 | "phpstan.phar" 549 | ], 550 | "type": "library", 551 | "autoload": { 552 | "files": [ 553 | "bootstrap.php" 554 | ] 555 | }, 556 | "notification-url": "https://packagist.org/downloads/", 557 | "license": [ 558 | "MIT" 559 | ], 560 | "description": "PHPStan - PHP Static Analysis Tool", 561 | "keywords": [ 562 | "dev", 563 | "static analysis" 564 | ], 565 | "support": { 566 | "docs": "https://phpstan.org/user-guide/getting-started", 567 | "forum": "https://github.com/phpstan/phpstan/discussions", 568 | "issues": "https://github.com/phpstan/phpstan/issues", 569 | "security": "https://github.com/phpstan/phpstan/security/policy", 570 | "source": "https://github.com/phpstan/phpstan-src" 571 | }, 572 | "funding": [ 573 | { 574 | "url": "https://github.com/ondrejmirtes", 575 | "type": "github" 576 | }, 577 | { 578 | "url": "https://github.com/phpstan", 579 | "type": "github" 580 | } 581 | ], 582 | "time": "2025-09-30T10:16:31+00:00" 583 | }, 584 | { 585 | "name": "phpunit/php-code-coverage", 586 | "version": "9.2.32", 587 | "source": { 588 | "type": "git", 589 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 590 | "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" 591 | }, 592 | "dist": { 593 | "type": "zip", 594 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", 595 | "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", 596 | "shasum": "" 597 | }, 598 | "require": { 599 | "ext-dom": "*", 600 | "ext-libxml": "*", 601 | "ext-xmlwriter": "*", 602 | "nikic/php-parser": "^4.19.1 || ^5.1.0", 603 | "php": ">=7.3", 604 | "phpunit/php-file-iterator": "^3.0.6", 605 | "phpunit/php-text-template": "^2.0.4", 606 | "sebastian/code-unit-reverse-lookup": "^2.0.3", 607 | "sebastian/complexity": "^2.0.3", 608 | "sebastian/environment": "^5.1.5", 609 | "sebastian/lines-of-code": "^1.0.4", 610 | "sebastian/version": "^3.0.2", 611 | "theseer/tokenizer": "^1.2.3" 612 | }, 613 | "require-dev": { 614 | "phpunit/phpunit": "^9.6" 615 | }, 616 | "suggest": { 617 | "ext-pcov": "PHP extension that provides line coverage", 618 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 619 | }, 620 | "type": "library", 621 | "extra": { 622 | "branch-alias": { 623 | "dev-main": "9.2.x-dev" 624 | } 625 | }, 626 | "autoload": { 627 | "classmap": [ 628 | "src/" 629 | ] 630 | }, 631 | "notification-url": "https://packagist.org/downloads/", 632 | "license": [ 633 | "BSD-3-Clause" 634 | ], 635 | "authors": [ 636 | { 637 | "name": "Sebastian Bergmann", 638 | "email": "sebastian@phpunit.de", 639 | "role": "lead" 640 | } 641 | ], 642 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 643 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 644 | "keywords": [ 645 | "coverage", 646 | "testing", 647 | "xunit" 648 | ], 649 | "support": { 650 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", 651 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", 652 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" 653 | }, 654 | "funding": [ 655 | { 656 | "url": "https://github.com/sebastianbergmann", 657 | "type": "github" 658 | } 659 | ], 660 | "time": "2024-08-22T04:23:01+00:00" 661 | }, 662 | { 663 | "name": "phpunit/php-file-iterator", 664 | "version": "3.0.6", 665 | "source": { 666 | "type": "git", 667 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 668 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" 669 | }, 670 | "dist": { 671 | "type": "zip", 672 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 673 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 674 | "shasum": "" 675 | }, 676 | "require": { 677 | "php": ">=7.3" 678 | }, 679 | "require-dev": { 680 | "phpunit/phpunit": "^9.3" 681 | }, 682 | "type": "library", 683 | "extra": { 684 | "branch-alias": { 685 | "dev-master": "3.0-dev" 686 | } 687 | }, 688 | "autoload": { 689 | "classmap": [ 690 | "src/" 691 | ] 692 | }, 693 | "notification-url": "https://packagist.org/downloads/", 694 | "license": [ 695 | "BSD-3-Clause" 696 | ], 697 | "authors": [ 698 | { 699 | "name": "Sebastian Bergmann", 700 | "email": "sebastian@phpunit.de", 701 | "role": "lead" 702 | } 703 | ], 704 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 705 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 706 | "keywords": [ 707 | "filesystem", 708 | "iterator" 709 | ], 710 | "support": { 711 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", 712 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" 713 | }, 714 | "funding": [ 715 | { 716 | "url": "https://github.com/sebastianbergmann", 717 | "type": "github" 718 | } 719 | ], 720 | "time": "2021-12-02T12:48:52+00:00" 721 | }, 722 | { 723 | "name": "phpunit/php-invoker", 724 | "version": "3.1.1", 725 | "source": { 726 | "type": "git", 727 | "url": "https://github.com/sebastianbergmann/php-invoker.git", 728 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" 729 | }, 730 | "dist": { 731 | "type": "zip", 732 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 733 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 734 | "shasum": "" 735 | }, 736 | "require": { 737 | "php": ">=7.3" 738 | }, 739 | "require-dev": { 740 | "ext-pcntl": "*", 741 | "phpunit/phpunit": "^9.3" 742 | }, 743 | "suggest": { 744 | "ext-pcntl": "*" 745 | }, 746 | "type": "library", 747 | "extra": { 748 | "branch-alias": { 749 | "dev-master": "3.1-dev" 750 | } 751 | }, 752 | "autoload": { 753 | "classmap": [ 754 | "src/" 755 | ] 756 | }, 757 | "notification-url": "https://packagist.org/downloads/", 758 | "license": [ 759 | "BSD-3-Clause" 760 | ], 761 | "authors": [ 762 | { 763 | "name": "Sebastian Bergmann", 764 | "email": "sebastian@phpunit.de", 765 | "role": "lead" 766 | } 767 | ], 768 | "description": "Invoke callables with a timeout", 769 | "homepage": "https://github.com/sebastianbergmann/php-invoker/", 770 | "keywords": [ 771 | "process" 772 | ], 773 | "support": { 774 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues", 775 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" 776 | }, 777 | "funding": [ 778 | { 779 | "url": "https://github.com/sebastianbergmann", 780 | "type": "github" 781 | } 782 | ], 783 | "time": "2020-09-28T05:58:55+00:00" 784 | }, 785 | { 786 | "name": "phpunit/php-text-template", 787 | "version": "2.0.4", 788 | "source": { 789 | "type": "git", 790 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 791 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" 792 | }, 793 | "dist": { 794 | "type": "zip", 795 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 796 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 797 | "shasum": "" 798 | }, 799 | "require": { 800 | "php": ">=7.3" 801 | }, 802 | "require-dev": { 803 | "phpunit/phpunit": "^9.3" 804 | }, 805 | "type": "library", 806 | "extra": { 807 | "branch-alias": { 808 | "dev-master": "2.0-dev" 809 | } 810 | }, 811 | "autoload": { 812 | "classmap": [ 813 | "src/" 814 | ] 815 | }, 816 | "notification-url": "https://packagist.org/downloads/", 817 | "license": [ 818 | "BSD-3-Clause" 819 | ], 820 | "authors": [ 821 | { 822 | "name": "Sebastian Bergmann", 823 | "email": "sebastian@phpunit.de", 824 | "role": "lead" 825 | } 826 | ], 827 | "description": "Simple template engine.", 828 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 829 | "keywords": [ 830 | "template" 831 | ], 832 | "support": { 833 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues", 834 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" 835 | }, 836 | "funding": [ 837 | { 838 | "url": "https://github.com/sebastianbergmann", 839 | "type": "github" 840 | } 841 | ], 842 | "time": "2020-10-26T05:33:50+00:00" 843 | }, 844 | { 845 | "name": "phpunit/php-timer", 846 | "version": "5.0.3", 847 | "source": { 848 | "type": "git", 849 | "url": "https://github.com/sebastianbergmann/php-timer.git", 850 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" 851 | }, 852 | "dist": { 853 | "type": "zip", 854 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 855 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 856 | "shasum": "" 857 | }, 858 | "require": { 859 | "php": ">=7.3" 860 | }, 861 | "require-dev": { 862 | "phpunit/phpunit": "^9.3" 863 | }, 864 | "type": "library", 865 | "extra": { 866 | "branch-alias": { 867 | "dev-master": "5.0-dev" 868 | } 869 | }, 870 | "autoload": { 871 | "classmap": [ 872 | "src/" 873 | ] 874 | }, 875 | "notification-url": "https://packagist.org/downloads/", 876 | "license": [ 877 | "BSD-3-Clause" 878 | ], 879 | "authors": [ 880 | { 881 | "name": "Sebastian Bergmann", 882 | "email": "sebastian@phpunit.de", 883 | "role": "lead" 884 | } 885 | ], 886 | "description": "Utility class for timing", 887 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 888 | "keywords": [ 889 | "timer" 890 | ], 891 | "support": { 892 | "issues": "https://github.com/sebastianbergmann/php-timer/issues", 893 | "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" 894 | }, 895 | "funding": [ 896 | { 897 | "url": "https://github.com/sebastianbergmann", 898 | "type": "github" 899 | } 900 | ], 901 | "time": "2020-10-26T13:16:10+00:00" 902 | }, 903 | { 904 | "name": "phpunit/phpunit", 905 | "version": "9.6.29", 906 | "source": { 907 | "type": "git", 908 | "url": "https://github.com/sebastianbergmann/phpunit.git", 909 | "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3" 910 | }, 911 | "dist": { 912 | "type": "zip", 913 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9ecfec57835a5581bc888ea7e13b51eb55ab9dd3", 914 | "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3", 915 | "shasum": "" 916 | }, 917 | "require": { 918 | "doctrine/instantiator": "^1.5.0 || ^2", 919 | "ext-dom": "*", 920 | "ext-json": "*", 921 | "ext-libxml": "*", 922 | "ext-mbstring": "*", 923 | "ext-xml": "*", 924 | "ext-xmlwriter": "*", 925 | "myclabs/deep-copy": "^1.13.4", 926 | "phar-io/manifest": "^2.0.4", 927 | "phar-io/version": "^3.2.1", 928 | "php": ">=7.3", 929 | "phpunit/php-code-coverage": "^9.2.32", 930 | "phpunit/php-file-iterator": "^3.0.6", 931 | "phpunit/php-invoker": "^3.1.1", 932 | "phpunit/php-text-template": "^2.0.4", 933 | "phpunit/php-timer": "^5.0.3", 934 | "sebastian/cli-parser": "^1.0.2", 935 | "sebastian/code-unit": "^1.0.8", 936 | "sebastian/comparator": "^4.0.9", 937 | "sebastian/diff": "^4.0.6", 938 | "sebastian/environment": "^5.1.5", 939 | "sebastian/exporter": "^4.0.8", 940 | "sebastian/global-state": "^5.0.8", 941 | "sebastian/object-enumerator": "^4.0.4", 942 | "sebastian/resource-operations": "^3.0.4", 943 | "sebastian/type": "^3.2.1", 944 | "sebastian/version": "^3.0.2" 945 | }, 946 | "suggest": { 947 | "ext-soap": "To be able to generate mocks based on WSDL files", 948 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 949 | }, 950 | "bin": [ 951 | "phpunit" 952 | ], 953 | "type": "library", 954 | "extra": { 955 | "branch-alias": { 956 | "dev-master": "9.6-dev" 957 | } 958 | }, 959 | "autoload": { 960 | "files": [ 961 | "src/Framework/Assert/Functions.php" 962 | ], 963 | "classmap": [ 964 | "src/" 965 | ] 966 | }, 967 | "notification-url": "https://packagist.org/downloads/", 968 | "license": [ 969 | "BSD-3-Clause" 970 | ], 971 | "authors": [ 972 | { 973 | "name": "Sebastian Bergmann", 974 | "email": "sebastian@phpunit.de", 975 | "role": "lead" 976 | } 977 | ], 978 | "description": "The PHP Unit Testing framework.", 979 | "homepage": "https://phpunit.de/", 980 | "keywords": [ 981 | "phpunit", 982 | "testing", 983 | "xunit" 984 | ], 985 | "support": { 986 | "issues": "https://github.com/sebastianbergmann/phpunit/issues", 987 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy", 988 | "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.29" 989 | }, 990 | "funding": [ 991 | { 992 | "url": "https://phpunit.de/sponsors.html", 993 | "type": "custom" 994 | }, 995 | { 996 | "url": "https://github.com/sebastianbergmann", 997 | "type": "github" 998 | }, 999 | { 1000 | "url": "https://liberapay.com/sebastianbergmann", 1001 | "type": "liberapay" 1002 | }, 1003 | { 1004 | "url": "https://thanks.dev/u/gh/sebastianbergmann", 1005 | "type": "thanks_dev" 1006 | }, 1007 | { 1008 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", 1009 | "type": "tidelift" 1010 | } 1011 | ], 1012 | "time": "2025-09-24T06:29:11+00:00" 1013 | }, 1014 | { 1015 | "name": "sebastian/cli-parser", 1016 | "version": "1.0.2", 1017 | "source": { 1018 | "type": "git", 1019 | "url": "https://github.com/sebastianbergmann/cli-parser.git", 1020 | "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" 1021 | }, 1022 | "dist": { 1023 | "type": "zip", 1024 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", 1025 | "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", 1026 | "shasum": "" 1027 | }, 1028 | "require": { 1029 | "php": ">=7.3" 1030 | }, 1031 | "require-dev": { 1032 | "phpunit/phpunit": "^9.3" 1033 | }, 1034 | "type": "library", 1035 | "extra": { 1036 | "branch-alias": { 1037 | "dev-master": "1.0-dev" 1038 | } 1039 | }, 1040 | "autoload": { 1041 | "classmap": [ 1042 | "src/" 1043 | ] 1044 | }, 1045 | "notification-url": "https://packagist.org/downloads/", 1046 | "license": [ 1047 | "BSD-3-Clause" 1048 | ], 1049 | "authors": [ 1050 | { 1051 | "name": "Sebastian Bergmann", 1052 | "email": "sebastian@phpunit.de", 1053 | "role": "lead" 1054 | } 1055 | ], 1056 | "description": "Library for parsing CLI options", 1057 | "homepage": "https://github.com/sebastianbergmann/cli-parser", 1058 | "support": { 1059 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues", 1060 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" 1061 | }, 1062 | "funding": [ 1063 | { 1064 | "url": "https://github.com/sebastianbergmann", 1065 | "type": "github" 1066 | } 1067 | ], 1068 | "time": "2024-03-02T06:27:43+00:00" 1069 | }, 1070 | { 1071 | "name": "sebastian/code-unit", 1072 | "version": "1.0.8", 1073 | "source": { 1074 | "type": "git", 1075 | "url": "https://github.com/sebastianbergmann/code-unit.git", 1076 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" 1077 | }, 1078 | "dist": { 1079 | "type": "zip", 1080 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", 1081 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", 1082 | "shasum": "" 1083 | }, 1084 | "require": { 1085 | "php": ">=7.3" 1086 | }, 1087 | "require-dev": { 1088 | "phpunit/phpunit": "^9.3" 1089 | }, 1090 | "type": "library", 1091 | "extra": { 1092 | "branch-alias": { 1093 | "dev-master": "1.0-dev" 1094 | } 1095 | }, 1096 | "autoload": { 1097 | "classmap": [ 1098 | "src/" 1099 | ] 1100 | }, 1101 | "notification-url": "https://packagist.org/downloads/", 1102 | "license": [ 1103 | "BSD-3-Clause" 1104 | ], 1105 | "authors": [ 1106 | { 1107 | "name": "Sebastian Bergmann", 1108 | "email": "sebastian@phpunit.de", 1109 | "role": "lead" 1110 | } 1111 | ], 1112 | "description": "Collection of value objects that represent the PHP code units", 1113 | "homepage": "https://github.com/sebastianbergmann/code-unit", 1114 | "support": { 1115 | "issues": "https://github.com/sebastianbergmann/code-unit/issues", 1116 | "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" 1117 | }, 1118 | "funding": [ 1119 | { 1120 | "url": "https://github.com/sebastianbergmann", 1121 | "type": "github" 1122 | } 1123 | ], 1124 | "time": "2020-10-26T13:08:54+00:00" 1125 | }, 1126 | { 1127 | "name": "sebastian/code-unit-reverse-lookup", 1128 | "version": "2.0.3", 1129 | "source": { 1130 | "type": "git", 1131 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 1132 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" 1133 | }, 1134 | "dist": { 1135 | "type": "zip", 1136 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 1137 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 1138 | "shasum": "" 1139 | }, 1140 | "require": { 1141 | "php": ">=7.3" 1142 | }, 1143 | "require-dev": { 1144 | "phpunit/phpunit": "^9.3" 1145 | }, 1146 | "type": "library", 1147 | "extra": { 1148 | "branch-alias": { 1149 | "dev-master": "2.0-dev" 1150 | } 1151 | }, 1152 | "autoload": { 1153 | "classmap": [ 1154 | "src/" 1155 | ] 1156 | }, 1157 | "notification-url": "https://packagist.org/downloads/", 1158 | "license": [ 1159 | "BSD-3-Clause" 1160 | ], 1161 | "authors": [ 1162 | { 1163 | "name": "Sebastian Bergmann", 1164 | "email": "sebastian@phpunit.de" 1165 | } 1166 | ], 1167 | "description": "Looks up which function or method a line of code belongs to", 1168 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 1169 | "support": { 1170 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", 1171 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" 1172 | }, 1173 | "funding": [ 1174 | { 1175 | "url": "https://github.com/sebastianbergmann", 1176 | "type": "github" 1177 | } 1178 | ], 1179 | "time": "2020-09-28T05:30:19+00:00" 1180 | }, 1181 | { 1182 | "name": "sebastian/comparator", 1183 | "version": "4.0.9", 1184 | "source": { 1185 | "type": "git", 1186 | "url": "https://github.com/sebastianbergmann/comparator.git", 1187 | "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5" 1188 | }, 1189 | "dist": { 1190 | "type": "zip", 1191 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5", 1192 | "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5", 1193 | "shasum": "" 1194 | }, 1195 | "require": { 1196 | "php": ">=7.3", 1197 | "sebastian/diff": "^4.0", 1198 | "sebastian/exporter": "^4.0" 1199 | }, 1200 | "require-dev": { 1201 | "phpunit/phpunit": "^9.3" 1202 | }, 1203 | "type": "library", 1204 | "extra": { 1205 | "branch-alias": { 1206 | "dev-master": "4.0-dev" 1207 | } 1208 | }, 1209 | "autoload": { 1210 | "classmap": [ 1211 | "src/" 1212 | ] 1213 | }, 1214 | "notification-url": "https://packagist.org/downloads/", 1215 | "license": [ 1216 | "BSD-3-Clause" 1217 | ], 1218 | "authors": [ 1219 | { 1220 | "name": "Sebastian Bergmann", 1221 | "email": "sebastian@phpunit.de" 1222 | }, 1223 | { 1224 | "name": "Jeff Welch", 1225 | "email": "whatthejeff@gmail.com" 1226 | }, 1227 | { 1228 | "name": "Volker Dusch", 1229 | "email": "github@wallbash.com" 1230 | }, 1231 | { 1232 | "name": "Bernhard Schussek", 1233 | "email": "bschussek@2bepublished.at" 1234 | } 1235 | ], 1236 | "description": "Provides the functionality to compare PHP values for equality", 1237 | "homepage": "https://github.com/sebastianbergmann/comparator", 1238 | "keywords": [ 1239 | "comparator", 1240 | "compare", 1241 | "equality" 1242 | ], 1243 | "support": { 1244 | "issues": "https://github.com/sebastianbergmann/comparator/issues", 1245 | "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9" 1246 | }, 1247 | "funding": [ 1248 | { 1249 | "url": "https://github.com/sebastianbergmann", 1250 | "type": "github" 1251 | }, 1252 | { 1253 | "url": "https://liberapay.com/sebastianbergmann", 1254 | "type": "liberapay" 1255 | }, 1256 | { 1257 | "url": "https://thanks.dev/u/gh/sebastianbergmann", 1258 | "type": "thanks_dev" 1259 | }, 1260 | { 1261 | "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", 1262 | "type": "tidelift" 1263 | } 1264 | ], 1265 | "time": "2025-08-10T06:51:50+00:00" 1266 | }, 1267 | { 1268 | "name": "sebastian/complexity", 1269 | "version": "2.0.3", 1270 | "source": { 1271 | "type": "git", 1272 | "url": "https://github.com/sebastianbergmann/complexity.git", 1273 | "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" 1274 | }, 1275 | "dist": { 1276 | "type": "zip", 1277 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", 1278 | "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", 1279 | "shasum": "" 1280 | }, 1281 | "require": { 1282 | "nikic/php-parser": "^4.18 || ^5.0", 1283 | "php": ">=7.3" 1284 | }, 1285 | "require-dev": { 1286 | "phpunit/phpunit": "^9.3" 1287 | }, 1288 | "type": "library", 1289 | "extra": { 1290 | "branch-alias": { 1291 | "dev-master": "2.0-dev" 1292 | } 1293 | }, 1294 | "autoload": { 1295 | "classmap": [ 1296 | "src/" 1297 | ] 1298 | }, 1299 | "notification-url": "https://packagist.org/downloads/", 1300 | "license": [ 1301 | "BSD-3-Clause" 1302 | ], 1303 | "authors": [ 1304 | { 1305 | "name": "Sebastian Bergmann", 1306 | "email": "sebastian@phpunit.de", 1307 | "role": "lead" 1308 | } 1309 | ], 1310 | "description": "Library for calculating the complexity of PHP code units", 1311 | "homepage": "https://github.com/sebastianbergmann/complexity", 1312 | "support": { 1313 | "issues": "https://github.com/sebastianbergmann/complexity/issues", 1314 | "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" 1315 | }, 1316 | "funding": [ 1317 | { 1318 | "url": "https://github.com/sebastianbergmann", 1319 | "type": "github" 1320 | } 1321 | ], 1322 | "time": "2023-12-22T06:19:30+00:00" 1323 | }, 1324 | { 1325 | "name": "sebastian/diff", 1326 | "version": "4.0.6", 1327 | "source": { 1328 | "type": "git", 1329 | "url": "https://github.com/sebastianbergmann/diff.git", 1330 | "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" 1331 | }, 1332 | "dist": { 1333 | "type": "zip", 1334 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", 1335 | "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", 1336 | "shasum": "" 1337 | }, 1338 | "require": { 1339 | "php": ">=7.3" 1340 | }, 1341 | "require-dev": { 1342 | "phpunit/phpunit": "^9.3", 1343 | "symfony/process": "^4.2 || ^5" 1344 | }, 1345 | "type": "library", 1346 | "extra": { 1347 | "branch-alias": { 1348 | "dev-master": "4.0-dev" 1349 | } 1350 | }, 1351 | "autoload": { 1352 | "classmap": [ 1353 | "src/" 1354 | ] 1355 | }, 1356 | "notification-url": "https://packagist.org/downloads/", 1357 | "license": [ 1358 | "BSD-3-Clause" 1359 | ], 1360 | "authors": [ 1361 | { 1362 | "name": "Sebastian Bergmann", 1363 | "email": "sebastian@phpunit.de" 1364 | }, 1365 | { 1366 | "name": "Kore Nordmann", 1367 | "email": "mail@kore-nordmann.de" 1368 | } 1369 | ], 1370 | "description": "Diff implementation", 1371 | "homepage": "https://github.com/sebastianbergmann/diff", 1372 | "keywords": [ 1373 | "diff", 1374 | "udiff", 1375 | "unidiff", 1376 | "unified diff" 1377 | ], 1378 | "support": { 1379 | "issues": "https://github.com/sebastianbergmann/diff/issues", 1380 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" 1381 | }, 1382 | "funding": [ 1383 | { 1384 | "url": "https://github.com/sebastianbergmann", 1385 | "type": "github" 1386 | } 1387 | ], 1388 | "time": "2024-03-02T06:30:58+00:00" 1389 | }, 1390 | { 1391 | "name": "sebastian/environment", 1392 | "version": "5.1.5", 1393 | "source": { 1394 | "type": "git", 1395 | "url": "https://github.com/sebastianbergmann/environment.git", 1396 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" 1397 | }, 1398 | "dist": { 1399 | "type": "zip", 1400 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", 1401 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", 1402 | "shasum": "" 1403 | }, 1404 | "require": { 1405 | "php": ">=7.3" 1406 | }, 1407 | "require-dev": { 1408 | "phpunit/phpunit": "^9.3" 1409 | }, 1410 | "suggest": { 1411 | "ext-posix": "*" 1412 | }, 1413 | "type": "library", 1414 | "extra": { 1415 | "branch-alias": { 1416 | "dev-master": "5.1-dev" 1417 | } 1418 | }, 1419 | "autoload": { 1420 | "classmap": [ 1421 | "src/" 1422 | ] 1423 | }, 1424 | "notification-url": "https://packagist.org/downloads/", 1425 | "license": [ 1426 | "BSD-3-Clause" 1427 | ], 1428 | "authors": [ 1429 | { 1430 | "name": "Sebastian Bergmann", 1431 | "email": "sebastian@phpunit.de" 1432 | } 1433 | ], 1434 | "description": "Provides functionality to handle HHVM/PHP environments", 1435 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1436 | "keywords": [ 1437 | "Xdebug", 1438 | "environment", 1439 | "hhvm" 1440 | ], 1441 | "support": { 1442 | "issues": "https://github.com/sebastianbergmann/environment/issues", 1443 | "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" 1444 | }, 1445 | "funding": [ 1446 | { 1447 | "url": "https://github.com/sebastianbergmann", 1448 | "type": "github" 1449 | } 1450 | ], 1451 | "time": "2023-02-03T06:03:51+00:00" 1452 | }, 1453 | { 1454 | "name": "sebastian/exporter", 1455 | "version": "4.0.8", 1456 | "source": { 1457 | "type": "git", 1458 | "url": "https://github.com/sebastianbergmann/exporter.git", 1459 | "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c" 1460 | }, 1461 | "dist": { 1462 | "type": "zip", 1463 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c", 1464 | "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c", 1465 | "shasum": "" 1466 | }, 1467 | "require": { 1468 | "php": ">=7.3", 1469 | "sebastian/recursion-context": "^4.0" 1470 | }, 1471 | "require-dev": { 1472 | "ext-mbstring": "*", 1473 | "phpunit/phpunit": "^9.3" 1474 | }, 1475 | "type": "library", 1476 | "extra": { 1477 | "branch-alias": { 1478 | "dev-master": "4.0-dev" 1479 | } 1480 | }, 1481 | "autoload": { 1482 | "classmap": [ 1483 | "src/" 1484 | ] 1485 | }, 1486 | "notification-url": "https://packagist.org/downloads/", 1487 | "license": [ 1488 | "BSD-3-Clause" 1489 | ], 1490 | "authors": [ 1491 | { 1492 | "name": "Sebastian Bergmann", 1493 | "email": "sebastian@phpunit.de" 1494 | }, 1495 | { 1496 | "name": "Jeff Welch", 1497 | "email": "whatthejeff@gmail.com" 1498 | }, 1499 | { 1500 | "name": "Volker Dusch", 1501 | "email": "github@wallbash.com" 1502 | }, 1503 | { 1504 | "name": "Adam Harvey", 1505 | "email": "aharvey@php.net" 1506 | }, 1507 | { 1508 | "name": "Bernhard Schussek", 1509 | "email": "bschussek@gmail.com" 1510 | } 1511 | ], 1512 | "description": "Provides the functionality to export PHP variables for visualization", 1513 | "homepage": "https://www.github.com/sebastianbergmann/exporter", 1514 | "keywords": [ 1515 | "export", 1516 | "exporter" 1517 | ], 1518 | "support": { 1519 | "issues": "https://github.com/sebastianbergmann/exporter/issues", 1520 | "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.8" 1521 | }, 1522 | "funding": [ 1523 | { 1524 | "url": "https://github.com/sebastianbergmann", 1525 | "type": "github" 1526 | }, 1527 | { 1528 | "url": "https://liberapay.com/sebastianbergmann", 1529 | "type": "liberapay" 1530 | }, 1531 | { 1532 | "url": "https://thanks.dev/u/gh/sebastianbergmann", 1533 | "type": "thanks_dev" 1534 | }, 1535 | { 1536 | "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", 1537 | "type": "tidelift" 1538 | } 1539 | ], 1540 | "time": "2025-09-24T06:03:27+00:00" 1541 | }, 1542 | { 1543 | "name": "sebastian/global-state", 1544 | "version": "5.0.8", 1545 | "source": { 1546 | "type": "git", 1547 | "url": "https://github.com/sebastianbergmann/global-state.git", 1548 | "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6" 1549 | }, 1550 | "dist": { 1551 | "type": "zip", 1552 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6", 1553 | "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6", 1554 | "shasum": "" 1555 | }, 1556 | "require": { 1557 | "php": ">=7.3", 1558 | "sebastian/object-reflector": "^2.0", 1559 | "sebastian/recursion-context": "^4.0" 1560 | }, 1561 | "require-dev": { 1562 | "ext-dom": "*", 1563 | "phpunit/phpunit": "^9.3" 1564 | }, 1565 | "suggest": { 1566 | "ext-uopz": "*" 1567 | }, 1568 | "type": "library", 1569 | "extra": { 1570 | "branch-alias": { 1571 | "dev-master": "5.0-dev" 1572 | } 1573 | }, 1574 | "autoload": { 1575 | "classmap": [ 1576 | "src/" 1577 | ] 1578 | }, 1579 | "notification-url": "https://packagist.org/downloads/", 1580 | "license": [ 1581 | "BSD-3-Clause" 1582 | ], 1583 | "authors": [ 1584 | { 1585 | "name": "Sebastian Bergmann", 1586 | "email": "sebastian@phpunit.de" 1587 | } 1588 | ], 1589 | "description": "Snapshotting of global state", 1590 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1591 | "keywords": [ 1592 | "global state" 1593 | ], 1594 | "support": { 1595 | "issues": "https://github.com/sebastianbergmann/global-state/issues", 1596 | "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8" 1597 | }, 1598 | "funding": [ 1599 | { 1600 | "url": "https://github.com/sebastianbergmann", 1601 | "type": "github" 1602 | }, 1603 | { 1604 | "url": "https://liberapay.com/sebastianbergmann", 1605 | "type": "liberapay" 1606 | }, 1607 | { 1608 | "url": "https://thanks.dev/u/gh/sebastianbergmann", 1609 | "type": "thanks_dev" 1610 | }, 1611 | { 1612 | "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", 1613 | "type": "tidelift" 1614 | } 1615 | ], 1616 | "time": "2025-08-10T07:10:35+00:00" 1617 | }, 1618 | { 1619 | "name": "sebastian/lines-of-code", 1620 | "version": "1.0.4", 1621 | "source": { 1622 | "type": "git", 1623 | "url": "https://github.com/sebastianbergmann/lines-of-code.git", 1624 | "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" 1625 | }, 1626 | "dist": { 1627 | "type": "zip", 1628 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", 1629 | "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", 1630 | "shasum": "" 1631 | }, 1632 | "require": { 1633 | "nikic/php-parser": "^4.18 || ^5.0", 1634 | "php": ">=7.3" 1635 | }, 1636 | "require-dev": { 1637 | "phpunit/phpunit": "^9.3" 1638 | }, 1639 | "type": "library", 1640 | "extra": { 1641 | "branch-alias": { 1642 | "dev-master": "1.0-dev" 1643 | } 1644 | }, 1645 | "autoload": { 1646 | "classmap": [ 1647 | "src/" 1648 | ] 1649 | }, 1650 | "notification-url": "https://packagist.org/downloads/", 1651 | "license": [ 1652 | "BSD-3-Clause" 1653 | ], 1654 | "authors": [ 1655 | { 1656 | "name": "Sebastian Bergmann", 1657 | "email": "sebastian@phpunit.de", 1658 | "role": "lead" 1659 | } 1660 | ], 1661 | "description": "Library for counting the lines of code in PHP source code", 1662 | "homepage": "https://github.com/sebastianbergmann/lines-of-code", 1663 | "support": { 1664 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", 1665 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" 1666 | }, 1667 | "funding": [ 1668 | { 1669 | "url": "https://github.com/sebastianbergmann", 1670 | "type": "github" 1671 | } 1672 | ], 1673 | "time": "2023-12-22T06:20:34+00:00" 1674 | }, 1675 | { 1676 | "name": "sebastian/object-enumerator", 1677 | "version": "4.0.4", 1678 | "source": { 1679 | "type": "git", 1680 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1681 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" 1682 | }, 1683 | "dist": { 1684 | "type": "zip", 1685 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", 1686 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", 1687 | "shasum": "" 1688 | }, 1689 | "require": { 1690 | "php": ">=7.3", 1691 | "sebastian/object-reflector": "^2.0", 1692 | "sebastian/recursion-context": "^4.0" 1693 | }, 1694 | "require-dev": { 1695 | "phpunit/phpunit": "^9.3" 1696 | }, 1697 | "type": "library", 1698 | "extra": { 1699 | "branch-alias": { 1700 | "dev-master": "4.0-dev" 1701 | } 1702 | }, 1703 | "autoload": { 1704 | "classmap": [ 1705 | "src/" 1706 | ] 1707 | }, 1708 | "notification-url": "https://packagist.org/downloads/", 1709 | "license": [ 1710 | "BSD-3-Clause" 1711 | ], 1712 | "authors": [ 1713 | { 1714 | "name": "Sebastian Bergmann", 1715 | "email": "sebastian@phpunit.de" 1716 | } 1717 | ], 1718 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1719 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1720 | "support": { 1721 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", 1722 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" 1723 | }, 1724 | "funding": [ 1725 | { 1726 | "url": "https://github.com/sebastianbergmann", 1727 | "type": "github" 1728 | } 1729 | ], 1730 | "time": "2020-10-26T13:12:34+00:00" 1731 | }, 1732 | { 1733 | "name": "sebastian/object-reflector", 1734 | "version": "2.0.4", 1735 | "source": { 1736 | "type": "git", 1737 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1738 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" 1739 | }, 1740 | "dist": { 1741 | "type": "zip", 1742 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 1743 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 1744 | "shasum": "" 1745 | }, 1746 | "require": { 1747 | "php": ">=7.3" 1748 | }, 1749 | "require-dev": { 1750 | "phpunit/phpunit": "^9.3" 1751 | }, 1752 | "type": "library", 1753 | "extra": { 1754 | "branch-alias": { 1755 | "dev-master": "2.0-dev" 1756 | } 1757 | }, 1758 | "autoload": { 1759 | "classmap": [ 1760 | "src/" 1761 | ] 1762 | }, 1763 | "notification-url": "https://packagist.org/downloads/", 1764 | "license": [ 1765 | "BSD-3-Clause" 1766 | ], 1767 | "authors": [ 1768 | { 1769 | "name": "Sebastian Bergmann", 1770 | "email": "sebastian@phpunit.de" 1771 | } 1772 | ], 1773 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 1774 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 1775 | "support": { 1776 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues", 1777 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" 1778 | }, 1779 | "funding": [ 1780 | { 1781 | "url": "https://github.com/sebastianbergmann", 1782 | "type": "github" 1783 | } 1784 | ], 1785 | "time": "2020-10-26T13:14:26+00:00" 1786 | }, 1787 | { 1788 | "name": "sebastian/recursion-context", 1789 | "version": "4.0.6", 1790 | "source": { 1791 | "type": "git", 1792 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1793 | "reference": "539c6691e0623af6dc6f9c20384c120f963465a0" 1794 | }, 1795 | "dist": { 1796 | "type": "zip", 1797 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0", 1798 | "reference": "539c6691e0623af6dc6f9c20384c120f963465a0", 1799 | "shasum": "" 1800 | }, 1801 | "require": { 1802 | "php": ">=7.3" 1803 | }, 1804 | "require-dev": { 1805 | "phpunit/phpunit": "^9.3" 1806 | }, 1807 | "type": "library", 1808 | "extra": { 1809 | "branch-alias": { 1810 | "dev-master": "4.0-dev" 1811 | } 1812 | }, 1813 | "autoload": { 1814 | "classmap": [ 1815 | "src/" 1816 | ] 1817 | }, 1818 | "notification-url": "https://packagist.org/downloads/", 1819 | "license": [ 1820 | "BSD-3-Clause" 1821 | ], 1822 | "authors": [ 1823 | { 1824 | "name": "Sebastian Bergmann", 1825 | "email": "sebastian@phpunit.de" 1826 | }, 1827 | { 1828 | "name": "Jeff Welch", 1829 | "email": "whatthejeff@gmail.com" 1830 | }, 1831 | { 1832 | "name": "Adam Harvey", 1833 | "email": "aharvey@php.net" 1834 | } 1835 | ], 1836 | "description": "Provides functionality to recursively process PHP variables", 1837 | "homepage": "https://github.com/sebastianbergmann/recursion-context", 1838 | "support": { 1839 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues", 1840 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6" 1841 | }, 1842 | "funding": [ 1843 | { 1844 | "url": "https://github.com/sebastianbergmann", 1845 | "type": "github" 1846 | }, 1847 | { 1848 | "url": "https://liberapay.com/sebastianbergmann", 1849 | "type": "liberapay" 1850 | }, 1851 | { 1852 | "url": "https://thanks.dev/u/gh/sebastianbergmann", 1853 | "type": "thanks_dev" 1854 | }, 1855 | { 1856 | "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", 1857 | "type": "tidelift" 1858 | } 1859 | ], 1860 | "time": "2025-08-10T06:57:39+00:00" 1861 | }, 1862 | { 1863 | "name": "sebastian/resource-operations", 1864 | "version": "3.0.4", 1865 | "source": { 1866 | "type": "git", 1867 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1868 | "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" 1869 | }, 1870 | "dist": { 1871 | "type": "zip", 1872 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", 1873 | "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", 1874 | "shasum": "" 1875 | }, 1876 | "require": { 1877 | "php": ">=7.3" 1878 | }, 1879 | "require-dev": { 1880 | "phpunit/phpunit": "^9.0" 1881 | }, 1882 | "type": "library", 1883 | "extra": { 1884 | "branch-alias": { 1885 | "dev-main": "3.0-dev" 1886 | } 1887 | }, 1888 | "autoload": { 1889 | "classmap": [ 1890 | "src/" 1891 | ] 1892 | }, 1893 | "notification-url": "https://packagist.org/downloads/", 1894 | "license": [ 1895 | "BSD-3-Clause" 1896 | ], 1897 | "authors": [ 1898 | { 1899 | "name": "Sebastian Bergmann", 1900 | "email": "sebastian@phpunit.de" 1901 | } 1902 | ], 1903 | "description": "Provides a list of PHP built-in functions that operate on resources", 1904 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1905 | "support": { 1906 | "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" 1907 | }, 1908 | "funding": [ 1909 | { 1910 | "url": "https://github.com/sebastianbergmann", 1911 | "type": "github" 1912 | } 1913 | ], 1914 | "time": "2024-03-14T16:00:52+00:00" 1915 | }, 1916 | { 1917 | "name": "sebastian/type", 1918 | "version": "3.2.1", 1919 | "source": { 1920 | "type": "git", 1921 | "url": "https://github.com/sebastianbergmann/type.git", 1922 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" 1923 | }, 1924 | "dist": { 1925 | "type": "zip", 1926 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", 1927 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", 1928 | "shasum": "" 1929 | }, 1930 | "require": { 1931 | "php": ">=7.3" 1932 | }, 1933 | "require-dev": { 1934 | "phpunit/phpunit": "^9.5" 1935 | }, 1936 | "type": "library", 1937 | "extra": { 1938 | "branch-alias": { 1939 | "dev-master": "3.2-dev" 1940 | } 1941 | }, 1942 | "autoload": { 1943 | "classmap": [ 1944 | "src/" 1945 | ] 1946 | }, 1947 | "notification-url": "https://packagist.org/downloads/", 1948 | "license": [ 1949 | "BSD-3-Clause" 1950 | ], 1951 | "authors": [ 1952 | { 1953 | "name": "Sebastian Bergmann", 1954 | "email": "sebastian@phpunit.de", 1955 | "role": "lead" 1956 | } 1957 | ], 1958 | "description": "Collection of value objects that represent the types of the PHP type system", 1959 | "homepage": "https://github.com/sebastianbergmann/type", 1960 | "support": { 1961 | "issues": "https://github.com/sebastianbergmann/type/issues", 1962 | "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" 1963 | }, 1964 | "funding": [ 1965 | { 1966 | "url": "https://github.com/sebastianbergmann", 1967 | "type": "github" 1968 | } 1969 | ], 1970 | "time": "2023-02-03T06:13:03+00:00" 1971 | }, 1972 | { 1973 | "name": "sebastian/version", 1974 | "version": "3.0.2", 1975 | "source": { 1976 | "type": "git", 1977 | "url": "https://github.com/sebastianbergmann/version.git", 1978 | "reference": "c6c1022351a901512170118436c764e473f6de8c" 1979 | }, 1980 | "dist": { 1981 | "type": "zip", 1982 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", 1983 | "reference": "c6c1022351a901512170118436c764e473f6de8c", 1984 | "shasum": "" 1985 | }, 1986 | "require": { 1987 | "php": ">=7.3" 1988 | }, 1989 | "type": "library", 1990 | "extra": { 1991 | "branch-alias": { 1992 | "dev-master": "3.0-dev" 1993 | } 1994 | }, 1995 | "autoload": { 1996 | "classmap": [ 1997 | "src/" 1998 | ] 1999 | }, 2000 | "notification-url": "https://packagist.org/downloads/", 2001 | "license": [ 2002 | "BSD-3-Clause" 2003 | ], 2004 | "authors": [ 2005 | { 2006 | "name": "Sebastian Bergmann", 2007 | "email": "sebastian@phpunit.de", 2008 | "role": "lead" 2009 | } 2010 | ], 2011 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 2012 | "homepage": "https://github.com/sebastianbergmann/version", 2013 | "support": { 2014 | "issues": "https://github.com/sebastianbergmann/version/issues", 2015 | "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" 2016 | }, 2017 | "funding": [ 2018 | { 2019 | "url": "https://github.com/sebastianbergmann", 2020 | "type": "github" 2021 | } 2022 | ], 2023 | "time": "2020-09-28T06:39:44+00:00" 2024 | }, 2025 | { 2026 | "name": "squizlabs/php_codesniffer", 2027 | "version": "3.13.4", 2028 | "source": { 2029 | "type": "git", 2030 | "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", 2031 | "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119" 2032 | }, 2033 | "dist": { 2034 | "type": "zip", 2035 | "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ad545ea9c1b7d270ce0fc9cbfb884161cd706119", 2036 | "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119", 2037 | "shasum": "" 2038 | }, 2039 | "require": { 2040 | "ext-simplexml": "*", 2041 | "ext-tokenizer": "*", 2042 | "ext-xmlwriter": "*", 2043 | "php": ">=5.4.0" 2044 | }, 2045 | "require-dev": { 2046 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" 2047 | }, 2048 | "bin": [ 2049 | "bin/phpcbf", 2050 | "bin/phpcs" 2051 | ], 2052 | "type": "library", 2053 | "extra": { 2054 | "branch-alias": { 2055 | "dev-master": "3.x-dev" 2056 | } 2057 | }, 2058 | "notification-url": "https://packagist.org/downloads/", 2059 | "license": [ 2060 | "BSD-3-Clause" 2061 | ], 2062 | "authors": [ 2063 | { 2064 | "name": "Greg Sherwood", 2065 | "role": "Former lead" 2066 | }, 2067 | { 2068 | "name": "Juliette Reinders Folmer", 2069 | "role": "Current lead" 2070 | }, 2071 | { 2072 | "name": "Contributors", 2073 | "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" 2074 | } 2075 | ], 2076 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 2077 | "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", 2078 | "keywords": [ 2079 | "phpcs", 2080 | "standards", 2081 | "static analysis" 2082 | ], 2083 | "support": { 2084 | "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", 2085 | "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", 2086 | "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", 2087 | "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" 2088 | }, 2089 | "funding": [ 2090 | { 2091 | "url": "https://github.com/PHPCSStandards", 2092 | "type": "github" 2093 | }, 2094 | { 2095 | "url": "https://github.com/jrfnl", 2096 | "type": "github" 2097 | }, 2098 | { 2099 | "url": "https://opencollective.com/php_codesniffer", 2100 | "type": "open_collective" 2101 | }, 2102 | { 2103 | "url": "https://thanks.dev/u/gh/phpcsstandards", 2104 | "type": "thanks_dev" 2105 | } 2106 | ], 2107 | "time": "2025-09-05T05:47:09+00:00" 2108 | }, 2109 | { 2110 | "name": "swoole/ide-helper", 2111 | "version": "4.8.8", 2112 | "source": { 2113 | "type": "git", 2114 | "url": "https://github.com/swoole/ide-helper.git", 2115 | "reference": "dd87843a5040831f9ad40b68fb57879b7342ef61" 2116 | }, 2117 | "dist": { 2118 | "type": "zip", 2119 | "url": "https://api.github.com/repos/swoole/ide-helper/zipball/dd87843a5040831f9ad40b68fb57879b7342ef61", 2120 | "reference": "dd87843a5040831f9ad40b68fb57879b7342ef61", 2121 | "shasum": "" 2122 | }, 2123 | "type": "library", 2124 | "notification-url": "https://packagist.org/downloads/", 2125 | "license": [ 2126 | "Apache-2.0" 2127 | ], 2128 | "authors": [ 2129 | { 2130 | "name": "Team Swoole", 2131 | "email": "team@swoole.com" 2132 | } 2133 | ], 2134 | "description": "IDE help files for Swoole.", 2135 | "support": { 2136 | "issues": "https://github.com/swoole/ide-helper/issues", 2137 | "source": "https://github.com/swoole/ide-helper/tree/4.8.8" 2138 | }, 2139 | "funding": [ 2140 | { 2141 | "url": "https://gitee.com/swoole/swoole?donate=true", 2142 | "type": "custom" 2143 | }, 2144 | { 2145 | "url": "https://github.com/swoole", 2146 | "type": "github" 2147 | } 2148 | ], 2149 | "time": "2022-03-17T18:24:39+00:00" 2150 | }, 2151 | { 2152 | "name": "theseer/tokenizer", 2153 | "version": "1.2.3", 2154 | "source": { 2155 | "type": "git", 2156 | "url": "https://github.com/theseer/tokenizer.git", 2157 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" 2158 | }, 2159 | "dist": { 2160 | "type": "zip", 2161 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", 2162 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", 2163 | "shasum": "" 2164 | }, 2165 | "require": { 2166 | "ext-dom": "*", 2167 | "ext-tokenizer": "*", 2168 | "ext-xmlwriter": "*", 2169 | "php": "^7.2 || ^8.0" 2170 | }, 2171 | "type": "library", 2172 | "autoload": { 2173 | "classmap": [ 2174 | "src/" 2175 | ] 2176 | }, 2177 | "notification-url": "https://packagist.org/downloads/", 2178 | "license": [ 2179 | "BSD-3-Clause" 2180 | ], 2181 | "authors": [ 2182 | { 2183 | "name": "Arne Blankerts", 2184 | "email": "arne@blankerts.de", 2185 | "role": "Developer" 2186 | } 2187 | ], 2188 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 2189 | "support": { 2190 | "issues": "https://github.com/theseer/tokenizer/issues", 2191 | "source": "https://github.com/theseer/tokenizer/tree/1.2.3" 2192 | }, 2193 | "funding": [ 2194 | { 2195 | "url": "https://github.com/theseer", 2196 | "type": "github" 2197 | } 2198 | ], 2199 | "time": "2024-03-03T12:36:25+00:00" 2200 | }, 2201 | { 2202 | "name": "utopia-php/console", 2203 | "version": "0.0.1", 2204 | "source": { 2205 | "type": "git", 2206 | "url": "https://github.com/utopia-php/console.git", 2207 | "reference": "f77104e4a888fa9cb3e08f32955ec09479ab7a92" 2208 | }, 2209 | "dist": { 2210 | "type": "zip", 2211 | "url": "https://api.github.com/repos/utopia-php/console/zipball/f77104e4a888fa9cb3e08f32955ec09479ab7a92", 2212 | "reference": "f77104e4a888fa9cb3e08f32955ec09479ab7a92", 2213 | "shasum": "" 2214 | }, 2215 | "require": { 2216 | "php": ">=7.4" 2217 | }, 2218 | "require-dev": { 2219 | "laravel/pint": "1.2.*", 2220 | "phpstan/phpstan": "^1.10", 2221 | "phpunit/phpunit": "^9.3", 2222 | "squizlabs/php_codesniffer": "^3.6", 2223 | "swoole/ide-helper": "4.8.8" 2224 | }, 2225 | "type": "library", 2226 | "autoload": { 2227 | "psr-4": { 2228 | "Utopia\\": "src/" 2229 | } 2230 | }, 2231 | "notification-url": "https://packagist.org/downloads/", 2232 | "license": [ 2233 | "MIT" 2234 | ], 2235 | "description": "Console helpers for logging, prompting, and executing commands", 2236 | "keywords": [ 2237 | "cli", 2238 | "console", 2239 | "php", 2240 | "terminal", 2241 | "utopia" 2242 | ], 2243 | "support": { 2244 | "issues": "https://github.com/utopia-php/console/issues", 2245 | "source": "https://github.com/utopia-php/console/tree/0.0.1" 2246 | }, 2247 | "time": "2025-10-20T14:41:36+00:00" 2248 | } 2249 | ], 2250 | "aliases": [], 2251 | "minimum-stability": "stable", 2252 | "stability-flags": {}, 2253 | "prefer-stable": false, 2254 | "prefer-lowest": false, 2255 | "platform": { 2256 | "php": ">=7.4" 2257 | }, 2258 | "platform-dev": {}, 2259 | "plugin-api-version": "2.6.0" 2260 | } 2261 | --------------------------------------------------------------------------------